Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 98ac769b29 | |||
| e73793dd6e | |||
| e680032d0e |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -971,7 +971,7 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "owlry"
|
||||
version = "0.1.9"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "owlry"
|
||||
version = "0.1.9"
|
||||
version = "0.2.1"
|
||||
edition = "2024"
|
||||
rust-version = "1.90"
|
||||
description = "A lightweight, owl-themed application launcher for Wayland"
|
||||
|
||||
@@ -48,3 +48,9 @@ calculator = true
|
||||
# Frecency: boost frequently/recently used items in search results
|
||||
frecency = true
|
||||
frecency_weight = 0.3 # 0.0 = disabled, 1.0 = strong boost
|
||||
|
||||
# Web search provider (type "? query" or "web query")
|
||||
websearch = true
|
||||
# Options: google, duckduckgo, bing, startpage, searxng, brave, ecosia
|
||||
# Or custom URL with {query} placeholder, e.g. "https://search.example.com/?q={query}"
|
||||
search_engine = "duckduckgo"
|
||||
|
||||
@@ -126,6 +126,11 @@
|
||||
color: var(--owlry-badge-uuctl, @orange_3);
|
||||
}
|
||||
|
||||
.owlry-badge-web {
|
||||
background-color: alpha(var(--owlry-badge-web, @teal_3), 0.2);
|
||||
color: var(--owlry-badge-web, @teal_3);
|
||||
}
|
||||
|
||||
/* Header bar */
|
||||
.owlry-header {
|
||||
margin-bottom: 4px;
|
||||
@@ -195,6 +200,12 @@
|
||||
border-color: alpha(var(--owlry-badge-dmenu, @green_3), 0.4);
|
||||
}
|
||||
|
||||
.owlry-filter-web:checked {
|
||||
background-color: alpha(var(--owlry-badge-web, @teal_3), 0.2);
|
||||
color: var(--owlry-badge-web, @teal_3);
|
||||
border-color: alpha(var(--owlry-badge-web, @teal_3), 0.4);
|
||||
}
|
||||
|
||||
/* Hints bar at bottom */
|
||||
.owlry-hints {
|
||||
padding-top: 8px;
|
||||
|
||||
@@ -40,7 +40,8 @@ impl OwlryApp {
|
||||
debug!("Activating Owlry");
|
||||
|
||||
let config = Rc::new(RefCell::new(Config::load_or_default()));
|
||||
let providers = Rc::new(RefCell::new(ProviderManager::new()));
|
||||
let search_engine = config.borrow().providers.search_engine.clone();
|
||||
let providers = Rc::new(RefCell::new(ProviderManager::with_search_engine(&search_engine)));
|
||||
let frecency = Rc::new(RefCell::new(FrecencyStore::load_or_default()));
|
||||
|
||||
// Create filter from CLI args and config
|
||||
|
||||
@@ -39,6 +39,7 @@ pub struct ThemeColors {
|
||||
pub badge_cmd: Option<String>,
|
||||
pub badge_dmenu: Option<String>,
|
||||
pub badge_uuctl: Option<String>,
|
||||
pub badge_web: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -69,6 +70,18 @@ pub struct ProvidersConfig {
|
||||
/// Weight for frecency boost (0.0 = disabled, 1.0 = strong boost)
|
||||
#[serde(default = "default_frecency_weight")]
|
||||
pub frecency_weight: f64,
|
||||
/// Enable web search provider (? query or web query)
|
||||
#[serde(default = "default_true")]
|
||||
pub websearch: bool,
|
||||
/// Search engine for web search
|
||||
/// Options: google, duckduckgo, bing, startpage, searxng, brave, ecosia
|
||||
/// Or custom URL with {query} placeholder
|
||||
#[serde(default = "default_search_engine")]
|
||||
pub search_engine: String,
|
||||
}
|
||||
|
||||
fn default_search_engine() -> String {
|
||||
"duckduckgo".to_string()
|
||||
}
|
||||
|
||||
fn default_true() -> bool {
|
||||
@@ -193,6 +206,8 @@ impl Default for Config {
|
||||
calculator: true,
|
||||
frecency: true,
|
||||
frecency_weight: 0.3,
|
||||
websearch: true,
|
||||
search_engine: "duckduckgo".to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,8 @@ impl ProviderFilter {
|
||||
(":cmd ", ProviderType::Command),
|
||||
(":command ", ProviderType::Command),
|
||||
(":uuctl ", ProviderType::Uuctl),
|
||||
(":web ", ProviderType::WebSearch),
|
||||
(":search ", ProviderType::WebSearch),
|
||||
];
|
||||
|
||||
for (prefix_str, provider) in prefixes {
|
||||
@@ -154,6 +156,8 @@ impl ProviderFilter {
|
||||
(":cmd", ProviderType::Command),
|
||||
(":command", ProviderType::Command),
|
||||
(":uuctl", ProviderType::Uuctl),
|
||||
(":web", ProviderType::WebSearch),
|
||||
(":search", ProviderType::WebSearch),
|
||||
];
|
||||
|
||||
for (prefix_str, provider) in partial_prefixes {
|
||||
@@ -179,7 +183,8 @@ impl ProviderFilter {
|
||||
ProviderType::Calculator => 1,
|
||||
ProviderType::Command => 2,
|
||||
ProviderType::Uuctl => 3,
|
||||
ProviderType::Dmenu => 4,
|
||||
ProviderType::WebSearch => 4,
|
||||
ProviderType::Dmenu => 5,
|
||||
});
|
||||
providers
|
||||
}
|
||||
@@ -192,6 +197,7 @@ impl ProviderFilter {
|
||||
ProviderType::Calculator => "Calc",
|
||||
ProviderType::Command => "Commands",
|
||||
ProviderType::Uuctl => "uuctl",
|
||||
ProviderType::WebSearch => "Web",
|
||||
ProviderType::Dmenu => "dmenu",
|
||||
};
|
||||
}
|
||||
@@ -203,6 +209,7 @@ impl ProviderFilter {
|
||||
ProviderType::Calculator => "Calc",
|
||||
ProviderType::Command => "Commands",
|
||||
ProviderType::Uuctl => "uuctl",
|
||||
ProviderType::WebSearch => "Web",
|
||||
ProviderType::Dmenu => "dmenu",
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -18,14 +18,17 @@ impl CalculatorProvider {
|
||||
/// Check if a query is a calculator expression
|
||||
pub fn is_calculator_query(query: &str) -> bool {
|
||||
let trimmed = query.trim();
|
||||
trimmed.starts_with("= ") || trimmed.starts_with("calc ")
|
||||
trimmed.starts_with("=") || trimmed.starts_with("calc ")
|
||||
}
|
||||
|
||||
/// Extract the expression from a calculator query
|
||||
fn extract_expression(query: &str) -> Option<&str> {
|
||||
let trimmed = query.trim();
|
||||
// Support both "= expr" and "=expr" (with or without space)
|
||||
if let Some(expr) = trimmed.strip_prefix("= ") {
|
||||
Some(expr.trim())
|
||||
} else if let Some(expr) = trimmed.strip_prefix("=") {
|
||||
Some(expr.trim())
|
||||
} else if let Some(expr) = trimmed.strip_prefix("calc ") {
|
||||
Some(expr.trim())
|
||||
} else {
|
||||
@@ -33,6 +36,49 @@ impl CalculatorProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if string looks like a math expression (for :calc mode)
|
||||
pub fn looks_like_expression(query: &str) -> bool {
|
||||
let trimmed = query.trim();
|
||||
if trimmed.is_empty() {
|
||||
return false;
|
||||
}
|
||||
// Contains math operators or is a number
|
||||
trimmed.chars().any(|c| "+-*/^()".contains(c))
|
||||
|| trimmed.parse::<f64>().is_ok()
|
||||
|| ["pi", "e", "sqrt", "sin", "cos", "tan", "abs", "ln", "log"]
|
||||
.iter()
|
||||
.any(|f| trimmed.to_lowercase().contains(f))
|
||||
}
|
||||
|
||||
/// Evaluate a raw expression (for :calc filter mode)
|
||||
pub fn evaluate_raw(&mut self, expr: &str) -> Option<LaunchItem> {
|
||||
let trimmed = expr.trim();
|
||||
if trimmed.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match meval::eval_str(trimmed) {
|
||||
Ok(result) => {
|
||||
let result_str = if result.fract() == 0.0 && result.abs() < 1e15 {
|
||||
format!("{}", result as i64)
|
||||
} else {
|
||||
format!("{:.10}", result).trim_end_matches('0').trim_end_matches('.').to_string()
|
||||
};
|
||||
|
||||
Some(LaunchItem {
|
||||
id: format!("calc:{}", trimmed),
|
||||
name: format!("{} = {}", trimmed, result_str),
|
||||
description: Some("Press Enter to copy result".to_string()),
|
||||
icon: Some("accessories-calculator".to_string()),
|
||||
provider: ProviderType::Calculator,
|
||||
command: format!("echo -n '{}' | wl-copy", result_str),
|
||||
terminal: false,
|
||||
})
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluate an expression and return a LaunchItem result
|
||||
pub fn evaluate(&mut self, query: &str) -> Option<LaunchItem> {
|
||||
let expr = Self::extract_expression(query)?;
|
||||
|
||||
@@ -3,12 +3,14 @@ mod calculator;
|
||||
mod command;
|
||||
mod dmenu;
|
||||
mod uuctl;
|
||||
mod websearch;
|
||||
|
||||
pub use application::ApplicationProvider;
|
||||
pub use calculator::CalculatorProvider;
|
||||
pub use command::CommandProvider;
|
||||
pub use dmenu::DmenuProvider;
|
||||
pub use uuctl::UuctlProvider;
|
||||
pub use websearch::WebSearchProvider;
|
||||
|
||||
use fuzzy_matcher::FuzzyMatcher;
|
||||
use fuzzy_matcher::skim::SkimMatcherV2;
|
||||
@@ -36,6 +38,7 @@ pub enum ProviderType {
|
||||
Command,
|
||||
Dmenu,
|
||||
Uuctl,
|
||||
WebSearch,
|
||||
}
|
||||
|
||||
impl std::str::FromStr for ProviderType {
|
||||
@@ -48,6 +51,7 @@ impl std::str::FromStr for ProviderType {
|
||||
"cmd" | "command" | "commands" => Ok(ProviderType::Command),
|
||||
"uuctl" => Ok(ProviderType::Uuctl),
|
||||
"dmenu" => Ok(ProviderType::Dmenu),
|
||||
"web" | "websearch" | "search" => Ok(ProviderType::WebSearch),
|
||||
_ => Err(format!(
|
||||
"Unknown provider: '{}'. Valid: app, calc, cmd, uuctl",
|
||||
s
|
||||
@@ -64,6 +68,7 @@ impl std::fmt::Display for ProviderType {
|
||||
ProviderType::Command => write!(f, "cmd"),
|
||||
ProviderType::Dmenu => write!(f, "dmenu"),
|
||||
ProviderType::Uuctl => write!(f, "uuctl"),
|
||||
ProviderType::WebSearch => write!(f, "web"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,14 +86,21 @@ pub trait Provider: Send {
|
||||
pub struct ProviderManager {
|
||||
providers: Vec<Box<dyn Provider>>,
|
||||
calculator: CalculatorProvider,
|
||||
websearch: WebSearchProvider,
|
||||
matcher: SkimMatcherV2,
|
||||
}
|
||||
|
||||
impl ProviderManager {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Self {
|
||||
Self::with_search_engine("duckduckgo")
|
||||
}
|
||||
|
||||
pub fn with_search_engine(search_engine: &str) -> Self {
|
||||
let mut manager = Self {
|
||||
providers: Vec::new(),
|
||||
calculator: CalculatorProvider::new(),
|
||||
websearch: WebSearchProvider::with_engine(search_engine),
|
||||
matcher: SkimMatcherV2::default(),
|
||||
};
|
||||
|
||||
@@ -229,15 +241,37 @@ impl ProviderManager {
|
||||
) -> Vec<(LaunchItem, i64)> {
|
||||
let mut results: Vec<(LaunchItem, i64)> = Vec::new();
|
||||
|
||||
// Check for calculator query first
|
||||
// Check for calculator query (= or calc prefix)
|
||||
if CalculatorProvider::is_calculator_query(query) {
|
||||
if let Some(calc_result) = self.calculator.evaluate(query) {
|
||||
// Calculator results get a high score to appear first
|
||||
results.push((calc_result, 10000));
|
||||
}
|
||||
}
|
||||
// Also check for raw expression when in :calc filter mode
|
||||
else if filter.active_prefix() == Some(ProviderType::Calculator)
|
||||
&& CalculatorProvider::looks_like_expression(query)
|
||||
{
|
||||
if let Some(calc_result) = self.calculator.evaluate_raw(query) {
|
||||
results.push((calc_result, 10000));
|
||||
}
|
||||
}
|
||||
|
||||
// Empty query (after checking calculator) - return frecency-sorted items
|
||||
// Check for web search query
|
||||
if WebSearchProvider::is_websearch_query(query) {
|
||||
if let Some(web_result) = self.websearch.evaluate(query) {
|
||||
// Web search results get a high score to appear first
|
||||
results.push((web_result, 9000));
|
||||
}
|
||||
}
|
||||
// Also check for raw query when in :web filter mode
|
||||
else if filter.active_prefix() == Some(ProviderType::WebSearch) && !query.is_empty() {
|
||||
if let Some(web_result) = self.websearch.evaluate_raw(query) {
|
||||
results.push((web_result, 9000));
|
||||
}
|
||||
}
|
||||
|
||||
// Empty query (after checking special providers) - return frecency-sorted items
|
||||
if query.is_empty() {
|
||||
let mut items: Vec<(LaunchItem, i64)> = self
|
||||
.providers
|
||||
|
||||
195
src/providers/websearch.rs
Normal file
195
src/providers/websearch.rs
Normal file
@@ -0,0 +1,195 @@
|
||||
use crate::providers::{LaunchItem, ProviderType};
|
||||
|
||||
/// Common search engine URL templates
|
||||
/// {query} is replaced with the URL-encoded search term
|
||||
pub const SEARCH_ENGINES: &[(&str, &str)] = &[
|
||||
("google", "https://www.google.com/search?q={query}"),
|
||||
("duckduckgo", "https://duckduckgo.com/?q={query}"),
|
||||
("bing", "https://www.bing.com/search?q={query}"),
|
||||
("startpage", "https://www.startpage.com/search?q={query}"),
|
||||
("searxng", "https://searx.be/search?q={query}"),
|
||||
("brave", "https://search.brave.com/search?q={query}"),
|
||||
("ecosia", "https://www.ecosia.org/search?q={query}"),
|
||||
];
|
||||
|
||||
/// Default search engine if not configured
|
||||
pub const DEFAULT_ENGINE: &str = "duckduckgo";
|
||||
|
||||
/// Web search provider - opens browser with search query
|
||||
pub struct WebSearchProvider {
|
||||
/// URL template with {query} placeholder
|
||||
url_template: String,
|
||||
}
|
||||
|
||||
impl WebSearchProvider {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Self {
|
||||
Self::with_engine(DEFAULT_ENGINE)
|
||||
}
|
||||
|
||||
/// Create provider with specific search engine
|
||||
pub fn with_engine(engine_name: &str) -> Self {
|
||||
let url_template = SEARCH_ENGINES
|
||||
.iter()
|
||||
.find(|(name, _)| *name == engine_name.to_lowercase())
|
||||
.map(|(_, url)| url.to_string())
|
||||
.unwrap_or_else(|| {
|
||||
// If not a known engine, treat it as a custom URL template
|
||||
if engine_name.contains("{query}") {
|
||||
engine_name.to_string()
|
||||
} else {
|
||||
// Fall back to default
|
||||
SEARCH_ENGINES
|
||||
.iter()
|
||||
.find(|(name, _)| *name == DEFAULT_ENGINE)
|
||||
.map(|(_, url)| url.to_string())
|
||||
.unwrap()
|
||||
}
|
||||
});
|
||||
|
||||
Self { url_template }
|
||||
}
|
||||
|
||||
/// Check if query is a web search query
|
||||
/// Triggers on: `? query`, `web query`, `search query`
|
||||
pub fn is_websearch_query(query: &str) -> bool {
|
||||
let trimmed = query.trim();
|
||||
trimmed.starts_with("? ")
|
||||
|| trimmed.starts_with("?")
|
||||
|| trimmed.to_lowercase().starts_with("web ")
|
||||
|| trimmed.to_lowercase().starts_with("search ")
|
||||
}
|
||||
|
||||
/// Extract the search term from the query
|
||||
fn extract_search_term(query: &str) -> Option<&str> {
|
||||
let trimmed = query.trim();
|
||||
|
||||
if let Some(rest) = trimmed.strip_prefix("? ") {
|
||||
Some(rest.trim())
|
||||
} else if let Some(rest) = trimmed.strip_prefix("?") {
|
||||
Some(rest.trim())
|
||||
} else if trimmed.to_lowercase().starts_with("web ") {
|
||||
// Need to get the original casing
|
||||
Some(trimmed[4..].trim())
|
||||
} else if trimmed.to_lowercase().starts_with("search ") {
|
||||
Some(trimmed[7..].trim())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// URL-encode a search query
|
||||
fn url_encode(query: &str) -> String {
|
||||
// TODO: This is where you can implement the URL encoding logic!
|
||||
// Consider: Should we use a crate like `urlencoding` or implement manually?
|
||||
// Manual encoding needs to handle: spaces, &, =, ?, #, etc.
|
||||
query
|
||||
.chars()
|
||||
.map(|c| match c {
|
||||
' ' => "+".to_string(),
|
||||
'&' => "%26".to_string(),
|
||||
'=' => "%3D".to_string(),
|
||||
'?' => "%3F".to_string(),
|
||||
'#' => "%23".to_string(),
|
||||
'+' => "%2B".to_string(),
|
||||
'%' => "%25".to_string(),
|
||||
c if c.is_ascii_alphanumeric() || "-_.~".contains(c) => c.to_string(),
|
||||
c => format!("%{:02X}", c as u32),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Build the search URL from a query
|
||||
fn build_search_url(&self, search_term: &str) -> String {
|
||||
let encoded = Self::url_encode(search_term);
|
||||
self.url_template.replace("{query}", &encoded)
|
||||
}
|
||||
|
||||
/// Evaluate a web search query and return a LaunchItem if valid
|
||||
pub fn evaluate(&self, query: &str) -> Option<LaunchItem> {
|
||||
let search_term = Self::extract_search_term(query)?;
|
||||
|
||||
if search_term.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.evaluate_raw(search_term)
|
||||
}
|
||||
|
||||
/// Evaluate a raw search term (for :web filter mode)
|
||||
pub fn evaluate_raw(&self, search_term: &str) -> Option<LaunchItem> {
|
||||
let trimmed = search_term.trim();
|
||||
if trimmed.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let url = self.build_search_url(trimmed);
|
||||
|
||||
// Use xdg-open to open the browser
|
||||
let command = format!("xdg-open '{}'", url);
|
||||
|
||||
Some(LaunchItem {
|
||||
id: format!("websearch:{}", trimmed),
|
||||
name: format!("Search: {}", trimmed),
|
||||
description: Some("Open in browser".to_string()),
|
||||
icon: Some("web-browser".to_string()),
|
||||
provider: ProviderType::WebSearch,
|
||||
command,
|
||||
terminal: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_is_websearch_query() {
|
||||
assert!(WebSearchProvider::is_websearch_query("? rust programming"));
|
||||
assert!(WebSearchProvider::is_websearch_query("?rust"));
|
||||
assert!(WebSearchProvider::is_websearch_query("web rust"));
|
||||
assert!(WebSearchProvider::is_websearch_query("search rust"));
|
||||
assert!(!WebSearchProvider::is_websearch_query("rust"));
|
||||
assert!(!WebSearchProvider::is_websearch_query("= 5+3"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_search_term() {
|
||||
assert_eq!(
|
||||
WebSearchProvider::extract_search_term("? rust programming"),
|
||||
Some("rust programming")
|
||||
);
|
||||
assert_eq!(
|
||||
WebSearchProvider::extract_search_term("?rust"),
|
||||
Some("rust")
|
||||
);
|
||||
assert_eq!(
|
||||
WebSearchProvider::extract_search_term("web rust docs"),
|
||||
Some("rust docs")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_url_encode() {
|
||||
assert_eq!(WebSearchProvider::url_encode("hello world"), "hello+world");
|
||||
assert_eq!(WebSearchProvider::url_encode("foo&bar"), "foo%26bar");
|
||||
assert_eq!(WebSearchProvider::url_encode("a=b"), "a%3Db");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_search_url() {
|
||||
let provider = WebSearchProvider::with_engine("duckduckgo");
|
||||
let url = provider.build_search_url("rust programming");
|
||||
assert_eq!(url, "https://duckduckgo.com/?q=rust+programming");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_evaluate() {
|
||||
let provider = WebSearchProvider::new();
|
||||
let item = provider.evaluate("? rust docs").unwrap();
|
||||
assert_eq!(item.name, "Search: rust docs");
|
||||
assert!(item.command.contains("xdg-open"));
|
||||
assert!(item.command.contains("duckduckgo"));
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,9 @@ pub fn generate_variables_css(config: &AppearanceConfig) -> String {
|
||||
if let Some(ref badge_uuctl) = config.colors.badge_uuctl {
|
||||
css.push_str(&format!(" --owlry-badge-uuctl: {};\n", badge_uuctl));
|
||||
}
|
||||
if let Some(ref badge_web) = config.colors.badge_web {
|
||||
css.push_str(&format!(" --owlry-badge-web: {};\n", badge_web));
|
||||
}
|
||||
|
||||
css.push_str("}\n");
|
||||
css
|
||||
|
||||
@@ -143,7 +143,7 @@ impl MainWindow {
|
||||
hints_box.add_css_class("owlry-hints");
|
||||
|
||||
let hints_label = Label::builder()
|
||||
.label("Tab: cycle mode ↑↓: navigate Enter: launch Esc: close = calc :app :cmd :uuctl")
|
||||
.label("Tab: cycle mode ↑↓: navigate Enter: launch Esc: close = calc ? web :app :cmd")
|
||||
.halign(gtk4::Align::Center)
|
||||
.hexpand(true)
|
||||
.build();
|
||||
@@ -209,6 +209,7 @@ impl MainWindow {
|
||||
ProviderType::Calculator => "owlry-filter-calc",
|
||||
ProviderType::Command => "owlry-filter-cmd",
|
||||
ProviderType::Uuctl => "owlry-filter-uuctl",
|
||||
ProviderType::WebSearch => "owlry-filter-web",
|
||||
ProviderType::Dmenu => "owlry-filter-dmenu",
|
||||
};
|
||||
button.add_css_class(css_class);
|
||||
@@ -229,6 +230,7 @@ impl MainWindow {
|
||||
ProviderType::Calculator => "calculator",
|
||||
ProviderType::Command => "commands",
|
||||
ProviderType::Uuctl => "uuctl units",
|
||||
ProviderType::WebSearch => "web",
|
||||
ProviderType::Dmenu => "options",
|
||||
})
|
||||
.collect();
|
||||
@@ -334,7 +336,7 @@ impl MainWindow {
|
||||
|
||||
// Restore UI
|
||||
mode_label.set_label(filter.borrow().mode_display_name());
|
||||
hints_label.set_label("Tab: cycle mode ↑↓: navigate Enter: launch Esc: close = calc :app :cmd :uuctl");
|
||||
hints_label.set_label("Tab: cycle mode ↑↓: navigate Enter: launch Esc: close = calc ? web :app :cmd");
|
||||
search_entry.set_placeholder_text(Some(&Self::build_placeholder(&filter.borrow())));
|
||||
search_entry.set_text(&saved_search);
|
||||
|
||||
@@ -411,6 +413,7 @@ impl MainWindow {
|
||||
ProviderType::Calculator => "calculator",
|
||||
ProviderType::Command => "commands",
|
||||
ProviderType::Uuctl => "uuctl units",
|
||||
ProviderType::WebSearch => "web",
|
||||
ProviderType::Dmenu => "options",
|
||||
};
|
||||
search_entry_for_change
|
||||
|
||||
@@ -36,6 +36,7 @@ impl ResultRow {
|
||||
crate::providers::ProviderType::Command => "utilities-terminal",
|
||||
crate::providers::ProviderType::Dmenu => "view-list-symbolic",
|
||||
crate::providers::ProviderType::Uuctl => "system-run",
|
||||
crate::providers::ProviderType::WebSearch => "web-browser",
|
||||
};
|
||||
Image::from_icon_name(default_icon)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user