address most of the comments

pull/8675/merge^2
Matt Paras 2025-07-17 21:37:02 -07:00
parent bafe5bdb0e
commit 81e8ba82e4
12 changed files with 67 additions and 79 deletions

View File

@ -18,8 +18,8 @@ tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "p
# the event registry is essentially read only but must be an rwlock so we can
# setup new events on intalization, hardware-lock-elision hugnly benefits this case
# as is essentially makes the lock entirely free as long as there is no writes
once_cell = "1.21"
parking_lot = { workspace = true, features = ["hardware-lock-elision"] }
once_cell = "1.21"
anyhow = "1"
log = "0.4"

View File

@ -95,7 +95,6 @@ grep-searcher = "0.1.14"
# plugin support
steel-core = { workspace = true, optional = true }
steel-doc = { git = "https://github.com/mattwparas/steel.git", version = "0.7.0" }
# steel-doc = { path = "/home/matt/code/scratch/steel/crates/steel-doc", version = "0.6.0" }
globset = "0.4.16"

View File

@ -15,9 +15,6 @@ pub use lsp::*;
pub use engine::ScriptingEngine;
#[cfg(feature = "steel")]
pub use engine::steel::{helix_module_file, steel_init_file};
use tui::{
text::{Span, Spans},
widgets::Cell,
@ -252,7 +249,6 @@ impl MappableCommand {
pub fn execute(&self, cx: &mut Context) {
match &self {
Self::Typable { name, args, doc: _ } => {
// TODO: Swap the order to allow overriding the existing commands?
if let Some(command) = typed::TYPABLE_COMMAND_MAP.get(name.as_str()) {
let mut cx = compositor::Context {
editor: cx.editor,
@ -265,7 +261,6 @@ impl MappableCommand {
cx.editor.set_error(format!("{}", e));
}
} else {
// TODO: Update this
let args = args.split_whitespace().map(Cow::from).collect();
if !ScriptingEngine::call_function_by_name(cx, name, args) {
cx.editor.set_error(format!("no such command: '{name}'"));
@ -3162,11 +3157,9 @@ fn file_explorer_in_current_directory(cx: &mut Context) {
fn buffer_picker(cx: &mut Context) {
let current = view!(cx.editor).doc;
#[allow(unused)]
struct BufferMeta {
id: DocumentId,
path: Option<PathBuf>,
name: Option<String>,
is_modified: bool,
is_current: bool,
focused_at: std::time::Instant,
@ -3175,7 +3168,6 @@ fn buffer_picker(cx: &mut Context) {
let new_meta = |doc: &Document| BufferMeta {
id: doc.id(),
path: doc.path().cloned(),
name: doc.name.clone(),
is_modified: doc.is_modified(),
is_current: doc.id() == current,
focused_at: doc.focused_at,
@ -4171,18 +4163,6 @@ pub mod insert {
helix_event::dispatch(PostInsertChar { c, cx });
}
pub fn insert_string(cx: &mut Context, string: String) {
let (view, doc) = current!(cx.editor);
let indent = Tendril::from(string);
let transaction = Transaction::insert(
doc.text(),
&doc.selection(view.id).clone().cursors(doc.text().slice(..)),
indent,
);
doc.apply(&transaction, view.id);
}
pub fn smart_tab(cx: &mut Context) {
let (view, doc) = current_ref!(cx.editor);
let view_id = view.id;

View File

@ -5,13 +5,15 @@ use helix_core::{
diagnostic::Severity,
extensions::steel_implementations::{rope_module, SteelRopeSlice},
find_workspace, graphemes,
syntax::config::{
default_timeout, AutoPairConfig, LanguageConfiguration, LanguageServerConfiguration,
SoftWrap,
syntax::{
self,
config::{
default_timeout, AutoPairConfig, LanguageConfiguration, LanguageServerConfiguration,
SoftWrap,
},
},
syntax::{self},
text_annotations::InlineAnnotation,
Range, Selection, Tendril,
Range, Selection, Tendril, Transaction,
};
use helix_event::register_hook;
use helix_view::{
@ -71,7 +73,7 @@ use super::{
components::{self, helix_component_module},
Context, MappableCommand, TYPABLE_COMMAND_LIST,
};
use insert::{insert_char, insert_string};
use insert::insert_char;
pub static INTERRUPT_HANDLER: OnceCell<InterruptHandler> = OnceCell::new();
@ -1586,9 +1588,8 @@ fn theme_from_json_string(name: String, value: SteelVal) -> Result<SteelTheme, a
// Mutate the theme?
fn add_theme(cx: &mut Context, theme: SteelTheme) {
cx.editor
.user_defined_themes
.insert(theme.0.name().to_owned(), theme.0);
Arc::make_mut(&mut cx.editor.theme_loader)
.add_dynamic_theme(theme.0.name().to_owned(), theme.0);
}
fn get_style(theme: &SteelTheme, name: SteelString) -> helix_view::theme::Style {
@ -1726,7 +1727,10 @@ Get the `Rect` associated with the currently focused buffer.
);
register_0!(
"selected-register!",
|cx: &mut Context| cx.editor.selected_register.unwrap_or(cx.editor.config().default_yank_register),
|cx: &mut Context| cx
.editor
.selected_register
.unwrap_or(cx.editor.config().default_yank_register),
r#"Get currently selected register"#
);
@ -5312,3 +5316,15 @@ pub fn remove_inlay_hint(cx: &mut Context, char_index: usize, _completion: Steel
doc.set_inlay_hints(view_id, new_inlay_hints);
true
}
pub fn insert_string(cx: &mut Context, string: SteelString) {
let (view, doc) = current!(cx.editor);
let indent = Tendril::from(string.as_str());
let transaction = Transaction::insert(
doc.text(),
&doc.selection(view.id).clone().cursors(doc.text().slice(..)),
indent,
);
doc.apply(&transaction, view.id);
}

View File

@ -1000,20 +1000,7 @@ fn theme(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow
// Ensures that a preview theme gets cleaned up if the user backspaces until the prompt is empty.
cx.editor.unset_theme_preview();
} else if let Some(theme_name) = args.first() {
// if let Ok(theme) = cx.editor.theme_loader.load(theme_name) {
// if !(true_color || theme.is_16_color()) {
// bail!("Unsupported theme: theme requires true color support");
// }
// cx.editor.set_theme_preview(theme);
// };
if let Ok(theme) = cx.editor.theme_loader.load(theme_name).or_else(|_| {
cx.editor
.user_defined_themes
.get(theme_name)
.ok_or_else(|| anyhow::anyhow!("Could not load theme"))
.cloned()
}) {
if let Ok(theme) = cx.editor.theme_loader.load(theme_name) {
if !(true_color || theme.is_16_color()) {
bail!("Unsupported theme: theme requires true color support");
}
@ -1023,19 +1010,12 @@ fn theme(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow
}
PromptEvent::Validate => {
if let Some(theme_name) = args.first() {
let theme = cx.editor.theme_loader.load(theme_name).or_else(|_| {
cx.editor
.user_defined_themes
.get(theme_name)
.ok_or_else(|| anyhow::anyhow!("Could not load theme"))
.cloned()
})?;
let theme = cx
.editor
.theme_loader
.load(theme_name)
.map_err(|err| anyhow::anyhow!("could not load theme: {}", err))?;
// let theme = cx
// .editor
// .theme_loader
// .load(theme_name)
// .map_err(|err| anyhow::anyhow!("Could not load theme: {}", err))?;
if !(true_color || theme.is_16_color()) {
bail!("Unsupported theme: theme requires true color support");
}

View File

@ -3,9 +3,17 @@ mod steel_implementations {
use crate::{
compositor::Component,
ui::{Popup, Text},
ui::{overlay::Overlay, Popup, Prompt, Text},
};
impl steel::rvals::Custom for Text {}
impl<T: steel::rvals::IntoSteelVal + Component> steel::rvals::Custom for Popup<T> {}
// TODO: For this to be sound, all of the various functions
// have to now be marked as send + sync + 'static. Annoying,
// and something I'll look into with steel.
unsafe impl<T> Send for Overlay<T> {}
unsafe impl<T> Sync for Overlay<T> {}
unsafe impl Send for Prompt {}
unsafe impl Sync for Prompt {}
}

View File

@ -412,7 +412,7 @@ pub mod completers {
names.push("base16_default".into());
// Include any user defined themes as well
names.extend(editor.user_defined_themes.keys().map(|x| x.into()));
names.extend(editor.theme_loader.dynamic_themes().map(|x| x.into()));
names.sort();
names.dedup();

View File

@ -15,12 +15,6 @@ pub struct Overlay<T> {
pub calc_child_size: Box<dyn Fn(Rect) -> Rect>,
}
// TODO: For this to be sound, all of the various functions
// have to now be marked as send + sync + 'static. Annoying,
// and something I'll look into with steel.
unsafe impl<T> Send for Overlay<T> {}
unsafe impl<T> Sync for Overlay<T> {}
/// Surrounds the component with a margin of 5% on each side, and an additional 2 rows at the bottom
pub fn overlaid<T>(content: T) -> Overlay<T> {
Overlay {

View File

@ -49,12 +49,6 @@ pub struct Prompt {
language: Option<(&'static str, Arc<ArcSwap<syntax::Loader>>)>,
}
// TODO: For this to be sound, all of the various functions
// have to now be marked as send + sync + 'static. Annoying,
// and something I'll look into with steel.
unsafe impl Send for Prompt {}
unsafe impl Sync for Prompt {}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum PromptEvent {
/// The prompt input has been updated.

View File

@ -1142,7 +1142,6 @@ pub struct Editor {
pub cursor_cache: CursorCache,
pub editor_clipping: ClippingConfiguration,
pub user_defined_themes: HashMap<String, Theme>,
}
#[derive(Default)]
@ -1274,7 +1273,6 @@ impl Editor {
mouse_down_range: None,
cursor_cache: CursorCache::default(),
editor_clipping: ClippingConfiguration::default(),
user_defined_themes: Default::default(),
}
}

View File

@ -39,6 +39,9 @@ pub static BASE16_DEFAULT_THEME: Lazy<Theme> = Lazy::new(|| Theme {
pub struct Loader {
/// Theme directories to search from highest to lowest priority
theme_dirs: Vec<PathBuf>,
/// Themes which are dynamically created at runtime
dynamic_themes: HashMap<String, Theme>,
}
impl Loader {
/// Creates a new loader that can load themes from multiple directories.
@ -48,18 +51,34 @@ impl Loader {
pub fn new(dirs: &[PathBuf]) -> Self {
Self {
theme_dirs: dirs.iter().map(|p| p.join("themes")).collect(),
dynamic_themes: HashMap::new(),
}
}
pub fn dynamic_themes(&self) -> impl Iterator<Item = &String> {
self.dynamic_themes.keys()
}
/// Loads a theme searching directories in priority order.
pub fn load(&self, name: &str) -> Result<Theme> {
let (theme, warnings) = self.load_with_warnings(name)?;
match self.load_with_warnings(name) {
Ok((theme, warnings)) => {
for warning in warnings {
warn!("Theme '{}': {}", name, warning);
}
for warning in warnings {
warn!("Theme '{}': {}", name, warning);
Ok(theme)
}
Err(_) => self
.dynamic_themes
.get(name)
.ok_or_else(|| anyhow::anyhow!("Could not load theme: {}", name))
.cloned(),
}
}
Ok(theme)
pub fn add_dynamic_theme(&mut self, name: String, theme: Theme) {
self.dynamic_themes.insert(name, theme);
}
/// Loads a theme searching directories in priority order, returning any warnings

View File

@ -145,7 +145,7 @@ pub mod tasks {
Usage: Run with `cargo xtask <task>`, eg. `cargo xtask docgen`.
Tasks:
steel: Install steel
steel Install steel
docgen Generate files to be included in the mdbook output.
query-check [languages] Check that tree-sitter queries are valid for the given
languages, or all languages if none are specified.