diff --git a/helix-event/Cargo.toml b/helix-event/Cargo.toml index 6d86d165b..db0ed69df 100644 --- a/helix-event/Cargo.toml +++ b/helix-event/Cargo.toml @@ -18,8 +18,8 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p # the event registry is essentially read only but must be an rwlock so we can # setup new events on intalization, hardware-lock-elision hugnly benefits this case # as is essentially makes the lock entirely free as long as there is no writes -once_cell = "1.21" parking_lot = { workspace = true, features = ["hardware-lock-elision"] } +once_cell = "1.21" anyhow = "1" log = "0.4" diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index f2f9f9fca..be794d500 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -95,7 +95,6 @@ grep-searcher = "0.1.14" # plugin support steel-core = { workspace = true, optional = true } steel-doc = { git = "https://github.com/mattwparas/steel.git", version = "0.7.0" } -# steel-doc = { path = "/home/matt/code/scratch/steel/crates/steel-doc", version = "0.6.0" } globset = "0.4.16" diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index dbbae22f1..96b01ec5b 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -15,9 +15,6 @@ pub use lsp::*; pub use engine::ScriptingEngine; -#[cfg(feature = "steel")] -pub use engine::steel::{helix_module_file, steel_init_file}; - use tui::{ text::{Span, Spans}, widgets::Cell, @@ -252,7 +249,6 @@ impl MappableCommand { pub fn execute(&self, cx: &mut Context) { match &self { Self::Typable { name, args, doc: _ } => { - // TODO: Swap the order to allow overriding the existing commands? if let Some(command) = typed::TYPABLE_COMMAND_MAP.get(name.as_str()) { let mut cx = compositor::Context { editor: cx.editor, @@ -265,7 +261,6 @@ impl MappableCommand { cx.editor.set_error(format!("{}", e)); } } else { - // TODO: Update this let args = args.split_whitespace().map(Cow::from).collect(); if !ScriptingEngine::call_function_by_name(cx, name, args) { cx.editor.set_error(format!("no such command: '{name}'")); @@ -3162,11 +3157,9 @@ fn file_explorer_in_current_directory(cx: &mut Context) { fn buffer_picker(cx: &mut Context) { let current = view!(cx.editor).doc; - #[allow(unused)] struct BufferMeta { id: DocumentId, path: Option, - name: Option, is_modified: bool, is_current: bool, focused_at: std::time::Instant, @@ -3175,7 +3168,6 @@ fn buffer_picker(cx: &mut Context) { let new_meta = |doc: &Document| BufferMeta { id: doc.id(), path: doc.path().cloned(), - name: doc.name.clone(), is_modified: doc.is_modified(), is_current: doc.id() == current, focused_at: doc.focused_at, @@ -4171,18 +4163,6 @@ pub mod insert { helix_event::dispatch(PostInsertChar { c, cx }); } - pub fn insert_string(cx: &mut Context, string: String) { - let (view, doc) = current!(cx.editor); - - let indent = Tendril::from(string); - let transaction = Transaction::insert( - doc.text(), - &doc.selection(view.id).clone().cursors(doc.text().slice(..)), - indent, - ); - doc.apply(&transaction, view.id); - } - pub fn smart_tab(cx: &mut Context) { let (view, doc) = current_ref!(cx.editor); let view_id = view.id; diff --git a/helix-term/src/commands/engine/steel.rs b/helix-term/src/commands/engine/steel.rs index a3902f3e5..b08aec257 100644 --- a/helix-term/src/commands/engine/steel.rs +++ b/helix-term/src/commands/engine/steel.rs @@ -5,13 +5,15 @@ use helix_core::{ diagnostic::Severity, extensions::steel_implementations::{rope_module, SteelRopeSlice}, find_workspace, graphemes, - syntax::config::{ - default_timeout, AutoPairConfig, LanguageConfiguration, LanguageServerConfiguration, - SoftWrap, + syntax::{ + self, + config::{ + default_timeout, AutoPairConfig, LanguageConfiguration, LanguageServerConfiguration, + SoftWrap, + }, }, - syntax::{self}, text_annotations::InlineAnnotation, - Range, Selection, Tendril, + Range, Selection, Tendril, Transaction, }; use helix_event::register_hook; use helix_view::{ @@ -71,7 +73,7 @@ use super::{ components::{self, helix_component_module}, Context, MappableCommand, TYPABLE_COMMAND_LIST, }; -use insert::{insert_char, insert_string}; +use insert::insert_char; pub static INTERRUPT_HANDLER: OnceCell = OnceCell::new(); @@ -1586,9 +1588,8 @@ fn theme_from_json_string(name: String, value: SteelVal) -> Result helix_view::theme::Style { @@ -1726,7 +1727,10 @@ Get the `Rect` associated with the currently focused buffer. ); register_0!( "selected-register!", - |cx: &mut Context| cx.editor.selected_register.unwrap_or(cx.editor.config().default_yank_register), + |cx: &mut Context| cx + .editor + .selected_register + .unwrap_or(cx.editor.config().default_yank_register), r#"Get currently selected register"# ); @@ -5312,3 +5316,15 @@ pub fn remove_inlay_hint(cx: &mut Context, char_index: usize, _completion: Steel doc.set_inlay_hints(view_id, new_inlay_hints); true } + +pub fn insert_string(cx: &mut Context, string: SteelString) { + let (view, doc) = current!(cx.editor); + + let indent = Tendril::from(string.as_str()); + let transaction = Transaction::insert( + doc.text(), + &doc.selection(view.id).clone().cursors(doc.text().slice(..)), + indent, + ); + doc.apply(&transaction, view.id); +} diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 0703fec7a..e0002768a 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1000,20 +1000,7 @@ fn theme(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow // Ensures that a preview theme gets cleaned up if the user backspaces until the prompt is empty. cx.editor.unset_theme_preview(); } else 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); - // }; - - if let Ok(theme) = cx.editor.theme_loader.load(theme_name).or_else(|_| { - cx.editor - .user_defined_themes - .get(theme_name) - .ok_or_else(|| anyhow::anyhow!("Could not load theme")) - .cloned() - }) { + 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"); } @@ -1023,19 +1010,12 @@ fn theme(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow } PromptEvent::Validate => { if let Some(theme_name) = args.first() { - let theme = cx.editor.theme_loader.load(theme_name).or_else(|_| { - cx.editor - .user_defined_themes - .get(theme_name) - .ok_or_else(|| anyhow::anyhow!("Could not load theme")) - .cloned() - })?; + let theme = cx + .editor + .theme_loader + .load(theme_name) + .map_err(|err| anyhow::anyhow!("could not load theme: {}", err))?; - // let theme = cx - // .editor - // .theme_loader - // .load(theme_name) - // .map_err(|err| anyhow::anyhow!("Could not load theme: {}", err))?; if !(true_color || theme.is_16_color()) { bail!("Unsupported theme: theme requires true color support"); } diff --git a/helix-term/src/ui/extension.rs b/helix-term/src/ui/extension.rs index 71552c433..fad86182e 100644 --- a/helix-term/src/ui/extension.rs +++ b/helix-term/src/ui/extension.rs @@ -3,9 +3,17 @@ mod steel_implementations { use crate::{ compositor::Component, - ui::{Popup, Text}, + ui::{overlay::Overlay, Popup, Prompt, Text}, }; impl steel::rvals::Custom for Text {} impl steel::rvals::Custom for Popup {} + + // TODO: For this to be sound, all of the various functions + // have to now be marked as send + sync + 'static. Annoying, + // and something I'll look into with steel. + unsafe impl Send for Overlay {} + unsafe impl Sync for Overlay {} + unsafe impl Send for Prompt {} + unsafe impl Sync for Prompt {} } diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 1b055543e..44b618063 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -412,7 +412,7 @@ pub mod completers { names.push("base16_default".into()); // Include any user defined themes as well - names.extend(editor.user_defined_themes.keys().map(|x| x.into())); + names.extend(editor.theme_loader.dynamic_themes().map(|x| x.into())); names.sort(); names.dedup(); diff --git a/helix-term/src/ui/overlay.rs b/helix-term/src/ui/overlay.rs index 2dcbcdc92..ff184d407 100644 --- a/helix-term/src/ui/overlay.rs +++ b/helix-term/src/ui/overlay.rs @@ -15,12 +15,6 @@ pub struct Overlay { pub calc_child_size: Box Rect>, } -// TODO: For this to be sound, all of the various functions -// have to now be marked as send + sync + 'static. Annoying, -// and something I'll look into with steel. -unsafe impl Send for Overlay {} -unsafe impl Sync for Overlay {} - /// Surrounds the component with a margin of 5% on each side, and an additional 2 rows at the bottom pub fn overlaid(content: T) -> Overlay { Overlay { diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 0c1b0c1d3..ff4ca1fcc 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -49,12 +49,6 @@ pub struct Prompt { language: Option<(&'static str, Arc>)>, } -// TODO: For this to be sound, all of the various functions -// have to now be marked as send + sync + 'static. Annoying, -// and something I'll look into with steel. -unsafe impl Send for Prompt {} -unsafe impl Sync for Prompt {} - #[derive(Clone, Copy, PartialEq, Eq)] pub enum PromptEvent { /// The prompt input has been updated. diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 1bdde6485..e67277551 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1142,7 +1142,6 @@ pub struct Editor { pub cursor_cache: CursorCache, pub editor_clipping: ClippingConfiguration, - pub user_defined_themes: HashMap, } #[derive(Default)] @@ -1274,7 +1273,6 @@ impl Editor { mouse_down_range: None, cursor_cache: CursorCache::default(), editor_clipping: ClippingConfiguration::default(), - user_defined_themes: Default::default(), } } diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 1ddf106a5..65b056ebd 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -39,6 +39,9 @@ pub static BASE16_DEFAULT_THEME: Lazy = Lazy::new(|| Theme { pub struct Loader { /// Theme directories to search from highest to lowest priority theme_dirs: Vec, + + /// Themes which are dynamically created at runtime + dynamic_themes: HashMap, } impl Loader { /// Creates a new loader that can load themes from multiple directories. @@ -48,18 +51,34 @@ impl Loader { pub fn new(dirs: &[PathBuf]) -> Self { Self { theme_dirs: dirs.iter().map(|p| p.join("themes")).collect(), + dynamic_themes: HashMap::new(), } } + pub fn dynamic_themes(&self) -> impl Iterator { + self.dynamic_themes.keys() + } + /// Loads a theme searching directories in priority order. pub fn load(&self, name: &str) -> Result { - let (theme, warnings) = self.load_with_warnings(name)?; + match self.load_with_warnings(name) { + Ok((theme, warnings)) => { + for warning in warnings { + warn!("Theme '{}': {}", name, warning); + } - for warning in warnings { - warn!("Theme '{}': {}", name, warning); + Ok(theme) + } + Err(_) => self + .dynamic_themes + .get(name) + .ok_or_else(|| anyhow::anyhow!("Could not load theme: {}", name)) + .cloned(), } + } - Ok(theme) + pub fn add_dynamic_theme(&mut self, name: String, theme: Theme) { + self.dynamic_themes.insert(name, theme); } /// Loads a theme searching directories in priority order, returning any warnings diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 5895e00d2..f542462c0 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -145,7 +145,7 @@ pub mod tasks { Usage: Run with `cargo xtask `, eg. `cargo xtask docgen`. Tasks: - steel: Install steel + steel Install steel docgen Generate files to be included in the mdbook output. query-check [languages] Check that tree-sitter queries are valid for the given languages, or all languages if none are specified.