Skip to content

Commit 15c0adc

Browse files
authored
Merge pull request #15 from unsecretised/shellcommands
Shellcommands are annoying...
2 parents 68ed09d + e96ba73 commit 15c0adc

4 files changed

Lines changed: 107 additions & 115 deletions

File tree

src/app.rs

Lines changed: 32 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,9 @@ use std::time::Duration;
2828
pub const WINDOW_WIDTH: f32 = 500.;
2929
pub const DEFAULT_WINDOW_HEIGHT: f32 = 65.;
3030

31-
#[allow(unused)]
3231
#[derive(Debug, Clone)]
3332
pub struct App {
34-
pub open_command: String,
33+
pub open_command: Vec<String>,
3534
pub icons: Option<iced::widget::image::Handle>,
3635
pub name: String,
3736
pub name_lc: String,
@@ -94,7 +93,7 @@ pub enum Message {
9493
SearchQueryChanged(String, Id),
9594
KeyPressed(u32),
9695
HideWindow(Id),
97-
RunShellCommand(String),
96+
RunShellCommand(Vec<String>),
9897
ClearSearchResults,
9998
WindowFocusChanged(Id, bool),
10099
ClearSearchQuery,
@@ -129,7 +128,6 @@ pub struct Tile {
129128
focused: bool,
130129
frontmost: Option<Retained<NSRunningApplication>>,
131130
config: Config,
132-
default_config: Config,
133131
open_hotkey_id: u32,
134132
}
135133

@@ -146,15 +144,7 @@ impl Tile {
146144
transform_process_to_ui_element();
147145
}));
148146

149-
// SHOULD NEVER HAVE NONE VALUES
150-
let default_config = Config::default();
151-
152-
let store_icons = config
153-
.theme
154-
.as_ref()
155-
.unwrap_or(default_config.theme.as_ref().unwrap())
156-
.show_icons
157-
.unwrap();
147+
let store_icons = config.theme.show_icons;
158148

159149
let user_local_path = std::env::var("HOME").unwrap() + "/Applications/";
160150

@@ -165,27 +155,27 @@ impl Tile {
165155
"/System/Applications/Utilities/",
166156
];
167157

168-
let mut apps: Vec<App> = paths
158+
let mut options: Vec<App> = paths
169159
.par_iter()
170160
.map(|path| get_installed_apps(path, store_icons))
171161
.flatten()
172162
.collect();
173163

174-
apps.par_sort_by_key(|x| x.name.len());
164+
options.par_sort_by_key(|x| x.name.len());
165+
options.extend(config.shells.iter().map(|x| x.to_app()));
175166

176167
(
177168
Self {
178169
query: String::new(),
179170
query_lc: String::new(),
180171
prev_query_lc: String::new(),
181172
results: vec![],
182-
options: apps,
173+
options,
183174
visible: true,
184175
frontmost: None,
185176
focused: false,
186177
config: config.clone(),
187-
default_config,
188-
theme: config.theme.to_owned().unwrap().to_iced_theme(),
178+
theme: config.theme.to_owned().to_iced_theme(),
189179
open_hotkey_id: keybind_id,
190180
},
191181
Task::batch([open.map(|_| Message::OpenWindow)]),
@@ -216,18 +206,12 @@ impl Tile {
216206
);
217207
} else if self.query_lc == "randomvar" {
218208
self.results = vec![App {
219-
open_command: "".to_string(),
209+
open_command: vec!["".to_string()],
220210
icons: None,
221211
name: rand::random_range(0..100).to_string(),
222212
name_lc: String::new(),
223213
}];
224-
return window::resize(
225-
id,
226-
iced::Size {
227-
width: WINDOW_WIDTH,
228-
height: DEFAULT_WINDOW_HEIGHT + 55.,
229-
},
230-
);
214+
return Task::none();
231215
}
232216

