use in memory representation of configuration

pull/8675/merge^2
mattwparas 10 months ago
parent 01996b2bec
commit d6c3804ed8

23
Cargo.lock generated

@ -1686,9 +1686,12 @@ dependencies = [
[[package]] [[package]]
name = "im-lists" name = "im-lists"
version = "0.7.0" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8ce6c776654abe411e4ccd52524f87e8ca16e2c487dbe127521eb048a46f7e6" checksum = "0c07eff2c41645923382085ea8627509e5184f7a668f75d0c1e16091f7af4798"
dependencies = [
"smallvec",
]
[[package]] [[package]]
name = "im-rc" name = "im-rc"
@ -2524,8 +2527,8 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "steel-core" name = "steel-core"
version = "0.5.0" version = "0.6.0"
source = "git+https://github.com/mattwparas/steel.git#03fe335199334f44396949fda2508de3545bc895" source = "git+https://github.com/mattwparas/steel.git#9cc058dcd868edf81985909e09cafd94dbb9a1e3"
dependencies = [ dependencies = [
"abi_stable", "abi_stable",
"anyhow", "anyhow",
@ -2549,6 +2552,7 @@ dependencies = [
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"smallvec",
"steel-derive", "steel-derive",
"steel-gen", "steel-gen",
"steel-parser", "steel-parser",
@ -2558,8 +2562,8 @@ dependencies = [
[[package]] [[package]]
name = "steel-derive" name = "steel-derive"
version = "0.4.0" version = "0.5.0"
source = "git+https://github.com/mattwparas/steel.git#03fe335199334f44396949fda2508de3545bc895" source = "git+https://github.com/mattwparas/steel.git#9cc058dcd868edf81985909e09cafd94dbb9a1e3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2569,7 +2573,7 @@ dependencies = [
[[package]] [[package]]
name = "steel-gen" name = "steel-gen"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/mattwparas/steel.git#03fe335199334f44396949fda2508de3545bc895" source = "git+https://github.com/mattwparas/steel.git#9cc058dcd868edf81985909e09cafd94dbb9a1e3"
dependencies = [ dependencies = [
"codegen", "codegen",
"serde", "serde",
@ -2578,9 +2582,10 @@ dependencies = [
[[package]] [[package]]
name = "steel-parser" name = "steel-parser"
version = "0.4.0" version = "0.6.0"
source = "git+https://github.com/mattwparas/steel.git#03fe335199334f44396949fda2508de3545bc895" source = "git+https://github.com/mattwparas/steel.git#9cc058dcd868edf81985909e09cafd94dbb9a1e3"
dependencies = [ dependencies = [
"fxhash",
"lasso", "lasso",
"num-bigint", "num-bigint",
"once_cell", "once_cell",

@ -19,8 +19,8 @@ default-members = [
[workspace.dependencies] [workspace.dependencies]
# If working locally, use the local path dependency # If working locally, use the local path dependency
# steel-core = { path = "../../steel/crates/steel-core", version = "0.5.0", features = ["modules", "anyhow", "dylibs"] } # steel-core = { path = "../../steel/crates/steel-core", version = "0.6.0", features = ["anyhow", "dylibs"] }
steel-core = { git = "https://github.com/mattwparas/steel.git", version = "0.5.0", features = ["modules", "anyhow", "dylibs"] } steel-core = { git = "https://github.com/mattwparas/steel.git", version = "0.6.0", features = ["anyhow", "dylibs"] }
tree-sitter = { version = "0.20", git = "https://github.com/tree-sitter/tree-sitter", rev = "ab09ae20d640711174b8da8a654f6b3dec93da1a" } tree-sitter = { version = "0.20", git = "https://github.com/tree-sitter/tree-sitter", rev = "ab09ae20d640711174b8da8a654f6b3dec93da1a" }
nucleo = "0.2.0" nucleo = "0.2.0"

@ -260,7 +260,10 @@ impl Application {
jobs: &mut app.jobs, jobs: &mut app.jobs,
}; };
crate::commands::ScriptingEngine::run_initialization_script(&mut cx); crate::commands::ScriptingEngine::run_initialization_script(
&mut cx,
app.config.clone(),
);
} }
Ok(app) Ok(app)
@ -405,6 +408,7 @@ impl Application {
}; };
self.config.store(Arc::new(app_config)); self.config.store(Arc::new(app_config));
} }
ConfigEvent::Change => {}
} }
// Update all the relevant members in the editor after updating // Update all the relevant members in the editor after updating

@ -1,10 +1,12 @@
use arc_swap::ArcSwapAny;
use helix_core::syntax::Configuration; use helix_core::syntax::Configuration;
use helix_view::{document::Mode, input::KeyEvent, Theme}; use helix_view::{document::Mode, input::KeyEvent, Theme};
use std::borrow::Cow; use std::{borrow::Cow, sync::Arc};
use crate::{ use crate::{
compositor, compositor,
config::Config,
keymap::KeymapResult, keymap::KeymapResult,
ui::{self, PromptEvent}, ui::{self, PromptEvent},
}; };
@ -60,9 +62,12 @@ impl ScriptingEngine {
} }
} }
pub fn run_initialization_script(cx: &mut Context) { pub fn run_initialization_script(
cx: &mut Context,
configuration: Arc<ArcSwapAny<Arc<Config>>>,
) {
for kind in PLUGIN_PRECEDENCE { for kind in PLUGIN_PRECEDENCE {
manual_dispatch!(kind, run_initialization_script(cx)) manual_dispatch!(kind, run_initialization_script(cx, configuration.clone()))
} }
} }
@ -188,7 +193,12 @@ pub trait PluginSystem {
/// Post initialization, once the context is available. This means you should be able to /// Post initialization, once the context is available. This means you should be able to
/// run anything here that could modify the context before the main editor is available. /// run anything here that could modify the context before the main editor is available.
fn run_initialization_script(&self, _cx: &mut Context) {} fn run_initialization_script(
&self,
_cx: &mut Context,
_configuration: Arc<ArcSwapAny<Arc<Config>>>,
) {
}
/// Allow the engine to directly handle a keymap event. This is some of the tightest integration /// Allow the engine to directly handle a keymap event. This is some of the tightest integration
/// with the engine, directly intercepting any keymap events. By default, this just delegates to the /// with the engine, directly intercepting any keymap events. By default, this just delegates to the

@ -1,18 +1,23 @@
use arc_swap::ArcSwapAny;
use helix_core::{ use helix_core::{
extensions::steel_implementations::{rope_module, SteelRopeSlice}, extensions::steel_implementations::{rope_module, SteelRopeSlice},
graphemes, graphemes,
path::expand_tilde, path::expand_tilde,
regex::Regex, regex::Regex,
shellwords::Shellwords, shellwords::Shellwords,
syntax::Configuration, syntax::{AutoPairConfig, Configuration, SoftWrap},
Range, Selection, Tendril, Range, Selection, Tendril,
}; };
use helix_event::register_hook; use helix_event::register_hook;
use helix_loader::merge_toml_values; use helix_loader::{config_dir, merge_toml_values};
use helix_lsp::lsp::CompletionItem; use helix_lsp::lsp::CompletionItem;
use helix_view::{ use helix_view::{
document::Mode, document::Mode,
editor::{Action, ConfigEvent}, editor::{
Action, BufferLine, ConfigEvent, CursorShapeConfig, FilePickerConfig, GutterConfig,
IndentGuidesConfig, LineEndingConfig, LineNumber, LspConfig, SearchConfig, SmartTabConfig,
StatusLineConfig, TerminalConfig, WhitespaceConfig,
},
extension::document_id_to_usize, extension::document_id_to_usize,
input::KeyEvent, input::KeyEvent,
Document, DocumentId, Editor, Theme, ViewId, Document, DocumentId, Editor, Theme, ViewId,
@ -22,14 +27,14 @@ use serde_json::Value;
use steel::{ use steel::{
gc::unsafe_erased_pointers::CustomReference, gc::unsafe_erased_pointers::CustomReference,
rerrs::ErrorKind, rerrs::ErrorKind,
rvals::{as_underlying_type, AsRefMutSteelValFromRef, FromSteelVal, IntoSteelVal, SteelString}, rvals::{as_underlying_type, FromSteelVal, IntoSteelVal, SteelString},
steel_vm::{engine::Engine, register_fn::RegisterFn}, steel_vm::{engine::Engine, register_fn::RegisterFn},
steelerr, List, SteelErr, SteelVal, steelerr, List, SteelErr, SteelVal,
}; };
use std::{ use std::{
borrow::Cow, cell::RefCell, collections::HashMap, ops::Deref, path::PathBuf, rc::Rc, borrow::Cow, cell::RefCell, collections::HashMap, ops::Deref, path::PathBuf, rc::Rc,
sync::atomic::AtomicUsize, sync::atomic::AtomicUsize, time::Duration,
}; };
use std::{ use std::{
collections::HashSet, collections::HashSet,
@ -384,9 +389,10 @@ fn load_static_commands(engine: &mut Engine) {
template_function_no_context("get-helix-scm-path"); template_function_no_context("get-helix-scm-path");
template_function_no_context("get-init-scm-path"); template_function_no_context("get-init-scm-path");
let mut target_directory = PathBuf::from(std::env::var("STEEL_HOME").unwrap()); // let mut target_directory = PathBuf::from(std::env::var("HELIX_RUNTIME").unwrap());
target_directory.push("cogs"); // target_directory.push("cogs");
target_directory.push("helix"); // target_directory.push("helix");
let mut target_directory = helix_runtime_search_path();
if !target_directory.exists() { if !target_directory.exists() {
std::fs::create_dir(&target_directory).unwrap(); std::fs::create_dir(&target_directory).unwrap();
@ -470,10 +476,11 @@ fn load_typed_commands(engine: &mut Engine) {
)); ));
} }
let mut target_directory = PathBuf::from(std::env::var("STEEL_HOME").unwrap()); // let mut target_directory = PathBuf::from(std::env::var("HELIX_RUNTIME").unwrap());
target_directory.push("cogs"); // target_directory.push("cogs");
target_directory.push("helix"); // target_directory.push("helix");
let mut target_directory = helix_runtime_search_path();
if !target_directory.exists() { if !target_directory.exists() {
std::fs::create_dir(&target_directory).unwrap(); std::fs::create_dir(&target_directory).unwrap();
} }
@ -485,6 +492,243 @@ fn load_typed_commands(engine: &mut Engine) {
engine.register_module(module); engine.register_module(module);
} }
fn fp_hidden(config: &mut FilePickerConfig, option: bool) {
config.hidden = option;
}
fn fp_follow_symlinks(config: &mut FilePickerConfig, option: bool) {
config.follow_symlinks = option;
}
fn fp_deduplicate_links(config: &mut FilePickerConfig, option: bool) {
config.deduplicate_links = option;
}
fn fp_parents(config: &mut FilePickerConfig, option: bool) {
config.parents = option;
}
fn fp_ignore(config: &mut FilePickerConfig, option: bool) {
config.ignore = option;
}
fn fp_git_ignore(config: &mut FilePickerConfig, option: bool) {
config.git_ignore = option;
}
fn fp_git_global(config: &mut FilePickerConfig, option: bool) {
config.git_global = option;
}
fn fp_git_exclude(config: &mut FilePickerConfig, option: bool) {
config.git_exclude = option;
}
fn fp_max_depth(config: &mut FilePickerConfig, option: Option<usize>) {
config.max_depth = option;
}
fn load_configuration_api(engine: &mut Engine) {
let mut module = BuiltInModule::new("helix/core/configuration");
module.register_fn("update-configuration!", |ctx: &mut Context| {
ctx.editor
.config_events
.0
.send(ConfigEvent::Change)
.unwrap();
});
let mut builtin_configuration_module =
"(require-builtin helix/core/configuration as helix.)".to_string();
builtin_configuration_module.push_str(&format!(
r#"
(provide update-configuration!)
(define (update-configuration!)
(helix.update-configuration! *helix.cx*))
"#,
));
let mut template_file_picker_function = |name: &str| {
builtin_configuration_module.push_str(&format!(
r#"
(provide {})
(define ({} arg)
(lambda (picker)
(helix.{} picker arg)
picker))
"#,
name, name, name
));
};
let file_picker_functions = &[
"fp-hidden",
"fp-follow-symlinks",
"fp-deduplicate-links",
"fp-parents",
"fp-ignore",
"fp-git-ignore",
"fp-git-global",
"fp-git-exclude",
"fp-max-depth",
];
for name in file_picker_functions {
template_file_picker_function(name);
}
builtin_configuration_module.push_str(&format!(
r#"
(provide file-picker)
(define (file-picker . args)
(helix.register-file-picker
*helix.config*
(foldl (lambda (func config) (func config)) (helix.raw-file-picker) args)))
"#,
));
module
.register_fn("raw-file-picker", || FilePickerConfig::default())
.register_fn("register-file-picker", HelixConfiguration::file_picker)
.register_fn("fp-hidden", fp_hidden)
.register_fn("fp-follow-symlinks", fp_follow_symlinks)
.register_fn("fp-deduplicate-links", fp_deduplicate_links)
.register_fn("fp-parents", fp_parents)
.register_fn("fp-ignore", fp_ignore)
.register_fn("fp-git-ignore", fp_git_ignore)
.register_fn("fp-git-global", fp_git_global)
.register_fn("fp-git-exclude", fp_git_exclude)
.register_fn("fp-max-depth", fp_max_depth);
let mut template_function_arity_1 = |name: &str| {
builtin_configuration_module.push_str(&format!(
r#"
(provide {})
(define ({} arg)
(helix.{} *helix.config* arg))
"#,
name, name, name
));
};
let functions = &[
"scrolloff",
"scroll_lines",
"mouse",
"shell",
"line-number",
"cursorline",
"cursorcolumn",
"middle-click-paste",
// "auto-pairs",
"auto-completion",
"auto-format",
"auto-save",
"text-width",
"idle-timeout",
"completion-timeout",
"preview-completion-insert",
"completion-trigger-len",
"completion-replace",
"auto-info",
"cursor-shape",
"true-color",
"insert-final-newline",
"color-modes",
"gutters",
// "file-picker",
"statusline",
"undercurl",
"search",
"lsp",
"terminal",
"rulers",
"whitespace",
"bufferline",
"indent-guides",
// "soft-wrap",
"workspace-lsp-roots",
"default-line-ending",
"smart-tab",
];
for func in functions {
template_function_arity_1(func);
}
module
.register_fn("scrolloff", HelixConfiguration::scrolloff)
.register_fn("scroll_lines", HelixConfiguration::scroll_lines)
.register_fn("mouse", HelixConfiguration::mouse)
.register_fn("shell", HelixConfiguration::shell)
.register_fn("line-number", HelixConfiguration::line_number)
.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-completion", HelixConfiguration::auto_completion)
.register_fn("auto-format", HelixConfiguration::auto_format)
.register_fn("auto-save", HelixConfiguration::auto_save)
.register_fn("text-width", HelixConfiguration::text_width)
.register_fn("idle-timeout", HelixConfiguration::idle_timeout)
.register_fn("completion-timeout", HelixConfiguration::completion_timeout)
.register_fn(
"preview-completion-insert",
HelixConfiguration::preview_completion_insert,
)
.register_fn(
"completion-trigger-len",
HelixConfiguration::completion_trigger_len,
)
.register_fn("completion-replace", HelixConfiguration::completion_replace)
.register_fn("auto-info", HelixConfiguration::auto_info)
.register_fn("cursor-shape", HelixConfiguration::cursor_shape)
.register_fn("true-color", HelixConfiguration::true_color)
.register_fn(
"insert-final-newline",
HelixConfiguration::insert_final_newline,
)
.register_fn("color-modes", HelixConfiguration::color_modes)
.register_fn("gutters", HelixConfiguration::gutters)
// .register_fn("file-picker", HelixConfiguration::file_picker)
.register_fn("statusline", HelixConfiguration::statusline)
.register_fn("undercurl", HelixConfiguration::undercurl)
.register_fn("search", HelixConfiguration::search)
.register_fn("lsp", HelixConfiguration::lsp)
.register_fn("terminal", HelixConfiguration::terminal)
.register_fn("rulers", HelixConfiguration::rulers)
.register_fn("whitespace", HelixConfiguration::whitespace)
.register_fn("bufferline", HelixConfiguration::bufferline)
.register_fn("indent-guides", HelixConfiguration::indent_guides)
// .register_fn("soft-wrap", HelixConfiguration::soft_wrap)
.register_fn(
"workspace-lsp-roots",
HelixConfiguration::workspace_lsp_roots,
)
.register_fn(
"default-line-ending",
HelixConfiguration::default_line_ending,
)
.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() {
std::fs::create_dir(&target_directory).unwrap();
}
target_directory.push("configuration.scm");
std::fs::write(target_directory, builtin_configuration_module).unwrap();
engine.register_module(module);
}
fn load_editor_api(engine: &mut Engine) { fn load_editor_api(engine: &mut Engine) {
let mut module = BuiltInModule::new("helix/core/editor"); let mut module = BuiltInModule::new("helix/core/editor");
@ -578,9 +822,10 @@ fn load_editor_api(engine: &mut Engine) {
// module.register_fn("cx->themes", get_themes); // module.register_fn("cx->themes", get_themes);
// Not the best usage here, duplicating it in a bunch of spots for now // Not the best usage here, duplicating it in a bunch of spots for now
let mut target_directory = PathBuf::from(std::env::var("STEEL_HOME").unwrap()); // let mut target_directory = PathBuf::from(std::env::var("HELIX_RUNTIME").unwrap());
target_directory.push("cogs"); // target_directory.push("cogs");
target_directory.push("helix"); // target_directory.push("helix");
let mut target_directory = helix_runtime_search_path();
if !target_directory.exists() { if !target_directory.exists() {
std::fs::create_dir(&target_directory).unwrap(); std::fs::create_dir(&target_directory).unwrap();
@ -604,8 +849,12 @@ impl super::PluginSystem for SteelScriptingEngine {
super::PluginSystemKind::Steel super::PluginSystemKind::Steel
} }
fn run_initialization_script(&self, cx: &mut Context) { fn run_initialization_script(
run_initialization_script(cx); &self,
cx: &mut Context,
configuration: Arc<ArcSwapAny<Arc<Config>>>,
) {
run_initialization_script(cx, configuration);
} }
fn handle_keymap_event( fn handle_keymap_event(
@ -635,7 +884,7 @@ impl super::PluginSystem for SteelScriptingEngine {
args: &[Cow<str>], args: &[Cow<str>],
) -> bool { ) -> bool {
if ENGINE.with(|x| x.borrow().global_exists(name)) { if ENGINE.with(|x| x.borrow().global_exists(name)) {
let mut args = args let args = args
.iter() .iter()
.map(|x| x.clone().into_steelval().unwrap()) .map(|x| x.clone().into_steelval().unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -649,8 +898,6 @@ impl super::PluginSystem for SteelScriptingEngine {
let context = arguments[0].clone(); let context = arguments[0].clone();
engine.update_value("*helix.cx*", context); engine.update_value("*helix.cx*", context);
// arguments.append(&mut args);
// TODO: Get rid of this clone // TODO: Get rid of this clone
engine.call_function_by_name_with_args(name, args.clone()) engine.call_function_by_name_with_args(name, args.clone())
}, },
@ -978,9 +1225,257 @@ pub fn steel_init_file() -> PathBuf {
helix_loader::config_dir().join("init.scm") helix_loader::config_dir().join("init.scm")
} }
#[derive(Clone)]
struct HelixConfiguration {
configuration: Arc<ArcSwapAny<Arc<Config>>>,
}
impl Custom for HelixConfiguration {}
// impl Custom for LineNumber {}
impl HelixConfiguration {
fn load_config(&self) -> Config {
(*self.configuration.load().clone()).clone()
}
fn store_config(&self, config: Config) {
self.configuration.store(Arc::new(config));
}
fn scrolloff(&self, lines: usize) {
let mut app_config = self.load_config();
app_config.editor.scrolloff = lines;
self.store_config(app_config);
}
fn scroll_lines(&self, lines: isize) {
let mut app_config = self.load_config();
app_config.editor.scroll_lines = lines;
self.store_config(app_config);
}
fn mouse(&self, m: bool) {
let mut app_config = self.load_config();
app_config.editor.mouse = m;
self.store_config(app_config);
}
fn shell(&self, shell: Vec<String>) {
let mut app_config = self.load_config();
app_config.editor.shell = shell;
self.store_config(app_config);
}
// TODO: Make this a symbol, probably!
fn line_number(&self, mode: LineNumber) {
let mut app_config = self.load_config();
app_config.editor.line_number = mode;
self.store_config(app_config);
}
fn cursorline(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.cursorline = option;
self.store_config(app_config);
}
fn cursorcolumn(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.cursorcolumn = option;
self.store_config(app_config);
}
fn middle_click_paste(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.middle_click_paste = option;
self.store_config(app_config);
}
fn auto_pairs(&self, config: AutoPairConfig) {
let mut app_config = self.load_config();
app_config.editor.auto_pairs = config;
self.store_config(app_config);
}
fn auto_completion(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.auto_completion = option;
self.store_config(app_config);
}
fn auto_format(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.auto_format = option;
self.store_config(app_config);
}
fn auto_save(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.auto_save = option;
self.store_config(app_config);
}
fn text_width(&self, width: usize) {
let mut app_config = self.load_config();
app_config.editor.text_width = width;
self.store_config(app_config);
}
fn idle_timeout(&self, ms: usize) {
let mut app_config = self.load_config();
app_config.editor.idle_timeout = Duration::from_millis(ms as u64);
self.store_config(app_config);
}
fn completion_timeout(&self, ms: usize) {
let mut app_config = self.load_config();
app_config.editor.completion_timeout = Duration::from_millis(ms as u64);
self.store_config(app_config);
}
fn preview_completion_insert(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.preview_completion_insert = option;
self.store_config(app_config);
}
// TODO: Make sure this conversion works automatically
fn completion_trigger_len(&self, length: u8) {
let mut app_config = self.load_config();
app_config.editor.completion_trigger_len = length;
self.store_config(app_config);
}
fn completion_replace(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.completion_replace = option;
self.store_config(app_config);
}
fn auto_info(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.auto_info = option;
self.store_config(app_config);
}
fn cursor_shape(&self, config: CursorShapeConfig) {
let mut app_config = self.load_config();
app_config.editor.cursor_shape = config;
self.store_config(app_config);
}
fn true_color(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.true_color = option;
self.store_config(app_config);
}
fn insert_final_newline(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.insert_final_newline = option;
self.store_config(app_config);
}
fn color_modes(&self, option: bool) {
let mut app_config = self.load_config();
app_config.editor.color_modes = option;
self.store_config(app_config);
}
fn gutters(&self, config: GutterConfig) {
let mut app_config = self.load_config();
app_config.editor.gutters = config;
self.store_config(app_config);
}
fn file_picker(&self, picker: FilePickerConfig) {
let mut app_config = self.load_config();
app_config.editor.file_picker = picker;
self.store_config(app_config);
}
fn statusline(&self, config: StatusLineConfig) {
let mut app_config = self.load_config();
app_config.editor.statusline = config;
self.store_config(app_config);
}
fn undercurl(&self, undercurl: bool) {
let mut app_config = self.load_config();
app_config.editor.undercurl = undercurl;
self.store_config(app_config);
}
fn search(&self, config: SearchConfig) {
let mut app_config = self.load_config();
app_config.editor.search = config;
self.store_config(app_config);
}
fn lsp(&self, config: LspConfig) {
let mut app_config = self.load_config();
app_config.editor.lsp = config;
self.store_config(app_config);
}
fn terminal(&self, config: Option<TerminalConfig>) {
let mut app_config = self.load_config();
app_config.editor.terminal = config;
self.store_config(app_config);
}
fn rulers(&self, cols: Vec<u16>) {
let mut app_config = self.load_config();
app_config.editor.rulers = cols;
self.store_config(app_config);
}
fn whitespace(&self, config: WhitespaceConfig) {
let mut app_config = self.load_config();
app_config.editor.whitespace = config;
self.store_config(app_config);
}
fn bufferline(&self, config: BufferLine) {
let mut app_config = self.load_config();
app_config.editor.bufferline = config;
self.store_config(app_config);
}
fn indent_guides(&self, config: IndentGuidesConfig) {
let mut app_config = self.load_config();
app_config.editor.indent_guides = config;
self.store_config(app_config);
}
fn soft_wrap(&self, config: SoftWrap) {
let mut app_config = self.load_config();
app_config.editor.soft_wrap = config;
self.store_config(app_config);
}
fn workspace_lsp_roots(&self, roots: Vec<PathBuf>) {
let mut app_config = self.load_config();
app_config.editor.workspace_lsp_roots = roots;
self.store_config(app_config);
}
fn default_line_ending(&self, config: LineEndingConfig) {
let mut app_config = self.load_config();
app_config.editor.default_line_ending = config;
self.store_config(app_config);
}
fn smart_tab(&self, config: Option<SmartTabConfig>) {
let mut app_config = self.load_config();
app_config.editor.smart_tab = config;
self.store_config(app_config);
}
}
/// Run the initialization script located at `$helix_config/init.scm` /// Run the initialization script located at `$helix_config/init.scm`
/// This runs the script in the global environment, and does _not_ load it as a module directly /// This runs the script in the global environment, and does _not_ load it as a module directly
fn run_initialization_script(cx: &mut Context) { fn run_initialization_script(cx: &mut Context, configuration: Arc<ArcSwapAny<Arc<Config>>>) {
log::info!("Loading init.scm..."); log::info!("Loading init.scm...");
let helix_module_path = helix_module_file(); let helix_module_path = helix_module_file();
@ -989,6 +1484,16 @@ fn run_initialization_script(cx: &mut Context) {
ENGINE.with(|engine| { ENGINE.with(|engine| {
let mut guard = engine.borrow_mut(); let mut guard = engine.borrow_mut();
// Embed the configuration so we don't have to communicate over the refresh
// channel. The state is still stored within the `Application` struct, but
// now we can just access it and signal a refresh of the config when we need to.
guard.update_value(
"*helix.config*",
HelixConfiguration { configuration }
.into_steelval()
.unwrap(),
);
let res = guard.run_with_reference( let res = guard.run_with_reference(
cx, cx,
"*helix.cx*", "*helix.cx*",
@ -1018,7 +1523,7 @@ fn run_initialization_script(cx: &mut Context) {
let docs = exported let docs = exported
.iter() .iter()
.filter_map(|x| { .filter_map(|x| {
if let Ok(value) = guard.run(&format!( if let Ok(value) = guard.compile_and_run_raw_program(format!(
"(#%function-ptr-table-get #%function-ptr-table {})", "(#%function-ptr-table-get #%function-ptr-table {})",
x x
)) { )) {
@ -1314,7 +1819,7 @@ impl SteelEngine {
} }
pub fn require_module(&mut self, module: SteelString) -> steel::rvals::Result<()> { pub fn require_module(&mut self, module: SteelString) -> steel::rvals::Result<()> {
self.0.run(&format!("(require \"{}\")", module)).map(|_| ()) self.0.run(format!("(require \"{}\")", module)).map(|_| ())
} }
} }
@ -1428,9 +1933,7 @@ fn load_misc_api(engine: &mut Engine) {
template_function_arity_2("enqueue-thread-local-callback-with-delay"); template_function_arity_2("enqueue-thread-local-callback-with-delay");
template_function_arity_2("helix-await-callback"); template_function_arity_2("helix-await-callback");
let mut target_directory = PathBuf::from(std::env::var("STEEL_HOME").unwrap()); let mut target_directory = helix_runtime_search_path();
target_directory.push("cogs");
target_directory.push("helix");
if !target_directory.exists() { if !target_directory.exists() {
std::fs::create_dir(&target_directory).unwrap(); std::fs::create_dir(&target_directory).unwrap();
@ -1443,20 +1946,26 @@ fn load_misc_api(engine: &mut Engine) {
engine.register_module(module); engine.register_module(module);
} }
fn helix_runtime_search_path() -> PathBuf {
helix_loader::config_dir().join("helix")
}
fn configure_engine_impl(mut engine: Engine) -> Engine { fn configure_engine_impl(mut engine: Engine) -> Engine {
log::info!("Loading engine!"); log::info!("Loading engine!");
engine.add_search_directory(helix_loader::config_dir());
engine.register_value("*helix.cx*", SteelVal::Void); engine.register_value("*helix.cx*", SteelVal::Void);
engine.register_value("*helix.config*", SteelVal::Void);
// TODO: Load (require-builtin helix/core/editor) in more or less every file that needs it
load_editor_api(&mut engine); load_editor_api(&mut engine);
load_configuration_api(&mut engine);
load_typed_commands(&mut engine); load_typed_commands(&mut engine);
load_static_commands(&mut engine); load_static_commands(&mut engine);
load_keymap_api(&mut engine, KeyMapApi::new()); load_keymap_api(&mut engine, KeyMapApi::new());
load_theme_api(&mut engine); load_theme_api(&mut engine);
load_rope_api(&mut engine); load_rope_api(&mut engine);
load_language_configuration_api(&mut engine); load_language_configuration_api(&mut engine);
load_misc_api(&mut engine); load_misc_api(&mut engine);
// load_engine_api(&mut engine); // load_engine_api(&mut engine);
@ -1749,7 +2258,7 @@ fn get_selection(cx: &mut Context) -> String {
fn run_in_engine(cx: &mut Context, arg: String) -> anyhow::Result<()> { fn run_in_engine(cx: &mut Context, arg: String) -> anyhow::Result<()> {
let callback = async move { let callback = async move {
let output = ENGINE let output = ENGINE
.with(|x| x.borrow_mut().run(&arg)) .with(|x| x.borrow_mut().run(arg))
.map(|x| format!("{:?}", x)); .map(|x| format!("{:?}", x));
let (output, success) = match output { let (output, success) = match output {
@ -1814,34 +2323,14 @@ fn set_scratch_buffer_name(cx: &mut Context, name: String) {
} }
} }
// TODO: Use this over handing around the editor reference, probably
// fn cx_current_focus(cx: &mut Context) -> helix_view::ViewId {
// cx.editor.tree.focus
// }
// TODO: Expose the below in a separate module, make things a bit more clear!
fn current_focus(editor: &mut Editor) -> helix_view::ViewId {
editor.tree.focus
}
fn cx_current_focus(cx: &mut Context) -> helix_view::ViewId { fn cx_current_focus(cx: &mut Context) -> helix_view::ViewId {
cx.editor.tree.focus cx.editor.tree.focus
} }
// Get the document id
fn get_document_id(editor: &mut Editor, view_id: helix_view::ViewId) -> DocumentId {
editor.tree.get(view_id).doc
}
fn cx_get_document_id(cx: &mut Context, view_id: helix_view::ViewId) -> DocumentId { fn cx_get_document_id(cx: &mut Context, view_id: helix_view::ViewId) -> DocumentId {
cx.editor.tree.get(view_id).doc cx.editor.tree.get(view_id).doc
} }
// Get the document from the document id - TODO: Add result type here
fn get_document(editor: &mut Editor, doc_id: DocumentId) -> &Document {
editor.documents.get(&doc_id).unwrap()
}
fn cx_get_document<'a>(cx: &'a mut Context, doc_id: DocumentId) -> &'a Document { fn cx_get_document<'a>(cx: &'a mut Context, doc_id: DocumentId) -> &'a Document {
cx.editor.documents.get(&doc_id).unwrap() cx.editor.documents.get(&doc_id).unwrap()
} }
@ -1850,14 +2339,6 @@ fn document_to_text(doc: &Document) -> SteelRopeSlice {
SteelRopeSlice::new(doc.text().clone()) SteelRopeSlice::new(doc.text().clone())
} }
fn is_document_in_view(editor: &mut Editor, doc_id: DocumentId) -> Option<helix_view::ViewId> {
editor
.tree
.traverse()
.find(|(_, v)| v.doc == doc_id)
.map(|(id, _)| id)
}
fn cx_is_document_in_view(cx: &mut Context, doc_id: DocumentId) -> Option<helix_view::ViewId> { fn cx_is_document_in_view(cx: &mut Context, doc_id: DocumentId) -> Option<helix_view::ViewId> {
cx.editor cx.editor
.tree .tree
@ -1866,10 +2347,6 @@ fn cx_is_document_in_view(cx: &mut Context, doc_id: DocumentId) -> Option<helix_
.map(|(id, _)| id) .map(|(id, _)| id)
} }
fn document_exists(editor: &mut Editor, doc_id: DocumentId) -> bool {
editor.documents.get(&doc_id).is_some()
}
fn cx_document_exists(cx: &mut Context, doc_id: DocumentId) -> bool { fn cx_document_exists(cx: &mut Context, doc_id: DocumentId) -> bool {
cx.editor.documents.get(&doc_id).is_some() cx.editor.documents.get(&doc_id).is_some()
} }
@ -1878,48 +2355,22 @@ fn document_path(doc: &Document) -> Option<String> {
doc.path().and_then(|x| x.to_str()).map(|x| x.to_string()) doc.path().and_then(|x| x.to_str()).map(|x| x.to_string())
} }
// Get the time the document was focused
fn document_focused_at(doc: &Document) -> std::time::Instant {
doc.focused_at
}
// Get all the editor documents
fn editor_all_documents(editor: &mut Editor) -> Vec<DocumentId> {
editor.documents.keys().copied().collect()
}
fn cx_editor_all_documents(cx: &mut Context) -> Vec<DocumentId> { fn cx_editor_all_documents(cx: &mut Context) -> Vec<DocumentId> {
cx.editor.documents.keys().copied().collect() cx.editor.documents.keys().copied().collect()
} }
fn switch(editor: &mut Editor, doc_id: DocumentId) {
editor.switch(doc_id, Action::VerticalSplit)
}
fn cx_switch(cx: &mut Context, doc_id: DocumentId) { fn cx_switch(cx: &mut Context, doc_id: DocumentId) {
cx.editor.switch(doc_id, Action::VerticalSplit) cx.editor.switch(doc_id, Action::VerticalSplit)
} }
fn editor_get_mode(editor: &mut Editor) -> Mode {
editor.mode
}
fn cx_get_mode(cx: &mut Context) -> Mode { fn cx_get_mode(cx: &mut Context) -> Mode {
cx.editor.mode cx.editor.mode
} }
fn editor_set_mode(editor: &mut Editor, mode: Mode) {
editor.mode = mode
}
fn cx_set_mode(cx: &mut Context, mode: Mode) { fn cx_set_mode(cx: &mut Context, mode: Mode) {
cx.editor.mode = mode cx.editor.mode = mode
} }
fn is_context(value: SteelVal) -> bool {
Context::as_mut_ref_from_ref(&value).is_ok()
}
// Overlay the dynamic component, see what happens? // Overlay the dynamic component, see what happens?
// Probably need to pin the values to this thread - wrap it in a shim which pins the value // Probably need to pin the values to this thread - wrap it in a shim which pins the value
// to this thread? - call methods on the thread local value? // to this thread? - call methods on the thread local value?

@ -971,6 +971,7 @@ pub enum ConfigEvent {
Refresh, Refresh,
Update(Box<Config>), Update(Box<Config>),
UpdateLanguageConfiguration, UpdateLanguageConfiguration,
Change,
} }
enum ThemeAction { enum ThemeAction {

@ -10,7 +10,15 @@ mod steel_implementations {
use steel::{gc::unsafe_erased_pointers::CustomReference, rvals::Custom}; use steel::{gc::unsafe_erased_pointers::CustomReference, rvals::Custom};
use crate::{ use crate::{
document::Mode, graphics::Rect, input::Event, Document, DocumentId, Editor, ViewId, document::Mode,
editor::{
BufferLine, CursorShapeConfig, FilePickerConfig, GutterConfig, IndentGuidesConfig,
LineEndingConfig, LineNumber, LspConfig, SearchConfig, SmartTabConfig,
StatusLineConfig, TerminalConfig, WhitespaceConfig,
},
graphics::Rect,
input::Event,
Document, DocumentId, Editor, ViewId,
}; };
impl steel::gc::unsafe_erased_pointers::CustomReference for Editor {} impl steel::gc::unsafe_erased_pointers::CustomReference for Editor {}
@ -26,4 +34,19 @@ mod steel_implementations {
impl Custom for DocumentId {} impl Custom for DocumentId {}
impl Custom for ViewId {} impl Custom for ViewId {}
impl CustomReference for Document {} impl CustomReference for Document {}
impl Custom for FilePickerConfig {}
impl Custom for StatusLineConfig {}
impl Custom for SearchConfig {}
impl Custom for TerminalConfig {}
impl Custom for WhitespaceConfig {}
impl Custom for CursorShapeConfig {}
impl Custom for BufferLine {}
impl Custom for LineNumber {}
impl Custom for GutterConfig {}
impl Custom for LspConfig {}
impl Custom for IndentGuidesConfig {}
impl Custom for LineEndingConfig {}
impl Custom for SmartTabConfig {}
// impl Custom for SoftW
} }

Loading…
Cancel
Save