add new xtask for code generation of core libraries

pull/8675/merge^2
mattwparas 10 months ago
parent 38f344c21c
commit eb20adbaad

24
Cargo.lock generated

@ -1488,9 +1488,9 @@ dependencies = [
[[package]] [[package]]
name = "im-lists" name = "im-lists"
version = "0.7.1" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c07eff2c41645923382085ea8627509e5184f7a668f75d0c1e16091f7af4798" checksum = "3e7233fb8b1ffc0b1d6033fd311a74a0443164628c62abbc871185ee95098b63"
dependencies = [ dependencies = [
"smallvec", "smallvec",
] ]
@ -1742,6 +1742,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
dependencies = [ dependencies = [
"num-traits", "num-traits",
"serde",
] ]
[[package]] [[package]]
@ -1775,6 +1776,7 @@ dependencies = [
"num-bigint", "num-bigint",
"num-integer", "num-integer",
"num-traits", "num-traits",
"serde",
] ]
[[package]] [[package]]
@ -2307,7 +2309,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "steel-core" name = "steel-core"
version = "0.6.0" version = "0.6.0"
source = "git+https://github.com/mattwparas/steel.git#ad307d9ab163b99ac6dc0bc06a04601042a3f325" source = "git+https://github.com/mattwparas/steel.git#1fb88e561474c723a4fd2675553d6091a380aef1"
dependencies = [ dependencies = [
"abi_stable", "abi_stable",
"anyhow", "anyhow",
@ -2335,6 +2337,7 @@ dependencies = [
"steel-derive", "steel-derive",
"steel-gen", "steel-gen",
"steel-parser", "steel-parser",
"strsim",
"weak-table", "weak-table",
"which 4.4.2", "which 4.4.2",
] ]
@ -2342,7 +2345,7 @@ dependencies = [
[[package]] [[package]]
name = "steel-derive" name = "steel-derive"
version = "0.5.0" version = "0.5.0"
source = "git+https://github.com/mattwparas/steel.git#ad307d9ab163b99ac6dc0bc06a04601042a3f325" source = "git+https://github.com/mattwparas/steel.git#1fb88e561474c723a4fd2675553d6091a380aef1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2352,7 +2355,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#ad307d9ab163b99ac6dc0bc06a04601042a3f325" source = "git+https://github.com/mattwparas/steel.git#1fb88e561474c723a4fd2675553d6091a380aef1"
dependencies = [ dependencies = [
"codegen", "codegen",
"serde", "serde",
@ -2362,15 +2365,16 @@ dependencies = [
[[package]] [[package]]
name = "steel-parser" name = "steel-parser"
version = "0.6.0" version = "0.6.0"
source = "git+https://github.com/mattwparas/steel.git#ad307d9ab163b99ac6dc0bc06a04601042a3f325" source = "git+https://github.com/mattwparas/steel.git#1fb88e561474c723a4fd2675553d6091a380aef1"
dependencies = [ dependencies = [
"fxhash", "fxhash",
"lasso", "lasso",
"num-bigint", "num",
"once_cell", "once_cell",
"pretty", "pretty",
"serde", "serde",
"serde_derive", "serde_derive",
"smallvec",
] ]
[[package]] [[package]]
@ -2379,6 +2383,12 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c" checksum = "e9557cb6521e8d009c51a8666f09356f4b817ba9ba0981a305bd86aee47bd35c"
[[package]]
name = "strsim"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "1.0.109"

@ -81,7 +81,6 @@ use ignore::{DirEntry, WalkBuilder, WalkState};
pub type OnKeyCallback = Box<dyn FnOnce(&mut Context, KeyEvent)>; pub type OnKeyCallback = Box<dyn FnOnce(&mut Context, KeyEvent)>;
#[repr(C)]
pub struct Context<'a> { pub struct Context<'a> {
pub register: Option<char>, pub register: Option<char>,
pub count: Option<NonZeroUsize>, pub count: Option<NonZeroUsize>,

@ -1,6 +1,5 @@
use arc_swap::ArcSwapAny; use arc_swap::ArcSwapAny;
use helix_core::syntax::Configuration; use helix_view::{document::Mode, input::KeyEvent};
use helix_view::{document::Mode, input::KeyEvent, Theme};
use std::{borrow::Cow, sync::Arc}; use std::{borrow::Cow, sync::Arc};
@ -11,7 +10,7 @@ use crate::{
ui::{self, PromptEvent}, ui::{self, PromptEvent},
}; };
use super::{shell_impl, Context, MappableCommand, TYPABLE_COMMAND_LIST}; use super::{Context, MappableCommand, TYPABLE_COMMAND_LIST};
#[cfg(feature = "steel")] #[cfg(feature = "steel")]
mod components; mod components;
@ -138,6 +137,12 @@ impl ScriptingEngine {
.flat_map(|kind| manual_dispatch!(kind, available_commands())) .flat_map(|kind| manual_dispatch!(kind, available_commands()))
.collect() .collect()
} }
pub fn generate_sources() {
for kind in PLUGIN_PRECEDENCE {
manual_dispatch!(kind, generate_sources())
}
}
} }
impl PluginSystem for NoEngine { impl PluginSystem for NoEngine {
@ -215,4 +220,6 @@ pub trait PluginSystem {
fn available_commands<'a>(&self) -> Vec<Cow<'a, str>> { fn available_commands<'a>(&self) -> Vec<Cow<'a, str>> {
Vec::new() Vec::new()
} }
fn generate_sources(&self) {}
} }

@ -21,17 +21,19 @@ use helix_view::{
Document, DocumentId, Editor, ViewId, Document, DocumentId, Editor, ViewId,
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
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, 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, SteelErr, SteelVal,
}; };
use std::{ use std::{
borrow::Cow, collections::HashMap, ops::Deref, path::PathBuf, sync::atomic::AtomicUsize, borrow::Cow,
collections::HashMap,
path::PathBuf,
sync::atomic::{AtomicUsize, Ordering},
time::Duration, time::Duration,
}; };
use std::{ use std::{
@ -56,13 +58,20 @@ use components::SteelDynamicComponent;
use super::{components, Context, MappableCommand, TYPABLE_COMMAND_LIST}; use super::{components, Context, MappableCommand, TYPABLE_COMMAND_LIST};
use insert::{insert_char, insert_string}; use insert::{insert_char, insert_string};
static ENGINE_COUNT: AtomicUsize = AtomicUsize::new(0);
// TODO: // TODO:
// I'm not entirely sure this is correct, however from observation it seems that // 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 // 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 // multiple instances of the engine getting created. I'll need to go observe how
// and when the engine gets accessed. // and when the engine gets accessed.
thread_local! { thread_local! {
pub static ENGINE: std::rc::Rc<std::cell::RefCell<steel::steel_vm::engine::Engine>> = configure_engine(); pub static ENGINE: std::rc::Rc<std::cell::RefCell<steel::steel_vm::engine::Engine>> = {
if ENGINE_COUNT.fetch_add(1, Ordering::SeqCst) != 0 {
panic!("More than one instance of the steel runtime is not allowed!");
}
configure_engine()
};
} }
pub struct KeyMapApi { pub struct KeyMapApi {
@ -94,7 +103,8 @@ impl KeyMapApi {
// and can instead just refer to the single configuration object. // and can instead just refer to the single configuration object.
// //
// Possibly also introduce buffer / language specific keybindings // Possibly also introduce buffer / language specific keybindings
// there as well. // there as well, however how that interaction is done is still up
// for debate.
thread_local! { thread_local! {
pub static BUFFER_OR_EXTENSION_KEYBINDING_MAP: SteelVal = pub static BUFFER_OR_EXTENSION_KEYBINDING_MAP: SteelVal =
SteelVal::boxed(SteelVal::empty_hashmap()); SteelVal::boxed(SteelVal::empty_hashmap());
@ -135,11 +145,14 @@ fn load_keymap_api(engine: &mut Engine, api: KeyMapApi) {
engine.register_module(module); engine.register_module(module);
} }
fn load_static_commands(engine: &mut Engine) { fn load_static_commands(engine: &mut Engine, generate_sources: bool) {
let mut module = BuiltInModule::new("helix/core/static"); let mut module = BuiltInModule::new("helix/core/static");
let mut builtin_static_command_module = let mut builtin_static_command_module = if generate_sources {
"(require-builtin helix/core/static as helix.static.)".to_string(); "(require-builtin helix/core/static as helix.static.)".to_string()
} else {
"".to_string()
};
for command in TYPABLE_COMMAND_LIST { for command in TYPABLE_COMMAND_LIST {
let func = |cx: &mut Context| { let func = |cx: &mut Context| {
@ -161,6 +174,7 @@ fn load_static_commands(engine: &mut Engine) {
if let MappableCommand::Static { name, fun, .. } = command { if let MappableCommand::Static { name, fun, .. } = command {
module.register_fn(name, fun); module.register_fn(name, fun);
if generate_sources {
builtin_static_command_module.push_str(&format!( builtin_static_command_module.push_str(&format!(
r#" r#"
(provide {}) (provide {})
@ -171,8 +185,10 @@ fn load_static_commands(engine: &mut Engine) {
)); ));
} }
} }
}
let mut template_function_arity_1 = |name: &str| { let mut template_function_arity_1 = |name: &str| {
if generate_sources {
builtin_static_command_module.push_str(&format!( builtin_static_command_module.push_str(&format!(
r#" r#"
(provide {}) (provide {})
@ -181,6 +197,7 @@ fn load_static_commands(engine: &mut Engine) {
"#, "#,
name, name, name name, name, name
)); ));
}
}; };
// Adhoc static commands that probably needs evaluating // Adhoc static commands that probably needs evaluating
@ -209,6 +226,7 @@ fn load_static_commands(engine: &mut Engine) {
template_function_arity_1("cx->current-file"); template_function_arity_1("cx->current-file");
let mut template_function_arity_0 = |name: &str| { let mut template_function_arity_0 = |name: &str| {
if generate_sources {
builtin_static_command_module.push_str(&format!( builtin_static_command_module.push_str(&format!(
r#" r#"
(provide {}) (provide {})
@ -217,6 +235,7 @@ fn load_static_commands(engine: &mut Engine) {
"#, "#,
name, name, name name, name, name
)); ));
}
}; };
// Arity 0 // Arity 0
@ -242,6 +261,7 @@ fn load_static_commands(engine: &mut Engine) {
template_function_arity_0("move-window-far-right"); template_function_arity_0("move-window-far-right");
let mut template_function_no_context = |name: &str| { let mut template_function_no_context = |name: &str| {
if generate_sources {
builtin_static_command_module.push_str(&format!( builtin_static_command_module.push_str(&format!(
r#" r#"
(provide {}) (provide {})
@ -249,6 +269,7 @@ fn load_static_commands(engine: &mut Engine) {
"#, "#,
name, name, name name, name, name
)) ))
}
}; };
module.register_fn("get-helix-scm-path", get_helix_scm_path); module.register_fn("get-helix-scm-path", get_helix_scm_path);
@ -257,6 +278,7 @@ 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");
if generate_sources {
let mut target_directory = helix_runtime_search_path(); let mut target_directory = helix_runtime_search_path();
if !target_directory.exists() { if !target_directory.exists() {
@ -266,40 +288,20 @@ fn load_static_commands(engine: &mut Engine) {
target_directory.push("static.scm"); target_directory.push("static.scm");
std::fs::write(target_directory, builtin_static_command_module).unwrap(); std::fs::write(target_directory, builtin_static_command_module).unwrap();
}
engine.register_module(module); engine.register_module(module);
} }
fn load_typed_commands(engine: &mut Engine) { fn load_typed_commands(engine: &mut Engine, generate_sources: bool) {
let mut module = BuiltInModule::new("helix/core/typable".to_string()); let mut module = BuiltInModule::new("helix/core/typable".to_string());
let mut builtin_typable_command_module =
"(require-builtin helix/core/typable as helix.)".to_string();
{ let mut builtin_typable_command_module = if generate_sources {
let func = |cx: &mut Context, args: &[Cow<str>]| { "(require-builtin helix/core/typable as helix.)".to_string()
let mut cx = compositor::Context { } else {
editor: cx.editor, "".to_string()
scroll: None,
jobs: cx.jobs,
};
set_options(&mut cx, args, PromptEvent::Validate)
}; };
module.register_fn("set-options", func);
let name = "set-options";
builtin_typable_command_module.push_str(&format!(
r#"
(provide {})
(define ({} . args)
(helix.{} *helix.cx* args))
"#,
name, name, name
));
}
// Register everything in the typable command list. Now these are all available // Register everything in the typable command list. Now these are all available
for command in TYPABLE_COMMAND_LIST { for command in TYPABLE_COMMAND_LIST {
let func = |cx: &mut Context, args: &[Cow<str>]| { let func = |cx: &mut Context, args: &[Cow<str>]| {
@ -314,6 +316,7 @@ fn load_typed_commands(engine: &mut Engine) {
module.register_fn(command.name, func); module.register_fn(command.name, func);
if generate_sources {
// Create an ephemeral builtin module to reference until I figure out how // Create an ephemeral builtin module to reference until I figure out how
// to wrap the functions with a reference to the engine context better. // to wrap the functions with a reference to the engine context better.
builtin_typable_command_module.push_str(&format!( builtin_typable_command_module.push_str(&format!(
@ -340,7 +343,9 @@ fn load_typed_commands(engine: &mut Engine) {
command.name command.name
)); ));
} }
}
if generate_sources {
let mut target_directory = helix_runtime_search_path(); 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();
@ -349,6 +354,7 @@ fn load_typed_commands(engine: &mut Engine) {
target_directory.push("commands.scm"); target_directory.push("commands.scm");
std::fs::write(target_directory, builtin_typable_command_module).unwrap(); std::fs::write(target_directory, builtin_typable_command_module).unwrap();
}
engine.register_module(module); engine.register_module(module);
} }
@ -389,7 +395,27 @@ fn fp_max_depth(config: &mut FilePickerConfig, option: Option<usize>) {
config.max_depth = option; config.max_depth = option;
} }
fn load_configuration_api(engine: &mut Engine) { fn sw_enable(config: &mut SoftWrap, option: Option<bool>) {
config.enable = option;
}
fn sw_max_wrap(config: &mut SoftWrap, option: Option<u16>) {
config.max_wrap = option;
}
fn sw_max_indent_retain(config: &mut SoftWrap, option: Option<u16>) {
config.max_indent_retain = option;
}
fn sw_wrap_indicator(config: &mut SoftWrap, option: Option<String>) {
config.wrap_indicator = option;
}
fn wrap_at_text_width(config: &mut SoftWrap, option: Option<bool>) {
config.wrap_at_text_width = option;
}
fn load_configuration_api(engine: &mut Engine, generate_sources: bool) {
let mut module = BuiltInModule::new("helix/core/configuration"); let mut module = BuiltInModule::new("helix/core/configuration");
module.register_fn("update-configuration!", |ctx: &mut Context| { module.register_fn("update-configuration!", |ctx: &mut Context| {
@ -400,6 +426,96 @@ fn load_configuration_api(engine: &mut Engine) {
.unwrap(); .unwrap();
}); });
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);
module
.register_fn("raw-soft-wrap", || SoftWrap::default())
.register_fn("register-soft-wrap", HelixConfiguration::soft_wrap)
.register_fn("sw-enable", sw_enable)
.register_fn("sw-max-wrap", sw_max_wrap)
.register_fn("sw-max-indent-retain", sw_max_indent_retain)
.register_fn("sw-wrap-indicator", sw_wrap_indicator)
.register_fn("sw-wrap-at-text-width", wrap_at_text_width);
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)
// Specific constructors for the auto pairs configuration
.register_fn("auto-pairs-default", |enabled: bool| {
AutoPairConfig::Enable(enabled)
})
.register_fn("auto-pairs-map", |map: HashMap<char, char>| {
AutoPairConfig::Pairs(map)
})
.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);
// Keybinding stuff
module
.register_fn("keybindings", HelixConfiguration::keybindings)
.register_fn("get-keybindings", HelixConfiguration::get_keybindings);
if generate_sources {
let mut builtin_configuration_module = let mut builtin_configuration_module =
"(require-builtin helix/core/configuration as helix.)".to_string(); "(require-builtin helix/core/configuration as helix.)".to_string();
@ -411,6 +527,40 @@ fn load_configuration_api(engine: &mut Engine) {
"#, "#,
)); ));
// Register the get keybindings function
builtin_configuration_module.push_str(&format!(
r#"
(provide get-keybindings)
(define (get-keybindings)
(helix.get-keybindings *helix.cx*))
"#,
));
let mut template_soft_wrap = |name: &str| {
builtin_configuration_module.push_str(&format!(
r#"
(provide {})
(define ({} arg)
(lambda (picker)
(helix.{} picker arg)
picker))
"#,
name, name, name
));
};
let soft_wrap_functions = &[
"sw-enable",
"sw-max-wrap",
"sw-max-indent-retain",
"sw-wrap-indicator",
"sw-wrap-at-text-width",
];
for name in soft_wrap_functions {
template_soft_wrap(name);
}
let mut template_file_picker_function = |name: &str| { let mut template_file_picker_function = |name: &str| {
builtin_configuration_module.push_str(&format!( builtin_configuration_module.push_str(&format!(
r#" r#"
@ -450,18 +600,15 @@ fn load_configuration_api(engine: &mut Engine) {
"#, "#,
)); ));
module builtin_configuration_module.push_str(&format!(
.register_fn("raw-file-picker", || FilePickerConfig::default()) r#"
.register_fn("register-file-picker", HelixConfiguration::file_picker) (provide soft-wrap)
.register_fn("fp-hidden", fp_hidden) (define (soft-wrap . args)
.register_fn("fp-follow-symlinks", fp_follow_symlinks) (helix.register-soft-wrap
.register_fn("fp-deduplicate-links", fp_deduplicate_links) *helix.config*
.register_fn("fp-parents", fp_parents) (foldl (lambda (func config) (func config)) (helix.raw-soft-wrap) args)))
.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| { let mut template_function_arity_1 = |name: &str| {
builtin_configuration_module.push_str(&format!( builtin_configuration_module.push_str(&format!(
@ -513,74 +660,13 @@ fn load_configuration_api(engine: &mut Engine) {
"workspace-lsp-roots", "workspace-lsp-roots",
"default-line-ending", "default-line-ending",
"smart-tab", "smart-tab",
"keybindings",
]; ];
for func in functions { for func in functions {
template_function_arity_1(func); 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)
// Specific constructors for the auto pairs configuration
.register_fn("auto-pairs-default", |enabled: bool| {
AutoPairConfig::Enable(enabled)
})
.register_fn("auto-pairs-map", |map: HashMap<char, char>| {
AutoPairConfig::Pairs(map)
})
.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 = helix_runtime_search_path(); let mut target_directory = helix_runtime_search_path();
if !target_directory.exists() { if !target_directory.exists() {
@ -590,13 +676,46 @@ fn load_configuration_api(engine: &mut Engine) {
target_directory.push("configuration.scm"); target_directory.push("configuration.scm");
std::fs::write(target_directory, builtin_configuration_module).unwrap(); std::fs::write(target_directory, builtin_configuration_module).unwrap();
}
engine.register_module(module); engine.register_module(module);
} }
fn load_editor_api(engine: &mut Engine) { fn load_editor_api(engine: &mut Engine, generate_sources: bool) {
let mut module = BuiltInModule::new("helix/core/editor"); let mut module = BuiltInModule::new("helix/core/editor");
// Arity 0
module.register_fn("editor-focus", cx_current_focus);
module.register_fn("editor-mode", cx_get_mode);
module.register_fn("cx->themes", get_themes);
module.register_fn("editor-all-documents", cx_editor_all_documents);
module.register_fn("cx->cursor", |cx: &mut Context| cx.editor.cursor());
// Arity 1
module.register_fn("editor->doc-id", cx_get_document_id);
module.register_fn("editor-switch!", cx_switch);
module.register_fn("editor-set-focus!", |cx: &mut Context, view_id: ViewId| {
cx.editor.focus(view_id)
});
module.register_fn("editor-set-mode!", cx_set_mode);
module.register_fn("editor-doc-in-view?", cx_is_document_in_view);
module.register_fn("set-scratch-buffer-name!", set_scratch_buffer_name);
module.register_fn("editor-doc-exists?", cx_document_exists);
// Arity 1
RegisterFn::<
_,
steel::steel_vm::register_fn::MarkerWrapper8<(
Context,
DocumentId,
Document,
Document,
Context,
)>,
Document,
>::register_fn(&mut module, "editor->get-document", cx_get_document); // I do not like this
if generate_sources {
let mut builtin_editor_command_module = let mut builtin_editor_command_module =
"(require-builtin helix/core/editor as helix.)".to_string(); "(require-builtin helix/core/editor as helix.)".to_string();
@ -611,13 +730,6 @@ fn load_editor_api(engine: &mut Engine) {
)); ));
}; };
// Arity 0
module.register_fn("editor-focus", cx_current_focus);
module.register_fn("editor-mode", cx_get_mode);
module.register_fn("cx->themes", get_themes);
module.register_fn("editor-all-documents", cx_editor_all_documents);
module.register_fn("cx->cursor", |cx: &mut Context| cx.editor.cursor());
template_function_arity_0("editor-focus"); template_function_arity_0("editor-focus");
template_function_arity_0("editor-mode"); template_function_arity_0("editor-mode");
template_function_arity_0("cx->themes"); template_function_arity_0("cx->themes");
@ -635,17 +747,6 @@ fn load_editor_api(engine: &mut Engine) {
)); ));
}; };
// Arity 1
module.register_fn("editor->doc-id", cx_get_document_id);
module.register_fn("editor-switch!", cx_switch);
module.register_fn("editor-set-focus!", |cx: &mut Context, view_id: ViewId| {
cx.editor.focus(view_id)
});
module.register_fn("editor-set-mode!", cx_set_mode);
module.register_fn("editor-doc-in-view?", cx_is_document_in_view);
module.register_fn("set-scratch-buffer-name!", set_scratch_buffer_name);
module.register_fn("editor-doc-exists?", cx_document_exists);
template_function_arity_1("editor->doc-id"); template_function_arity_1("editor->doc-id");
template_function_arity_1("editor-switch!"); template_function_arity_1("editor-switch!");
template_function_arity_1("editor-set-focus!"); template_function_arity_1("editor-set-focus!");
@ -655,41 +756,6 @@ fn load_editor_api(engine: &mut Engine) {
template_function_arity_1("editor-doc-exists?"); template_function_arity_1("editor-doc-exists?");
template_function_arity_1("editor->get-document"); template_function_arity_1("editor->get-document");
// Doesn't use the context
// module.register_fn("doc-id->usize", document_id_to_usize);
// Arity 1
RegisterFn::<
_,
steel::steel_vm::register_fn::MarkerWrapper8<(
Context,
DocumentId,
Document,
Document,
Context,
)>,
Document,
>::register_fn(&mut module, "editor->get-document", cx_get_document); // I do not like this
// module.register_fn("Document-path", document_path);
// module.register_fn("helix.context?", is_context);
// module.register_type::<DocumentId>("DocumentId?");
// TODO:
// Position related functions. These probably should be defined alongside the actual impl for Custom in the core crate
// module.register_fn("position", helix_core::Position::new);
// module.register_fn("position-default", helix_core::Position::default);
// module.register_fn("position-row", |position: helix_core::Position| {
// position.row
// });
// module.register_fn("cx->themes", get_themes);
// Not the best usage here, duplicating it in a bunch of spots for now
// 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(); let mut target_directory = helix_runtime_search_path();
if !target_directory.exists() { if !target_directory.exists() {
@ -699,6 +765,7 @@ fn load_editor_api(engine: &mut Engine) {
target_directory.push("editor.scm"); target_directory.push("editor.scm");
std::fs::write(target_directory, builtin_editor_command_module).unwrap(); std::fs::write(target_directory, builtin_editor_command_module).unwrap();
}
engine.register_module(module); engine.register_module(module);
} }
@ -853,6 +920,12 @@ impl super::PluginSystem for SteelScriptingEngine {
.map(|x| x.clone().into()) .map(|x| x.clone().into())
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
fn generate_sources(&self) {
// Generate sources directly with a fresh engine
let mut engine = Engine::new();
configure_builtin_sources(&mut engine, true);
}
} }
impl SteelScriptingEngine { impl SteelScriptingEngine {
@ -1089,6 +1162,17 @@ impl HelixConfiguration {
self.configuration.store(Arc::new(config)); self.configuration.store(Arc::new(config));
} }
// Overlay new keybindings
fn keybindings(&self, keybindings: EmbeddedKeyMap) {
let mut app_config = self.load_config();
merge_keys(&mut app_config.keys, keybindings.0);
self.store_config(app_config);
}
fn get_keybindings(&self) -> EmbeddedKeyMap {
EmbeddedKeyMap(self.load_config().keys.clone())
}
fn scrolloff(&self, lines: usize) { fn scrolloff(&self, lines: usize) {
let mut app_config = self.load_config(); let mut app_config = self.load_config();
app_config.editor.scrolloff = lines; app_config.editor.scrolloff = lines;
@ -1424,9 +1508,6 @@ fn run_initialization_script(cx: &mut Context, configuration: Arc<ArcSwapAny<Arc
}); });
} }
// pub static KEYBINDING_QUEUE: Lazy<SharedKeyBindingsEventQueue> =
// Lazy::new(|| SharedKeyBindingsEventQueue::new());
pub static EXPORTED_IDENTIFIERS: Lazy<ExportedIdentifiers> = pub static EXPORTED_IDENTIFIERS: Lazy<ExportedIdentifiers> =
Lazy::new(|| ExportedIdentifiers::default()); Lazy::new(|| ExportedIdentifiers::default());
@ -1648,7 +1729,7 @@ impl SteelEngine {
pub fn call_function_by_name( pub fn call_function_by_name(
&mut self, &mut self,
function_name: SteelString, function_name: SteelString,
args: List<SteelVal>, args: Vec<SteelVal>,
) -> steel::rvals::Result<SteelVal> { ) -> steel::rvals::Result<SteelVal> {
self.0 self.0
.call_function_by_name_with_args(function_name.as_str(), args.into_iter().collect()) .call_function_by_name_with_args(function_name.as_str(), args.into_iter().collect())
@ -1659,7 +1740,7 @@ impl SteelEngine {
pub fn call_function( pub fn call_function(
&mut self, &mut self,
function: SteelVal, function: SteelVal,
args: List<SteelVal>, args: Vec<SteelVal>,
) -> steel::rvals::Result<SteelVal> { ) -> steel::rvals::Result<SteelVal> {
self.0 self.0
.call_function_with_args(function, args.into_iter().collect()) .call_function_with_args(function, args.into_iter().collect())
@ -1716,12 +1797,17 @@ fn load_engine_api(engine: &mut Engine) {
.register_fn("helix.controller.id->engine", id_to_engine); .register_fn("helix.controller.id->engine", id_to_engine);
} }
fn load_misc_api(engine: &mut Engine) { fn load_misc_api(engine: &mut Engine, generate_sources: bool) {
let mut module = BuiltInModule::new("helix/core/misc"); let mut module = BuiltInModule::new("helix/core/misc");
let mut builtin_misc_module = "(require-builtin helix/core/misc as helix.)".to_string(); let mut builtin_misc_module = if generate_sources {
"(require-builtin helix/core/misc as helix.)".to_string()
} else {
"".to_string()
};
let mut template_function_arity_0 = |name: &str| { let mut template_function_arity_0 = |name: &str| {
if generate_sources {
builtin_misc_module.push_str(&format!( builtin_misc_module.push_str(&format!(
r#" r#"
(provide {}) (provide {})
@ -1730,6 +1816,7 @@ fn load_misc_api(engine: &mut Engine) {
"#, "#,
name, name, name name, name, name
)); ));
}
}; };
// Arity 0 // Arity 0
@ -1738,6 +1825,7 @@ fn load_misc_api(engine: &mut Engine) {
template_function_arity_0("hx.cx->pos"); template_function_arity_0("hx.cx->pos");
let mut template_function_arity_1 = |name: &str| { let mut template_function_arity_1 = |name: &str| {
if generate_sources {
builtin_misc_module.push_str(&format!( builtin_misc_module.push_str(&format!(
r#" r#"
(provide {}) (provide {})
@ -1746,6 +1834,7 @@ fn load_misc_api(engine: &mut Engine) {
"#, "#,
name, name, name name, name, name
)); ));
}
}; };
// Arity 1 // Arity 1
@ -1758,6 +1847,7 @@ fn load_misc_api(engine: &mut Engine) {
template_function_arity_1("enqueue-thread-local-callback"); template_function_arity_1("enqueue-thread-local-callback");
let mut template_function_arity_2 = |name: &str| { let mut template_function_arity_2 = |name: &str| {
if generate_sources {
builtin_misc_module.push_str(&format!( builtin_misc_module.push_str(&format!(
r#" r#"
(provide {}) (provide {})
@ -1766,6 +1856,7 @@ fn load_misc_api(engine: &mut Engine) {
"#, "#,
name, name, name name, name, name
)); ));
}
}; };
// Arity 2 // Arity 2
@ -1780,6 +1871,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");
if generate_sources {
let mut target_directory = helix_runtime_search_path(); let mut target_directory = helix_runtime_search_path();
if !target_directory.exists() { if !target_directory.exists() {
@ -1789,6 +1881,7 @@ fn load_misc_api(engine: &mut Engine) {
target_directory.push("misc.scm"); target_directory.push("misc.scm");
std::fs::write(target_directory, builtin_misc_module).unwrap(); std::fs::write(target_directory, builtin_misc_module).unwrap();
}
engine.register_module(module); engine.register_module(module);
} }
@ -1797,6 +1890,19 @@ fn helix_runtime_search_path() -> PathBuf {
helix_loader::config_dir().join("helix") helix_loader::config_dir().join("helix")
} }
pub fn configure_builtin_sources(engine: &mut Engine, generate_sources: bool) {
load_editor_api(engine, generate_sources);
load_configuration_api(engine, generate_sources);
load_typed_commands(engine, generate_sources);
load_static_commands(engine, generate_sources);
if !generate_sources {
// Note: This is going to be completely revamped soon.
load_keymap_api(engine, KeyMapApi::new());
}
load_rope_api(engine);
load_misc_api(engine, generate_sources);
}
fn configure_engine_impl(mut engine: Engine) -> Engine { fn configure_engine_impl(mut engine: Engine) -> Engine {
log::info!("Loading engine!"); log::info!("Loading engine!");
@ -1805,13 +1911,8 @@ fn configure_engine_impl(mut engine: Engine) -> Engine {
engine.register_value("*helix.cx*", SteelVal::Void); engine.register_value("*helix.cx*", SteelVal::Void);
engine.register_value("*helix.config*", SteelVal::Void); engine.register_value("*helix.config*", SteelVal::Void);
load_editor_api(&mut engine); // Don't generate source directories here
load_configuration_api(&mut engine); configure_builtin_sources(&mut engine, false);
load_typed_commands(&mut engine);
load_static_commands(&mut engine);
load_keymap_api(&mut engine, KeyMapApi::new());
load_rope_api(&mut engine);
load_misc_api(&mut engine);
// Hooks // Hooks
engine.register_fn("register-hook!", register_hook); engine.register_fn("register-hook!", register_hook);
@ -1922,9 +2023,7 @@ fn configure_engine_impl(mut engine: Engine) -> Engine {
}, },
); );
engine.register_fn( engine.register_fn("picker", |values: Vec<String>| -> WrappedDynComponent {
"picker",
|values: steel::List<String>| -> WrappedDynComponent {
let picker = ui::Picker::new( let picker = ui::Picker::new(
Vec::new(), Vec::new(),
PathBuf::from(""), PathBuf::from(""),
@ -1952,8 +2051,7 @@ fn configure_engine_impl(mut engine: Engine) -> Engine {
WrappedDynComponent { WrappedDynComponent {
inner: Some(Box::new(ui::overlay::overlaid(picker))), inner: Some(Box::new(ui::overlay::overlaid(picker))),
} }
}, });
);
engine.register_fn("Component::Text", |contents: String| WrappedDynComponent { engine.register_fn("Component::Text", |contents: String| WrappedDynComponent {
inner: Some(Box::new(crate::ui::Text::new(contents))), inner: Some(Box::new(crate::ui::Text::new(contents))),
@ -2017,7 +2115,7 @@ fn configure_engine_impl(mut engine: Engine) -> Engine {
engine engine
} }
fn configure_engine() -> std::rc::Rc<std::cell::RefCell<steel::steel_vm::engine::Engine>> { pub fn configure_engine() -> std::rc::Rc<std::cell::RefCell<steel::steel_vm::engine::Engine>> {
let engine = configure_engine_impl(steel::steel_vm::engine::Engine::new()); let engine = configure_engine_impl(steel::steel_vm::engine::Engine::new());
std::rc::Rc::new(std::cell::RefCell::new(engine)) std::rc::Rc::new(std::cell::RefCell::new(engine))
@ -2366,53 +2464,6 @@ fn create_directory(path: String) {
} }
} }
/// Change config at runtime. Access nested values by dot syntax, for
/// example to disable smart case search, use `:set search.smart-case false`.
fn set_options(
cx: &mut compositor::Context,
args: &[Cow<str>],
event: PromptEvent,
) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}
if args.len() % 2 != 0 {
anyhow::bail!("Bad arguments. Usage: `:set key field`");
}
let mut config = serde_json::json!(&cx.editor.config().deref());
// let key_error = || anyhow::anyhow!("Unknown key `{}`", key);
// let field_error = |_| anyhow::anyhow!("Could not parse field `{}`", arg);
for args in args.chunks_exact(2) {
let (key, arg) = (&args[0].to_lowercase(), &args[1]);
let key_error = || anyhow::anyhow!("Unknown key `{}`", key);
let field_error = |_| anyhow::anyhow!("Could not parse field `{}`", arg);
// let mut config = serde_json::json!(&cx.editor.config().deref());
let pointer = format!("/{}", key.replace('.', "/"));
let value = config.pointer_mut(&pointer).ok_or_else(key_error)?;
*value = if value.is_string() {
// JSON strings require quotes, so we can't .parse() directly
Value::String(arg.to_string())
} else {
arg.parse().map_err(field_error)?
};
}
let config =
serde_json::from_value(config).map_err(|_| anyhow::anyhow!("Could not parse config"))?;
cx.editor
.config_events
.0
.send(ConfigEvent::Update(config))?;
Ok(())
}
pub fn cx_pos_within_text(cx: &mut Context) -> usize { pub fn cx_pos_within_text(cx: &mut Context) -> usize {
let (view, doc) = current_ref!(cx.editor); let (view, doc) = current_ref!(cx.editor);

@ -0,0 +1,5 @@
use helix_term::commands::ScriptingEngine;
pub fn code_gen() {
ScriptingEngine::generate_sources()
}

@ -1,3 +1,4 @@
mod codegen;
mod docgen; mod docgen;
mod helpers; mod helpers;
mod path; mod path;
@ -9,6 +10,7 @@ use std::{env, error::Error};
type DynError = Box<dyn Error>; type DynError = Box<dyn Error>;
pub mod tasks { pub mod tasks {
use crate::codegen::code_gen;
use crate::docgen::{lang_features, typable_commands, write}; use crate::docgen::{lang_features, typable_commands, write};
use crate::docgen::{LANG_SUPPORT_MD_OUTPUT, TYPABLE_COMMANDS_MD_OUTPUT}; use crate::docgen::{LANG_SUPPORT_MD_OUTPUT, TYPABLE_COMMANDS_MD_OUTPUT};
use crate::querycheck::query_check; use crate::querycheck::query_check;
@ -32,6 +34,10 @@ pub mod tasks {
query_check() query_check()
} }
pub fn codegen() {
code_gen()
}
pub fn print_help() { pub fn print_help() {
println!( println!(
" "
@ -54,6 +60,7 @@ fn main() -> Result<(), DynError> {
"docgen" => tasks::docgen()?, "docgen" => tasks::docgen()?,
"themelint" => tasks::themelint(env::args().nth(2))?, "themelint" => tasks::themelint(env::args().nth(2))?,
"query-check" => tasks::querycheck()?, "query-check" => tasks::querycheck()?,
"code-gen" => tasks::codegen(),
invalid => return Err(format!("Invalid task name: {}", invalid).into()), invalid => return Err(format!("Invalid task name: {}", invalid).into()),
}, },
}; };

Loading…
Cancel
Save