233217
self.handle_search_query_changed();
@@ -267,26 +251,11 @@ impl Tile {
267251
let to_close = window::latest().map(|x| x.unwrap());
268252
Task::batch([
269253
to_close.map(Message::HideWindow),
270-
Task::done(
271-
if self
272-
.config
273-
.buffer_rules
274-
.clone()
275-
.and_then(|x| x.clear_on_hide)
276-
.unwrap_or(
277-
self.default_config
278-
.buffer_rules
279-
.clone()
280-
.unwrap()
281-
.clear_on_hide
282-
.unwrap(),
283-
)
284-
{
285-
Message::ClearSearchQuery
286-
} else {
287-
Message::_Nothing
288-
},
289-
),
254+
Task::done(if self.config.buffer_rules.clone().clear_on_hide {
255+
Message::ClearSearchQuery
256+
} else {
257+
Message::_Nothing
258+
}),
290259
])
291260
}
292261
} else {
@@ -295,31 +264,20 @@ impl Tile {
295264
}
296265

297266
Message::RunShellCommand(shell_command) => {
298-
let cmd = shell_command.split_once(" ").unwrap_or(("", ""));
299-
Command::new(cmd.0).arg(cmd.1).spawn().ok();
300-
window::latest()
301-
.map(|x| x.unwrap())
302-
.map(Message::HideWindow)
303-
.chain({
304-
let buf_rules = self
305-
.config
306-
.buffer_rules
307-
.clone()
308-
.and_then(|x| x.clear_on_enter)
309-
.unwrap_or_else(|| {
310-
self.default_config
311-
.buffer_rules
312-
.clone()
313-
.unwrap()
314-
.clear_on_enter
315-
.unwrap()
316-
});
317-
if buf_rules {
318-
Task::done(Message::ClearSearchQuery)
319-
} else {
320-
Task::none()
321-
}
322-
})
267+
Command::new("sh")
268+
.arg("-c")
269+
.arg(shell_command.join(" "))
270+
.status()
271+
.ok();
272+
273+
if self.config.buffer_rules.clear_on_enter {
274+
window::latest()
275+
.map(|x| x.unwrap())
276+
.map(Message::HideWindow)
277+
.chain(Task::done(Message::ClearSearchQuery))
278+
} else {
279+
Task::none()
280+
}
323281
}
324282

325283
Message::HideWindow(a) => {
@@ -348,7 +306,7 @@ impl Tile {
348306

349307
pub fn view(&self, wid: window::Id) -> Element<'_, Message> {
350308
if self.visible {
351-
let title_input = text_input(self.config.placeholder.as_ref().unwrap(), &self.query)
309+
let title_input = text_input(self.config.placeholder.as_str(), &self.query)
352310
.on_input(move |a| Message::SearchQueryChanged(a, wid))
353311
.on_paste(move |a| Message::SearchQueryChanged(a, wid))
354312
.on_submit({
@@ -367,8 +325,8 @@ impl Tile {
367325

368326
let mut search_results = Column::new();
369327
for result in &self.results {
370-
search_results = search_results
371-
.push(result.render(self.config.theme.clone().unwrap().show_icons.unwrap()));
328+
search_results =
329+
search_results.push(result.render(self.config.theme.clone().show_icons));
372330
}
373331

374332
Column::new()

src/config.rs

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,68 @@
1-
use std::sync::Arc;
1+
use std::{path::Path, sync::Arc};
22

3-
use iced::theme::Custom;
3+
use iced::{theme::Custom, widget::image::Handle};
44
use serde::{Deserialize, Serialize};
55

6+
use crate::{app::App, utils::handle_from_icns};
7+
68
#[derive(Debug, Clone, Deserialize, Serialize)]
9+
#[serde(default)]
710
pub struct Config {
8-
pub toggle_mod: Option<String>,
9-
pub toggle_key: Option<String>,
10-
pub buffer_rules: Option<Buffer>,
11-
pub theme: Option<Theme>,
12-
pub placeholder: Option<String>,
11+
pub toggle_mod: String,
12+
pub toggle_key: String,
13+
pub buffer_rules: Buffer,
14+
pub theme: Theme,
15+
pub placeholder: String,
16+
pub shells: Vec<Shelly>,
1317
}
1418

1519
impl Default for Config {
1620
fn default() -> Self {
1721
Self {
18-
toggle_mod: Some("ALT".to_string()),
19-
toggle_key: Some("Space".to_string()),
20-
buffer_rules: Some(Buffer::default()),
21-
theme: Some(Theme::default()),
22-
placeholder: Some(String::from("Time to be productive!")),
22+
toggle_mod: "ALT".to_string(),
23+
toggle_key: "Space".to_string(),
24+
buffer_rules: Buffer::default(),
25+
theme: Theme::default(),
26+
placeholder: String::from("Time to be productive!"),
27+
shells: vec![],
2328
}
2429
}
2530
}
2631

2732
#[derive(Debug, Clone, Deserialize, Serialize)]
33+
#[serde(default)]
2834
pub struct Theme {
29-
pub text_color: Option<(f32, f32, f32)>,
30-
pub background_color: Option<(f32, f32, f32)>,
31-
pub background_opacity: Option<f32>,
32-
pub blur: Option<bool>,
33-
pub show_icons: Option<bool>,
34-
pub show_scroll_bar: Option<bool>,
35+
pub text_color: (f32, f32, f32),
36+
pub background_color: (f32, f32, f32),
37+
pub background_opacity: f32,
38+
pub blur: bool,
39+
pub show_icons: bool,
40+
pub show_scroll_bar: bool,
3541
}
3642

3743
impl Default for Theme {
3844
fn default() -> Self {
3945
Self {
40-
text_color: Some((0.95, 0.95, 0.96)),
41-
background_color: Some((0.11, 0.11, 0.13)),
42-
background_opacity: Some(1.),
43-
blur: Some(false),
44-
show_icons: Some(true),
45-
show_scroll_bar: Some(true),
46+
text_color: (0.95, 0.95, 0.96),
47+
background_color: (0.11, 0.11, 0.13),
48+
background_opacity: 1.,
49+
blur: false,
50+
show_icons: true,
51+
show_scroll_bar: true,
4652
}
4753
}
4854
}
4955

5056
impl Theme {
5157
pub fn to_iced_theme(&self) -> iced::Theme {
52-
let default = Self::default();
53-
let text_color = self.text_color.unwrap_or(default.text_color.unwrap());
54-
let bg_color = self
55-
.background_color
56-
.unwrap_or(default.background_color.unwrap());
58+
let text_color = self.text_color;
59+
let bg_color = self.background_color;
5760
let palette = iced::theme::Palette {
5861
background: iced::Color {
5962
r: bg_color.0,
6063
g: bg_color.1,
6164
b: bg_color.2,
62-
a: self.background_opacity.unwrap_or(1.),
65+
a: self.background_opacity,
6366
},
6467
text: iced::Color {
6568
r: text_color.0,
@@ -97,16 +100,51 @@ impl Theme {
97100
}
98101

99102
#[derive(Debug, Clone, Deserialize, Serialize)]
103+
#[serde(default)]
100104
pub struct Buffer {
101-
pub clear_on_hide: Option<bool>,
102-
pub clear_on_enter: Option<bool>,
105+
pub clear_on_hide: bool,
106+
pub clear_on_enter: bool,
103107
}
104108

105109
impl Default for Buffer {
106110
fn default() -> Self {
107111
Buffer {
108-
clear_on_hide: Some(true),
109-
clear_on_enter: Some(true),
112+
clear_on_hide: true,
113+
clear_on_enter: true,
114+
}
115+
}
116+
}
117+
118+
/// Command is the command it will run when the button is clicked
119+
/// Icon_path is the path to an icon, but this is optional
120+
/// Alias is the text that is used to call this command / search for it
121+
#[derive(Debug, Clone, Deserialize, Serialize)]
122+
pub struct Shelly {
123+
command: Vec<String>,
124+
icon_path: Option<String>,
125+
alias: String,
126+
alias_lc: String,
127+
}
128+
129+
impl Shelly {
130+
pub fn to_app(&self) -> App {
131+
let self_clone = self.clone();
132+
let icon = self_clone
133+
.icon_path
134+
.map(|x| {
135+
let x = x.replace("~", &std::env::var("HOME").unwrap());
136+
if x.ends_with(".icns") {
137+
handle_from_icns(Path::new(&x))
138+
} else {
139+
Some(Handle::from_path(Path::new(&x)))
140+
}
141+
})
142+
.flatten();
143+
App {
144+
open_command: self_clone.command,
145+
icons: icon,
146+
name: self_clone.alias,
147+
name_lc: self_clone.alias_lc,
110148
}
111149
}
112150
}

src/main.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,8 @@ fn main() -> iced::Result {
2424
let manager = GlobalHotKeyManager::new().unwrap();
2525

2626
let show_hide = HotKey::new(
27-
Some(
28-
Modifiers::from_name(&config.toggle_mod.clone().unwrap_or("ALT".to_string()))
29-
.unwrap_or(Modifiers::ALT),
30-
),
31-
to_key_code(&config.toggle_key.clone().unwrap_or("SPACE".to_string()))
32-
.unwrap_or(Code::Space),
27+
Some(Modifiers::from_name(&config.toggle_mod).unwrap_or(Modifiers::ALT)),
28+
to_key_code(&config.toggle_key).unwrap_or(Code::Space),
3329
);
3430

3531
manager

src/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ pub(crate) fn get_installed_apps(dir: impl AsRef<Path>, store_icons: bool) -> Ve
153153

154154
let name = file_name.strip_suffix(".app").unwrap().to_string();
155155
Some(App {
156-
open_command: format!("open {}", path_str),
156+
open_command: vec!["open".to_string(), format!(r#""{path_str}""#)],
157157
icons,
158158
name_lc: name.to_lowercase(),
159159
name,

0 commit comments

Comments
 (0)