adding hooks

pull/8675/merge^2
Matt Paras 2025-01-27 21:42:39 -08:00
parent 72949830ee
commit 374389e9d1
4 changed files with 179 additions and 44 deletions

View File

@ -17,7 +17,7 @@ use helix_view::{
GutterConfig, IndentGuidesConfig, LineEndingConfig, LineNumber, LspConfig, SearchConfig, GutterConfig, IndentGuidesConfig, LineEndingConfig, LineNumber, LspConfig, SearchConfig,
SmartTabConfig, StatusLineConfig, TerminalConfig, WhitespaceConfig, SmartTabConfig, StatusLineConfig, TerminalConfig, WhitespaceConfig,
}, },
events::{DocumentFocusLost, SelectionDidChange}, events::{DocumentFocusLost, DocumentOpened, SelectionDidChange},
extension::document_id_to_usize, extension::document_id_to_usize,
input::KeyEvent, input::KeyEvent,
theme::Color, theme::Color,
@ -590,6 +590,22 @@ fn load_configuration_api(engine: &mut Engine, generate_sources: bool) {
module.register_fn("get-config-option-value", get_option_value); module.register_fn("get-config-option-value", get_option_value);
module.register_fn("set-configuration-for-file!", set_configuration_for_file);
module
.register_fn(
"get-language-config",
HelixConfiguration::get_language_config,
)
.register_fn(
"get-language-config-by-filename",
HelixConfiguration::get_individual_language_config_for_filename,
)
.register_fn(
"set-language-config!",
HelixConfiguration::update_individual_language_config,
);
module module
.register_fn("raw-file-picker", || FilePickerConfig::default()) .register_fn("raw-file-picker", || FilePickerConfig::default())
.register_fn("register-file-picker", HelixConfiguration::file_picker) .register_fn("register-file-picker", HelixConfiguration::file_picker)
@ -713,6 +729,14 @@ fn load_configuration_api(engine: &mut Engine, generate_sources: bool) {
"#, "#,
)); ));
builtin_configuration_module.push_str(&format!(
r#"
(provide set-configuration-for-file!)
(define (set-configuration-for-file! path config)
(helix.set-configuration-for-file! *helix.cx* path config))
"#,
));
// Register the get keybindings function // Register the get keybindings function
builtin_configuration_module.push_str(&format!( builtin_configuration_module.push_str(&format!(
r#" r#"
@ -847,6 +871,10 @@ fn load_configuration_api(engine: &mut Engine, generate_sources: bool) {
"keybindings", "keybindings",
"inline-diagnostics-cursor-line-enable", "inline-diagnostics-cursor-line-enable",
"inline-diagnostics-end-of-line-enable", "inline-diagnostics-end-of-line-enable",
// language configuration functions
"get-language-config",
"get-language-config-by-filename",
"set-language-config!",
]; ];
for func in functions { for func in functions {
@ -1449,26 +1477,60 @@ impl IndividualLanguageConfiguration {
// Apply end of line configuration on doc open? // Apply end of line configuration on doc open?
// pub fn set_end_of_line(&mut self) { // pub fn set_end_of_line(&mut self) {
// self. // self.config.end
// } // }
} }
impl Custom for HelixConfiguration {} impl Custom for HelixConfiguration {}
// impl Custom for LineNumber {} // Set the configuration for an individual file.
fn update_configuration_for_file(ctx: &mut Context, doc: DocumentId) {
if let Some(document) = ctx.editor.documents.get_mut(&doc) {
let path = document.path().unwrap();
let config_for_file = ctx
.editor
.syn_loader
.load()
.language_config_for_file_name(path);
document.language = config_for_file;
}
}
fn set_configuration_for_file(
ctx: &mut Context,
file_name: SteelString,
configuration: IndividualLanguageConfiguration,
) {
if let Some(document) = ctx.editor.document_by_path_mut(file_name.as_str()) {
document.language = Some(Arc::new(configuration.config));
}
}
impl HelixConfiguration { impl HelixConfiguration {
fn store_language_configuration(&self, language_config: syntax::Loader) { fn store_language_configuration(&self, language_config: syntax::Loader) {
self.language_configuration.store(Arc::new(language_config)) self.language_configuration.store(Arc::new(language_config))
} }
fn get_individual_language_config_for_filename( fn get_language_config(
&self, &self,
file_name: &str, language: SteelString,
) -> Option<IndividualLanguageConfiguration> { ) -> Option<IndividualLanguageConfiguration> {
self.language_configuration self.language_configuration
.load() .load()
.language_config_for_file_name(std::path::Path::new(file_name)) .language_config_for_language_id(language.as_str())
.map(|config| IndividualLanguageConfiguration {
config: (*config).clone(),
})
}
fn get_individual_language_config_for_filename(
&self,
file_name: SteelString,
) -> Option<IndividualLanguageConfiguration> {
self.language_configuration
.load()
.language_config_for_file_name(std::path::Path::new(file_name.as_str()))
.map(|config| IndividualLanguageConfiguration { .map(|config| IndividualLanguageConfiguration {
config: (*config).clone(), config: (*config).clone(),
}) })
@ -1495,6 +1557,11 @@ impl HelixConfiguration {
} }
} }
// // Refresh configuration for a specific file
// fn refresh_language_configuration(&mut self) {
// todo!()
// }
fn load_config(&self) -> Config { fn load_config(&self) -> Config {
(*self.configuration.load().clone()).clone() (*self.configuration.load().clone()).clone()
} }
@ -2040,6 +2107,7 @@ fn register_hook(event_kind: String, callback_fn: SteelVal) -> steel::UnRecovera
// and act accordingly? // and act accordingly?
register_hook!(move |event: &mut DocumentFocusLost<'_>| { register_hook!(move |event: &mut DocumentFocusLost<'_>| {
let cloned_func = rooted.value().clone(); let cloned_func = rooted.value().clone();
let doc_id = event.doc;
let callback = move |editor: &mut Editor, let callback = move |editor: &mut Editor,
_compositor: &mut Compositor, _compositor: &mut Compositor,
@ -2058,8 +2126,13 @@ fn register_hook(event_kind: String, callback_fn: SteelVal) -> steel::UnRecovera
.consume(move |engine, args| { .consume(move |engine, args| {
let context = args[0].clone(); let context = args[0].clone();
engine.update_value("*helix.cx*", context); engine.update_value("*helix.cx*", context);
let mut args = [doc_id.into_steelval().unwrap()];
// TODO: Do something with this error! // TODO: Do something with this error!
engine.call_function_with_args(cloned_func.clone(), Vec::new()) engine.call_function_with_args_from_mut_slice(
cloned_func.clone(),
&mut args,
)
}) })
{ {
present_error_inside_engine_context(&mut ctx, guard, e); present_error_inside_engine_context(&mut ctx, guard, e);
@ -2079,34 +2152,83 @@ fn register_hook(event_kind: String, callback_fn: SteelVal) -> steel::UnRecovera
// is probably the most helpful so that way we can look the document up // is probably the most helpful so that way we can look the document up
// and act accordingly? // and act accordingly?
register_hook!(move |event: &mut SelectionDidChange<'_>| { register_hook!(move |event: &mut SelectionDidChange<'_>| {
// let cloned_func = rooted.value().clone(); let cloned_func = rooted.value().clone();
let view_id = event.view;
// let callback = move |editor: &mut Editor, let callback = move |editor: &mut Editor,
// _compositor: &mut Compositor, _compositor: &mut Compositor,
// jobs: &mut job::Jobs| { jobs: &mut job::Jobs| {
// let mut ctx = Context { let mut ctx = Context {
// register: None, register: None,
// count: None, count: None,
// editor, editor,
// callback: Vec::new(), callback: Vec::new(),
// on_next_key_callback: None, on_next_key_callback: None,
// jobs, jobs,
// }; };
// enter_engine(|guard| { enter_engine(|guard| {
// if let Err(e) = guard if let Err(e) = guard
// .with_mut_reference::<Context, Context>(&mut ctx) .with_mut_reference::<Context, Context>(&mut ctx)
// .consume(move |engine, args| { .consume(move |engine, args| {
// let context = args[0].clone(); let context = args[0].clone();
// engine.update_value("*helix.cx*", context); engine.update_value("*helix.cx*", context);
// // TODO: Do something with this error! // TODO: Reuse this allocation
// engine.call_function_with_args(cloned_func.clone(), Vec::new()) let mut args = [view_id.into_steelval().unwrap()];
// }) engine.call_function_with_args_from_mut_slice(
// { cloned_func.clone(),
// present_error_inside_engine_context(&mut ctx, guard, e); &mut args,
// } )
// }) })
// }; {
// job::dispatch_blocking_jobs(callback); present_error_inside_engine_context(&mut ctx, guard, e);
}
})
};
job::dispatch_blocking_jobs(callback);
Ok(())
});
Ok(SteelVal::Void).into()
}
"document-opened" => {
// TODO: Share this code with the above since most of it is
// exactly the same
register_hook!(move |event: &mut DocumentOpened<'_>| {
let cloned_func = rooted.value().clone();
let doc_id = event.doc;
let callback = move |editor: &mut Editor,
_compositor: &mut Compositor,
jobs: &mut job::Jobs| {
let mut ctx = Context {
register: None,
count: None,
editor,
callback: Vec::new(),
on_next_key_callback: None,
jobs,
};
enter_engine(|guard| {
if let Err(e) = guard
.with_mut_reference::<Context, Context>(&mut ctx)
.consume(move |engine, args| {
let context = args[0].clone();
engine.update_value("*helix.cx*", context);
// TODO: Reuse this allocation if possible
let mut args = [doc_id.into_steelval().unwrap()];
engine.call_function_with_args_from_mut_slice(
cloned_func.clone(),
&mut args,
)
})
{
present_error_inside_engine_context(&mut ctx, guard, e);
}
})
};
job::dispatch_blocking_jobs(callback);
Ok(()) Ok(())
}); });
@ -2114,13 +2236,6 @@ fn register_hook(event_kind: String, callback_fn: SteelVal) -> steel::UnRecovera
Ok(SteelVal::Void).into() Ok(SteelVal::Void).into()
} }
// Unimplemented!
// "document-did-change" => {
// todo!()
// }
// "selection-did-change" => {
// todo!()
// }
_ => steelerr!(Generic => "Unable to register hook: Unknown event type: {}", event_kind) _ => steelerr!(Generic => "Unable to register hook: Unknown event type: {}", event_kind)
.into(), .into(),
} }

