From 94a377f263545db85bfd69aec217eece7b209e0b Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 12 Mar 2022 01:14:16 -0500 Subject: [PATCH 01/28] Add theme picker with live preview --- helix-term/src/application.rs | 44 +++++++++++++++--------- helix-term/src/commands.rs | 59 ++++++++++++++++++++++++++++++-- helix-term/src/commands/dap.rs | 8 +++-- helix-term/src/commands/lsp.rs | 4 +-- helix-term/src/commands/typed.rs | 8 ++--- helix-term/src/keymap.rs | 1 + helix-term/src/ui/mod.rs | 2 +- helix-term/src/ui/picker.rs | 30 ++++++++++------ helix-view/src/editor.rs | 8 +++-- helix-view/src/theme.rs | 29 ++++++++++++++-- 10 files changed, 148 insertions(+), 45 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 269ce13d15a8..c29fa913eed3 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -38,6 +38,15 @@ use { #[cfg(windows)] type Signals = futures_util::stream::Empty<()>; + +fn default_theme(theme_loader: Arc, true_color: bool) -> (String, theme::Theme) { + if true_color { + (String::from("default"), theme_loader.default()) + } else { + (String::from("base16_default"), theme_loader.base16_default()) + } +} + pub struct Application { compositor: Compositor, editor: Editor, @@ -67,26 +76,26 @@ impl Application { std::sync::Arc::new(theme::Loader::new(&conf_dir, &helix_loader::runtime_dir())); let true_color = config.editor.true_color || crate::true_color(); - let theme = config - .theme - .as_ref() - .and_then(|theme| { - theme_loader - .load(theme) + + let (theme_name, theme) = match config.theme.as_ref() { + Some(theme_name) => { + match theme_loader + .load(theme_name) .map_err(|e| { - log::warn!("failed to load theme `{}` - {}", theme, e); + log::warn!("failed to load theme `{}` - {}", theme_name, e); e }) .ok() - .filter(|theme| (true_color || theme.is_16_color())) - }) - .unwrap_or_else(|| { - if true_color { - theme_loader.default() - } else { - theme_loader.base16_default() - } - }); + .filter(|theme| (true_color || theme.is_16_color())) { + Some(theme) => (theme_name.clone(), theme), + None => default_theme(theme_loader.clone(), true_color) + } + + } + None => { + default_theme(theme_loader.clone(), true_color) + } + }; let syn_loader_conf = user_syntax_loader().unwrap_or_else(|err| { eprintln!("Bad language config: {}", err); @@ -103,6 +112,7 @@ impl Application { theme_loader.clone(), syn_loader.clone(), config.editor.clone(), + theme_name.clone(), ); let editor_view = Box::new(ui::EditorView::new(std::mem::take(&mut config.keys))); @@ -159,7 +169,7 @@ impl Application { .unwrap_or_else(|_| editor.new_file(Action::VerticalSplit)); } - editor.set_theme(theme); + editor.set_theme(theme, theme_name.clone()); #[cfg(windows)] let signals = futures_util::stream::empty(); diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 0052b43e4056..5e871dbac831 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -31,6 +31,7 @@ use helix_view::{ info::Info, input::KeyEvent, keyboard::KeyCode, + theme, view::View, Document, DocumentId, Editor, ViewId, }; @@ -431,6 +432,7 @@ impl MappableCommand { decrement, "Decrement", record_macro, "Record macro", replay_macro, "Replay macro", + theme_picker, "Set the current theme", command_palette, "Open command pallete", ); } @@ -1794,7 +1796,7 @@ fn global_search(cx: &mut Context) { let picker = FilePicker::new( all_matches, - move |(_line_num, path)| { + move |_, (_line_num, path)| { let relative_path = helix_core::path::get_relative_path(path) .to_string_lossy() .into_owned(); @@ -2077,7 +2079,7 @@ fn buffer_picker(cx: &mut Context) { .iter() .map(|(_, doc)| new_meta(doc)) .collect(), - BufferMeta::format, + |_, a| BufferMeta::format(a), |cx, meta, action| { cx.editor.switch(meta.id, action); }, @@ -2094,6 +2096,55 @@ fn buffer_picker(cx: &mut Context) { cx.push_layer(Box::new(overlayed(picker))); } +pub fn theme_picker(cx: &mut Context) { + let names = [ + theme::Loader::read_names(&helix_loader::runtime_dir().join("themes")), + theme::Loader::read_names(&helix_loader::config_dir().join("themes")), + vec!["default".into(), "base16_default".into()], + ] + .concat(); + + cx.callback = Some(Box::new( + move |compositor: &mut Compositor, cx: &mut compositor::Context| { + let true_color = cx.editor.config.true_color || crate::true_color(); + + let original_theme = cx.editor.current_theme.clone(); + let picker = Picker::new( + names, + move |_cx, theme_name| Cow::from(theme_name), + |_cx, _theme, _action| {}, + move |cx, theme_name| { + let theme = cx + .editor + .theme_loader + .load(theme_name) + .with_context(|| format!("Failed setting theme {}", theme_name)); + match theme { + Ok(theme) => { + if true_color || theme.is_16_color() { + cx.editor.set_theme(theme, theme_name.clone()); + } + } + _ => {} + } + }, + move |cx| { + let theme = cx + .editor + .theme_loader + .load(&original_theme) + .with_context(|| { + format!("Failed reverting to previously set theme {}", &original_theme) + }) + .unwrap(); + cx.editor.set_theme(theme, original_theme.clone()); + }, + ); + compositor.push(Box::new(picker)); + }, + )); +} + pub fn command_palette(cx: &mut Context) { cx.callback = Some(Box::new( move |compositor: &mut Compositor, cx: &mut compositor::Context| { @@ -2127,7 +2178,7 @@ pub fn command_palette(cx: &mut Context) { let picker = Picker::new( commands, - move |command| match command { + move |_, command| match command { MappableCommand::Typable { doc, name, .. } => match keymap.get(name as &String) { Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(), @@ -2149,6 +2200,8 @@ pub fn command_palette(cx: &mut Context) { }; command.execute(&mut ctx); }, + |_, _| {}, + |_| {}, ); compositor.push(Box::new(picker)); }, diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index cba293e23272..013eafb65c02 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -118,7 +118,7 @@ fn thread_picker( let thread_states = debugger.thread_states.clone(); let picker = FilePicker::new( threads, - move |thread| { + move |_, thread| { format!( "{} ({})", thread.name, @@ -320,7 +320,7 @@ pub fn dap_launch(cx: &mut Context) { cx.push_layer(Box::new(overlayed(Picker::new( templates, - |template| template.name.as_str().into(), + |_, template| template.name.as_str().into(), |cx, template, _action| { let completions = template.completion.clone(); let name = template.name.clone(); @@ -334,6 +334,8 @@ pub fn dap_launch(cx: &mut Context) { }); cx.jobs.callback(callback); }, + |_, _| {}, + |_| {}, )))); } @@ -792,7 +794,7 @@ pub fn dap_switch_stack_frame(cx: &mut Context) { let picker = FilePicker::new( frames, - |frame| frame.name.as_str().into(), // TODO: include thread_states in the label + |_, frame| frame.name.as_str().into(), // TODO: include thread_states in the label move |cx, frame, _action| { let debugger = debugger!(cx.editor); // TODO: this should be simpler to find diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 308ff82920c6..b86226fd27f1 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -73,7 +73,7 @@ fn sym_picker( let current_path2 = current_path.clone(); let mut picker = FilePicker::new( symbols, - move |symbol| { + move |_, symbol| { if current_path.as_ref() == Some(&symbol.location.uri) { symbol.name.as_str().into() } else { @@ -455,7 +455,7 @@ fn goto_impl( _locations => { let picker = FilePicker::new( locations, - move |location| { + move |_, location| { let file: Cow<'_, str> = (location.uri.scheme() == "file") .then(|| { location diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 3301d1486bd9..6accd480010c 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -527,17 +527,17 @@ fn theme( args: &[Cow], _event: PromptEvent, ) -> anyhow::Result<()> { - let theme = args.first().context("Theme not provided")?; + let theme_name = args.first().context("Theme not provided")?; let theme = cx .editor .theme_loader - .load(theme) - .with_context(|| format!("Failed setting theme {}", theme))?; + .load(theme_name) + .with_context(|| format!("Failed setting theme {}", theme_name))?; let true_color = cx.editor.config.true_color || crate::true_color(); if !(true_color || theme.is_16_color()) { bail!("Unsupported theme: theme requires true color support"); } - cx.editor.set_theme(theme); + cx.editor.set_theme(theme, theme_name.to_string()); Ok(()) } diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 1fe1f633385f..e80d3ada8516 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -741,6 +741,7 @@ impl Default for Keymaps { "/" => global_search, "k" => hover, "r" => rename_symbol, + "t" => theme_picker, "?" => command_palette, }, "z" => { "View" diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 6299a473967c..b59a6ce494f8 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -159,7 +159,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi FilePicker::new( files, - move |path: &PathBuf| { + move |_, path: &PathBuf| { // format_fn path.strip_prefix(&root).unwrap_or(path).to_string_lossy() }, diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 5d88622c9cb7..ff8fe0c8e541 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -87,12 +87,12 @@ impl Preview<'_, '_> { impl FilePicker { pub fn new( options: Vec, - format_fn: impl Fn(&T) -> Cow + 'static, + format_fn: impl for<'a> Fn(&'a mut Context, &'a T) -> Cow<'a, str> + 'static, callback_fn: impl Fn(&mut Context, &T, Action) + 'static, preview_fn: impl Fn(&Editor, &T) -> Option + 'static, ) -> Self { Self { - picker: Picker::new(options, format_fn, callback_fn), + picker: Picker::new(options, format_fn, callback_fn, |_, _| {}, |_| {}), truncate_start: true, preview_cache: HashMap::new(), read_buffer: Vec::with_capacity(1024), @@ -292,15 +292,19 @@ pub struct Picker { /// Whether to truncate the start (default true) pub truncate_start: bool, - format_fn: Box Cow>, + format_fn: Box Fn(&'a mut Context, &'a T) -> Cow<'a, str>>, callback_fn: Box, + highlighted_fn: Box, + close_fn: Box, } impl Picker { pub fn new( options: Vec, - format_fn: impl Fn(&T) -> Cow + 'static, + format_fn: impl for<'a> Fn(&'a mut Context, &'a T) -> Cow<'a, str> + 'static, callback_fn: impl Fn(&mut Context, &T, Action) + 'static, + highlighted_fn: impl Fn(&mut Context, &T) + 'static, + close_fn: impl Fn(&mut Context) + 'static, ) -> Self { let prompt = Prompt::new( "".into(), @@ -320,6 +324,8 @@ impl Picker { truncate_start: true, format_fn: Box::new(format_fn), callback_fn: Box::new(callback_fn), + highlighted_fn: Box::new(highlighted_fn), + close_fn: Box::new(close_fn), completion_height: 0, }; @@ -336,7 +342,7 @@ impl Picker { picker } - pub fn score(&mut self) { + pub fn score(&mut self, cx: &mut Context) { let now = Instant::now(); let pattern = &self.prompt.line; @@ -364,7 +370,7 @@ impl Picker { self.matches.retain_mut(|(index, score)| { let option = &self.options[*index]; // TODO: maybe using format_fn isn't the best idea here - let text = (self.format_fn)(option); + let text = (self.format_fn)(cx, option); match self.matcher.fuzzy_match(&text, pattern) { Some(s) => { @@ -393,7 +399,7 @@ impl Picker { } // TODO: maybe using format_fn isn't the best idea here - let text = (self.format_fn)(option); + let text = (self.format_fn)(cx, option); self.matcher .fuzzy_match(&text, pattern) @@ -478,7 +484,7 @@ impl Component for Picker { _ => return EventResult::Ignored(None), }; - let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _| { + let close_fn = EventResult::Consumed(Some(Box::new(|compositor: &mut Compositor, _cx| { // remove the layer compositor.last_picker = compositor.pop(); }))); @@ -503,6 +509,7 @@ impl Component for Picker { self.to_end(); } key!(Esc) | ctrl!('c') => { + (self.close_fn)(cx); return close_fn; } key!(Enter) => { @@ -529,7 +536,10 @@ impl Component for Picker { _ => { if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) { // TODO: recalculate only if pattern changed - self.score(); + self.score(cx); + if let Some(option) = self.selection() { + (self.highlighted_fn)(cx, option); + } } } } @@ -598,7 +608,7 @@ impl Component for Picker { surface.set_string(inner.x.saturating_sub(2), inner.y + i as u16, ">", selected); } - let formatted = (self.format_fn)(option); + let formatted = (self.format_fn)(cx, option); let (_score, highlights) = self .matcher diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 0eb613087d80..d6196ac3da1c 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -291,7 +291,7 @@ pub struct Editor { pub syn_loader: Arc, pub theme_loader: Arc, - + pub current_theme: String, pub status_msg: Option<(Cow<'static, str>, Severity)>, pub autoinfo: Option, @@ -327,6 +327,7 @@ impl Editor { theme_loader: Arc, syn_loader: Arc, config: Config, + current_theme: String, ) -> Self { let language_servers = helix_lsp::Registry::new(); let auto_pairs = (&config.auto_pairs).into(); @@ -350,6 +351,7 @@ impl Editor { breakpoints: HashMap::new(), syn_loader, theme_loader, + current_theme, registers: Registers::default(), clipboard_provider: get_clipboard_provider(), status_msg: None, @@ -391,7 +393,7 @@ impl Editor { self.status_msg = Some((error.into(), Severity::Error)); } - pub fn set_theme(&mut self, theme: Theme) { + pub fn set_theme(&mut self, theme: Theme, theme_name: String) { // `ui.selection` is the only scope required to be able to render a theme. if theme.find_scope_index("ui.selection").is_none() { self.set_error("Invalid theme: `ui.selection` required"); @@ -400,7 +402,7 @@ impl Editor { let scopes = theme.scopes(); self.syn_loader.set_scopes(scopes.to_vec()); - + self.current_theme = theme_name; self.theme = theme; self._refresh(); } diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 3f45aac6ea3f..9145824c3bd9 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -1,6 +1,6 @@ use std::{ collections::HashMap, - path::{Path, PathBuf}, + path::{Path, PathBuf}, sync::{Arc, Mutex}, }; use anyhow::Context; @@ -24,6 +24,7 @@ pub static BASE16_DEFAULT_THEME: Lazy = Lazy::new(|| { pub struct Loader { user_dir: PathBuf, default_dir: PathBuf, + theme_cache: Arc>>, } impl Loader { /// Creates a new loader that can load themes from two directories. @@ -31,6 +32,7 @@ impl Loader { Self { user_dir: user_dir.as_ref().join("themes"), default_dir: default_dir.as_ref().join("themes"), + theme_cache: Arc::new(Mutex::new(HashMap::new())), } } @@ -51,8 +53,31 @@ impl Loader { self.default_dir.join(filename) }; + let path_str = path.to_str(); + + // We can return the theme from the cache if it already exists + if let Some(path_str) = path_str { + let tc = self.theme_cache.lock().unwrap(); + if tc.contains_key(path_str) { + let theme = tc.get(path_str).unwrap().clone(); + return Result::Ok(theme); + } + } + let data = std::fs::read(&path)?; - toml::from_slice(data.as_slice()).context("Failed to deserialize theme") + let theme = toml::from_slice::(data.as_slice()); + match theme { + Ok(theme) => { + if let Some(p) = path_str { + let mut tc = self.theme_cache.lock().unwrap(); + tc.insert(p.to_string(), theme.clone()); + } + Ok(theme) + }, + Result::Err(e) => { + Err(e).context("Failed to deserialize theme") + } + } } pub fn read_names(path: &Path) -> Vec { From 753131ec2ad833353f566b77ce6fdf449e0e6bc3 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 12 Mar 2022 13:41:23 -0500 Subject: [PATCH 02/28] Add live theme preview to :theme command --- helix-term/src/commands/typed.rs | 307 ++++++++++++++++++++++++------- helix-view/src/editor.rs | 18 +- 2 files changed, 253 insertions(+), 72 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 6accd480010c..5a9d8694d0be 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -16,8 +16,11 @@ pub struct TypableCommand { fn quit( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } // last view and we have unsaved changes if cx.editor.tree.views().count() == 1 { buffers_remaining_impl(cx.editor)? @@ -31,18 +34,20 @@ fn quit( fn force_quit( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } cx.editor.close(view!(cx.editor).id); Ok(()) } -fn open( - cx: &mut compositor::Context, - args: &[Cow], - _event: PromptEvent, -) -> anyhow::Result<()> { +fn open(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } ensure!(!args.is_empty(), "wrong argument count"); for arg in args { let (path, pos) = args::parse_file(arg); @@ -108,8 +113,11 @@ fn buffer_gather_paths_impl(editor: &mut Editor, args: &[Cow]) -> Vec], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let document_ids = buffer_gather_paths_impl(cx.editor, args); buffer_close_by_ids_impl(cx.editor, &document_ids, false) } @@ -117,8 +125,11 @@ fn buffer_close( fn force_buffer_close( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let document_ids = buffer_gather_paths_impl(cx.editor, args); buffer_close_by_ids_impl(cx.editor, &document_ids, true) } @@ -135,8 +146,11 @@ fn buffer_gather_others_impl(editor: &mut Editor) -> Vec { fn buffer_close_others( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let document_ids = buffer_gather_others_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, false) } @@ -144,8 +158,11 @@ fn buffer_close_others( fn force_buffer_close_others( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let document_ids = buffer_gather_others_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, true) } @@ -157,8 +174,11 @@ fn buffer_gather_all_impl(editor: &mut Editor) -> Vec { fn buffer_close_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let document_ids = buffer_gather_all_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, false) } @@ -166,8 +186,11 @@ fn buffer_close_all( fn force_buffer_close_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let document_ids = buffer_gather_all_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, true) } @@ -207,16 +230,22 @@ fn write_impl(cx: &mut compositor::Context, path: Option<&Cow>) -> anyhow:: fn write( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } write_impl(cx, args.first()) } fn new_file( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } cx.editor.new_file(Action::Replace); Ok(()) @@ -225,8 +254,11 @@ fn new_file( fn format( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let doc = doc!(cx.editor); if let Some(format) = doc.format() { let callback = @@ -239,8 +271,11 @@ fn format( fn set_indent_style( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } use IndentStyle::*; // If no argument, report current indent style. @@ -278,8 +313,11 @@ fn set_indent_style( fn set_line_ending( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } use LineEnding::*; // If no argument, report current line ending setting. @@ -322,8 +360,11 @@ fn set_line_ending( fn earlier( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; let (view, doc) = current!(cx.editor); @@ -338,8 +379,11 @@ fn earlier( fn later( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; let (view, doc) = current!(cx.editor); let success = doc.later(view.id, uk); @@ -355,6 +399,9 @@ fn write_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } write_impl(cx, args.first())?; quit(cx, &[], event) } @@ -364,12 +411,15 @@ fn force_write_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } write_impl(cx, args.first())?; force_quit(cx, &[], event) } /// Results an error if there are modified buffers remaining and sets editor error, -/// otherwise returns `Ok(())` +// otherwise returns `Ok(())` pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> { let modified: Vec<_> = editor .documents() @@ -445,6 +495,9 @@ fn write_all( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } write_all_impl(cx, args, event, false, false) } @@ -453,6 +506,9 @@ fn write_all_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } write_all_impl(cx, args, event, true, false) } @@ -461,6 +517,9 @@ fn force_write_all_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } write_all_impl(cx, args, event, true, true) } @@ -481,24 +540,33 @@ fn quit_all_impl(editor: &mut Editor, force: bool) -> anyhow::Result<()> { fn quit_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } quit_all_impl(cx.editor, false) } fn force_quit_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } quit_all_impl(cx.editor, true) } fn cquit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let exit_code = args .first() .and_then(|code| code.parse::().ok()) @@ -511,8 +579,11 @@ fn cquit( fn force_cquit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let exit_code = args .first() .and_then(|code| code.parse::().ok()) @@ -525,35 +596,59 @@ fn force_cquit( fn theme( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { - let theme_name = args.first().context("Theme not provided")?; - let theme = cx - .editor - .theme_loader - .load(theme_name) - .with_context(|| format!("Failed setting theme {}", theme_name))?; let true_color = cx.editor.config.true_color || crate::true_color(); - if !(true_color || theme.is_16_color()) { - bail!("Unsupported theme: theme requires true color support"); - } - cx.editor.set_theme(theme, theme_name.to_string()); + match event { + PromptEvent::Abort => { + cx.editor.unset_theme_preview(); + } + PromptEvent::Update => { + if let Some(theme_name) = args.first() { + if let Ok(theme) = cx.editor.theme_loader.load(theme_name) { + if !(true_color || theme.is_16_color()) { + bail!("Unsupported theme: theme requires true color support"); + } + cx.editor.set_theme_preview(theme); + }; + }; + } + PromptEvent::Validate => { + let theme_name = args.first().with_context(|| "Theme name not provided")?; + let theme = cx + .editor + .theme_loader + .load(theme_name) + .with_context(|| "Theme does not exist")?; + if !(true_color || theme.is_16_color()) { + bail!("Unsupported theme: theme requires true color support"); + } + cx.editor.set_theme(theme, theme_name.to_string()); + } + }; + Ok(()) } fn yank_main_selection_to_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard) } fn yank_joined_to_clipboard( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let doc = doc!(cx.editor); let default_sep = Cow::Borrowed(doc.line_ending.as_str()); let separator = args.first().unwrap_or(&default_sep); @@ -563,16 +658,22 @@ fn yank_joined_to_clipboard( fn yank_main_selection_to_primary_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Selection) } fn yank_joined_to_primary_clipboard( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let doc = doc!(cx.editor); let default_sep = Cow::Borrowed(doc.line_ending.as_str()); let separator = args.first().unwrap_or(&default_sep); @@ -582,32 +683,44 @@ fn yank_joined_to_primary_clipboard( fn paste_clipboard_after( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard, 1) } fn paste_clipboard_before( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard, 1) } fn paste_primary_clipboard_after( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection, 1) } fn paste_primary_clipboard_before( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection, 1) } @@ -635,24 +748,33 @@ fn replace_selections_with_clipboard_impl( fn replace_selections_with_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } replace_selections_with_clipboard_impl(cx, ClipboardType::Clipboard) } fn replace_selections_with_primary_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } replace_selections_with_clipboard_impl(cx, ClipboardType::Selection) } fn show_clipboard_provider( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } cx.editor .set_status(cx.editor.clipboard_provider.name().to_string()); Ok(()) @@ -661,8 +783,11 @@ fn show_clipboard_provider( fn change_current_directory( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let dir = helix_core::path::expand_tilde( args.first() .context("target directory not provided")? @@ -685,8 +810,11 @@ fn change_current_directory( fn show_current_directory( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let cwd = std::env::current_dir().context("Couldn't get the new working directory")?; cx.editor .set_status(format!("Current working directory is {}", cwd.display())); @@ -697,8 +825,11 @@ fn show_current_directory( fn set_encoding( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let doc = doc_mut!(cx.editor); if let Some(label) = args.first() { doc.set_encoding(label) @@ -713,8 +844,11 @@ fn set_encoding( fn reload( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let (view, doc) = current!(cx.editor); doc.reload(view.id) } @@ -722,8 +856,11 @@ fn reload( fn tree_sitter_scopes( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); @@ -736,8 +873,11 @@ fn tree_sitter_scopes( fn vsplit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let id = view!(cx.editor).doc; if args.is_empty() { @@ -755,8 +895,11 @@ fn vsplit( fn hsplit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let id = view!(cx.editor).doc; if args.is_empty() { @@ -774,8 +917,11 @@ fn hsplit( fn debug_eval( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } if let Some(debugger) = cx.editor.debugger.as_mut() { let (frame, thread_id) = match (debugger.active_frame, debugger.thread_id) { (Some(frame), Some(thread_id)) => (frame, thread_id), @@ -796,8 +942,11 @@ fn debug_eval( fn debug_start( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let mut args = args.to_owned(); let name = match args.len() { 0 => None, @@ -809,8 +958,11 @@ fn debug_start( fn debug_remote( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let mut args = args.to_owned(); let address = match args.len() { 0 => None, @@ -826,8 +978,11 @@ fn debug_remote( fn tutor( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let path = helix_loader::runtime_dir().join("tutor.txt"); cx.editor.open(path, Action::Replace)?; // Unset path to prevent accidentally saving to the original tutor file. @@ -838,8 +993,11 @@ fn tutor( pub(super) fn goto_line_number( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } ensure!(!args.is_empty(), "Line number required"); let line = args[0].parse::()?; @@ -855,8 +1013,11 @@ pub(super) fn goto_line_number( fn setting( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let runtime_config = &mut cx.editor.config; if args.len() != 2 { @@ -884,19 +1045,21 @@ fn setting( Ok(()) } -fn sort( - cx: &mut compositor::Context, - args: &[Cow], - _event: PromptEvent, -) -> anyhow::Result<()> { +fn sort(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } sort_impl(cx, args, false) } fn sort_reverse( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } sort_impl(cx, args, true) } @@ -937,8 +1100,11 @@ fn sort_impl( fn tree_sitter_subtree( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } let (view, doc) = current!(cx.editor); if let Some(syntax) = doc.syntax() { @@ -1406,10 +1572,6 @@ pub fn command_mode(cx: &mut Context) { } }, // completion move |cx: &mut compositor::Context, input: &str, event: PromptEvent| { - if event != PromptEvent::Validate { - return; - } - let parts = input.split_whitespace().collect::>(); if parts.is_empty() { return; @@ -1439,6 +1601,9 @@ pub fn command_mode(cx: &mut Context) { cx.editor.set_error(format!("{}", e)); } } else { + if event != PromptEvent::Validate { + return; + } cx.editor .set_error(format!("no such command: '{}'", parts[0])); }; diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index d6196ac3da1c..f59e033b66b1 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -393,7 +393,24 @@ impl Editor { self.status_msg = Some((error.into(), Severity::Error)); } + pub fn unset_theme_preview(&mut self) { + let theme = self + .theme_loader + .load(&self.current_theme) + .unwrap(); + self.set_theme(theme, self.current_theme.clone()); + } + + pub fn set_theme_preview(&mut self, theme: Theme) { + self.set_theme_impl(theme); + } + pub fn set_theme(&mut self, theme: Theme, theme_name: String) { + self.current_theme = theme_name; + self.set_theme_impl(theme); + } + + fn set_theme_impl(&mut self, theme: Theme) { // `ui.selection` is the only scope required to be able to render a theme. if theme.find_scope_index("ui.selection").is_none() { self.set_error("Invalid theme: `ui.selection` required"); @@ -402,7 +419,6 @@ impl Editor { let scopes = theme.scopes(); self.syn_loader.set_scopes(scopes.to_vec()); - self.current_theme = theme_name; self.theme = theme; self._refresh(); } From b0c4f7c66c401987f008d0ab5255a01f46a5f700 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 12 Mar 2022 13:58:28 -0500 Subject: [PATCH 03/28] cargo fmt --- helix-term/src/application.rs | 20 ++++++++++---------- helix-term/src/commands.rs | 5 ++++- helix-view/src/editor.rs | 5 +---- helix-view/src/theme.rs | 7 +++---- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index c29fa913eed3..6c459e168457 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -38,12 +38,14 @@ use { #[cfg(windows)] type Signals = futures_util::stream::Empty<()>; - fn default_theme(theme_loader: Arc, true_color: bool) -> (String, theme::Theme) { if true_color { (String::from("default"), theme_loader.default()) } else { - (String::from("base16_default"), theme_loader.base16_default()) + ( + String::from("base16_default"), + theme_loader.base16_default(), + ) } } @@ -86,15 +88,13 @@ impl Application { e }) .ok() - .filter(|theme| (true_color || theme.is_16_color())) { - Some(theme) => (theme_name.clone(), theme), - None => default_theme(theme_loader.clone(), true_color) - } - - } - None => { - default_theme(theme_loader.clone(), true_color) + .filter(|theme| (true_color || theme.is_16_color())) + { + Some(theme) => (theme_name.clone(), theme), + None => default_theme(theme_loader.clone(), true_color), + } } + None => default_theme(theme_loader.clone(), true_color), }; let syn_loader_conf = user_syntax_loader().unwrap_or_else(|err| { diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5e871dbac831..c59dbb3c98b8 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2134,7 +2134,10 @@ pub fn theme_picker(cx: &mut Context) { .theme_loader .load(&original_theme) .with_context(|| { - format!("Failed reverting to previously set theme {}", &original_theme) + format!( + "Failed reverting to previously set theme {}", + &original_theme + ) }) .unwrap(); cx.editor.set_theme(theme, original_theme.clone()); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index f59e033b66b1..2dd817ecfd2d 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -394,10 +394,7 @@ impl Editor { } pub fn unset_theme_preview(&mut self) { - let theme = self - .theme_loader - .load(&self.current_theme) - .unwrap(); + let theme = self.theme_loader.load(&self.current_theme).unwrap(); self.set_theme(theme, self.current_theme.clone()); } diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 9145824c3bd9..740ff6ef9d12 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -1,6 +1,7 @@ use std::{ collections::HashMap, - path::{Path, PathBuf}, sync::{Arc, Mutex}, + path::{Path, PathBuf}, + sync::{Arc, Mutex}, }; use anyhow::Context; @@ -73,10 +74,8 @@ impl Loader { tc.insert(p.to_string(), theme.clone()); } Ok(theme) - }, - Result::Err(e) => { - Err(e).context("Failed to deserialize theme") } + Result::Err(e) => Err(e).context("Failed to deserialize theme"), } } From 6bfde2130e7d45d37191fd6281d4b884b6ca3bb1 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 12 Mar 2022 14:10:09 -0500 Subject: [PATCH 04/28] Fix clippy warnings --- helix-term/src/application.rs | 2 +- helix-term/src/commands.rs | 9 +++------ helix-term/src/ui/picker.rs | 4 +++- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 6c459e168457..c94fc95b79ec 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -169,7 +169,7 @@ impl Application { .unwrap_or_else(|_| editor.new_file(Action::VerticalSplit)); } - editor.set_theme(theme, theme_name.clone()); + editor.set_theme(theme, theme_name); #[cfg(windows)] let signals = futures_util::stream::empty(); diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index c59dbb3c98b8..d04f38f198c5 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2119,13 +2119,10 @@ pub fn theme_picker(cx: &mut Context) { .theme_loader .load(theme_name) .with_context(|| format!("Failed setting theme {}", theme_name)); - match theme { - Ok(theme) => { - if true_color || theme.is_16_color() { - cx.editor.set_theme(theme, theme_name.clone()); - } + if let Ok(theme) = theme { + if true_color || theme.is_16_color() { + cx.editor.set_theme(theme, theme_name.clone()); } - _ => {} } }, move |cx| { diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index ff8fe0c8e541..56b9abd67e36 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -273,6 +273,8 @@ impl Component for FilePicker { } } +type FormatFn = dyn for<'a> Fn(&'a mut Context, &'a T) -> Cow<'a, str>; + pub struct Picker { options: Vec, // filter: String, @@ -292,7 +294,7 @@ pub struct Picker { /// Whether to truncate the start (default true) pub truncate_start: bool, - format_fn: Box Fn(&'a mut Context, &'a T) -> Cow<'a, str>>, + format_fn: Box>, callback_fn: Box, highlighted_fn: Box, close_fn: Box, From 1481093fa94c7166655894a4516dec0ab177962f Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 13 Mar 2022 15:40:02 -0400 Subject: [PATCH 05/28] Remove picker variant --- helix-term/src/commands.rs | 52 ---------------------------------- helix-term/src/commands/dap.rs | 2 -- helix-term/src/keymap.rs | 1 - helix-term/src/ui/picker.rs | 12 +------- 4 files changed, 1 insertion(+), 66 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index d04f38f198c5..5ae4b2669592 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -432,7 +432,6 @@ impl MappableCommand { decrement, "Decrement", record_macro, "Record macro", replay_macro, "Replay macro", - theme_picker, "Set the current theme", command_palette, "Open command pallete", ); } @@ -2096,55 +2095,6 @@ fn buffer_picker(cx: &mut Context) { cx.push_layer(Box::new(overlayed(picker))); } -pub fn theme_picker(cx: &mut Context) { - let names = [ - theme::Loader::read_names(&helix_loader::runtime_dir().join("themes")), - theme::Loader::read_names(&helix_loader::config_dir().join("themes")), - vec!["default".into(), "base16_default".into()], - ] - .concat(); - - cx.callback = Some(Box::new( - move |compositor: &mut Compositor, cx: &mut compositor::Context| { - let true_color = cx.editor.config.true_color || crate::true_color(); - - let original_theme = cx.editor.current_theme.clone(); - let picker = Picker::new( - names, - move |_cx, theme_name| Cow::from(theme_name), - |_cx, _theme, _action| {}, - move |cx, theme_name| { - let theme = cx - .editor - .theme_loader - .load(theme_name) - .with_context(|| format!("Failed setting theme {}", theme_name)); - if let Ok(theme) = theme { - if true_color || theme.is_16_color() { - cx.editor.set_theme(theme, theme_name.clone()); - } - } - }, - move |cx| { - let theme = cx - .editor - .theme_loader - .load(&original_theme) - .with_context(|| { - format!( - "Failed reverting to previously set theme {}", - &original_theme - ) - }) - .unwrap(); - cx.editor.set_theme(theme, original_theme.clone()); - }, - ); - compositor.push(Box::new(picker)); - }, - )); -} - pub fn command_palette(cx: &mut Context) { cx.callback = Some(Box::new( move |compositor: &mut Compositor, cx: &mut compositor::Context| { @@ -2200,8 +2150,6 @@ pub fn command_palette(cx: &mut Context) { }; command.execute(&mut ctx); }, - |_, _| {}, - |_| {}, ); compositor.push(Box::new(picker)); }, diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index 013eafb65c02..b0198ce68a73 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -334,8 +334,6 @@ pub fn dap_launch(cx: &mut Context) { }); cx.jobs.callback(callback); }, - |_, _| {}, - |_| {}, )))); } diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index e80d3ada8516..1fe1f633385f 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -741,7 +741,6 @@ impl Default for Keymaps { "/" => global_search, "k" => hover, "r" => rename_symbol, - "t" => theme_picker, "?" => command_palette, }, "z" => { "View" diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 56b9abd67e36..272373599553 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -92,7 +92,7 @@ impl FilePicker { preview_fn: impl Fn(&Editor, &T) -> Option + 'static, ) -> Self { Self { - picker: Picker::new(options, format_fn, callback_fn, |_, _| {}, |_| {}), + picker: Picker::new(options, format_fn, callback_fn), truncate_start: true, preview_cache: HashMap::new(), read_buffer: Vec::with_capacity(1024), @@ -296,8 +296,6 @@ pub struct Picker { format_fn: Box>, callback_fn: Box, - highlighted_fn: Box, - close_fn: Box, } impl Picker { @@ -305,8 +303,6 @@ impl Picker { options: Vec, format_fn: impl for<'a> Fn(&'a mut Context, &'a T) -> Cow<'a, str> + 'static, callback_fn: impl Fn(&mut Context, &T, Action) + 'static, - highlighted_fn: impl Fn(&mut Context, &T) + 'static, - close_fn: impl Fn(&mut Context) + 'static, ) -> Self { let prompt = Prompt::new( "".into(), @@ -326,8 +322,6 @@ impl Picker { truncate_start: true, format_fn: Box::new(format_fn), callback_fn: Box::new(callback_fn), - highlighted_fn: Box::new(highlighted_fn), - close_fn: Box::new(close_fn), completion_height: 0, }; @@ -511,7 +505,6 @@ impl Component for Picker { self.to_end(); } key!(Esc) | ctrl!('c') => { - (self.close_fn)(cx); return close_fn; } key!(Enter) => { @@ -539,9 +532,6 @@ impl Component for Picker { if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) { // TODO: recalculate only if pattern changed self.score(cx); - if let Some(option) = self.selection() { - (self.highlighted_fn)(cx, option); - } } } } From fe5ec9e78fd2cd2506e59835183586dc5e3febb5 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 13 Mar 2022 15:46:57 -0400 Subject: [PATCH 06/28] Remove unused import --- helix-term/src/commands.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 5ae4b2669592..44b13b3ce02b 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -31,7 +31,6 @@ use helix_view::{ info::Info, input::KeyEvent, keyboard::KeyCode, - theme, view::View, Document, DocumentId, Editor, ViewId, }; From 2d96be23f19f39b7b618629d74f9d0d3b3a903c0 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Mon, 14 Mar 2022 21:44:58 -0400 Subject: [PATCH 07/28] Cleanup --- helix-term/src/commands.rs | 6 +++--- helix-term/src/commands/dap.rs | 6 +++--- helix-term/src/commands/lsp.rs | 4 ++-- helix-term/src/ui/mod.rs | 2 +- helix-term/src/ui/picker.rs | 18 ++++++++---------- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 44b13b3ce02b..0052b43e4056 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1794,7 +1794,7 @@ fn global_search(cx: &mut Context) { let picker = FilePicker::new( all_matches, - move |_, (_line_num, path)| { + move |(_line_num, path)| { let relative_path = helix_core::path::get_relative_path(path) .to_string_lossy() .into_owned(); @@ -2077,7 +2077,7 @@ fn buffer_picker(cx: &mut Context) { .iter() .map(|(_, doc)| new_meta(doc)) .collect(), - |_, a| BufferMeta::format(a), + BufferMeta::format, |cx, meta, action| { cx.editor.switch(meta.id, action); }, @@ -2127,7 +2127,7 @@ pub fn command_palette(cx: &mut Context) { let picker = Picker::new( commands, - move |_, command| match command { + move |command| match command { MappableCommand::Typable { doc, name, .. } => match keymap.get(name as &String) { Some(bindings) => format!("{} ({})", doc, fmt_binding(bindings)).into(), diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs index b0198ce68a73..cba293e23272 100644 --- a/helix-term/src/commands/dap.rs +++ b/helix-term/src/commands/dap.rs @@ -118,7 +118,7 @@ fn thread_picker( let thread_states = debugger.thread_states.clone(); let picker = FilePicker::new( threads, - move |_, thread| { + move |thread| { format!( "{} ({})", thread.name, @@ -320,7 +320,7 @@ pub fn dap_launch(cx: &mut Context) { cx.push_layer(Box::new(overlayed(Picker::new( templates, - |_, template| template.name.as_str().into(), + |template| template.name.as_str().into(), |cx, template, _action| { let completions = template.completion.clone(); let name = template.name.clone(); @@ -792,7 +792,7 @@ pub fn dap_switch_stack_frame(cx: &mut Context) { let picker = FilePicker::new( frames, - |_, frame| frame.name.as_str().into(), // TODO: include thread_states in the label + |frame| frame.name.as_str().into(), // TODO: include thread_states in the label move |cx, frame, _action| { let debugger = debugger!(cx.editor); // TODO: this should be simpler to find diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index b86226fd27f1..308ff82920c6 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -73,7 +73,7 @@ fn sym_picker( let current_path2 = current_path.clone(); let mut picker = FilePicker::new( symbols, - move |_, symbol| { + move |symbol| { if current_path.as_ref() == Some(&symbol.location.uri) { symbol.name.as_str().into() } else { @@ -455,7 +455,7 @@ fn goto_impl( _locations => { let picker = FilePicker::new( locations, - move |_, location| { + move |location| { let file: Cow<'_, str> = (location.uri.scheme() == "file") .then(|| { location diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index b59a6ce494f8..6299a473967c 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -159,7 +159,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi FilePicker::new( files, - move |_, path: &PathBuf| { + move |path: &PathBuf| { // format_fn path.strip_prefix(&root).unwrap_or(path).to_string_lossy() }, diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 272373599553..330ed632b133 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -87,7 +87,7 @@ impl Preview<'_, '_> { impl FilePicker { pub fn new( options: Vec, - format_fn: impl for<'a> Fn(&'a mut Context, &'a T) -> Cow<'a, str> + 'static, + format_fn: impl Fn(&T) -> Cow + 'static, callback_fn: impl Fn(&mut Context, &T, Action) + 'static, preview_fn: impl Fn(&Editor, &T) -> Option + 'static, ) -> Self { @@ -273,8 +273,6 @@ impl Component for FilePicker { } } -type FormatFn = dyn for<'a> Fn(&'a mut Context, &'a T) -> Cow<'a, str>; - pub struct Picker { options: Vec, // filter: String, @@ -294,14 +292,14 @@ pub struct Picker { /// Whether to truncate the start (default true) pub truncate_start: bool, - format_fn: Box>, + format_fn: Box Cow>, callback_fn: Box, } impl Picker { pub fn new( options: Vec, - format_fn: impl for<'a> Fn(&'a mut Context, &'a T) -> Cow<'a, str> + 'static, + format_fn: impl Fn(&T) -> Cow + 'static, callback_fn: impl Fn(&mut Context, &T, Action) + 'static, ) -> Self { let prompt = Prompt::new( @@ -338,7 +336,7 @@ impl Picker { picker } - pub fn score(&mut self, cx: &mut Context) { + pub fn score(&mut self) { let now = Instant::now(); let pattern = &self.prompt.line; @@ -366,7 +364,7 @@ impl Picker { self.matches.retain_mut(|(index, score)| { let option = &self.options[*index]; // TODO: maybe using format_fn isn't the best idea here - let text = (self.format_fn)(cx, option); + let text = (self.format_fn)(option); match self.matcher.fuzzy_match(&text, pattern) { Some(s) => { @@ -395,7 +393,7 @@ impl Picker { } // TODO: maybe using format_fn isn't the best idea here - let text = (self.format_fn)(cx, option); + let text = (self.format_fn)(option); self.matcher .fuzzy_match(&text, pattern) @@ -531,7 +529,7 @@ impl Component for Picker { _ => { if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) { // TODO: recalculate only if pattern changed - self.score(cx); + self.score(); } } } @@ -600,7 +598,7 @@ impl Component for Picker { surface.set_string(inner.x.saturating_sub(2), inner.y + i as u16, ">", selected); } - let formatted = (self.format_fn)(cx, option); + let formatted = (self.format_fn)(option); let (_score, highlights) = self .matcher From c638d0b57d718edb953f81d47910ac6f97badc27 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Tue, 15 Mar 2022 00:11:51 -0400 Subject: [PATCH 08/28] Change current_theme to last_theme --- helix-term/src/application.rs | 31 ++++++++++++++----------------- helix-term/src/commands/typed.rs | 2 +- helix-view/src/editor.rs | 20 ++++++++++++++------ helix-view/src/theme.rs | 21 +++++++++++++++++---- 4 files changed, 46 insertions(+), 28 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index c94fc95b79ec..88d97434be33 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -38,17 +38,6 @@ use { #[cfg(windows)] type Signals = futures_util::stream::Empty<()>; -fn default_theme(theme_loader: Arc, true_color: bool) -> (String, theme::Theme) { - if true_color { - (String::from("default"), theme_loader.default()) - } else { - ( - String::from("base16_default"), - theme_loader.base16_default(), - ) - } -} - pub struct Application { compositor: Compositor, editor: Editor, @@ -79,7 +68,7 @@ impl Application { let true_color = config.editor.true_color || crate::true_color(); - let (theme_name, theme) = match config.theme.as_ref() { + let theme = match config.theme.as_ref() { Some(theme_name) => { match theme_loader .load(theme_name) @@ -90,11 +79,11 @@ impl Application { .ok() .filter(|theme| (true_color || theme.is_16_color())) { - Some(theme) => (theme_name.clone(), theme), - None => default_theme(theme_loader.clone(), true_color), + Some(theme) => theme, + None => Application::default_theme(theme_loader.clone(), true_color), } } - None => default_theme(theme_loader.clone(), true_color), + None => Application::default_theme(theme_loader.clone(), true_color), }; let syn_loader_conf = user_syntax_loader().unwrap_or_else(|err| { @@ -112,7 +101,7 @@ impl Application { theme_loader.clone(), syn_loader.clone(), config.editor.clone(), - theme_name.clone(), + theme.name.clone(), ); let editor_view = Box::new(ui::EditorView::new(std::mem::take(&mut config.keys))); @@ -169,7 +158,7 @@ impl Application { .unwrap_or_else(|_| editor.new_file(Action::VerticalSplit)); } - editor.set_theme(theme, theme_name); + editor.set_theme(theme); #[cfg(windows)] let signals = futures_util::stream::empty(); @@ -193,6 +182,14 @@ impl Application { Ok(app) } + fn default_theme(theme_loader: Arc, true_color: bool) -> theme::Theme { + if true_color { + theme_loader.default() + } else { + theme_loader.base16_default() + } + } + fn render(&mut self) { let mut cx = crate::compositor::Context { editor: &mut self.editor, diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 5a9d8694d0be..107edf129210 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -623,7 +623,7 @@ fn theme( if !(true_color || theme.is_16_color()) { bail!("Unsupported theme: theme requires true color support"); } - cx.editor.set_theme(theme, theme_name.to_string()); + cx.editor.set_theme(theme); } }; diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 2dd817ecfd2d..d3e2205baf88 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -291,7 +291,7 @@ pub struct Editor { pub syn_loader: Arc, pub theme_loader: Arc, - pub current_theme: String, + pub last_theme: Option, pub status_msg: Option<(Cow<'static, str>, Severity)>, pub autoinfo: Option, @@ -351,7 +351,7 @@ impl Editor { breakpoints: HashMap::new(), syn_loader, theme_loader, - current_theme, + last_theme: Some(current_theme), registers: Registers::default(), clipboard_provider: get_clipboard_provider(), status_msg: None, @@ -394,16 +394,24 @@ impl Editor { } pub fn unset_theme_preview(&mut self) { - let theme = self.theme_loader.load(&self.current_theme).unwrap(); - self.set_theme(theme, self.current_theme.clone()); + if let Some(last_theme) = &self.last_theme.clone() { + match self.theme_loader.load(last_theme) { + Ok(theme) => { + self.set_theme(theme); + } + Err(_e) => { + self.set_error(format!("Failed to set theme: '{}'", last_theme)); + } + }; + } } pub fn set_theme_preview(&mut self, theme: Theme) { self.set_theme_impl(theme); } - pub fn set_theme(&mut self, theme: Theme, theme_name: String) { - self.current_theme = theme_name; + pub fn set_theme(&mut self, theme: Theme) { + self.last_theme = Some(theme.name.clone()); self.set_theme_impl(theme); } diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 740ff6ef9d12..c9888821934d 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -14,10 +14,19 @@ use toml::Value; pub use crate::graphics::{Color, Modifier, Style}; pub static DEFAULT_THEME: Lazy = Lazy::new(|| { - toml::from_slice(include_bytes!("../../theme.toml")).expect("Failed to parse default theme") + toml::from_slice::(include_bytes!("../../theme.toml")) + .map(|mut theme| { + theme.name = "default".to_string(); + theme + }) + .expect("Failed to parse default theme") }); pub static BASE16_DEFAULT_THEME: Lazy = Lazy::new(|| { - toml::from_slice(include_bytes!("../../base16_theme.toml")) + toml::from_slice::(include_bytes!("../../base16_theme.toml")) + .map(|mut theme| { + theme.name = "base16_default".to_string(); + theme + }) .expect("Failed to parse base 16 default theme") }); @@ -60,7 +69,8 @@ impl Loader { if let Some(path_str) = path_str { let tc = self.theme_cache.lock().unwrap(); if tc.contains_key(path_str) { - let theme = tc.get(path_str).unwrap().clone(); + let mut theme = tc.get(path_str).unwrap().clone(); + theme.name = name.to_string(); return Result::Ok(theme); } } @@ -68,11 +78,12 @@ impl Loader { let data = std::fs::read(&path)?; let theme = toml::from_slice::(data.as_slice()); match theme { - Ok(theme) => { + Ok(mut theme) => { if let Some(p) = path_str { let mut tc = self.theme_cache.lock().unwrap(); tc.insert(p.to_string(), theme.clone()); } + theme.name = name.to_string(); Ok(theme) } Result::Err(e) => Err(e).context("Failed to deserialize theme"), @@ -114,6 +125,7 @@ impl Loader { #[derive(Clone, Debug)] pub struct Theme { + pub name: String, // UI styles are stored in a HashMap styles: HashMap, // tree-sitter highlight styles are stored in a Vec to optimize lookups @@ -160,6 +172,7 @@ impl<'de> Deserialize<'de> for Theme { } Ok(Self { + name: String::new(), scopes, styles, highlights, From dcb09e08964c37124380a8b116f691c3301e754e Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Tue, 15 Mar 2022 00:24:11 -0400 Subject: [PATCH 09/28] Fix accidental comment flash deletion --- helix-term/src/commands/typed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 107edf129210..60b48de8409c 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -419,7 +419,7 @@ fn force_write_quit( } /// Results an error if there are modified buffers remaining and sets editor error, -// otherwise returns `Ok(())` +/// otherwise returns `Ok(())` pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> { let modified: Vec<_> = editor .documents() From 01781624d820a64643ec79e551798e085c455416 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 18 Jun 2022 17:53:31 -0400 Subject: [PATCH 10/28] Typo --- helix-term/src/commands/typed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 45e09681f599..bbad2f1ea371 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -35,7 +35,7 @@ fn quit( fn force_quit( cx: &mut compositor::Context, args: &[Cow], - _eventt: PromptEvent, + _event: PromptEvent, ) -> anyhow::Result<()> { ensure!(args.is_empty(), ":quit! takes no arguments"); From 5f85522d2712debce0accd1167726be0a92b738d Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 18 Jun 2022 17:58:49 -0400 Subject: [PATCH 11/28] Remove theme cache --- helix-view/src/theme.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index c9888821934d..fc11f9c92e7f 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -1,7 +1,6 @@ use std::{ collections::HashMap, path::{Path, PathBuf}, - sync::{Arc, Mutex}, }; use anyhow::Context; @@ -34,7 +33,6 @@ pub static BASE16_DEFAULT_THEME: Lazy = Lazy::new(|| { pub struct Loader { user_dir: PathBuf, default_dir: PathBuf, - theme_cache: Arc>>, } impl Loader { /// Creates a new loader that can load themes from two directories. @@ -42,7 +40,6 @@ impl Loader { Self { user_dir: user_dir.as_ref().join("themes"), default_dir: default_dir.as_ref().join("themes"), - theme_cache: Arc::new(Mutex::new(HashMap::new())), } } @@ -63,26 +60,10 @@ impl Loader { self.default_dir.join(filename) }; - let path_str = path.to_str(); - - // We can return the theme from the cache if it already exists - if let Some(path_str) = path_str { - let tc = self.theme_cache.lock().unwrap(); - if tc.contains_key(path_str) { - let mut theme = tc.get(path_str).unwrap().clone(); - theme.name = name.to_string(); - return Result::Ok(theme); - } - } - let data = std::fs::read(&path)?; let theme = toml::from_slice::(data.as_slice()); match theme { Ok(mut theme) => { - if let Some(p) = path_str { - let mut tc = self.theme_cache.lock().unwrap(); - tc.insert(p.to_string(), theme.clone()); - } theme.name = name.to_string(); Ok(theme) } From 97ed0d6af5d1f030cef838eca872b34f38fef33f Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 18 Jun 2022 18:03:03 -0400 Subject: [PATCH 12/28] Add some comments --- helix-view/src/editor.rs | 1 + helix-view/src/theme.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index cfb2d7ad005a..c7aa7c101887 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -449,6 +449,7 @@ pub struct Editor { pub syn_loader: Arc, pub theme_loader: Arc, + // last_theme is currently just used for theme previews pub last_theme: Option, pub status_msg: Option<(Cow<'static, str>, Severity)>, pub autoinfo: Option, diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index fc11f9c92e7f..d31fbd79629e 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -106,6 +106,7 @@ impl Loader { #[derive(Clone, Debug)] pub struct Theme { + /// The name of the theme, taken from the filename that it came from. pub name: String, // UI styles are stored in a HashMap styles: HashMap, From 01467e3e74f16364080580dc22dd488115024829 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 18 Jun 2022 18:21:14 -0400 Subject: [PATCH 13/28] Refactor some theme handling TIL flatmap on Option is called and_then --- helix-term/src/application.rs | 33 ++++++++------------------------- helix-view/src/theme.rs | 8 ++++++++ 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 505625d8fc52..1c7b97073c4a 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -86,9 +86,11 @@ impl Application { let true_color = config.editor.true_color || crate::true_color(); - let theme = match config.theme.as_ref() { - Some(theme_name) => { - match theme_loader + let theme = config + .theme + .as_ref() + .and_then(|theme_name| { + theme_loader .load(theme_name) .map_err(|e| { log::warn!("failed to load theme `{}` - {}", theme_name, e); @@ -96,13 +98,8 @@ impl Application { }) .ok() .filter(|theme| (true_color || theme.is_16_color())) - { - Some(theme) => theme, - None => Application::default_theme(theme_loader.clone(), true_color), - } - } - None => Application::default_theme(theme_loader.clone(), true_color), - }; + }) + .unwrap_or_else(|| theme_loader.default_theme(true_color)); let syn_loader_conf = user_syntax_loader().unwrap_or_else(|err| { eprintln!("Bad language config: {}", err); @@ -204,14 +201,6 @@ impl Application { Ok(app) } - fn default_theme(theme_loader: Arc, true_color: bool) -> theme::Theme { - if true_color { - theme_loader.default() - } else { - theme_loader.base16_default() - } - } - fn render(&mut self) { let mut cx = crate::compositor::Context { editor: &mut self.editor, @@ -318,13 +307,7 @@ impl Application { }) .ok() .filter(|theme| (true_color || theme.is_16_color())) - .unwrap_or_else(|| { - if true_color { - self.theme_loader.default() - } else { - self.theme_loader.base16_default() - } - }), + .unwrap_or_else(|| self.theme_loader.default_theme(true_color)), ); } diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index d31fbd79629e..4b17df733660 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -93,6 +93,14 @@ impl Loader { names } + pub fn default_theme(&self, true_color: bool) -> Theme { + if true_color { + self.default() + } else { + self.base16_default() + } + } + /// Returns the default theme pub fn default(&self) -> Theme { DEFAULT_THEME.clone() From b782d07d696ebba7d4bd0bc514ac00772aeb381f Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 19 Jun 2022 00:13:12 -0400 Subject: [PATCH 14/28] Remove unnecessary renames --- helix-term/src/application.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 1c7b97073c4a..9d32a1adbd84 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -85,15 +85,14 @@ impl Application { )); let true_color = config.editor.true_color || crate::true_color(); - let theme = config .theme .as_ref() - .and_then(|theme_name| { + .and_then(|theme| { theme_loader - .load(theme_name) + .load(theme) .map_err(|e| { - log::warn!("failed to load theme `{}` - {}", theme_name, e); + log::warn!("failed to load theme `{}` - {}", theme, e); e }) .ok() From 3e9b33e26c22eaca74873105555c3fa0a5c34403 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 19 Jun 2022 18:37:23 -0400 Subject: [PATCH 15/28] Constrain last_theme theme preview lifecycle --- helix-term/src/application.rs | 1 - helix-term/src/commands/typed.rs | 10 +++++----- helix-view/src/editor.rs | 22 +++++++++++++--------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 9d32a1adbd84..f1faeeea9557 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -119,7 +119,6 @@ impl Application { Box::new(Map::new(Arc::clone(&config), |config: &Config| { &config.editor })), - theme.name.clone(), ); let keys = Box::new(Map::new(Arc::clone(&config), |config: &Config| { diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index bbad2f1ea371..fd5f4a390723 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -600,6 +600,9 @@ fn theme( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if cx.editor.last_theme.is_none() { + cx.editor.last_theme = Some(Box::new(cx.editor.theme.clone())); + } let true_color = cx.editor.config.load().true_color || crate::true_color(); match event { PromptEvent::Abort => { @@ -1903,13 +1906,10 @@ pub fn command_mode(cx: &mut Context) { if let Err(e) = (cmd.fun)(cx, &args[1..], event) { cx.editor.set_error(format!("{}", e)); } - } else { - if event != PromptEvent::Validate { - return; - } + } else if event == PromptEvent::Validate { cx.editor .set_error(format!("no such command: '{}'", parts[0])); - }; + } }, ); prompt.doc_fn = Box::new(|input: &str| { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index c7aa7c101887..aa9230b14646 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -438,7 +438,6 @@ pub struct Editor { pub registers: Registers, pub macro_recording: Option<(char, Vec)>, pub macro_replaying: Vec, - pub theme: Theme, pub language_servers: helix_lsp::Registry, pub debugger: Option, @@ -449,8 +448,13 @@ pub struct Editor { pub syn_loader: Arc, pub theme_loader: Arc, - // last_theme is currently just used for theme previews - pub last_theme: Option, + /// last_theme is used for theme previews. We store the current theme here, + /// and if previewing is cancelled, we can return to it. + pub last_theme: Option>, + /// The currently applied editor theme. While previewing a theme, the previewed theme + /// is set here. + pub theme: Theme, + pub status_msg: Option<(Cow<'static, str>, Severity)>, pub autoinfo: Option, @@ -494,7 +498,6 @@ impl Editor { theme_loader: Arc, syn_loader: Arc, config: Box>, - current_theme: String, ) -> Self { let language_servers = helix_lsp::Registry::new(); let conf = config.load(); @@ -518,7 +521,7 @@ impl Editor { breakpoints: HashMap::new(), syn_loader, theme_loader, - last_theme: Some(current_theme), + last_theme: None, registers: Registers::default(), clipboard_provider: get_clipboard_provider(), status_msg: None, @@ -575,13 +578,14 @@ impl Editor { } pub fn unset_theme_preview(&mut self) { - if let Some(last_theme) = &self.last_theme.clone() { - match self.theme_loader.load(last_theme) { + if let Some(last_theme) = self.last_theme.take() { + let theme_name = &(*last_theme).name; + match self.theme_loader.load(theme_name) { Ok(theme) => { self.set_theme(theme); } Err(_e) => { - self.set_error(format!("Failed to set theme: '{}'", last_theme)); + self.set_error(format!("Failed to set theme: '{}'", theme_name)); } }; } @@ -592,7 +596,7 @@ impl Editor { } pub fn set_theme(&mut self, theme: Theme) { - self.last_theme = Some(theme.name.clone()); + self.last_theme = Some(Box::new(theme.clone())); self.set_theme_impl(theme); } From a05186f7e0e6d0b4c030748f30379769a8e09e25 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 19 Jun 2022 19:32:55 -0400 Subject: [PATCH 16/28] Switch to bitflag implementation --- helix-term/src/commands/typed.rs | 144 ++++++++++++++++--------------- helix-term/src/ui/prompt.rs | 7 +- 2 files changed, 78 insertions(+), 73 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index fd5f4a390723..a73b187d6c76 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1,3 +1,5 @@ +use std::ops::BitAnd; + use super::*; use helix_view::editor::{Action, ConfigEvent}; @@ -12,7 +14,7 @@ pub struct TypableCommand { pub fun: fn(&mut compositor::Context, &[Cow], PromptEvent) -> anyhow::Result<()>, pub completer: Option, /// Use `prompt_events` to declare which events this command will respond to. - pub prompt_events: &'static [PromptEvent], + pub prompt_events: u8, } fn quit( @@ -1269,7 +1271,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close the current view.", fun: quit, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "quit!", @@ -1277,7 +1279,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close the current view forcefully (ignoring unsaved changes).", fun: force_quit, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "open", @@ -1285,7 +1287,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open a file from disk into the current view.", fun: open, completer: Some(completers::filename), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close", @@ -1293,7 +1295,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close the current buffer.", fun: buffer_close, completer: Some(completers::buffer), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close!", @@ -1301,7 +1303,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close the current buffer forcefully (ignoring unsaved changes).", fun: force_buffer_close, completer: Some(completers::buffer), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close-others", @@ -1309,7 +1311,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close all buffers but the currently focused one.", fun: buffer_close_others, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close-others!", @@ -1317,7 +1319,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close all buffers but the currently focused one.", fun: force_buffer_close_others, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close-all", @@ -1325,7 +1327,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close all buffers, without quitting.", fun: buffer_close_all, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close-all!", @@ -1333,7 +1335,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close all buffers forcefully (ignoring unsaved changes), without quitting.", fun: force_buffer_close_all, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-next", @@ -1341,7 +1343,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Go to next buffer.", fun: buffer_next, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-previous", @@ -1349,7 +1351,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Go to previous buffer.", fun: buffer_previous, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write", @@ -1357,7 +1359,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes to disk. Accepts an optional path (:write some/path.txt)", fun: write, completer: Some(completers::filename), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write!", @@ -1365,7 +1367,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes to disk forcefully (creating necessary subdirectories). Accepts an optional path (:write some/path.txt)", fun: force_write, completer: Some(completers::filename), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "new", @@ -1373,7 +1375,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Create a new scratch buffer.", fun: new_file, completer: Some(completers::filename), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "format", @@ -1381,7 +1383,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Format the file using the LSP formatter.", fun: format, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "indent-style", @@ -1389,7 +1391,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.)", fun: set_indent_style, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "line-ending", @@ -1400,7 +1402,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Set the document's default line ending. Options: crlf, lf, cr, ff, nel.", fun: set_line_ending, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "earlier", @@ -1408,7 +1410,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Jump back to an earlier point in edit history. Accepts a number of steps or a time span.", fun: earlier, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "later", @@ -1416,14 +1418,14 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Jump to a later point in edit history. Accepts a number of steps or a time span.", fun: later, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write-quit", aliases: &["wq", "x"], doc: "Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt)", fun: write_quit, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, completer: Some(completers::filename), }, TypableCommand { @@ -1432,7 +1434,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt)", fun: force_write_quit, completer: Some(completers::filename), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write-all", @@ -1440,7 +1442,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes from all buffers to disk.", fun: write_all, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write-quit-all", @@ -1448,7 +1450,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes from all buffers to disk and close all views.", fun: write_all_quit, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write-quit-all!", @@ -1456,7 +1458,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes).", fun: force_write_all_quit, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "quit-all", @@ -1464,14 +1466,14 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close all views.", fun: quit_all, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "quit-all!", aliases: &["qa!"], doc: "Close all views forcefully (ignoring unsaved changes).", fun: force_quit_all, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, completer: None, }, TypableCommand { @@ -1480,7 +1482,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2).", fun: cquit, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "cquit!", @@ -1488,7 +1490,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Quit with exit code (default 1) forcefully (ignoring unsaved changes). Accepts an optional integer exit code (:cq! 2).", fun: force_cquit, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "theme", @@ -1496,7 +1498,9 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Change the editor theme.", fun: theme, completer: Some(completers::theme), - prompt_events: &[PromptEvent::Update, PromptEvent::Validate, PromptEvent::Abort], + prompt_events: PromptEvent::Update as u8 + | PromptEvent::Validate as u8 + | PromptEvent::Abort as u8, }, TypableCommand { name: "clipboard-yank", @@ -1504,7 +1508,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Yank main selection into system clipboard.", fun: yank_main_selection_to_clipboard, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "clipboard-yank-join", @@ -1512,7 +1516,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Yank joined selections into system clipboard. A separator can be provided as first argument. Default value is newline.", // FIXME: current UI can't display long doc. fun: yank_joined_to_clipboard, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "primary-clipboard-yank", @@ -1520,7 +1524,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Yank main selection into system primary clipboard.", fun: yank_main_selection_to_primary_clipboard, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "primary-clipboard-yank-join", @@ -1528,7 +1532,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Yank joined selections into system primary clipboard. A separator can be provided as first argument. Default value is newline.", // FIXME: current UI can't display long doc. fun: yank_joined_to_primary_clipboard, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "clipboard-paste-after", @@ -1536,7 +1540,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Paste system clipboard after selections.", fun: paste_clipboard_after, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "clipboard-paste-before", @@ -1544,7 +1548,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Paste system clipboard before selections.", fun: paste_clipboard_before, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "clipboard-paste-replace", @@ -1552,7 +1556,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Replace selections with content of system clipboard.", fun: replace_selections_with_clipboard, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "primary-clipboard-paste-after", @@ -1560,7 +1564,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Paste primary clipboard after selections.", fun: paste_primary_clipboard_after, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "primary-clipboard-paste-before", @@ -1568,7 +1572,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Paste primary clipboard before selections.", fun: paste_primary_clipboard_before, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "primary-clipboard-paste-replace", @@ -1576,7 +1580,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Replace selections with content of system primary clipboard.", fun: replace_selections_with_primary_clipboard, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "show-clipboard-provider", @@ -1584,7 +1588,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Show clipboard provider name in status bar.", fun: show_clipboard_provider, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "change-current-directory", @@ -1592,7 +1596,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Change the current working directory.", fun: change_current_directory, completer: Some(completers::directory), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "show-directory", @@ -1600,7 +1604,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Show the current working directory.", fun: show_current_directory, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "encoding", @@ -1608,7 +1612,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Set encoding based on `https://encoding.spec.whatwg.org`", fun: set_encoding, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "reload", @@ -1616,7 +1620,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Discard changes and reload from the source file.", fun: reload, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "tree-sitter-scopes", @@ -1624,7 +1628,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Display tree sitter scopes, primarily for theming and development.", fun: tree_sitter_scopes, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "debug-start", @@ -1632,7 +1636,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Start a debug session from a given template with given parameters.", fun: debug_start, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "debug-remote", @@ -1640,7 +1644,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters.", fun: debug_remote, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "debug-eval", @@ -1648,7 +1652,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Evaluate expression in current debug context.", fun: debug_eval, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "vsplit", @@ -1656,7 +1660,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open the file in a vertical split.", fun: vsplit, completer: Some(completers::filename), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "vsplit-new", @@ -1664,7 +1668,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open a scratch buffer in a vertical split.", fun: vsplit_new, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "hsplit", @@ -1672,7 +1676,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open the file in a horizontal split.", fun: hsplit, completer: Some(completers::filename), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "hsplit-new", @@ -1680,7 +1684,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open a scratch buffer in a horizontal split.", fun: hsplit_new, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "tutor", @@ -1688,7 +1692,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open the tutorial.", fun: tutor, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "goto", @@ -1696,7 +1700,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Go to line number.", fun: goto_line_number, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "set-language", @@ -1704,7 +1708,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Set the language of current buffer.", fun: language, completer: Some(completers::language), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "set-option", @@ -1712,7 +1716,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Set a config option at runtime.\nFor example to disable smart case search, use `:set search.smart-case false`.", fun: set_option, completer: Some(completers::setting), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "get-option", @@ -1720,7 +1724,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Get the current value of a config option.", fun: get_option, completer: Some(completers::setting), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "sort", @@ -1728,7 +1732,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Sort ranges in selection.", fun: sort, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "rsort", @@ -1736,7 +1740,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Sort ranges in selection in reverse order.", fun: sort_reverse, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "reflow", @@ -1744,7 +1748,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Hard-wrap the current selection of lines to a given width.", fun: reflow, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "tree-sitter-subtree", @@ -1752,7 +1756,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Display tree sitter subtree under cursor, primarily for debugging queries.", fun: tree_sitter_subtree, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "config-reload", @@ -1760,7 +1764,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Refreshes helix's config.", fun: refresh_config, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "config-open", @@ -1768,7 +1772,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open the helix config.toml file.", fun: open_config, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "log-open", @@ -1776,7 +1780,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open the helix log file.", fun: open_log, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "insert-output", @@ -1784,7 +1788,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Run shell command, inserting output after each selection.", fun: insert_output, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "append-output", @@ -1792,7 +1796,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Run shell command, appending output after each selection.", fun: append_output, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "pipe", @@ -1800,7 +1804,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Pipe each selection to the shell command.", fun: pipe, completer: None, - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "run-shell-command", @@ -1808,7 +1812,7 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Run a shell command", fun: run_shell_command, completer: Some(completers::directory), - prompt_events: &[PromptEvent::Validate], + prompt_events: PromptEvent::Validate as u8, }, ]; @@ -1889,7 +1893,7 @@ pub fn command_mode(cx: &mut Context) { // Handle typable commands if let Some(cmd) = typed::TYPABLE_COMMAND_MAP.get(parts[0]) { - if !cmd.prompt_events.contains(&event) { + if cmd.prompt_events.bitand(event as u8) == 0 { return; } diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 64154bae3d9b..7a69a824ff81 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -32,14 +32,15 @@ pub struct Prompt { next_char_handler: Option, } +#[repr(u8)] #[derive(Clone, Copy, PartialEq)] pub enum PromptEvent { /// The prompt input has been updated. - Update, + Update = 1 << 0, /// Validate and finalize the change. - Validate, + Validate = 1 << 1, /// Abort the change, reverting to the initial state. - Abort, + Abort = 1 << 2, } pub enum CompletionDirection { From a83069eb60d62450896110d25cce135a0d2e136b Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 19 Jun 2022 20:02:04 -0400 Subject: [PATCH 17/28] Better handling of last_theme --- helix-term/src/commands/typed.rs | 3 --- helix-view/src/editor.rs | 17 ++++++----------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index a73b187d6c76..868d8ddd9071 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -602,9 +602,6 @@ fn theme( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { - if cx.editor.last_theme.is_none() { - cx.editor.last_theme = Some(Box::new(cx.editor.theme.clone())); - } let true_color = cx.editor.config.load().true_color || crate::true_color(); match event { PromptEvent::Abort => { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index aa9230b14646..f1a925a5392a 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -450,7 +450,7 @@ pub struct Editor { pub theme_loader: Arc, /// last_theme is used for theme previews. We store the current theme here, /// and if previewing is cancelled, we can return to it. - pub last_theme: Option>, + pub last_theme: Option, /// The currently applied editor theme. While previewing a theme, the previewed theme /// is set here. pub theme: Theme, @@ -579,24 +579,19 @@ impl Editor { pub fn unset_theme_preview(&mut self) { if let Some(last_theme) = self.last_theme.take() { - let theme_name = &(*last_theme).name; - match self.theme_loader.load(theme_name) { - Ok(theme) => { - self.set_theme(theme); - } - Err(_e) => { - self.set_error(format!("Failed to set theme: '{}'", theme_name)); - } - }; + self.set_theme(last_theme); } } pub fn set_theme_preview(&mut self, theme: Theme) { + if self.last_theme.is_none() { + self.last_theme = Some(self.theme.clone()); + } self.set_theme_impl(theme); } pub fn set_theme(&mut self, theme: Theme) { - self.last_theme = Some(Box::new(theme.clone())); + self.last_theme = None; self.set_theme_impl(theme); } From 89ec841092da22617e68e24d656fbbb250655d64 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 19 Jun 2022 20:02:11 -0400 Subject: [PATCH 18/28] Sort theme names --- helix-term/src/ui/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 23d0dca0a342..60e8a60dbdee 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -240,6 +240,7 @@ pub mod completers { )); names.push("default".into()); names.push("base16_default".into()); + names.sort(); let mut names: Vec<_> = names .into_iter() From 1d1c8cc8615fae1c4f1579c5e5ff6c2d7720ff92 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 19 Jun 2022 20:09:32 -0400 Subject: [PATCH 19/28] Better memory juggling --- helix-view/src/editor.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index f1a925a5392a..6ca8782b47bc 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -581,21 +581,18 @@ impl Editor { if let Some(last_theme) = self.last_theme.take() { self.set_theme(last_theme); } + // None likely occurs when the user types ":theme" and then exits before previewing } pub fn set_theme_preview(&mut self, theme: Theme) { - if self.last_theme.is_none() { - self.last_theme = Some(self.theme.clone()); - } - self.set_theme_impl(theme); + self.set_theme_impl(theme, true); } pub fn set_theme(&mut self, theme: Theme) { - self.last_theme = None; - self.set_theme_impl(theme); + self.set_theme_impl(theme, false); } - fn set_theme_impl(&mut self, theme: Theme) { + fn set_theme_impl(&mut self, theme: Theme, preview: bool) { // `ui.selection` is the only scope required to be able to render a theme. if theme.find_scope_index("ui.selection").is_none() { self.set_error("Invalid theme: `ui.selection` required"); @@ -604,7 +601,14 @@ impl Editor { let scopes = theme.scopes(); self.syn_loader.set_scopes(scopes.to_vec()); - self.theme = theme; + if preview { + if self.last_theme.is_none() { + self.last_theme = Some(std::mem::replace(&mut self.theme, theme)); + } + } else { + self.last_theme = None; + self.theme = theme; + } self._refresh(); } From 0af7ed63697ee7dd904ac3bcb122daa3be86be04 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 19 Jun 2022 20:12:25 -0400 Subject: [PATCH 20/28] Missed a branch --- helix-view/src/editor.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 6ca8782b47bc..320dc8da2b61 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -601,14 +601,20 @@ impl Editor { let scopes = theme.scopes(); self.syn_loader.set_scopes(scopes.to_vec()); + if preview { if self.last_theme.is_none() { + // On the first preview self.last_theme = Some(std::mem::replace(&mut self.theme, theme)); + } else { + // Subsequent previews + self.theme = theme; } } else { self.last_theme = None; self.theme = theme; } + self._refresh(); } From a8514d0271d1e6198212e743c4cfb4b856cb1ae0 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Tue, 21 Jun 2022 21:49:59 -0400 Subject: [PATCH 21/28] Remove name from theme, switch bitand to & --- helix-term/src/commands/typed.rs | 4 +--- helix-view/src/theme.rs | 20 +------------------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 868d8ddd9071..d6a291897ff9 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1,5 +1,3 @@ -use std::ops::BitAnd; - use super::*; use helix_view::editor::{Action, ConfigEvent}; @@ -1890,7 +1888,7 @@ pub fn command_mode(cx: &mut Context) { // Handle typable commands if let Some(cmd) = typed::TYPABLE_COMMAND_MAP.get(parts[0]) { - if cmd.prompt_events.bitand(event as u8) == 0 { + if cmd.prompt_events & (event as u8) == 0 { return; } diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 4b17df733660..4e3723fbec34 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -14,18 +14,10 @@ pub use crate::graphics::{Color, Modifier, Style}; pub static DEFAULT_THEME: Lazy = Lazy::new(|| { toml::from_slice::(include_bytes!("../../theme.toml")) - .map(|mut theme| { - theme.name = "default".to_string(); - theme - }) .expect("Failed to parse default theme") }); pub static BASE16_DEFAULT_THEME: Lazy = Lazy::new(|| { toml::from_slice::(include_bytes!("../../base16_theme.toml")) - .map(|mut theme| { - theme.name = "base16_default".to_string(); - theme - }) .expect("Failed to parse base 16 default theme") }); @@ -61,14 +53,7 @@ impl Loader { }; let data = std::fs::read(&path)?; - let theme = toml::from_slice::(data.as_slice()); - match theme { - Ok(mut theme) => { - theme.name = name.to_string(); - Ok(theme) - } - Result::Err(e) => Err(e).context("Failed to deserialize theme"), - } + toml::from_slice::(data.as_slice()).context("Failed to deserialize theme") } pub fn read_names(path: &Path) -> Vec { @@ -114,8 +99,6 @@ impl Loader { #[derive(Clone, Debug)] pub struct Theme { - /// The name of the theme, taken from the filename that it came from. - pub name: String, // UI styles are stored in a HashMap styles: HashMap, // tree-sitter highlight styles are stored in a Vec to optimize lookups @@ -162,7 +145,6 @@ impl<'de> Deserialize<'de> for Theme { } Ok(Self { - name: String::new(), scopes, styles, highlights, From 860665bad5701e9b67904ba08ab6509fa21036e6 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Tue, 21 Jun 2022 23:35:46 -0400 Subject: [PATCH 22/28] cargo fmt --- helix-view/src/editor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 44d1e1b91fc4..78566885a23f 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -615,7 +615,7 @@ impl Editor { self.set_theme(last_theme); } // None likely occurs when the user types ":theme" and then exits before previewing - } + } pub fn set_theme_preview(&mut self, theme: Theme) { self.set_theme_impl(theme, true); From 5eb1d41db11cb503e1a1afd480b5bb5f17b19752 Mon Sep 17 00:00:00 2001 From: Joe Date: Fri, 24 Jun 2022 02:05:26 -0400 Subject: [PATCH 23/28] Update helix-view/src/editor.rs --- helix-view/src/editor.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 78566885a23f..68945d7c8d35 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -636,13 +636,9 @@ impl Editor { self.syn_loader.set_scopes(scopes.to_vec()); if preview { - if self.last_theme.is_none() { - // On the first preview - self.last_theme = Some(std::mem::replace(&mut self.theme, theme)); - } else { - // Subsequent previews - self.theme = theme; - } + let last_theme = std::mem::replace(&mut self.theme, theme); + // only insert on first preview: this will be the last theme the user has saved + self.last_theme.get_or_insert(last_theme); } else { self.last_theme = None; self.theme = theme; From 5a313c91d6e3fc05e01289056016721dcfd2186d Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 26 Jun 2022 16:54:50 -0400 Subject: [PATCH 24/28] Switch boolean to enum --- helix-term/src/commands/typed.rs | 8 ++++---- helix-view/src/editor.rs | 32 ++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index ab78e225e688..b3e48694b769 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1293,16 +1293,16 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ aliases: &["bc", "bclose"], doc: "Close the current buffer.", fun: buffer_close, - completer: Some(completers::buffer), - prompt_events: PromptEvent::Validate as u8, + completer: Some(completers::buffer), + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close!", aliases: &["bc!", "bclose!"], doc: "Close the current buffer forcefully (ignoring unsaved changes).", fun: force_buffer_close, - completer: Some(completers::buffer), - prompt_events: PromptEvent::Validate as u8, + completer: Some(completers::buffer), + prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close-others", diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 78566885a23f..899a4d5f1175 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -497,6 +497,11 @@ pub enum ConfigEvent { Update(Box), } +enum ThemeAction { + Set, + Preview, +} + #[derive(Debug, Clone)] pub struct CompleteAction { pub trigger_offset: usize, @@ -618,14 +623,14 @@ impl Editor { } pub fn set_theme_preview(&mut self, theme: Theme) { - self.set_theme_impl(theme, true); + self.set_theme_impl(theme, ThemeAction::Preview); } pub fn set_theme(&mut self, theme: Theme) { - self.set_theme_impl(theme, false); + self.set_theme_impl(theme, ThemeAction::Set); } - fn set_theme_impl(&mut self, theme: Theme, preview: bool) { + fn set_theme_impl(&mut self, theme: Theme, preview: ThemeAction) { // `ui.selection` is the only scope required to be able to render a theme. if theme.find_scope_index("ui.selection").is_none() { self.set_error("Invalid theme: `ui.selection` required"); @@ -635,17 +640,20 @@ impl Editor { let scopes = theme.scopes(); self.syn_loader.set_scopes(scopes.to_vec()); - if preview { - if self.last_theme.is_none() { - // On the first preview - self.last_theme = Some(std::mem::replace(&mut self.theme, theme)); - } else { - // Subsequent previews + match preview { + ThemeAction::Preview => { + if self.last_theme.is_none() { + // On the first preview + self.last_theme = Some(std::mem::replace(&mut self.theme, theme)); + } else { + // Subsequent previews + self.theme = theme; + } + } + ThemeAction::Set => { + self.last_theme = None; self.theme = theme; } - } else { - self.last_theme = None; - self.theme = theme; } self._refresh(); From 670f0b81876c3197c6b2f5b028545372245ab27c Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 2 Jul 2022 12:25:50 -0400 Subject: [PATCH 25/28] Remove bitflag impl --- helix-term/src/commands/typed.rs | 475 ++++++++++++++++++++++--------- helix-term/src/ui/prompt.rs | 7 +- 2 files changed, 339 insertions(+), 143 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index b3e48694b769..f63705eb4dca 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -13,15 +13,17 @@ pub struct TypableCommand { // params, flags, helper, completer pub fun: fn(&mut compositor::Context, &[Cow], PromptEvent) -> anyhow::Result<()>, pub completer: Option, - /// Use `prompt_events` to declare which events this command will respond to. - pub prompt_events: u8, } fn quit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(args.is_empty(), ":quit takes no arguments"); // last view and we have unsaved changes @@ -37,8 +39,12 @@ fn quit( fn force_quit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(args.is_empty(), ":quit! takes no arguments"); cx.editor.close(view!(cx.editor).id); @@ -49,8 +55,12 @@ fn force_quit( fn open( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(!args.is_empty(), "wrong argument count"); for arg in args { let (path, pos) = args::parse_file(arg); @@ -69,6 +79,7 @@ fn buffer_close_by_ids_impl( doc_ids: &[DocumentId], force: bool, ) -> anyhow::Result<()> { + for &doc_id in doc_ids { editor.close_document(doc_id, force)?; } @@ -116,8 +127,12 @@ fn buffer_gather_paths_impl(editor: &mut Editor, args: &[Cow]) -> Vec], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_paths_impl(cx.editor, args); buffer_close_by_ids_impl(cx.editor, &document_ids, false) } @@ -125,8 +140,12 @@ fn buffer_close( fn force_buffer_close( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_paths_impl(cx.editor, args); buffer_close_by_ids_impl(cx.editor, &document_ids, true) } @@ -143,8 +162,12 @@ fn buffer_gather_others_impl(editor: &mut Editor) -> Vec { fn buffer_close_others( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_others_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, false) } @@ -152,8 +175,12 @@ fn buffer_close_others( fn force_buffer_close_others( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_others_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, true) } @@ -165,8 +192,12 @@ fn buffer_gather_all_impl(editor: &mut Editor) -> Vec { fn buffer_close_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_all_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, false) } @@ -174,8 +205,12 @@ fn buffer_close_all( fn force_buffer_close_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let document_ids = buffer_gather_all_impl(cx.editor); buffer_close_by_ids_impl(cx.editor, &document_ids, true) } @@ -183,8 +218,12 @@ fn force_buffer_close_all( fn buffer_next( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + goto_buffer(cx.editor, Direction::Forward); Ok(()) } @@ -192,8 +231,12 @@ fn buffer_next( fn buffer_previous( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + goto_buffer(cx.editor, Direction::Backward); Ok(()) } @@ -244,24 +287,36 @@ fn write_impl( fn write( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_impl(cx, args.first(), false) } fn force_write( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_impl(cx, args.first(), true) } fn new_file( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor.new_file(Action::Replace); Ok(()) @@ -270,8 +325,12 @@ fn new_file( fn format( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let doc = doc!(cx.editor); if let Some(format) = doc.format() { let callback = @@ -284,8 +343,12 @@ fn format( fn set_indent_style( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + use IndentStyle::*; // If no argument, report current indent style. @@ -323,8 +386,12 @@ fn set_indent_style( fn set_line_ending( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + use LineEnding::*; // If no argument, report current line ending setting. @@ -393,8 +460,12 @@ fn set_line_ending( fn earlier( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; let (view, doc) = current!(cx.editor); @@ -409,8 +480,12 @@ fn earlier( fn later( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; let (view, doc) = current!(cx.editor); let success = doc.later(view.id, uk); @@ -426,6 +501,10 @@ fn write_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_impl(cx, args.first(), false)?; helix_lsp::block_on(cx.jobs.finish())?; quit(cx, &[], event) @@ -436,6 +515,10 @@ fn force_write_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_impl(cx, args.first(), true)?; force_quit(cx, &[], event) } @@ -465,10 +548,14 @@ pub(super) fn buffers_remaining_impl(editor: &mut Editor) -> anyhow::Result<()> fn write_all_impl( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, quit: bool, force: bool, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let mut errors = String::new(); let auto_format = cx.editor.config().auto_format; let jobs = &mut cx.jobs; @@ -522,6 +609,10 @@ fn write_all( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_all_impl(cx, args, event, false, false) } @@ -530,6 +621,10 @@ fn write_all_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_all_impl(cx, args, event, true, false) } @@ -538,6 +633,10 @@ fn force_write_all_quit( args: &[Cow], event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + write_all_impl(cx, args, event, true, true) } @@ -558,24 +657,36 @@ fn quit_all_impl(editor: &mut Editor, force: bool) -> anyhow::Result<()> { fn quit_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + quit_all_impl(cx.editor, false) } fn force_quit_all( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + quit_all_impl(cx.editor, true) } fn cquit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let exit_code = args .first() .and_then(|code| code.parse::().ok()) @@ -588,8 +699,12 @@ fn cquit( fn force_cquit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let exit_code = args .first() .and_then(|code| code.parse::().ok()) @@ -639,16 +754,24 @@ fn theme( fn yank_main_selection_to_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard) } fn yank_joined_to_clipboard( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let doc = doc!(cx.editor); let default_sep = Cow::Borrowed(doc.line_ending.as_str()); let separator = args.first().unwrap_or(&default_sep); @@ -658,16 +781,24 @@ fn yank_joined_to_clipboard( fn yank_main_selection_to_primary_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Selection) } fn yank_joined_to_primary_clipboard( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let doc = doc!(cx.editor); let default_sep = Cow::Borrowed(doc.line_ending.as_str()); let separator = args.first().unwrap_or(&default_sep); @@ -677,32 +808,48 @@ fn yank_joined_to_primary_clipboard( fn paste_clipboard_after( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Clipboard, 1) } fn paste_clipboard_before( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Clipboard, 1) } fn paste_primary_clipboard_after( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + paste_clipboard_impl(cx.editor, Paste::After, ClipboardType::Selection, 1) } fn paste_primary_clipboard_before( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + paste_clipboard_impl(cx.editor, Paste::Before, ClipboardType::Selection, 1) } @@ -730,24 +877,36 @@ fn replace_selections_with_clipboard_impl( fn replace_selections_with_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + replace_selections_with_clipboard_impl(cx, ClipboardType::Clipboard) } fn replace_selections_with_primary_clipboard( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + replace_selections_with_clipboard_impl(cx, ClipboardType::Selection) } fn show_clipboard_provider( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor .set_status(cx.editor.clipboard_provider.name().to_string()); Ok(()) @@ -756,8 +915,12 @@ fn show_clipboard_provider( fn change_current_directory( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let dir = helix_core::path::expand_tilde( args.first() .context("target directory not provided")? @@ -780,8 +943,12 @@ fn change_current_directory( fn show_current_directory( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let cwd = std::env::current_dir().context("Couldn't get the new working directory")?; cx.editor .set_status(format!("Current working directory is {}", cwd.display())); @@ -792,8 +959,12 @@ fn show_current_directory( fn set_encoding( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let doc = doc_mut!(cx.editor); if let Some(label) = args.first() { doc.set_encoding(label) @@ -808,8 +979,12 @@ fn set_encoding( fn reload( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let scrolloff = cx.editor.config().scrolloff; let (view, doc) = current!(cx.editor); doc.reload(view.id).map(|_| { @@ -820,8 +995,12 @@ fn reload( fn tree_sitter_scopes( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let (view, doc) = current!(cx.editor); let text = doc.text().slice(..); @@ -834,8 +1013,12 @@ fn tree_sitter_scopes( fn vsplit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let id = view!(cx.editor).doc; if args.is_empty() { @@ -853,8 +1036,12 @@ fn vsplit( fn hsplit( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let id = view!(cx.editor).doc; if args.is_empty() { @@ -872,8 +1059,12 @@ fn hsplit( fn vsplit_new( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor.new_file(Action::VerticalSplit); Ok(()) @@ -882,8 +1073,12 @@ fn vsplit_new( fn hsplit_new( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor.new_file(Action::HorizontalSplit); Ok(()) @@ -892,8 +1087,12 @@ fn hsplit_new( fn debug_eval( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + if let Some(debugger) = cx.editor.debugger.as_mut() { let (frame, thread_id) = match (debugger.active_frame, debugger.thread_id) { (Some(frame), Some(thread_id)) => (frame, thread_id), @@ -914,8 +1113,12 @@ fn debug_eval( fn debug_start( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let mut args = args.to_owned(); let name = match args.len() { 0 => None, @@ -927,8 +1130,12 @@ fn debug_start( fn debug_remote( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let mut args = args.to_owned(); let address = match args.len() { 0 => None, @@ -944,8 +1151,12 @@ fn debug_remote( fn tutor( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let path = helix_loader::runtime_dir().join("tutor.txt"); cx.editor.open(&path, Action::Replace)?; // Unset path to prevent accidentally saving to the original tutor file. @@ -956,8 +1167,12 @@ fn tutor( pub(super) fn goto_line_number( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(!args.is_empty(), "Line number required"); let line = args[0].parse::()?; @@ -974,8 +1189,12 @@ pub(super) fn goto_line_number( fn get_option( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + if args.len() != 1 { anyhow::bail!("Bad arguments. Usage: `:get key`"); } @@ -996,8 +1215,12 @@ fn get_option( fn set_option( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + if args.len() != 2 { anyhow::bail!("Bad arguments. Usage: `:set key field`"); } @@ -1029,8 +1252,12 @@ fn set_option( fn language( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + if args.len() != 1 { anyhow::bail!("Bad arguments. Usage: `:set-language language`"); } @@ -1046,16 +1273,24 @@ fn language( fn sort( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + sort_impl(cx, args, false) } fn sort_reverse( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + sort_impl(cx, args, true) } @@ -1096,8 +1331,12 @@ fn sort_impl( fn reflow( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let (view, doc) = current!(cx.editor); const DEFAULT_MAX_LEN: usize = 79; @@ -1135,8 +1374,12 @@ fn reflow( fn tree_sitter_subtree( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let (view, doc) = current!(cx.editor); if let Some(syntax) = doc.syntax() { @@ -1171,8 +1414,12 @@ fn tree_sitter_subtree( fn open_config( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor .open(&helix_loader::config_file(), Action::Replace)?; Ok(()) @@ -1181,8 +1428,12 @@ fn open_config( fn open_log( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor.open(&helix_loader::log_file(), Action::Replace)?; Ok(()) } @@ -1190,8 +1441,12 @@ fn open_log( fn refresh_config( cx: &mut compositor::Context, _args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + cx.editor.config_events.0.send(ConfigEvent::Refresh)?; Ok(()) } @@ -1199,8 +1454,12 @@ fn refresh_config( fn append_output( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(!args.is_empty(), "Shell command required"); shell(cx, &args.join(" "), &ShellBehavior::Append); Ok(()) @@ -1209,8 +1468,12 @@ fn append_output( fn insert_output( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(!args.is_empty(), "Shell command required"); shell(cx, &args.join(" "), &ShellBehavior::Insert); Ok(()) @@ -1219,8 +1482,12 @@ fn insert_output( fn pipe( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + ensure!(!args.is_empty(), "Shell command required"); shell(cx, &args.join(" "), &ShellBehavior::Replace); Ok(()) @@ -1229,8 +1496,12 @@ fn pipe( fn run_shell_command( cx: &mut compositor::Context, args: &[Cow], - _event: PromptEvent, + event: PromptEvent, ) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + let shell = &cx.editor.config().shell; let (output, success) = shell_impl(shell, &args.join(" "), None)?; if success { @@ -1270,7 +1541,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close the current view.", fun: quit, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "quit!", @@ -1278,7 +1548,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close the current view forcefully (ignoring unsaved changes).", fun: force_quit, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "open", @@ -1286,7 +1555,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open a file from disk into the current view.", fun: open, completer: Some(completers::filename), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close", @@ -1294,7 +1562,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close the current buffer.", fun: buffer_close, completer: Some(completers::buffer), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close!", @@ -1302,7 +1569,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close the current buffer forcefully (ignoring unsaved changes).", fun: force_buffer_close, completer: Some(completers::buffer), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close-others", @@ -1310,7 +1576,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close all buffers but the currently focused one.", fun: buffer_close_others, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close-others!", @@ -1318,7 +1583,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close all buffers but the currently focused one.", fun: force_buffer_close_others, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close-all", @@ -1326,7 +1590,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close all buffers, without quitting.", fun: buffer_close_all, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-close-all!", @@ -1334,7 +1597,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close all buffers forcefully (ignoring unsaved changes), without quitting.", fun: force_buffer_close_all, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-next", @@ -1342,7 +1604,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Go to next buffer.", fun: buffer_next, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "buffer-previous", @@ -1350,7 +1611,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Go to previous buffer.", fun: buffer_previous, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write", @@ -1358,7 +1618,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes to disk. Accepts an optional path (:write some/path.txt)", fun: write, completer: Some(completers::filename), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write!", @@ -1366,7 +1625,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes to disk forcefully (creating necessary subdirectories). Accepts an optional path (:write some/path.txt)", fun: force_write, completer: Some(completers::filename), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "new", @@ -1374,7 +1632,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Create a new scratch buffer.", fun: new_file, completer: Some(completers::filename), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "format", @@ -1382,7 +1639,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Format the file using the LSP formatter.", fun: format, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "indent-style", @@ -1390,7 +1646,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Set the indentation style for editing. ('t' for tabs or 1-8 for number of spaces.)", fun: set_indent_style, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "line-ending", @@ -1401,7 +1656,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Set the document's default line ending. Options: crlf, lf, cr, ff, nel.", fun: set_line_ending, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "earlier", @@ -1409,7 +1663,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Jump back to an earlier point in edit history. Accepts a number of steps or a time span.", fun: earlier, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "later", @@ -1417,14 +1670,12 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Jump to a later point in edit history. Accepts a number of steps or a time span.", fun: later, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write-quit", aliases: &["wq", "x"], doc: "Write changes to disk and close the current view. Accepts an optional path (:wq some/path.txt)", fun: write_quit, - prompt_events: PromptEvent::Validate as u8, completer: Some(completers::filename), }, TypableCommand { @@ -1433,7 +1684,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes to disk and close the current view forcefully. Accepts an optional path (:wq! some/path.txt)", fun: force_write_quit, completer: Some(completers::filename), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write-all", @@ -1441,7 +1691,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes from all buffers to disk.", fun: write_all, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write-quit-all", @@ -1449,7 +1698,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes from all buffers to disk and close all views.", fun: write_all_quit, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "write-quit-all!", @@ -1457,7 +1705,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Write changes from all buffers to disk and close all views forcefully (ignoring unsaved changes).", fun: force_write_all_quit, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "quit-all", @@ -1465,14 +1712,12 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Close all views.", fun: quit_all, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "quit-all!", aliases: &["qa!"], doc: "Close all views forcefully (ignoring unsaved changes).", fun: force_quit_all, - prompt_events: PromptEvent::Validate as u8, completer: None, }, TypableCommand { @@ -1481,7 +1726,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2).", fun: cquit, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "cquit!", @@ -1489,7 +1733,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Quit with exit code (default 1) forcefully (ignoring unsaved changes). Accepts an optional integer exit code (:cq! 2).", fun: force_cquit, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "theme", @@ -1497,9 +1740,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Change the editor theme.", fun: theme, completer: Some(completers::theme), - prompt_events: PromptEvent::Update as u8 - | PromptEvent::Validate as u8 - | PromptEvent::Abort as u8, }, TypableCommand { name: "clipboard-yank", @@ -1507,7 +1747,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Yank main selection into system clipboard.", fun: yank_main_selection_to_clipboard, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "clipboard-yank-join", @@ -1515,7 +1754,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Yank joined selections into system clipboard. A separator can be provided as first argument. Default value is newline.", // FIXME: current UI can't display long doc. fun: yank_joined_to_clipboard, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "primary-clipboard-yank", @@ -1523,7 +1761,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Yank main selection into system primary clipboard.", fun: yank_main_selection_to_primary_clipboard, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "primary-clipboard-yank-join", @@ -1531,7 +1768,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Yank joined selections into system primary clipboard. A separator can be provided as first argument. Default value is newline.", // FIXME: current UI can't display long doc. fun: yank_joined_to_primary_clipboard, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "clipboard-paste-after", @@ -1539,7 +1775,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Paste system clipboard after selections.", fun: paste_clipboard_after, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "clipboard-paste-before", @@ -1547,7 +1782,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Paste system clipboard before selections.", fun: paste_clipboard_before, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "clipboard-paste-replace", @@ -1555,7 +1789,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Replace selections with content of system clipboard.", fun: replace_selections_with_clipboard, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "primary-clipboard-paste-after", @@ -1563,7 +1796,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Paste primary clipboard after selections.", fun: paste_primary_clipboard_after, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "primary-clipboard-paste-before", @@ -1571,7 +1803,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Paste primary clipboard before selections.", fun: paste_primary_clipboard_before, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "primary-clipboard-paste-replace", @@ -1579,7 +1810,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Replace selections with content of system primary clipboard.", fun: replace_selections_with_primary_clipboard, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "show-clipboard-provider", @@ -1587,7 +1817,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Show clipboard provider name in status bar.", fun: show_clipboard_provider, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "change-current-directory", @@ -1595,7 +1824,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Change the current working directory.", fun: change_current_directory, completer: Some(completers::directory), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "show-directory", @@ -1603,7 +1831,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Show the current working directory.", fun: show_current_directory, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "encoding", @@ -1611,7 +1838,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Set encoding based on `https://encoding.spec.whatwg.org`", fun: set_encoding, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "reload", @@ -1619,7 +1845,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Discard changes and reload from the source file.", fun: reload, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "tree-sitter-scopes", @@ -1627,7 +1852,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Display tree sitter scopes, primarily for theming and development.", fun: tree_sitter_scopes, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "debug-start", @@ -1635,7 +1859,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Start a debug session from a given template with given parameters.", fun: debug_start, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "debug-remote", @@ -1643,7 +1866,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Connect to a debug adapter by TCP address and start a debugging session from a given template with given parameters.", fun: debug_remote, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "debug-eval", @@ -1651,7 +1873,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Evaluate expression in current debug context.", fun: debug_eval, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "vsplit", @@ -1659,7 +1880,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open the file in a vertical split.", fun: vsplit, completer: Some(completers::filename), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "vsplit-new", @@ -1667,7 +1887,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open a scratch buffer in a vertical split.", fun: vsplit_new, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "hsplit", @@ -1675,7 +1894,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open the file in a horizontal split.", fun: hsplit, completer: Some(completers::filename), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "hsplit-new", @@ -1683,7 +1901,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open a scratch buffer in a horizontal split.", fun: hsplit_new, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "tutor", @@ -1691,7 +1908,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open the tutorial.", fun: tutor, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "goto", @@ -1699,7 +1915,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Go to line number.", fun: goto_line_number, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "set-language", @@ -1707,7 +1922,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Set the language of current buffer.", fun: language, completer: Some(completers::language), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "set-option", @@ -1715,7 +1929,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Set a config option at runtime.\nFor example to disable smart case search, use `:set search.smart-case false`.", fun: set_option, completer: Some(completers::setting), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "get-option", @@ -1723,7 +1936,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Get the current value of a config option.", fun: get_option, completer: Some(completers::setting), - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "sort", @@ -1731,7 +1943,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Sort ranges in selection.", fun: sort, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "rsort", @@ -1739,7 +1950,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Sort ranges in selection in reverse order.", fun: sort_reverse, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "reflow", @@ -1747,7 +1957,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Hard-wrap the current selection of lines to a given width.", fun: reflow, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "tree-sitter-subtree", @@ -1755,7 +1964,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Display tree sitter subtree under cursor, primarily for debugging queries.", fun: tree_sitter_subtree, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "config-reload", @@ -1763,7 +1971,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Refreshes helix's config.", fun: refresh_config, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "config-open", @@ -1771,7 +1978,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open the helix config.toml file.", fun: open_config, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "log-open", @@ -1779,7 +1985,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Open the helix log file.", fun: open_log, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "insert-output", @@ -1787,7 +1992,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Run shell command, inserting output after each selection.", fun: insert_output, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "append-output", @@ -1795,7 +1999,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Run shell command, appending output after each selection.", fun: append_output, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "pipe", @@ -1803,7 +2006,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Pipe each selection to the shell command.", fun: pipe, completer: None, - prompt_events: PromptEvent::Validate as u8, }, TypableCommand { name: "run-shell-command", @@ -1811,7 +2013,6 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ doc: "Run a shell command", fun: run_shell_command, completer: Some(completers::directory), - prompt_events: PromptEvent::Validate as u8, }, ]; @@ -1892,10 +2093,6 @@ pub fn command_mode(cx: &mut Context) { // Handle typable commands if let Some(cmd) = typed::TYPABLE_COMMAND_MAP.get(parts[0]) { - if cmd.prompt_events & (event as u8) == 0 { - return; - } - let args = shellwords::shellwords(input); if let Err(e) = (cmd.fun)(cx, &args[1..], event) { diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index ca56371d2c72..beba8ce9a06b 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -32,15 +32,14 @@ pub struct Prompt { next_char_handler: Option, } -#[repr(u8)] #[derive(Clone, Copy, PartialEq)] pub enum PromptEvent { /// The prompt input has been updated. - Update = 1 << 0, + Update, /// Validate and finalize the change. - Validate = 1 << 1, + Validate, /// Abort the change, reverting to the initial state. - Abort = 1 << 2, + Abort, } pub enum CompletionDirection { From b81aedf43842ffc4c22dd777fdf804b26b751d9f Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 2 Jul 2022 12:26:50 -0400 Subject: [PATCH 26/28] cargo fmt --- helix-term/src/commands/typed.rs | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index f63705eb4dca..4e1ac0da9a9c 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -15,11 +15,7 @@ pub struct TypableCommand { pub completer: Option, } -fn quit( - cx: &mut compositor::Context, - args: &[Cow], - event: PromptEvent, -) -> anyhow::Result<()> { +fn quit(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { if event != PromptEvent::Validate { return Ok(()); } @@ -52,11 +48,7 @@ fn force_quit( Ok(()) } -fn open( - cx: &mut compositor::Context, - args: &[Cow], - event: PromptEvent, -) -> anyhow::Result<()> { +fn open(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { if event != PromptEvent::Validate { return Ok(()); } @@ -79,7 +71,6 @@ fn buffer_close_by_ids_impl( doc_ids: &[DocumentId], force: bool, ) -> anyhow::Result<()> { - for &doc_id in doc_ids { editor.close_document(doc_id, force)?; } @@ -1270,11 +1261,7 @@ fn language( Ok(()) } -fn sort( - cx: &mut compositor::Context, - args: &[Cow], - event: PromptEvent, -) -> anyhow::Result<()> { +fn sort(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { if event != PromptEvent::Validate { return Ok(()); } @@ -1479,11 +1466,7 @@ fn insert_output( Ok(()) } -fn pipe( - cx: &mut compositor::Context, - args: &[Cow], - event: PromptEvent, -) -> anyhow::Result<()> { +fn pipe(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { if event != PromptEvent::Validate { return Ok(()); } From 8f6991f8faa977fed80ed099509ee402e0c2451c Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 2 Jul 2022 12:28:23 -0400 Subject: [PATCH 27/28] Remove un-needed type arg --- helix-view/src/theme.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 4e3723fbec34..8fd5680a84e2 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -13,11 +13,11 @@ use toml::Value; pub use crate::graphics::{Color, Modifier, Style}; pub static DEFAULT_THEME: Lazy = Lazy::new(|| { - toml::from_slice::(include_bytes!("../../theme.toml")) + toml::from_slice(include_bytes!("../../theme.toml")) .expect("Failed to parse default theme") }); pub static BASE16_DEFAULT_THEME: Lazy = Lazy::new(|| { - toml::from_slice::(include_bytes!("../../base16_theme.toml")) + toml::from_slice(include_bytes!("../../base16_theme.toml")) .expect("Failed to parse base 16 default theme") }); From 251d61af09012afcba4e3310d5c9aa0d3e8bd5d6 Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sat, 2 Jul 2022 12:29:15 -0400 Subject: [PATCH 28/28] cargo fmt --- helix-view/src/theme.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 8fd5680a84e2..fa5fa702804b 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -13,8 +13,7 @@ use toml::Value; pub use crate::graphics::{Color, Modifier, Style}; pub static DEFAULT_THEME: Lazy = Lazy::new(|| { - toml::from_slice(include_bytes!("../../theme.toml")) - .expect("Failed to parse default theme") + toml::from_slice(include_bytes!("../../theme.toml")).expect("Failed to parse default theme") }); pub static BASE16_DEFAULT_THEME: Lazy = Lazy::new(|| { toml::from_slice(include_bytes!("../../base16_theme.toml")) @@ -53,7 +52,7 @@ impl Loader { }; let data = std::fs::read(&path)?; - toml::from_slice::(data.as_slice()).context("Failed to deserialize theme") + toml::from_slice(data.as_slice()).context("Failed to deserialize theme") } pub fn read_names(path: &Path) -> Vec {