diff --git a/helix-core/src/extensions.rs b/helix-core/src/extensions.rs index e1e0bbb9d..7e8081a91 100644 --- a/helix-core/src/extensions.rs +++ b/helix-core/src/extensions.rs @@ -9,8 +9,12 @@ pub mod steel_implementations { steel_vm::{builtin::BuiltInModule, register_fn::RegisterFn}, }; + use crate::syntax::{AutoPairConfig, SoftWrap}; + impl steel::rvals::Custom for crate::Position {} impl steel::rvals::Custom for crate::Selection {} + impl steel::rvals::Custom for AutoPairConfig {} + impl steel::rvals::Custom for SoftWrap {} #[derive(Clone, Copy, Debug)] enum SliceKind { diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 503334eae..db1b72f3c 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -386,18 +386,6 @@ impl Application { pub fn handle_config_events(&mut self, config_event: ConfigEvent) { match config_event { ConfigEvent::Refresh => self.refresh_config(), - ConfigEvent::UpdateLanguageConfiguration => match self.refresh_language_config() { - Ok(_) => { - // If we don't stash the theme here, the syntax highlighting is broken - let current_theme = std::mem::take(&mut self.editor.theme); - self.editor.set_theme(current_theme); - - self.editor.set_status("Language config refreshed"); - } - Err(err) => { - self.editor.set_error(err.to_string()); - } - }, // Since only the Application can make changes to Editor's config, // the Editor must send up a new copy of a modified config so that @@ -427,8 +415,7 @@ impl Application { /// refresh language config after config change fn refresh_language_config(&mut self) -> Result<(), Error> { - let syntax_config = crate::commands::engine::ScriptingEngine::load_language_configuration() - .unwrap_or_else(|| helix_core::config::user_syntax_loader()) + let syntax_config = helix_core::config::user_syntax_loader() .map_err(|err| anyhow::anyhow!("Failed to load language config: {}", err))?; self.syn_loader = std::sync::Arc::new(syntax::Loader::new(syntax_config)); @@ -452,19 +439,15 @@ impl Application { let theme = config .theme .as_ref() - .and_then(|theme| crate::commands::engine::ScriptingEngine::load_theme(theme)) - .or_else(|| { - // Check the name again - config.theme.as_ref().and_then(|theme| { - self.theme_loader - .load(theme) - .map_err(|e| { - log::warn!("failed to load theme `{}` - {}", theme, e); - e - }) - .ok() - .filter(|theme| (true_color || theme.is_16_color())) - }) + .and_then(|theme| { + self.theme_loader + .load(theme) + .map_err(|e| { + log::warn!("failed to load theme `{}` - {}", theme, e); + e + }) + .ok() + .filter(|theme| (true_color || theme.is_16_color())) }) .unwrap_or_else(|| self.theme_loader.default_theme(true_color)); diff --git a/helix-term/src/commands/engine.rs b/helix-term/src/commands/engine.rs index 5fb13a831..9afaef7fc 100644 --- a/helix-term/src/commands/engine.rs +++ b/helix-term/src/commands/engine.rs @@ -138,42 +138,6 @@ impl ScriptingEngine { .flat_map(|kind| manual_dispatch!(kind, available_commands())) .collect() } - - pub fn load_theme(name: &str) -> Option { - for kind in PLUGIN_PRECEDENCE { - let theme = manual_dispatch!(kind, load_theme(name)); - - if theme.is_some() { - return theme; - } - } - - None - } - - pub fn themes() -> Option> { - for kind in PLUGIN_PRECEDENCE { - let themes = manual_dispatch!(kind, themes()); - - if themes.is_some() { - return themes; - } - } - - None - } - - pub fn load_language_configuration() -> Option> { - for kind in PLUGIN_PRECEDENCE { - let config = manual_dispatch!(kind, load_language_configuration()); - - if config.is_some() { - return config; - } - } - - None - } } impl PluginSystem for NoEngine { @@ -251,25 +215,4 @@ pub trait PluginSystem { fn available_commands<'a>(&self) -> Vec> { Vec::new() } - - /// Retrieve a theme for a given name - #[inline(always)] - fn load_theme(&self, _name: &str) -> Option { - None - } - - /// Retrieve the list of themes that exist within the runtime - #[inline(always)] - fn themes(&self) -> Option> { - None - } - - /// Fetch the language configuration as monitored by the plugin system. - /// - /// For now - this maintains backwards compatibility with the existing toml configuration, - /// and as such the toml error is exposed here. - #[inline(always)] - fn load_language_configuration(&self) -> Option> { - None - } } diff --git a/helix-term/src/commands/engine/scheme.rs b/helix-term/src/commands/engine/scheme.rs index c520c8dc7..48018c695 100644 --- a/helix-term/src/commands/engine/scheme.rs +++ b/helix-term/src/commands/engine/scheme.rs @@ -4,12 +4,10 @@ use helix_core::{ graphemes, regex::Regex, shellwords::Shellwords, - syntax::{AutoPairConfig, Configuration, SoftWrap}, + syntax::{AutoPairConfig, SoftWrap}, Range, Selection, Tendril, }; use helix_event::register_hook; -use helix_loader::{config_dir, merge_toml_values}; -use helix_lsp::lsp::CompletionItem; use helix_stdx::path::expand_tilde; use helix_view::{ document::Mode, @@ -20,7 +18,7 @@ use helix_view::{ }, extension::document_id_to_usize, input::KeyEvent, - Document, DocumentId, Editor, Theme, ViewId, + Document, DocumentId, Editor, ViewId, }; use once_cell::sync::Lazy; use serde_json::Value; @@ -33,8 +31,8 @@ use steel::{ }; use std::{ - borrow::Cow, cell::RefCell, collections::HashMap, ops::Deref, path::PathBuf, rc::Rc, - sync::atomic::AtomicUsize, time::Duration, + borrow::Cow, collections::HashMap, ops::Deref, path::PathBuf, sync::atomic::AtomicUsize, + time::Duration, }; use std::{ collections::HashSet, @@ -58,18 +56,15 @@ use components::SteelDynamicComponent; use super::{components, Context, MappableCommand, TYPABLE_COMMAND_LIST}; use insert::{insert_char, insert_string}; +// TODO: +// I'm not entirely sure this is correct, however from observation it seems that +// interactions with this really only happen on one thread. I haven't yet found +// multiple instances of the engine getting created. I'll need to go observe how +// and when the engine gets accessed. thread_local! { pub static ENGINE: std::rc::Rc> = configure_engine(); } -// APIs / Modules that need to be accepted by the plugin system -// Without these, the core functionality cannot operate -// pub struct DocumentApi; -// pub struct EditorApi; -// pub struct ComponentApi; -// pub struct TypedCommandsApi; -// pub struct StaticCommandsApi; - pub struct KeyMapApi { get_keymap: fn() -> EmbeddedKeyMap, default_keymap: fn() -> EmbeddedKeyMap, @@ -94,6 +89,12 @@ impl KeyMapApi { } } +// TODO: Refactor this into the configuration object instead. +// that way, we don't have to have multiple layers of objects, +// and can instead just refer to the single configuration object. +// +// Possibly also introduce buffer / language specific keybindings +// there as well. thread_local! { pub static BUFFER_OR_EXTENSION_KEYBINDING_MAP: SteelVal = SteelVal::boxed(SteelVal::empty_hashmap()); @@ -102,129 +103,6 @@ thread_local! { SteelVal::boxed(SteelVal::empty_hashmap()); pub static GLOBAL_KEYBINDING_MAP: SteelVal = get_keymap().into_steelval().unwrap(); - - static THEME_MAP: ThemeContainer = ThemeContainer::new(); - - static LANGUAGE_CONFIGURATIONS: LanguageConfigurationContainer = LanguageConfigurationContainer::new(); -} - -// Any configurations that we'd like to overlay from the toml -struct LanguageConfigurationContainer { - configuration: Rc>>, -} - -impl LanguageConfigurationContainer { - fn new() -> Self { - Self { - configuration: Rc::new(RefCell::new(None)), - } - } -} - -impl Custom for LanguageConfigurationContainer {} - -impl LanguageConfigurationContainer { - fn add_configuration(&self, config_as_string: String) -> Result<(), String> { - let left = self - .configuration - .replace(Some(toml::Value::Boolean(false))); - - if let Some(left) = left { - let right = serde_json::from_str(&config_as_string).map_err(|err| err.to_string()); - - match right { - Ok(right) => { - self.configuration - .replace(Some(merge_toml_values(left, right, 3))); - - Ok(()) - } - Err(e) => Err(e), - } - } else { - let right = serde_json::from_str(&config_as_string).map_err(|err| err.to_string())?; - - self.configuration.replace(Some(right)); - - Ok(()) - } - } - - fn as_language_configuration(&self) -> Option> { - if let Some(right) = self.configuration.borrow().clone() { - let config = helix_loader::config::user_lang_config(); - - let res = config - .map(|left| merge_toml_values(left, right, 3)) - .and_then(|x| x.try_into()); - - Some(res) - // ) - } else { - None - } - } - - fn get_language_configuration() -> Option> { - LANGUAGE_CONFIGURATIONS.with(|x| x.as_language_configuration()) - } -} - -struct ThemeContainer { - themes: Rc>>, -} - -impl Custom for ThemeContainer {} - -impl ThemeContainer { - fn new() -> Self { - Self { - themes: Rc::new(RefCell::new(HashMap::new())), - } - } - - fn get(name: &str) -> Option { - THEME_MAP.with(|x| x.themes.borrow().get(name).cloned()) - } - - fn names() -> Vec { - THEME_MAP.with(|x| x.themes.borrow().keys().cloned().collect()) - } - - fn register(name: String, theme: Theme) { - THEME_MAP.with(|x| x.themes.borrow_mut().insert(name, theme)); - } -} - -fn load_language_configuration_api(engine: &mut Engine) { - let mut module = BuiltInModule::new("helix/core/languages".to_string()); - - module.register_fn( - "register-language-configuration!", - |language_configuration: String| -> Result<(), String> { - LANGUAGE_CONFIGURATIONS.with(|x| x.add_configuration(language_configuration)) - }, - ); - - module.register_fn("flush-configuration", refresh_language_configuration); - - engine.register_module(module); -} - -fn load_theme_api(engine: &mut Engine) { - let mut module = BuiltInModule::new("helix/core/themes"); - - module.register_fn( - "register-theme!", - |name: String, theme_as_json_string: String| -> Result<(), String> { - Ok(ThemeContainer::register( - name, - serde_json::from_str(&theme_as_json_string).map_err(|err| err.to_string())?, - )) - }, - ); - - engine.register_module(module); } fn load_keymap_api(engine: &mut Engine, api: KeyMapApi) { @@ -239,11 +117,6 @@ fn load_keymap_api(engine: &mut Engine, api: KeyMapApi) { module.register_fn("helix-deep-copy-keymap", api.deep_copy_keymap); - // Alternatively, could store these values in a steel module, like so: - // let keymap_core_map = helix_loader::runtime_file(&PathBuf::from("steel").join("keymap.scm")); - // let require_module = format!("(require {})", keymap_core_map.to_str().unwrap()); - // engine.run(&require_module).unwrap(); - // This should be associated with a corresponding scheme module to wrap this up module.register_value( "*buffer-or-extension-keybindings*", @@ -332,8 +205,6 @@ fn load_static_commands(engine: &mut Engine) { template_function_arity_1("regex-selection"); module.register_fn("replace-selection-with", replace_selection); template_function_arity_1("replace-selection-with"); - // module.register_fn("show-completion-prompt-with", show_completion_prompt); - // template_function_arity_1("show-completion-prompt-with"); module.register_fn("cx->current-file", current_path); template_function_arity_1("cx->current-file"); @@ -370,9 +241,6 @@ fn load_static_commands(engine: &mut Engine) { module.register_fn("move-window-far-right", move_window_to_the_right); template_function_arity_0("move-window-far-right"); - // This should probably just get removed? - // module.register_fn("block-on-shell-command", run_shell_command_text); - let mut template_function_no_context = |name: &str| { builtin_static_command_module.push_str(&format!( r#" @@ -389,9 +257,6 @@ fn load_static_commands(engine: &mut Engine) { template_function_no_context("get-helix-scm-path"); template_function_no_context("get-init-scm-path"); - // let mut target_directory = PathBuf::from(std::env::var("HELIX_RUNTIME").unwrap()); - // target_directory.push("cogs"); - // target_directory.push("helix"); let mut target_directory = helix_runtime_search_path(); if !target_directory.exists() { @@ -476,10 +341,6 @@ fn load_typed_commands(engine: &mut Engine) { )); } - // let mut target_directory = PathBuf::from(std::env::var("HELIX_RUNTIME").unwrap()); - // target_directory.push("cogs"); - // target_directory.push("helix"); - let mut target_directory = helix_runtime_search_path(); if !target_directory.exists() { std::fs::create_dir(&target_directory).unwrap(); @@ -622,7 +483,7 @@ fn load_configuration_api(engine: &mut Engine) { "cursorline", "cursorcolumn", "middle-click-paste", - // "auto-pairs", + "auto-pairs", "auto-completion", "auto-format", "auto-save", @@ -667,7 +528,14 @@ fn load_configuration_api(engine: &mut Engine) { .register_fn("cursorline", HelixConfiguration::cursorline) .register_fn("cursorcolumn", HelixConfiguration::cursorcolumn) .register_fn("middle-click-paste", HelixConfiguration::middle_click_paste) - // .register_fn("auto-pairs", HelixConfiguration::auto_pairs) + .register_fn("auto-pairs", HelixConfiguration::auto_pairs) + // Specific constructors for the auto pairs configuration + .register_fn("auto-pairs-default", |enabled: bool| { + AutoPairConfig::Enable(enabled) + }) + .register_fn("auto-pairs-map", |map: HashMap| { + AutoPairConfig::Pairs(map) + }) .register_fn("auto-completion", HelixConfiguration::auto_completion) .register_fn("auto-format", HelixConfiguration::auto_format) .register_fn("auto-save", HelixConfiguration::auto_save) @@ -713,9 +581,6 @@ fn load_configuration_api(engine: &mut Engine) { ) .register_fn("smart-tab", HelixConfiguration::smart_tab); - // let mut target_directory = PathBuf::from(std::env::var("HELIX_RUNTIME").unwrap()); - // target_directory.push("cogs"); - // target_directory.push("helix"); let mut target_directory = helix_runtime_search_path(); if !target_directory.exists() { @@ -988,24 +853,6 @@ impl super::PluginSystem for SteelScriptingEngine { .map(|x| x.clone().into()) .collect::>() } - - fn load_theme(&self, name: &str) -> Option { - ThemeContainer::get(name) - } - - fn themes(&self) -> Option> { - let names = ThemeContainer::names(); - - if !names.is_empty() { - Some(names) - } else { - None - } - } - - fn load_language_configuration(&self) -> Option> { - LanguageConfigurationContainer::get_language_configuration() - } } impl SteelScriptingEngine { @@ -1963,13 +1810,9 @@ fn configure_engine_impl(mut engine: Engine) -> Engine { load_typed_commands(&mut engine); load_static_commands(&mut engine); load_keymap_api(&mut engine, KeyMapApi::new()); - load_theme_api(&mut engine); load_rope_api(&mut engine); - load_language_configuration_api(&mut engine); load_misc_api(&mut engine); - // load_engine_api(&mut engine); - // Hooks engine.register_fn("register-hook!", register_hook); engine.register_fn("log::info!", |message: String| log::info!("{}", message)); @@ -2177,9 +2020,6 @@ fn configure_engine_impl(mut engine: Engine) -> Engine { fn configure_engine() -> std::rc::Rc> { let engine = configure_engine_impl(steel::steel_vm::engine::Engine::new()); - // engine.run(&"(require \"/home/matt/Documents/helix-fork/helix/helix-term/src/commands/engine/controller.scm\" - // (for-syntax \"/home/matt/Documents/helix-fork/helix/helix-term/src/commands/engine/controller.scm\"))").unwrap(); - std::rc::Rc::new(std::cell::RefCell::new(engine)) } @@ -2573,15 +2413,6 @@ fn set_options( Ok(()) } -pub fn refresh_language_configuration(cx: &mut Context) -> anyhow::Result<()> { - cx.editor - .config_events - .0 - .send(ConfigEvent::UpdateLanguageConfiguration)?; - - Ok(()) -} - pub fn cx_pos_within_text(cx: &mut Context) -> usize { let (view, doc) = current_ref!(cx.editor); @@ -2735,43 +2566,6 @@ fn replace_selection(cx: &mut Context, value: String) { doc.apply(&transaction, view.id); } -// fn show_completion_prompt(cx: &mut Context, items: Vec) { -// let (view, doc) = current!(cx.editor); - -// let items = items -// .into_iter() -// .map(|x| crate::ui::CompletionItem { -// item: CompletionItem::new_simple(x, "".to_string()), -// language_server_id: usize::MAX, -// resolved: true, -// }) -// .collect(); - -// let text = doc.text(); -// let cursor = doc.selection(view.id).primary().cursor(text.slice(..)); - -// let trigger = crate::handlers::completion::Trigger::new( -// cursor, -// view.id, -// doc.id(), -// crate::handlers::completion::TriggerKind::Manual, -// ); - -// let savepoint = doc.savepoint(view); - -// let callback = async move { -// let call: job::Callback = Callback::EditorCompositor(Box::new( -// move |editor: &mut Editor, compositor: &mut Compositor| { -// crate::handlers::completion::show_completion( -// editor, compositor, items, trigger, savepoint, -// ); -// }, -// )); -// Ok(call) -// }; -// cx.jobs.callback(callback); -// } - // TODO: Remove this! fn move_window_to_the_left(cx: &mut Context) { while cx diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 6c7108af3..803d42685 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -880,10 +880,7 @@ fn theme( // 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) = crate::commands::engine::ScriptingEngine::load_theme(theme_name) - .map(|x| Ok(x)) - .unwrap_or_else(|| cx.editor.theme_loader.load(theme_name)) - { + 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"); } @@ -893,25 +890,15 @@ fn theme( } PromptEvent::Validate => { if let Some(theme_name) = args.first() { - // 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"); - // } - // cx.editor.set_theme(theme); - - if let Ok(theme) = crate::commands::engine::ScriptingEngine::load_theme(theme_name) - .map(|x| Ok(x)) - .unwrap_or_else(|| 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(theme); - }; + 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"); + } + cx.editor.set_theme(theme); } else { let name = cx.editor.theme.name().to_string(); diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index f569afd6e..4c837aff1 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -274,10 +274,6 @@ pub mod completers { names.extend(theme::Loader::read_names(&rt_dir.join("themes"))); } - if let Some(themes) = crate::commands::engine::ScriptingEngine::themes() { - names.extend(themes); - } - names.push("default".into()); names.push("base16_default".into()); names.sort(); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index af2e7368e..f2516b7bd 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -979,7 +979,6 @@ pub enum EditorEvent { pub enum ConfigEvent { Refresh, Update(Box), - UpdateLanguageConfiguration, Change, }