From 5c2b77b41fadd0e65e02455d36d8509f622bc520 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Thu, 1 Sep 2022 16:14:38 +0900 Subject: Make mode editor-wide rather than per-document --- helix-term/src/commands.rs | 68 +++++++++++++++++++---------------------- helix-term/src/ui/editor.rs | 32 +++++++++---------- helix-term/src/ui/statusline.rs | 4 +-- helix-view/src/document.rs | 9 ------ helix-view/src/editor.rs | 16 +++++++--- helix-view/src/gutter.rs | 2 +- 6 files changed, 62 insertions(+), 69 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index cd92c42d..906f201a 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -586,7 +586,7 @@ fn goto_line_end(cx: &mut Context) { goto_line_end_impl( view, doc, - if doc.mode == Mode::Select { + if cx.editor.mode == Mode::Select { Movement::Extend } else { Movement::Move @@ -616,7 +616,7 @@ fn goto_line_end_newline(cx: &mut Context) { goto_line_end_newline_impl( view, doc, - if doc.mode == Mode::Select { + if cx.editor.mode == Mode::Select { Movement::Extend } else { Movement::Move @@ -647,7 +647,7 @@ fn goto_line_start(cx: &mut Context) { goto_line_start_impl( view, doc, - if doc.mode == Mode::Select { + if cx.editor.mode == Mode::Select { Movement::Extend } else { Movement::Move @@ -752,7 +752,7 @@ fn goto_first_nonwhitespace(cx: &mut Context) { if let Some(pos) = find_first_non_whitespace_char(text.line(line)) { let pos = pos + text.line_to_char(line); - range.put_cursor(text, pos, doc.mode == Mode::Select) + range.put_cursor(text, pos, cx.editor.mode == Mode::Select) } else { range } @@ -952,7 +952,7 @@ where let motion = move |editor: &mut Editor| { let (view, doc) = current!(editor); let text = doc.text().slice(..); - let behavior = if doc.mode == Mode::Select { + let behavior = if editor.mode == Mode::Select { Movement::Extend } else { Movement::Move @@ -985,7 +985,7 @@ fn goto_file_start(cx: &mut Context) { let selection = doc .selection(view.id) .clone() - .transform(|range| range.put_cursor(text, 0, doc.mode == Mode::Select)); + .transform(|range| range.put_cursor(text, 0, cx.editor.mode == Mode::Select)); push_jump(view, doc); doc.set_selection(view.id, selection); } @@ -998,7 +998,7 @@ fn goto_file_end(cx: &mut Context) { let selection = doc .selection(view.id) .clone() - .transform(|range| range.put_cursor(text, pos, doc.mode == Mode::Select)); + .transform(|range| range.put_cursor(text, pos, cx.editor.mode == Mode::Select)); push_jump(view, doc); doc.set_selection(view.id, selection); } @@ -1375,7 +1375,7 @@ pub fn scroll(cx: &mut Context, offset: usize, direction: Direction) { if line != cursor.row { let head = pos_at_coords(text, Position::new(line, cursor.col), true); // this func will properly truncate to line end - let anchor = if doc.mode == Mode::Select { + let anchor = if cx.editor.mode == Mode::Select { range.anchor } else { head @@ -2098,7 +2098,7 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { exit_select_mode(cx); } Operation::Change => { - enter_insert_mode(doc); + enter_insert_mode(cx); } } } @@ -2167,14 +2167,14 @@ fn ensure_selections_forward(cx: &mut Context) { doc.set_selection(view.id, selection); } -fn enter_insert_mode(doc: &mut Document) { - doc.mode = Mode::Insert; +fn enter_insert_mode(cx: &mut Context) { + cx.editor.mode = Mode::Insert; } // inserts at the start of each selection fn insert_mode(cx: &mut Context) { + enter_insert_mode(cx); let (view, doc) = current!(cx.editor); - enter_insert_mode(doc); log::trace!( "entering insert mode with sel: {:?}, text: {:?}", @@ -2192,8 +2192,8 @@ fn insert_mode(cx: &mut Context) { // inserts at the end of each selection fn append_mode(cx: &mut Context) { + enter_insert_mode(cx); let (view, doc) = current!(cx.editor); - enter_insert_mode(doc); doc.restore_cursor = true; let text = doc.text().slice(..); @@ -2421,9 +2421,9 @@ impl ui::menu::Item for MappableCommand { pub fn command_palette(cx: &mut Context) { cx.callback = Some(Box::new( move |compositor: &mut Compositor, cx: &mut compositor::Context| { - let doc = doc_mut!(cx.editor); - let keymap = - compositor.find::().unwrap().keymaps.map()[&doc.mode].reverse_map(); + let keymap = compositor.find::().unwrap().keymaps.map() + [&cx.editor.mode] + .reverse_map(); let mut commands: Vec = MappableCommand::STATIC_COMMAND_LIST.into(); commands.extend(typed::TYPABLE_COMMAND_LIST.iter().map(|cmd| { @@ -2464,14 +2464,13 @@ fn last_picker(cx: &mut Context) { // I inserts at the first nonwhitespace character of each line with a selection fn prepend_to_line(cx: &mut Context) { goto_first_nonwhitespace(cx); - let doc = doc_mut!(cx.editor); - enter_insert_mode(doc); + enter_insert_mode(cx); } // A inserts at the end of each line with a selection fn append_to_line(cx: &mut Context) { + enter_insert_mode(cx); let (view, doc) = current!(cx.editor); - enter_insert_mode(doc); let selection = doc.selection(view.id).clone().transform(|range| { let text = doc.text().slice(..); @@ -2527,8 +2526,8 @@ pub enum Open { fn open(cx: &mut Context, open: Open) { let count = cx.count(); + enter_insert_mode(cx); let (view, doc) = current!(cx.editor); - enter_insert_mode(doc); let text = doc.text().slice(..); let contents = doc.text(); @@ -2606,13 +2605,12 @@ fn open_above(cx: &mut Context) { } fn normal_mode(cx: &mut Context) { - let (view, doc) = current!(cx.editor); - - if doc.mode == Mode::Normal { + if cx.editor.mode == Mode::Normal { return; } - doc.mode = Mode::Normal; + cx.editor.mode = Mode::Normal; + let (view, doc) = current!(cx.editor); try_restore_indent(doc, view.id); @@ -2690,7 +2688,7 @@ fn goto_line_impl(editor: &mut Editor, count: Option) { let selection = doc .selection(view.id) .clone() - .transform(|range| range.put_cursor(text, pos, doc.mode == Mode::Select)); + .transform(|range| range.put_cursor(text, pos, editor.mode == Mode::Select)); push_jump(view, doc); doc.set_selection(view.id, selection); @@ -2710,7 +2708,7 @@ fn goto_last_line(cx: &mut Context) { let selection = doc .selection(view.id) .clone() - .transform(|range| range.put_cursor(text, pos, doc.mode == Mode::Select)); + .transform(|range| range.put_cursor(text, pos, cx.editor.mode == Mode::Select)); push_jump(view, doc); doc.set_selection(view.id, selection); @@ -2733,7 +2731,7 @@ fn goto_last_modification(cx: &mut Context) { let selection = doc .selection(view.id) .clone() - .transform(|range| range.put_cursor(text, pos, doc.mode == Mode::Select)); + .transform(|range| range.put_cursor(text, pos, cx.editor.mode == Mode::Select)); doc.set_selection(view.id, selection); } } @@ -2770,13 +2768,12 @@ fn select_mode(cx: &mut Context) { }); doc.set_selection(view.id, selection); - doc_mut!(cx.editor).mode = Mode::Select; + cx.editor.mode = Mode::Select; } fn exit_select_mode(cx: &mut Context) { - let doc = doc_mut!(cx.editor); - if doc.mode == Mode::Select { - doc.mode = Mode::Normal; + if cx.editor.mode == Mode::Select { + cx.editor.mode = Mode::Normal; } } @@ -3439,11 +3436,11 @@ fn paste_impl(values: &[String], doc: &mut Document, view: &View, action: Paste, pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) { let count = cx.count(); - let (view, doc) = current!(cx.editor); - let paste = match doc.mode { + let paste = match cx.editor.mode { Mode::Insert | Mode::Select => Paste::Cursor, Mode::Normal => Paste::Before, }; + let (view, doc) = current!(cx.editor); paste_impl(&[contents], doc, view, paste, count); } @@ -3838,8 +3835,7 @@ pub fn completion(cx: &mut Context) { cx.callback( future, move |editor, compositor, response: Option| { - let doc = doc!(editor); - if doc.mode() != Mode::Insert { + if editor.mode != Mode::Insert { // we're not in insert mode anymore return; } @@ -4046,7 +4042,7 @@ fn match_brackets(cx: &mut Context) { if let Some(pos) = match_brackets::find_matching_bracket_fuzzy(syntax, doc.text(), range.cursor(text)) { - range.put_cursor(text, pos, doc.mode == Mode::Select) + range.put_cursor(text, pos, cx.editor.mode == Mode::Select) } else { range } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index f4e2d13e..539e164c 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -122,7 +122,13 @@ 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( + editor.mode(), + doc, + view, + theme, + &editor.config().cursor_shape, + ), )) } else { Box::new(highlights) @@ -297,6 +303,7 @@ impl EditorView { /// Get highlight spans for selections in a document view. pub fn doc_selection_highlights( + mode: Mode, doc: &Document, view: &View, theme: &Theme, @@ -306,7 +313,6 @@ impl EditorView { let selection = doc.selection(view.id); let primary_idx = selection.primary_index(); - let mode = doc.mode(); let cursorkind = cursor_shape_config.from_mode(mode); let cursor_is_block = cursorkind == CursorKind::Block; @@ -775,17 +781,9 @@ impl EditorView { let key_result = self.keymaps.get(mode, event); cxt.editor.autoinfo = self.keymaps.sticky().map(|node| node.infobox()); - // Track the currently open doc - let view = view!(cxt.editor); - let doc_id = view.doc; - let mut execute_command = |command: &commands::MappableCommand| { command.execute(cxt); - let doc = match cxt.editor.documents.get(&doc_id) { - Some(doc) => doc, - None => return, - }; - let current_mode = doc.mode(); + let current_mode = cxt.editor.mode(); match (last_mode, current_mode) { (Mode::Normal, Mode::Insert) => { // HAXX: if we just entered insert mode from normal, clear key buf @@ -956,8 +954,8 @@ impl EditorView { pub fn handle_idle_timeout(&mut self, cx: &mut crate::compositor::Context) -> EventResult { if self.completion.is_some() + || cx.editor.mode != Mode::Insert || !cx.editor.config().auto_completion - || doc!(cx.editor).mode != Mode::Insert { return EventResult::Ignored(None); } @@ -1177,12 +1175,13 @@ impl Component for EditorView { cx.editor.count = None; let config = cx.editor.config(); + let mode = cx.editor.mode(); let (view, doc) = current!(cx.editor); view.ensure_cursor_in_view(doc, config.scrolloff); // Store a history state if not in insert mode. Otherwise wait till we exit insert // to include any edits to the paste in the history state. - if doc.mode() != Mode::Insert { + if mode != Mode::Insert { doc.append_changes_to_history(view.id); } @@ -1200,9 +1199,9 @@ impl Component for EditorView { // clear status cx.editor.status_msg = None; - let (view, doc) = current!(cx.editor); + let mode = cx.editor.mode(); + let (view, _) = current!(cx.editor); let focus = view.id; - let mode = doc.mode(); if let Some(on_next_key) = self.on_next_key.take() { // if there's a command waiting input, do that first @@ -1265,6 +1264,7 @@ impl Component for EditorView { return EventResult::Ignored(None); } let config = cx.editor.config(); + let mode = cx.editor.mode(); let view = cx.editor.tree.get_mut(focus); let doc = cx.editor.documents.get_mut(&view.doc).unwrap(); @@ -1272,7 +1272,7 @@ impl Component for EditorView { // Store a history state if not in insert mode. This also takes care of // committing changes when leaving insert mode. - if doc.mode() != Mode::Insert { + if mode != Mode::Insert { doc.append_changes_to_history(view.id); } diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs index b2836f50..365e1ca9 100644 --- a/helix-term/src/ui/statusline.rs +++ b/helix-term/src/ui/statusline.rs @@ -160,7 +160,7 @@ where format!( " {} ", if visible { - match context.doc.mode() { + match context.editor.mode() { Mode::Insert => "INS", Mode::Select => "SEL", Mode::Normal => "NOR", @@ -171,7 +171,7 @@ where } ), if visible && context.editor.config().color_modes { - match context.doc.mode() { + match context.editor.mode() { Mode::Insert => Some(context.editor.theme.get("ui.statusline.insert")), Mode::Select => Some(context.editor.theme.get("ui.statusline.select")), Mode::Normal => Some(context.editor.theme.get("ui.statusline.normal")), diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index b2a66415..3c406f8b 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -90,8 +90,6 @@ pub struct Document { path: Option, encoding: &'static encoding::Encoding, - /// Current editing mode. - pub mode: Mode, pub restore_cursor: bool, /// Current indent style. @@ -133,7 +131,6 @@ impl fmt::Debug for Document { .field("selections", &self.selections) .field("path", &self.path) .field("encoding", &self.encoding) - .field("mode", &self.mode) .field("restore_cursor", &self.restore_cursor) .field("syntax", &self.syntax) .field("language", &self.language) @@ -349,7 +346,6 @@ impl Document { selections: HashMap::default(), indent_style: DEFAULT_INDENT, line_ending: DEFAULT_LINE_ENDING, - mode: Mode::Normal, restore_cursor: false, syntax: None, language: None, @@ -925,11 +921,6 @@ impl Document { self.last_saved_revision = current_revision; } - /// Current editing mode for the [`Document`]. - pub fn mode(&self) -> Mode { - self.mode - } - /// Corresponding language scope name. Usually `source.`. pub fn language_scope(&self) -> Option<&str> { self.language diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 0bf7ebd0..ed1813b3 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -595,6 +595,8 @@ pub struct Breakpoint { } pub struct Editor { + /// Current editing mode. + pub mode: Mode, pub tree: Tree, pub next_document_id: DocumentId, pub documents: BTreeMap, @@ -677,6 +679,7 @@ impl Editor { area.height -= 1; Self { + mode: Mode::Normal, tree: Tree::new(area), next_document_id: DocumentId::default(), documents: BTreeMap::new(), @@ -708,6 +711,11 @@ impl Editor { } } + /// Current editing mode for the [`Editor`]. + pub fn mode(&self) -> Mode { + self.mode + } + pub fn config(&self) -> DynGuard { self.config.load() } @@ -1103,8 +1111,7 @@ impl Editor { // if leaving the view: mode should reset if prev_id != view_id { - let doc_id = self.tree.get(prev_id).doc; - self.documents.get_mut(&doc_id).unwrap().mode = Mode::Normal; + self.mode = Mode::Normal; } } @@ -1115,8 +1122,7 @@ impl Editor { // if leaving the view: mode should reset if prev_id != id { - let doc_id = self.tree.get(prev_id).doc; - self.documents.get_mut(&doc_id).unwrap().mode = Mode::Normal; + self.mode = Mode::Normal; } } @@ -1187,7 +1193,7 @@ impl Editor { let inner = view.inner_area(); pos.col += inner.x as usize; pos.row += inner.y as usize; - let cursorkind = config.cursor_shape.from_mode(doc.mode()); + let cursorkind = config.cursor_shape.from_mode(self.mode); (Some(pos), cursorkind) } else { (None, CursorKind::default()) diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 8f7c3062..ab0e2986 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -72,7 +72,7 @@ pub fn line_numbers<'doc>( .char_to_line(doc.selection(view.id).primary().cursor(text)); let line_number = editor.config().line_number; - let mode = doc.mode; + let mode = editor.mode; Box::new(move |line: usize, selected: bool, out: &mut String| { if line == last_line && !draw_last { -- cgit v1.2.3-70-g09d2