View File

@ -1,7 +1,7 @@
use helix_event::{events, register_event}; use helix_event::{events, register_event};
use helix_view::document::Mode; use helix_view::document::Mode;
use helix_view::events::{ use helix_view::events::{
DiagnosticsDidChange, DocumentDidChange, DocumentFocusLost, SelectionDidChange, DiagnosticsDidChange, DocumentDidChange, DocumentFocusLost, DocumentOpened, SelectionDidChange,
}; };
use crate::commands; use crate::commands;
@ -21,4 +21,5 @@ pub fn register() {
register_event::<DocumentFocusLost>(); register_event::<DocumentFocusLost>();
register_event::<SelectionDidChange>(); register_event::<SelectionDidChange>();
register_event::<DiagnosticsDidChange>(); register_event::<DiagnosticsDidChange>();
register_event::<DocumentOpened>();
} }

View File

@ -2,9 +2,10 @@ use crate::{
annotations::diagnostics::{DiagnosticFilter, InlineDiagnosticsConfig}, annotations::diagnostics::{DiagnosticFilter, InlineDiagnosticsConfig},
clipboard::ClipboardProvider, clipboard::ClipboardProvider,
document::{ document::{
DocumentOpenError, DocumentSavedEventFuture, DocumentSavedEventResult, Mode, SavePoint, DocumentOpenError, DocumentSavedEvent, DocumentSavedEventFuture, DocumentSavedEventResult,
Mode, SavePoint,
}, },
events::DocumentFocusLost, events::{DocumentClosed, DocumentFocusLost, DocumentOpened, DocumentSaved},
graphics::{CursorKind, Rect}, graphics::{CursorKind, Rect},
handlers::Handlers, handlers::Handlers,
info::Info, info::Info,
@ -1784,6 +1785,11 @@ impl Editor {
let id = self.new_document(doc); let id = self.new_document(doc);
self.launch_language_servers(id); self.launch_language_servers(id);
dispatch(DocumentOpened {
editor: self,
doc: id,
});
id id
}; };
@ -1874,6 +1880,11 @@ impl Editor {
self._refresh(); self._refresh();
dispatch(DocumentClosed {
editor: self,
doc: doc_id,
});
Ok(()) Ok(())
} }
@ -1911,6 +1922,11 @@ impl Editor {
self.write_count += 1; self.write_count += 1;
dispatch(DocumentSaved {
editor: self,
doc: doc_id,
});
Ok(()) Ok(())
} }

View File

@ -15,4 +15,7 @@ events! {
DiagnosticsDidChange<'a> { editor: &'a mut Editor, doc: DocumentId } DiagnosticsDidChange<'a> { editor: &'a mut Editor, doc: DocumentId }
// called **after** a document loses focus (but not when its closed) // called **after** a document loses focus (but not when its closed)
DocumentFocusLost<'a> { editor: &'a mut Editor, doc: DocumentId } DocumentFocusLost<'a> { editor: &'a mut Editor, doc: DocumentId }
DocumentOpened<'a> { editor: &'a mut Editor, doc: DocumentId }
DocumentClosed<'a> { editor: &'a mut Editor, doc: DocumentId }
DocumentSaved<'a> { editor: &'a mut Editor, doc: DocumentId }
} }