From 03bade90d2dfe4863c4dcb31224612894cb984fc Mon Sep 17 00:00:00 2001 From: Joseph Harrison-Lim Date: Sun, 13 Mar 2022 01:05:06 -0500 Subject: [PATCH] Add refresh-config and open-config command --- Cargo.lock | 2 + helix-term/Cargo.toml | 1 + helix-term/src/application.rs | 57 +++++++++++++++++++++---- helix-term/src/commands.rs | 26 ++++++------ helix-term/src/commands/typed.rs | 72 +++++++++++++++++++++++--------- helix-term/src/config.rs | 24 ++++++++++- helix-term/src/main.rs | 16 +------ helix-term/src/ui/editor.rs | 15 +++---- helix-term/src/ui/mod.rs | 5 ++- helix-view/Cargo.toml | 2 + helix-view/src/editor.rs | 30 ++++++++----- helix-view/src/gutter.rs | 2 +- 12 files changed, 173 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e9f9765a..d07fdeb72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -435,6 +435,7 @@ name = "helix-term" version = "0.6.0" dependencies = [ "anyhow", + "arc-swap", "chrono", "content_inspector", "crossterm", @@ -483,6 +484,7 @@ name = "helix-view" version = "0.6.0" dependencies = [ "anyhow", + "arc-swap", "bitflags", "chardetng", "clipboard-win", diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml index 48365743f..923934135 100644 --- a/helix-term/Cargo.toml +++ b/helix-term/Cargo.toml @@ -40,6 +40,7 @@ crossterm = { version = "0.23", features = ["event-stream"] } signal-hook = "0.3" tokio-stream = "0.1" futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false } +arc-swap = { version = "1.5.0" } # Logging fern = "0.6" diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 269ce13d1..5fa1f21a2 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -1,10 +1,11 @@ +use arc_swap::{access::Map, ArcSwap}; use helix_core::{ config::{default_syntax_loader, user_syntax_loader}, pos_at_coords, syntax, Selection, }; use helix_dap::{self as dap, Payload, Request}; use helix_lsp::{lsp, util::lsp_pos_to_pos, LspProgressMap}; -use helix_view::{editor::Breakpoint, theme, Editor}; +use helix_view::{editor::{Breakpoint, ConfigEvent}, theme, Editor}; use serde_json::json; use crate::{ @@ -42,8 +43,7 @@ pub struct Application { compositor: Compositor, editor: Editor, - // TODO: share an ArcSwap with Editor? - config: Config, + config: Arc>, #[allow(dead_code)] theme_loader: Arc, @@ -56,7 +56,7 @@ pub struct Application { } impl Application { - pub fn new(args: Args, mut config: Config) -> Result { + pub fn new(args: Args, config: Config) -> Result { use helix_view::editor::Action; let mut compositor = Compositor::new()?; let size = compositor.size(); @@ -98,14 +98,16 @@ impl Application { }); let syn_loader = std::sync::Arc::new(syntax::Loader::new(syn_loader_conf)); + let config = Arc::new(ArcSwap::from_pointee(config)); let mut editor = Editor::new( size, theme_loader.clone(), syn_loader.clone(), - config.editor.clone(), + ArcSwap::from_pointee(config.load().editor.clone()) + // config.clone(), ); - let editor_view = Box::new(ui::EditorView::new(std::mem::take(&mut config.keys))); + let editor_view = Box::new(ui::EditorView::new(std::mem::take(&mut config.load().keys.clone()))); compositor.push(editor_view); if args.load_tutor { @@ -121,7 +123,7 @@ impl Application { if first.is_dir() { std::env::set_current_dir(&first)?; editor.new_file(Action::VerticalSplit); - let picker = ui::file_picker(".".into(), &config.editor); + let picker = ui::file_picker(".".into(), &config.load().editor); compositor.push(Box::new(overlayed(picker))); } else { let nr_of_files = args.files.len(); @@ -228,6 +230,10 @@ impl Application { Some(payload) = self.editor.debugger_events.next() => { self.handle_debugger_message(payload).await; } + Some(ConfigEvent) = self.editor.config_events.next() => { + self.refresh_config(); + self.render(); + } Some(callback) = self.jobs.futures.next() => { self.jobs.handle_callback(&mut self.editor, &mut self.compositor, callback); self.render(); @@ -245,6 +251,39 @@ impl Application { } } + pub fn refresh_config(&mut self) { + let config = Config::load(helix_loader::config_file()).unwrap(); + // Just an example to start; Some config properties like "theme" are a bit more involved and require a reload + if let Some(theme) = config.theme.clone() { + let true_color = self.true_color(); + self.editor.set_theme( + self.theme_loader + .load(&theme) + .map_err(|e| { + log::warn!("failed to load theme `{}` - {}", theme, e); + e + }) + .ok() + .filter(|theme| (true_color || theme.is_16_color())) + .unwrap_or_else(|| { + if true_color { + self.theme_loader.default() + } else { + self.theme_loader.base16_default() + } + }) + .clone(), + ); + } + self.config.store(Arc::new(config)); + // Is it possible to not do this manually? Presumably I've completely butchered using ArcSwap? + self.editor.config.store(Arc::new(self.config.load().editor.clone())); + } + + fn true_color(&self) -> bool { + self.config.load().editor.true_color || crate::true_color() + } + #[cfg(windows)] // no signal handling available on windows pub async fn handle_signals(&mut self, _signal: ()) {} @@ -700,7 +739,7 @@ impl Application { self.lsp_progress.update(server_id, token, work); } - if self.config.lsp.display_messages { + if self.config.load().lsp.display_messages { self.editor.set_status(status); } } @@ -809,7 +848,7 @@ impl Application { terminal::enable_raw_mode()?; let mut stdout = stdout(); execute!(stdout, terminal::EnterAlternateScreen)?; - if self.config.editor.mouse { + if self.config.load().editor.mouse { execute!(stdout, EnableMouseCapture)?; } Ok(()) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b9401d40e..a9c3aaca5 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -848,7 +848,7 @@ fn goto_window(cx: &mut Context, align: Align) { // - 1 so we have at least one gap in the middle. // a height of 6 with padding of 3 on each side will keep shifting the view back and forth // as we type - let scrolloff = cx.editor.config.scrolloff.min(height.saturating_sub(1) / 2); + let scrolloff = cx.editor.config.load().scrolloff.min(height.saturating_sub(1) / 2); let last_line = view.last_line(doc); @@ -1290,7 +1290,7 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { let height = view.inner_area().height; - let scrolloff = cx.editor.config.scrolloff.min(height as usize / 2); + let scrolloff = cx.editor.config.load().scrolloff.min(height as usize / 2); view.offset.row = match direction { Forward => view.offset.row + offset, @@ -1583,8 +1583,8 @@ fn rsearch(cx: &mut Context) { fn searcher(cx: &mut Context, direction: Direction) { let reg = cx.register.unwrap_or('/'); - let scrolloff = cx.editor.config.scrolloff; - let wrap_around = cx.editor.config.search.wrap_around; + let scrolloff = cx.editor.config.load().scrolloff; + let wrap_around = cx.editor.config.load().search.wrap_around; let doc = doc!(cx.editor); @@ -1627,13 +1627,13 @@ fn searcher(cx: &mut Context, direction: Direction) { } fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Direction) { - let scrolloff = cx.editor.config.scrolloff; + let scrolloff = cx.editor.config.load().scrolloff; let (view, doc) = current!(cx.editor); let registers = &cx.editor.registers; if let Some(query) = registers.read('/') { let query = query.last().unwrap(); let contents = doc.text().slice(..).to_string(); - let search_config = &cx.editor.config.search; + let search_config = &cx.editor.config.load().search; let case_insensitive = if search_config.smart_case { !query.chars().any(char::is_uppercase) } else { @@ -1693,8 +1693,8 @@ fn search_selection(cx: &mut Context) { fn global_search(cx: &mut Context) { let (all_matches_sx, all_matches_rx) = tokio::sync::mpsc::unbounded_channel::<(usize, PathBuf)>(); - let smart_case = cx.editor.config.search.smart_case; - let file_picker_config = cx.editor.config.file_picker.clone(); + let smart_case = cx.editor.config.load().search.smart_case; + let file_picker_config = cx.editor.config.load().file_picker.clone(); let completions = search_completions(cx, None); let prompt = ui::regex_prompt( @@ -2023,7 +2023,7 @@ fn append_mode(cx: &mut Context) { fn file_picker(cx: &mut Context) { // We don't specify language markers, root will be the root of the current git repo let root = find_root(None, &[]).unwrap_or_else(|| PathBuf::from("./")); - let picker = ui::file_picker(root, &cx.editor.config); + let picker = ui::file_picker(root, &cx.editor.config.load()); cx.push_layer(Box::new(overlayed(picker))); } @@ -2573,7 +2573,7 @@ pub mod insert { use helix_core::chars::char_is_word; let mut iter = text.chars_at(cursor); iter.reverse(); - for _ in 0..cx.editor.config.completion_trigger_len { + for _ in 0..cx.editor.config.load().completion_trigger_len { match iter.next() { Some(c) if char_is_word(c) => {} _ => return, @@ -4136,7 +4136,7 @@ fn shell_keep_pipe(cx: &mut Context) { Some('|'), ui::completers::none, move |cx: &mut compositor::Context, input: &str, event: PromptEvent| { - let shell = &cx.editor.config.shell; + let shell = &cx.editor.config.load().shell; if event != PromptEvent::Validate { return; } @@ -4232,7 +4232,7 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) { Some('|'), ui::completers::none, move |cx: &mut compositor::Context, input: &str, event: PromptEvent| { - let shell = &cx.editor.config.shell; + let shell = &cx.editor.config.load().shell; if event != PromptEvent::Validate { return; } @@ -4277,7 +4277,7 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) { // after replace cursor may be out of bounds, do this to // make sure cursor is in view and update scroll as well - view.ensure_cursor_in_view(doc, cx.editor.config.scrolloff); + view.ensure_cursor_in_view(doc, cx.editor.config.load().scrolloff); }, ); diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 3301d1486..84fb3b750 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1,6 +1,8 @@ +use std::{borrow::BorrowMut, sync::Arc}; + use super::*; -use helix_view::editor::Action; +use helix_view::editor::{Action, ConfigEvent}; use ui::completers::{self, Completer}; #[derive(Clone)] @@ -533,7 +535,7 @@ fn theme( .theme_loader .load(theme) .with_context(|| format!("Failed setting theme {}", theme))?; - let true_color = cx.editor.config.true_color || crate::true_color(); + let true_color = cx.editor.config.load().true_color || crate::true_color(); if !(true_color || theme.is_16_color()) { bail!("Unsupported theme: theme requires true color support"); } @@ -857,28 +859,28 @@ fn setting( args: &[Cow], _event: PromptEvent, ) -> anyhow::Result<()> { - let runtime_config = &mut cx.editor.config; - if args.len() != 2 { anyhow::bail!("Bad arguments. Usage: `:set key field`"); } - let (key, arg) = (&args[0].to_lowercase(), &args[1]); - match key.as_ref() { - "scrolloff" => runtime_config.scrolloff = arg.parse()?, - "scroll-lines" => runtime_config.scroll_lines = arg.parse()?, - "mouse" => runtime_config.mouse = arg.parse()?, - "line-number" => runtime_config.line_number = arg.parse()?, - "middle-click_paste" => runtime_config.middle_click_paste = arg.parse()?, - "auto-pairs" => runtime_config.auto_pairs = arg.parse()?, - "auto-completion" => runtime_config.auto_completion = arg.parse()?, - "completion-trigger-len" => runtime_config.completion_trigger_len = arg.parse()?, - "auto-info" => runtime_config.auto_info = arg.parse()?, - "true-color" => runtime_config.true_color = arg.parse()?, - "search.smart-case" => runtime_config.search.smart_case = arg.parse()?, - "search.wrap-around" => runtime_config.search.wrap_around = arg.parse()?, - _ => anyhow::bail!("Unknown key `{}`.", args[0]), + if let Ok(runtime_config) = &mut std::sync::Arc::try_unwrap(cx.editor.config.load().clone()) { + match key.as_ref() { + "scrolloff" => runtime_config.scrolloff = arg.parse()?, + "scroll-lines" => runtime_config.scroll_lines = arg.parse()?, + "mouse" => runtime_config.mouse = arg.parse()?, + "line-number" => runtime_config.line_number = arg.parse()?, + "middle-click_paste" => runtime_config.middle_click_paste = arg.parse()?, + "auto-pairs" => runtime_config.auto_pairs = arg.parse()?, + "auto-completion" => runtime_config.auto_completion = arg.parse()?, + "completion-trigger-len" => runtime_config.completion_trigger_len = arg.parse()?, + "auto-info" => runtime_config.auto_info = arg.parse()?, + "true-color" => runtime_config.true_color = arg.parse()?, + "search.smart-case" => runtime_config.search.smart_case = arg.parse()?, + "search.wrap-around" => runtime_config.search.wrap_around = arg.parse()?, + _ => anyhow::bail!("Unknown key `{}`.", args[0]), + } + cx.editor.config.store(Arc::new(runtime_config.clone())); } Ok(()) @@ -970,6 +972,24 @@ fn tree_sitter_subtree( Ok(()) } +fn open_config( + cx: &mut compositor::Context, + _args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + cx.editor.open(helix_loader::config_file(), Action::Replace)?; + Ok(()) +} + +fn refresh_config( + cx: &mut compositor::Context, + _args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + cx.editor.config_events.push(tokio_stream::once(ConfigEvent)); + Ok(()) +} + pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "quit", @@ -1342,6 +1362,20 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: tree_sitter_subtree, completer: None, }, + TypableCommand { + name: "refresh-config", + aliases: &[], + doc: "Refreshes helix's config.", + fun: refresh_config, + completer: None, + }, + TypableCommand { + name: "open-config", + aliases: &[], + doc: "Open the helix config.toml file.", + fun: open_config, + completer: None, + }, ]; pub static TYPABLE_COMMAND_MAP: Lazy> = diff --git a/helix-term/src/config.rs b/helix-term/src/config.rs index 6b8bbc1b8..3d5560362 100644 --- a/helix-term/src/config.rs +++ b/helix-term/src/config.rs @@ -1,6 +1,7 @@ +use crate::keymap::{merge_keys, Keymaps}; +use anyhow::{Error, Result}; use serde::Deserialize; - -use crate::keymap::Keymaps; +use std::path::PathBuf; #[derive(Debug, Default, Clone, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] @@ -20,6 +21,25 @@ pub struct LspConfig { pub display_messages: bool, } +impl Config { + pub fn load(config_path: PathBuf) -> Result { + match std::fs::read_to_string(config_path) { + Ok(config) => Result::Ok(toml::from_str(&config) + .map(merge_keys) + .unwrap_or_else(|err| { + eprintln!("Bad config: {}", err); + eprintln!("Press to continue with default config"); + use std::io::Read; + // This waits for an enter press. + let _ = std::io::stdin().read(&mut []); + Config::default() + })), + Err(err) if err.kind() == std::io::ErrorKind::NotFound => Result::Ok(Config::default()), + Err(err) => return Err(Error::new(err)), + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index e554a21b9..ca8bca72e 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -2,7 +2,6 @@ use anyhow::{Context, Error, Result}; use helix_term::application::Application; use helix_term::args::Args; use helix_term::config::Config; -use helix_term::keymap::merge_keys; use std::path::PathBuf; fn setup_logging(logpath: PathBuf, verbosity: u64) -> Result<()> { @@ -118,20 +117,7 @@ FLAGS: std::fs::create_dir_all(&conf_dir).ok(); } - let config = match std::fs::read_to_string(helix_loader::config_file()) { - Ok(config) => toml::from_str(&config) - .map(merge_keys) - .unwrap_or_else(|err| { - eprintln!("Bad config: {}", err); - eprintln!("Press to continue with default config"); - use std::io::Read; - // This waits for an enter press. - let _ = std::io::stdin().read(&mut []); - Config::default() - }), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Config::default(), - Err(err) => return Err(Error::new(err)), - }; + let config = Config::load(helix_loader::config_file())?; setup_logging(logpath, args.verbosity).context("failed to initialize logging")?; diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 31a9bfc86..d8d105960 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -118,7 +118,7 @@ impl EditorView { let highlights: Box> = if is_focused { Box::new(syntax::merge( highlights, - Self::doc_selection_highlights(doc, view, theme, &editor.config.cursor_shape), + Self::doc_selection_highlights(doc, view, theme, &editor.config.load().cursor_shape), )) } else { Box::new(highlights) @@ -846,7 +846,7 @@ impl EditorView { pub fn handle_idle_timeout(&mut self, cx: &mut crate::compositor::Context) -> EventResult { if self.completion.is_some() - || !cx.editor.config.auto_completion + || !cx.editor.config.load().auto_completion || doc!(cx.editor).mode != Mode::Insert { return EventResult::Ignored(None); @@ -872,6 +872,7 @@ impl EditorView { event: MouseEvent, cxt: &mut commands::Context, ) -> EventResult { + let config = cxt.editor.config.load(); match event { MouseEvent { kind: MouseEventKind::Down(MouseButton::Left), @@ -972,7 +973,7 @@ impl EditorView { None => return EventResult::Ignored(None), } - let offset = cxt.editor.config.scroll_lines.abs() as usize; + let offset = config.scroll_lines.abs() as usize; commands::scroll(cxt, offset, direction); cxt.editor.tree.focus = current_view; @@ -984,7 +985,7 @@ impl EditorView { kind: MouseEventKind::Up(MouseButton::Left), .. } => { - if !cxt.editor.config.middle_click_paste { + if !config.middle_click_paste { return EventResult::Ignored(None); } @@ -1040,7 +1041,7 @@ impl EditorView { .. } => { let editor = &mut cxt.editor; - if !editor.config.middle_click_paste { + if !config.middle_click_paste { return EventResult::Ignored(None); } @@ -1166,7 +1167,7 @@ impl Component for EditorView { } let (view, doc) = current!(cx.editor); - view.ensure_cursor_in_view(doc, cx.editor.config.scrolloff); + view.ensure_cursor_in_view(doc, cx.editor.config.load().scrolloff); // Store a history state if not in insert mode. This also takes care of // commiting changes when leaving insert mode. @@ -1217,7 +1218,7 @@ impl Component for EditorView { self.render_view(cx.editor, doc, view, area, surface, is_focused); } - if cx.editor.config.auto_info { + if cx.editor.config.load().auto_info { if let Some(mut info) = cx.editor.autoinfo.take() { info.render(area, surface, cx); cx.editor.autoinfo = Some(info) diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 2273477ff..bf687c188 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -37,6 +37,7 @@ pub fn regex_prompt( let doc_id = view.doc; let snapshot = doc.selection(view.id).clone(); let offset_snapshot = view.offset; + let config = cx.editor.config.load(); let mut prompt = Prompt::new( prompt, @@ -65,7 +66,7 @@ pub fn regex_prompt( return; } - let case_insensitive = if cx.editor.config.search.smart_case { + let case_insensitive = if config.search.smart_case { !input.chars().any(char::is_uppercase) } else { false @@ -84,7 +85,7 @@ pub fn regex_prompt( fun(view, doc, regex, event); - view.ensure_cursor_in_view(doc, cx.editor.config.scrolloff); + view.ensure_cursor_in_view(doc, config.scrolloff); } Err(_err) => (), // TODO: mark command line as error } diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index a4fa256d7..2616072ec 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -25,6 +25,8 @@ crossterm = { version = "0.23", optional = true } once_cell = "1.10" url = "2" +arc-swap = { version = "1.5.0" } + tokio = { version = "1", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot"] } tokio-stream = "0.1" futures-util = { version = "0.3", features = ["std", "async-await"], default-features = false } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 0eb613087..07d6c505e 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -13,7 +13,6 @@ use futures_util::future; use futures_util::stream::select_all::SelectAll; use tokio_stream::wrappers::UnboundedReceiverStream; -use log::debug; use std::{ borrow::Cow, collections::{BTreeMap, HashMap}, @@ -40,6 +39,8 @@ use helix_dap as dap; use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize}; +use arc_swap::{access::{DynAccess}, ArcSwap}; + fn deserialize_duration_millis<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -271,6 +272,8 @@ pub struct Breakpoint { pub log_message: Option, } +pub trait DynAccessDebug: DynAccess + std::fmt::Debug {} + #[derive(Debug)] pub struct Editor { pub tree: Tree, @@ -295,7 +298,7 @@ pub struct Editor { pub status_msg: Option<(Cow<'static, str>, Severity)>, pub autoinfo: Option, - pub config: Config, + pub config: ArcSwap, pub auto_pairs: Option, pub idle_timer: Pin>, @@ -305,8 +308,13 @@ pub struct Editor { pub last_completion: Option, pub exit_code: i32, + + pub config_events: SelectAll>, } +#[derive(Debug)] +pub struct ConfigEvent; + #[derive(Debug, Clone)] pub struct CompleteAction { pub trigger_offset: usize, @@ -326,12 +334,11 @@ impl Editor { mut area: Rect, theme_loader: Arc, syn_loader: Arc, - config: Config, + config: ArcSwap, ) -> Self { let language_servers = helix_lsp::Registry::new(); - let auto_pairs = (&config.auto_pairs).into(); - - debug!("Editor config: {config:#?}"); + let conf = config.load(); + let auto_pairs = (&conf.auto_pairs).into(); // HAXX: offset the render area height by 1 to account for prompt/commandline area.height -= 1; @@ -354,13 +361,14 @@ impl Editor { clipboard_provider: get_clipboard_provider(), status_msg: None, autoinfo: None, - idle_timer: Box::pin(sleep(config.idle_timeout)), + idle_timer: Box::pin(sleep(conf.idle_timeout)), last_motion: None, last_completion: None, pseudo_pending: None, config, auto_pairs, exit_code: 0, + config_events: SelectAll::new(), } } @@ -374,7 +382,7 @@ impl Editor { pub fn reset_idle_timer(&mut self) { self.idle_timer .as_mut() - .reset(Instant::now() + self.config.idle_timeout); + .reset(Instant::now() + self.config.load().idle_timeout); } pub fn clear_status(&mut self) { @@ -452,7 +460,7 @@ impl Editor { fn _refresh(&mut self) { for (view, _) in self.tree.views_mut() { let doc = &self.documents[&view.doc]; - view.ensure_cursor_in_view(doc, self.config.scrolloff) + view.ensure_cursor_in_view(doc, self.config.load().scrolloff) } } @@ -702,7 +710,7 @@ impl Editor { pub fn ensure_cursor_in_view(&mut self, id: ViewId) { let view = self.tree.get_mut(id); let doc = &self.documents[&view.doc]; - view.ensure_cursor_in_view(doc, self.config.scrolloff) + view.ensure_cursor_in_view(doc, self.config.load().scrolloff) } #[inline] @@ -745,7 +753,7 @@ impl Editor { let inner = view.inner_area(); pos.col += inner.x as usize; pos.row += inner.y as usize; - let cursorkind = self.config.cursor_shape.from_mode(doc.mode()); + let cursorkind = self.config.load().cursor_shape.from_mode(doc.mode()); (Some(pos), cursorkind) } else { (None, CursorKind::default()) diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 6a77c41fc..6d2b0d2ba 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -60,7 +60,7 @@ pub fn line_number<'doc>( .text() .char_to_line(doc.selection(view.id).primary().cursor(text)); - let config = editor.config.line_number; + let config = editor.config.load().line_number; let mode = doc.mode; Box::new(move |line: usize, selected: bool, out: &mut String| {