diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index b00e02b9478b0..b2fbd9efe9dee 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1,3 +1,8 @@ +// TODO: remove this when the MSRV is 1.62.0. +// This warning is benign and is removed in 1.62.0. +// See https://github.com/rust-lang/rust/pull/96268 +#![allow(mutable_borrow_reservation_conflict)] + pub(crate) mod dap; pub(crate) mod lsp; pub(crate) mod typed; @@ -27,7 +32,6 @@ use helix_core::{ SmallVec, Tendril, Transaction, }; use helix_view::{ - apply_transaction, clipboard::ClipboardType, document::{FormatterError, Mode, SCRATCH_BUFFER_NAME}, editor::{Action, Motion}, @@ -698,7 +702,7 @@ fn extend_to_line_start(cx: &mut Context) { } fn kill_to_line_start(cx: &mut Context) { - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let selection = doc.selection(view.id).clone().transform(|range| { @@ -722,13 +726,13 @@ fn kill_to_line_start(cx: &mut Context) { }; Range::new(head, anchor) }); - delete_selection_insert_mode(doc, view, &selection); + delete_selection_insert_mode(cx.editor, &selection); lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } fn kill_to_line_end(cx: &mut Context) { - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let selection = doc.selection(view.id).clone().transform(|range| { @@ -743,7 +747,7 @@ fn kill_to_line_end(cx: &mut Context) { } new_range }); - delete_selection_insert_mode(doc, view, &selection); + delete_selection_insert_mode(cx.editor, &selection); lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } @@ -799,9 +803,10 @@ fn trim_selections(cx: &mut Context) { // align text in selection fn align_selections(cx: &mut Context) { - let (view, doc) = current!(cx.editor); + let (view_id, doc_id) = current_ids!(cx.editor); + let doc = doc!(cx.editor, &doc_id); let text = doc.text().slice(..); - let selection = doc.selection(view.id); + let selection = doc.selection(view_id); let tab_width = doc.tab_width(); let mut column_widths: Vec> = Vec::new(); @@ -859,7 +864,7 @@ fn align_selections(cx: &mut Context) { changes.sort_unstable_by_key(|(from, _, _)| *from); let transaction = Transaction::change(doc.text(), changes.into_iter()); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc_id, view_id); } fn goto_window(cx: &mut Context, align: Align) { @@ -1267,7 +1272,7 @@ fn replace(cx: &mut Context) { // need to wait for next key cx.on_next_key(move |cx, event| { - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let ch: Option<&str> = match event { KeyEvent { code: KeyCode::Char(ch), @@ -1304,7 +1309,7 @@ fn replace(cx: &mut Context) { } }); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); exit_select_mode(cx); } }) @@ -1314,7 +1319,7 @@ fn switch_case_impl(cx: &mut Context, change_fn: F) where F: Fn(RopeSlice) -> Tendril, { - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let selection = doc.selection(view.id); let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { let text: Tendril = change_fn(range.slice(doc.text().slice(..))); @@ -1322,7 +1327,7 @@ where (range.from(), range.to(), Some(text)) }); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } fn switch_case(cx: &mut Context) { @@ -2133,7 +2138,7 @@ enum Operation { } fn delete_selection_impl(cx: &mut Context, op: Operation) { - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let selection = doc.selection(view.id); @@ -2149,7 +2154,7 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { (range.from(), range.to(), None) }); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); match op { Operation::Delete => { @@ -2163,11 +2168,12 @@ fn delete_selection_impl(cx: &mut Context, op: Operation) { } #[inline] -fn delete_selection_insert_mode(doc: &mut Document, view: &mut View, selection: &Selection) { +fn delete_selection_insert_mode(editor: &mut Editor, selection: &Selection) { + let (view, doc) = current_ref!(editor); let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { (range.from(), range.to(), None) }); - apply_transaction(&transaction, doc, view); + editor.apply_transaction(&transaction, doc.id(), view.id); } fn delete_selection(cx: &mut Context) { @@ -2246,8 +2252,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); - doc.restore_cursor = true; + doc_mut!(cx.editor).restore_cursor = true; + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); // Make sure there's room at the end of the document if the last @@ -2263,9 +2269,10 @@ fn append_mode(cx: &mut Context) { doc.text(), [(end, end, Some(doc.line_ending.as_str().into()))].into_iter(), ); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } + let (view, doc) = current!(cx.editor); let selection = doc.selection(view.id).clone().transform(|range| { Range::new( range.from(), @@ -2552,12 +2559,11 @@ async fn make_format_callback( } let scrolloff = editor.config().scrolloff; - let doc = doc_mut!(editor, &doc_id); - let view = view_mut!(editor, view_id); if let Ok(format) = format { - if doc.version() == doc_version { - apply_transaction(&format, doc, view); + if doc!(editor, &doc_id).version() == doc_version { + editor.apply_transaction(&format, doc_id, view_id); + let (view, doc) = current!(editor); doc.append_changes_to_history(view.id); doc.detect_indent_and_line_ending(); view.ensure_cursor_in_view(doc, scrolloff); @@ -2567,8 +2573,7 @@ async fn make_format_callback( } if let Some((path, force)) = write { - let id = doc.id(); - if let Err(err) = editor.save(id, path, force) { + if let Err(err) = editor.save(doc_id, path, force) { editor.set_error(format!("Error saving: {}", err)); } } @@ -2586,7 +2591,7 @@ pub enum Open { fn open(cx: &mut Context, open: Open) { let count = cx.count(); enter_insert_mode(cx); - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let contents = doc.text(); @@ -2650,7 +2655,7 @@ fn open(cx: &mut Context, open: Open) { transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } // o inserts a new line after each line with a selection @@ -2669,9 +2674,10 @@ fn normal_mode(cx: &mut Context) { } cx.editor.mode = Mode::Normal; - let (view, doc) = current!(cx.editor); - try_restore_indent(doc, view); + try_restore_indent(cx.editor); + + let (view, doc) = current!(cx.editor); // if leaving append mode, move cursor back by 1 if doc.restore_cursor { @@ -2688,7 +2694,7 @@ fn normal_mode(cx: &mut Context) { } } -fn try_restore_indent(doc: &mut Document, view: &mut View) { +fn try_restore_indent(editor: &mut Editor) { use helix_core::chars::char_is_whitespace; use helix_core::Operation; @@ -2705,6 +2711,8 @@ fn try_restore_indent(doc: &mut Document, view: &mut View) { } } + let (view, doc) = current_ref!(editor); + let doc_changes = doc.changes().changes(); let text = doc.text().slice(..); let range = doc.selection(view.id).primary(); @@ -2718,7 +2726,7 @@ fn try_restore_indent(doc: &mut Document, view: &mut View) { let line_start_pos = text.line_to_char(range.cursor_line(text)); (line_start_pos, pos, None) }); - apply_transaction(&transaction, doc, view); + editor.apply_transaction(&transaction, doc.id(), view.id); } } @@ -3030,9 +3038,8 @@ pub mod insert { .and_then(|ap| auto_pairs::hook(text, selection, c, ap)) .or_else(|| insert(text, selection, c)); - let (view, doc) = current!(cx.editor); - if let Some(t) = transaction { - apply_transaction(&t, doc, view); + if let Some(tx) = transaction { + cx.editor.apply_transaction(&tx, doc.id(), view.id); } // TODO: need a post insert hook too for certain triggers (autocomplete, signature help, etc) @@ -3044,7 +3051,7 @@ pub mod insert { } pub fn insert_tab(cx: &mut Context) { - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); // TODO: round out to nearest indentation level (for example a line with 3 spaces should // indent by one to reach 4 spaces). @@ -3054,7 +3061,7 @@ pub mod insert { &doc.selection(view.id).clone().cursors(doc.text().slice(..)), indent, ); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } pub fn insert_newline(cx: &mut Context) { @@ -3140,8 +3147,7 @@ pub mod insert { transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); - let (view, doc) = current!(cx.editor); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } pub fn delete_char_backward(cx: &mut Context) { @@ -3235,15 +3241,15 @@ pub mod insert { } } }); - let (view, doc) = current!(cx.editor); - apply_transaction(&transaction, doc, view); + let (view, doc) = current_ref!(cx.editor); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } pub fn delete_char_forward(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let transaction = Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| { @@ -3254,14 +3260,14 @@ pub mod insert { None, ) }); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } pub fn delete_word_backward(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let selection = doc.selection(view.id).clone().transform(|range| { @@ -3269,14 +3275,14 @@ pub mod insert { let next = Range::new(anchor, range.cursor(text)); exclude_cursor(text, next, range) }); - delete_selection_insert_mode(doc, view, &selection); + delete_selection_insert_mode(cx.editor, &selection); lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } pub fn delete_word_forward(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let selection = doc.selection(view.id).clone().transform(|range| { @@ -3284,7 +3290,7 @@ pub mod insert { Range::new(range.cursor(text), head) }); - delete_selection_insert_mode(doc, view, &selection); + delete_selection_insert_mode(cx.editor, &selection); lsp::signature_help_impl(cx, SignatureHelpInvoked::Automatic); } @@ -3294,9 +3300,9 @@ pub mod insert { fn undo(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view_id, doc_id) = current_ids!(cx.editor); for _ in 0..count { - if !doc.undo(view) { + if !cx.editor.undo(doc_id, view_id) { cx.editor.set_status("Already at oldest change"); break; } @@ -3305,9 +3311,9 @@ fn undo(cx: &mut Context) { fn redo(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view_id, doc_id) = current_ids!(cx.editor); for _ in 0..count { - if !doc.redo(view) { + if !cx.editor.redo(doc_id, view_id) { cx.editor.set_status("Already at newest change"); break; } @@ -3316,10 +3322,10 @@ fn redo(cx: &mut Context) { fn earlier(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view_id, doc_id) = current_ids!(cx.editor); for _ in 0..count { // rather than doing in batch we do this so get error halfway - if !doc.earlier(view, UndoKind::Steps(1)) { + if !cx.editor.earlier(doc_id, view_id, UndoKind::Steps(1)) { cx.editor.set_status("Already at oldest change"); break; } @@ -3328,10 +3334,10 @@ fn earlier(cx: &mut Context) { fn later(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view_id, doc_id) = current_ids!(cx.editor); for _ in 0..count { // rather than doing in batch we do this so get error halfway - if !doc.later(view, UndoKind::Steps(1)) { + if !cx.editor.later(doc_id, view_id, UndoKind::Steps(1)) { cx.editor.set_status("Already at newest change"); break; } @@ -3460,9 +3466,15 @@ enum Paste { Cursor, } -fn paste_impl(values: &[String], doc: &mut Document, view: &mut View, action: Paste, count: usize) { +fn paste_impl( + values: &[String], + doc: &Document, + view: &View, + action: Paste, + count: usize, +) -> Transaction { if values.is_empty() { - return; + return Transaction::new(doc.text()); } let repeat = std::iter::repeat( @@ -3524,9 +3536,7 @@ fn paste_impl(values: &[String], doc: &mut Document, view: &mut View, action: Pa (pos, pos, value) }); - let transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index())); - - apply_transaction(&transaction, doc, view); + transaction.with_selection(Selection::new(ranges, selection.primary_index())) } pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) { @@ -3535,8 +3545,9 @@ pub(crate) fn paste_bracketed_value(cx: &mut Context, contents: String) { Mode::Insert | Mode::Select => Paste::Cursor, Mode::Normal => Paste::Before, }; - let (view, doc) = current!(cx.editor); - paste_impl(&[contents], doc, view, paste, count); + let (view, doc) = current_ref!(cx.editor); + let transaction = paste_impl(&[contents], doc, view, paste, count); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } fn paste_clipboard_impl( @@ -3545,10 +3556,11 @@ fn paste_clipboard_impl( clipboard_type: ClipboardType, count: usize, ) -> anyhow::Result<()> { - let (view, doc) = current!(editor); match editor.clipboard_provider.get_contents(clipboard_type) { Ok(contents) => { - paste_impl(&[contents], doc, view, action, count); + let (view, doc) = current_ref!(editor); + let transaction = paste_impl(&[contents], doc, view, action, count); + editor.apply_transaction(&transaction, doc.id(), view.id); Ok(()) } Err(e) => Err(e.context("Couldn't get system clipboard contents")), @@ -3594,7 +3606,7 @@ fn paste_primary_clipboard_before(cx: &mut Context) { fn replace_with_yanked(cx: &mut Context) { let count = cx.count(); let reg_name = cx.register.unwrap_or('"'); - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let registers = &mut cx.editor.registers; if let Some(values) = registers.read(reg_name) { @@ -3618,7 +3630,7 @@ fn replace_with_yanked(cx: &mut Context) { } }); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); exit_select_mode(cx); } } @@ -3629,7 +3641,7 @@ fn replace_selections_with_clipboard_impl( clipboard_type: ClipboardType, ) -> anyhow::Result<()> { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); match cx.editor.clipboard_provider.get_contents(clipboard_type) { Ok(contents) => { @@ -3642,7 +3654,8 @@ fn replace_selections_with_clipboard_impl( ) }); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); + let (view, doc) = current!(cx.editor); doc.append_changes_to_history(view.id); } Err(e) => return Err(e.context("Couldn't get system clipboard contents")), @@ -3663,12 +3676,14 @@ fn replace_selections_with_primary_clipboard(cx: &mut Context) { fn paste(cx: &mut Context, pos: Paste) { let count = cx.count(); let reg_name = cx.register.unwrap_or('"'); - let (view, doc) = current!(cx.editor); - let registers = &mut cx.editor.registers; + let (view, doc) = current_ref!(cx.editor); + let values = match cx.editor.registers.read(reg_name) { + Some(values) => values, + None => return, + }; - if let Some(values) = registers.read(reg_name) { - paste_impl(values, doc, view, pos, count); - } + let transaction = paste_impl(values, doc, view, pos, count); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } fn paste_after(cx: &mut Context) { @@ -3697,7 +3712,7 @@ fn get_lines(doc: &Document, view_id: ViewId) -> Vec { fn indent(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let lines = get_lines(doc, view.id); // Indent by one level @@ -3714,12 +3729,12 @@ fn indent(cx: &mut Context) { Some((pos, pos, Some(indent.clone()))) }), ); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } fn unindent(cx: &mut Context) { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let lines = get_lines(doc, view.id); let mut changes = Vec::with_capacity(lines.len()); let tab_width = doc.tab_width(); @@ -3753,13 +3768,13 @@ fn unindent(cx: &mut Context) { let transaction = Transaction::change(doc.text(), changes.into_iter()); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } fn format_selections(cx: &mut Context) { use helix_lsp::{lsp, util::range_to_lsp_range}; - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); // via lsp if available // TODO: else via tree-sitter indentation calculations @@ -3802,12 +3817,12 @@ fn format_selections(cx: &mut Context) { language_server.offset_encoding(), ); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } fn join_selections_impl(cx: &mut Context, select_space: bool) { use movement::skip_while; - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text(); let slice = doc.text().slice(..); @@ -3856,7 +3871,7 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) { Transaction::change(doc.text(), changes.into_iter()) }; - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } fn keep_or_remove_selections_impl(cx: &mut Context, remove: bool) { @@ -3989,14 +4004,14 @@ pub fn completion(cx: &mut Context) { // comments fn toggle_comments(cx: &mut Context) { - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let token = doc .language_config() .and_then(|lc| lc.comment_token.as_ref()) .map(|tc| tc.as_ref()); let transaction = comment::toggle_line_comments(doc.text(), doc.selection(view.id), token); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); exit_select_mode(cx); } @@ -4021,7 +4036,7 @@ fn rotate_selections_backward(cx: &mut Context) { fn rotate_selection_contents(cx: &mut Context, direction: Direction) { let count = cx.count; - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let selection = doc.selection(view.id); @@ -4052,7 +4067,7 @@ fn rotate_selection_contents(cx: &mut Context, direction: Direction) { .map(|(range, fragment)| (range.from(), range.to(), Some(fragment))), ); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } fn rotate_selection_contents_forward(cx: &mut Context) { @@ -4527,7 +4542,7 @@ fn surround_add(cx: &mut Context) { Some(ch) => ch, None => return, }; - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let selection = doc.selection(view.id); let (open, close) = surround::get_pair(ch); // The number of chars in get_pair @@ -4557,7 +4572,7 @@ fn surround_add(cx: &mut Context) { let transaction = Transaction::change(doc.text(), changes.into_iter()) .with_selection(Selection::new(ranges, selection.primary_index())); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); }) } @@ -4569,7 +4584,7 @@ fn surround_replace(cx: &mut Context) { Some(ch) => Some(ch), None => return, }; - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let selection = doc.selection(view.id); @@ -4582,7 +4597,7 @@ fn surround_replace(cx: &mut Context) { }; cx.on_next_key(move |cx, event| { - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let to = match event.char() { Some(to) => to, None => return, @@ -4596,7 +4611,7 @@ fn surround_replace(cx: &mut Context) { (pos, pos + 1, Some(t)) }), ); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); }); }) } @@ -4609,7 +4624,7 @@ fn surround_delete(cx: &mut Context) { Some(ch) => Some(ch), None => return, }; - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let selection = doc.selection(view.id); @@ -4623,7 +4638,7 @@ fn surround_delete(cx: &mut Context) { let transaction = Transaction::change(doc.text(), change_pos.into_iter().map(|p| (p, p + 1, None))); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); }) } @@ -4781,7 +4796,7 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) { let config = cx.editor.config(); let shell = &config.shell; - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let selection = doc.selection(view.id); let mut changes = Vec::with_capacity(selection.len()); @@ -4828,12 +4843,14 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) { if behavior != &ShellBehavior::Ignore { let transaction = Transaction::change(doc.text(), changes.into_iter()) .with_selection(Selection::new(ranges, selection.primary_index())); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); + let (view, doc) = current!(cx.editor); doc.append_changes_to_history(view.id); } // after replace cursor may be out of bounds, do this to // make sure cursor is in view and update scroll as well + let (view, doc) = current!(cx.editor); view.ensure_cursor_in_view(doc, config.scrolloff); } @@ -4871,7 +4888,7 @@ fn add_newline_below(cx: &mut Context) { fn add_newline_impl(cx: &mut Context, open: Open) { let count = cx.count(); - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let selection = doc.selection(view.id); let text = doc.text(); let slice = text.slice(..); @@ -4891,7 +4908,7 @@ fn add_newline_impl(cx: &mut Context, open: Open) { }); let transaction = Transaction::change(text, changes); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } enum IncrementDirection { @@ -4952,7 +4969,7 @@ fn increment_impl(cx: &mut Context, increment_direction: IncrementDirection) { // If the register is `#` then increase or decrease the `amount` by 1 per element let increase_by = if cx.register == Some('#') { sign } else { 0 }; - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let selection = doc.selection(view.id); let text = doc.text().slice(..); @@ -5005,7 +5022,7 @@ fn increment_impl(cx: &mut Context, increment_direction: IncrementDirection) { let transaction = Transaction::change(doc.text(), changes.into_iter()); let transaction = transaction.with_selection(selection.clone()); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); } } diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs index 33d33440cacd4..fd01dfcf0f85d 100644 --- a/helix-term/src/commands/lsp.rs +++ b/helix-term/src/commands/lsp.rs @@ -9,7 +9,7 @@ use tui::text::{Span, Spans}; use super::{align_view, push_jump, Align, Context, Editor, Open}; use helix_core::{path, Selection}; -use helix_view::{apply_transaction, document::Mode, editor::Action, theme::Style}; +use helix_view::{document::Mode, editor::Action, theme::Style}; use crate::{ compositor::{self, Compositor}, @@ -711,7 +711,7 @@ pub fn apply_workspace_edit( } }; - let doc = doc_mut!(editor, &doc_id); + let doc = doc!(editor, &doc_id); // Need to determine a view for apply/append_changes_to_history let selections = doc.selections(); @@ -732,7 +732,8 @@ pub fn apply_workspace_edit( text_edits, offset_encoding, ); - apply_transaction(&transaction, doc, view_mut!(editor, view_id)); + editor.apply_transaction(&transaction, doc_id, view_id); + let doc = doc_mut!(editor, &doc_id); doc.append_changes_to_history(view_id); }; diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 4bbb20824d50d..18848b474022f 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -4,10 +4,7 @@ use crate::job::Job; use super::*; -use helix_view::{ - apply_transaction, - editor::{Action, CloseError, ConfigEvent}, -}; +use helix_view::editor::{Action, CloseError, ConfigEvent}; use ui::completers::{self, Completer}; #[derive(Clone)] @@ -445,8 +442,8 @@ fn set_line_ending( arg if arg.starts_with("nel") => Nel, _ => bail!("invalid line ending"), }; - let (view, doc) = current!(cx.editor); - doc.line_ending = line_ending; + doc_mut!(cx.editor).line_ending = line_ending; + let (view, doc) = current_ref!(cx.editor); let mut pos = 0; let transaction = Transaction::change( @@ -463,7 +460,8 @@ fn set_line_ending( } }), ); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); + let (view, doc) = current!(cx.editor); doc.append_changes_to_history(view.id); Ok(()) @@ -480,9 +478,8 @@ fn earlier( let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; - let (view, doc) = current!(cx.editor); - let success = doc.earlier(view, uk); - if !success { + let (view_id, doc_id) = current_ids!(cx.editor); + if !cx.editor.earlier(doc_id, view_id, uk) { cx.editor.set_status("Already at oldest change"); } @@ -499,9 +496,9 @@ fn later( } let uk = args.join(" ").parse::().map_err(|s| anyhow!(s))?; - let (view, doc) = current!(cx.editor); - let success = doc.later(view, uk); - if !success { + + let (view_id, doc_id) = current_ids!(cx.editor); + if !cx.editor.later(doc_id, view_id, uk) { cx.editor.set_status("Already at newest change"); } @@ -899,7 +896,7 @@ fn replace_selections_with_clipboard_impl( cx: &mut compositor::Context, clipboard_type: ClipboardType, ) -> anyhow::Result<()> { - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); match cx.editor.clipboard_provider.get_contents(clipboard_type) { Ok(contents) => { @@ -908,7 +905,8 @@ fn replace_selections_with_clipboard_impl( (range.from(), range.to(), Some(contents.as_str().into())) }); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); + let (view, doc) = current!(cx.editor); doc.append_changes_to_history(view.id); Ok(()) } @@ -1027,11 +1025,8 @@ fn reload( return Ok(()); } - let scrolloff = cx.editor.config().scrolloff; - let (view, doc) = current!(cx.editor); - doc.reload(view).map(|_| { - view.ensure_cursor_in_view(doc, scrolloff); - }) + let (view_id, doc_id) = current_ids!(cx.editor); + cx.editor.reload(doc_id, view_id) } /// Update the [`Document`] if it has been modified. @@ -1044,8 +1039,7 @@ fn update( return Ok(()); } - let (_view, doc) = current!(cx.editor); - if doc.is_modified() { + if doc!(cx.editor).is_modified() { write(cx, args, event) } else { Ok(()) @@ -1061,9 +1055,7 @@ fn lsp_workspace_command( return Ok(()); } - let (_, doc) = current!(cx.editor); - - let language_server = match doc.language_server() { + let language_server = match doc!(cx.editor).language_server() { Some(language_server) => language_server, None => { cx.editor @@ -1132,7 +1124,8 @@ fn lsp_restart( return Ok(()); } - let (_view, doc) = current!(cx.editor); + let doc = doc!(cx.editor); + let config = doc .language_config() .context("LSP not defined for the current document")?; @@ -1166,7 +1159,7 @@ fn tree_sitter_scopes( return Ok(()); } - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let pos = doc.selection(view.id).primary().cursor(text); @@ -1199,10 +1192,10 @@ fn vsplit( return Ok(()); } - let id = view!(cx.editor).doc; + let (_, doc_id) = current_ids!(cx.editor); if args.is_empty() { - cx.editor.switch(id, Action::VerticalSplit); + cx.editor.switch(doc_id, Action::VerticalSplit); } else { for arg in args { cx.editor @@ -1222,10 +1215,10 @@ fn hsplit( return Ok(()); } - let id = view!(cx.editor).doc; + let (_, doc_id) = current_ids!(cx.editor); if args.is_empty() { - cx.editor.switch(id, Action::HorizontalSplit); + cx.editor.switch(doc_id, Action::HorizontalSplit); } else { for arg in args { cx.editor @@ -1504,7 +1497,7 @@ fn sort_impl( _args: &[Cow], reverse: bool, ) -> anyhow::Result<()> { - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); let text = doc.text().slice(..); let selection = doc.selection(view.id); @@ -1527,7 +1520,8 @@ fn sort_impl( .map(|(s, fragment)| (s.from(), s.to(), Some(fragment))), ); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); + let (view, doc) = current!(cx.editor); doc.append_changes_to_history(view.id); Ok(()) @@ -1543,7 +1537,7 @@ fn reflow( } let scrolloff = cx.editor.config().scrolloff; - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); const DEFAULT_MAX_LEN: usize = 79; @@ -1571,7 +1565,8 @@ fn reflow( (range.from(), range.to(), Some(reflowed_text)) }); - apply_transaction(&transaction, doc, view); + cx.editor.apply_transaction(&transaction, doc.id(), view.id); + let (view, doc) = current!(cx.editor); doc.append_changes_to_history(view.id); view.ensure_cursor_in_view(doc, scrolloff); @@ -1587,7 +1582,7 @@ fn tree_sitter_subtree( return Ok(()); } - let (view, doc) = current!(cx.editor); + let (view, doc) = current_ref!(cx.editor); if let Some(syntax) = doc.syntax() { let primary_selection = doc.selection(view.id).primary(); diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 4e6ee4246775e..d1d8aa58a3e37 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -1,5 +1,5 @@ use crate::compositor::{Component, Context, Event, EventResult}; -use helix_view::{apply_transaction, editor::CompleteAction}; +use helix_view::editor::CompleteAction; use tui::buffer::Buffer as Surface; use tui::text::Spans; @@ -148,14 +148,14 @@ impl Completion { .collect() } - let (view, doc) = current!(editor); + let (view_id, doc_id) = current_ids!(editor); // if more text was entered, remove it - doc.restore(view); + editor.restore(doc_id, view_id); match event { PromptEvent::Abort => { - doc.restore(view); + editor.restore(doc_id, view_id); editor.last_completion = None; } PromptEvent::Update => { @@ -163,7 +163,7 @@ impl Completion { let item = item.unwrap(); let transaction = item_to_transaction( - doc, + doc!(editor, &doc_id), item, offset_encoding, start_offset, @@ -171,8 +171,8 @@ impl Completion { ); // initialize a savepoint - doc.savepoint(); - apply_transaction(&transaction, doc, view); + doc_mut!(editor, &doc_id).savepoint(); + editor.apply_transaction(&transaction, doc_id, view_id); editor.last_completion = Some(CompleteAction { trigger_offset, @@ -184,14 +184,14 @@ impl Completion { let item = item.unwrap(); let transaction = item_to_transaction( - doc, + doc!(editor, &doc_id), item, offset_encoding, start_offset, trigger_offset, ); - apply_transaction(&transaction, doc, view); + editor.apply_transaction(&transaction, doc_id, view_id); editor.last_completion = Some(CompleteAction { trigger_offset, @@ -207,7 +207,7 @@ impl Completion { { None } else { - Self::resolve_completion_item(doc, item.clone()) + Self::resolve_completion_item(doc!(editor, &doc_id), item.clone()) }; if let Some(additional_edits) = resolved_item @@ -216,12 +216,13 @@ impl Completion { .or(item.additional_text_edits.as_ref()) { if !additional_edits.is_empty() { + let doc = doc!(editor); let transaction = util::generate_transaction_from_edits( doc.text(), additional_edits.clone(), offset_encoding, // TODO: should probably transcode in Client ); - apply_transaction(&transaction, doc, view); + editor.apply_transaction(&transaction, doc_id, view_id); } } } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index f2a588e338f22..28e3c8e678494 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -17,7 +17,6 @@ use helix_core::{ visual_coords_at_pos, LineEnding, Position, Range, Selection, Transaction, }; use helix_view::{ - apply_transaction, document::{Mode, SCRATCH_BUFFER_NAME}, editor::{CompleteAction, CursorShapeConfig}, graphics::{Color, CursorKind, Modifier, Rect, Style}, @@ -1018,10 +1017,10 @@ impl EditorView { match key { InsertEvent::Key(key) => self.insert_mode(cxt, key), InsertEvent::CompletionApply(compl) => { - let (view, doc) = current!(cxt.editor); - - doc.restore(view); + let (view_id, doc_id) = current_ids!(cxt.editor); + cxt.editor.restore(doc_id, view_id); + let (view, doc) = current_ref!(cxt.editor); let text = doc.text().slice(..); let cursor = doc.selection(view.id).primary().cursor(text); @@ -1034,7 +1033,7 @@ impl EditorView { (shift_position(start), shift_position(end), t) }), ); - apply_transaction(&tx, doc, view); + cxt.editor.apply_transaction(&tx, doc_id, view_id); } InsertEvent::TriggerCompletion => { let (_, doc) = current!(cxt.editor); diff --git a/helix-term/tests/test/helpers.rs b/helix-term/tests/test/helpers.rs index 2c5043d68cf23..ef94ea39c8731 100644 --- a/helix-term/tests/test/helpers.rs +++ b/helix-term/tests/test/helpers.rs @@ -1,3 +1,6 @@ +// TODO: remove this when the MSRV is 1.62.0 +#![allow(mutable_borrow_reservation_conflict)] + use std::{ fs::File, io::{Read, Write}, @@ -121,7 +124,7 @@ pub async fn test_key_sequence_with_input_text>( None => Application::new(Args::default(), Config::default(), test_syntax_conf(None))?, }; - let (view, doc) = helix_view::current!(app.editor); + let (view, doc) = helix_view::current_ref!(app.editor); let sel = doc.selection(view.id).clone(); // replace the initial text with the input text @@ -130,7 +133,8 @@ pub async fn test_key_sequence_with_input_text>( }) .with_selection(test_case.in_selection.clone()); - helix_view::apply_transaction(&transaction, doc, view); + app.editor + .apply_transaction(&transaction, doc.id(), view.id); test_key_sequence( &mut app, @@ -307,7 +311,7 @@ impl AppBuilder { let mut app = Application::new(self.args, self.config, self.syn_conf)?; if let Some((text, selection)) = self.input { - let (view, doc) = helix_view::current!(app.editor); + let (view, doc) = helix_view::current_ref!(app.editor); let sel = doc.selection(view.id).clone(); let trans = Transaction::change_by_selection(doc.text(), &sel, |_| { (0, doc.text().len_chars(), Some((text.clone()).into())) @@ -315,7 +319,7 @@ impl AppBuilder { .with_selection(selection); // replace the initial text with the input text - helix_view::apply_transaction(&trans, doc, view); + app.editor.apply_transaction(&trans, doc.id(), view.id); } Ok(app) diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 0870852833918..f1b555e4c153d 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -24,7 +24,7 @@ use helix_core::{ DEFAULT_LINE_ENDING, }; -use crate::{apply_transaction, DocumentId, Editor, View, ViewId}; +use crate::{DocumentId, Editor, ViewId}; /// 8kB of buffer space for encoding and decoding `Rope`s. const BUF_SIZE: usize = 8192; @@ -624,7 +624,7 @@ impl Document { } /// Reload the document from its path. - pub fn reload(&mut self, view: &mut View) -> Result<(), Error> { + pub fn reload(&self) -> Result { let encoding = &self.encoding; let path = self.path().filter(|path| path.exists()); @@ -639,14 +639,7 @@ impl Document { // Calculate the difference between the buffer and source text, and apply it. // This is not considered a modification of the contents of the file regardless // of the encoding. - let transaction = helix_core::diff::compare_ropes(self.text(), &rope); - apply_transaction(&transaction, self, view); - self.append_changes_to_history(view.id); - self.reset_modified(); - - self.detect_indent_and_line_ending(); - - Ok(()) + Ok(helix_core::diff::compare_ropes(self.text(), &rope)) } /// Sets the [`Document`]'s encoding with the encoding correspondent to `label`. @@ -833,8 +826,8 @@ impl Document { } /// Apply a [`Transaction`] to the [`Document`] to change its text. - /// Instead of calling this function directly, use [crate::apply_transaction] - /// to ensure that the transaction is applied to the appropriate [`View`] as + /// Instead of calling this function directly, use [Editor::apply_transaction] + /// to ensure that the transaction is applied to the appropriate [`crate::view::View`] as /// well. pub fn apply(&mut self, transaction: &Transaction, view_id: ViewId) -> bool { // store the state just before any changes are made. This allows us to undo to the @@ -857,11 +850,11 @@ impl Document { success } - fn undo_redo_impl(&mut self, view: &mut View, undo: bool) -> bool { + fn undo_redo_impl(&mut self, view_id: ViewId, undo: bool) -> Option { let mut history = self.history.take(); - let txn = if undo { history.undo() } else { history.redo() }; - let success = if let Some(txn) = txn { - self.apply_impl(txn, view.id) && view.apply(txn, self) + let transaction = if undo { history.undo() } else { history.redo() }.cloned(); + let success = if let Some(ref txn) = transaction { + self.apply_impl(txn, view_id) } else { false }; @@ -870,57 +863,68 @@ impl Document { if success { // reset changeset to fix len self.changes = ChangeSet::new(self.text()); + transaction + } else { + None } - success } - /// Undo the last modification to the [`Document`]. Returns whether the undo was successful. - pub fn undo(&mut self, view: &mut View) -> bool { - self.undo_redo_impl(view, true) + /// Undo the last modification to the [`Document`]. + /// Use [Editor::undo] instead of calling this method directly. + pub fn undo(&mut self, view_id: ViewId) -> Option { + self.undo_redo_impl(view_id, true) } - /// Redo the last modification to the [`Document`]. Returns whether the redo was successful. - pub fn redo(&mut self, view: &mut View) -> bool { - self.undo_redo_impl(view, false) + /// Redo the last modification to the [`Document`]. + /// Use [Editor::redo] instead of calling this method directly. + pub fn redo(&mut self, view_id: ViewId) -> Option { + self.undo_redo_impl(view_id, false) } pub fn savepoint(&mut self) { self.savepoint = Some(Transaction::new(self.text())); } - pub fn restore(&mut self, view: &mut View) { - if let Some(revert) = self.savepoint.take() { - apply_transaction(&revert, self, view); - } + pub fn restore(&mut self) -> Option { + self.savepoint.take() } - fn earlier_later_impl(&mut self, view: &mut View, uk: UndoKind, earlier: bool) -> bool { + fn earlier_later_impl( + &mut self, + view_id: ViewId, + uk: UndoKind, + earlier: bool, + ) -> Vec { let txns = if earlier { self.history.get_mut().earlier(uk) } else { self.history.get_mut().later(uk) }; let mut success = false; - for txn in txns { - if self.apply_impl(&txn, view.id) && view.apply(&txn, self) { + for txn in txns.clone() { + if self.apply_impl(&txn, view_id) { success = true; } } if success { // reset changeset to fix len self.changes = ChangeSet::new(self.text()); + txns + } else { + Vec::new() } - success } /// Undo modifications to the [`Document`] according to `uk`. - pub fn earlier(&mut self, view: &mut View, uk: UndoKind) -> bool { - self.earlier_later_impl(view, uk, true) + /// Use [Editor::earlier] instead of calling this method directly. + pub fn earlier(&mut self, view_id: ViewId, uk: UndoKind) -> Vec { + self.earlier_later_impl(view_id, uk, true) } /// Redo modifications to the [`Document`] according to `uk`. - pub fn later(&mut self, view: &mut View, uk: UndoKind) -> bool { - self.earlier_later_impl(view, uk, false) + /// Use [Editor::later] instead of calling this method directly. + pub fn later(&mut self, view_id: ViewId, uk: UndoKind) -> Vec { + self.earlier_later_impl(view_id, uk, false) } /// Commit pending changes to history diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 23e0a4976a534..cb0da7e59ccc1 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -34,11 +34,11 @@ use anyhow::{anyhow, bail, Error}; pub use helix_core::diagnostic::Severity; pub use helix_core::register::Registers; -use helix_core::Position; use helix_core::{ auto_pairs::AutoPairs, + history::UndoKind, syntax::{self, AutoPairConfig}, - Change, + Change, Position, }; use helix_dap as dap; use helix_lsp::lsp; @@ -1225,6 +1225,101 @@ impl Editor { Ok(()) } + pub fn reload(&mut self, doc_id: DocumentId, view_id: ViewId) -> anyhow::Result<()> { + let scrolloff = self.config().scrolloff; + let doc = doc_mut!(self, &doc_id); + let transaction = doc.reload()?; + self.apply_transaction(&transaction, doc_id, view_id); + let doc = doc_mut!(self, &doc_id); + doc.append_changes_to_history(view_id); + doc.reset_modified(); + doc.detect_indent_and_line_ending(); + view_mut!(self, view_id).ensure_cursor_in_view(doc, scrolloff); + Ok(()) + } + + pub fn restore(&mut self, doc_id: DocumentId, view_id: ViewId) { + let doc = doc_mut!(self, &doc_id); + if let Some(transaction) = doc.restore() { + self.apply_transaction(&transaction, doc_id, view_id); + } + } + + pub fn undo(&mut self, doc_id: DocumentId, view_id: ViewId) -> bool { + let doc = doc_mut!(self, &doc_id); + let transaction = match doc.undo(view_id) { + Some(transaction) => transaction, + None => return false, + }; + self.apply_transaction_to_views(&transaction, doc_id); + true + } + + pub fn redo(&mut self, doc_id: DocumentId, view_id: ViewId) -> bool { + let doc = doc_mut!(self, &doc_id); + let transaction = match doc.redo(view_id) { + Some(transaction) => transaction, + None => return false, + }; + self.apply_transaction_to_views(&transaction, doc_id); + true + } + + pub fn earlier(&mut self, doc_id: DocumentId, view_id: ViewId, kind: UndoKind) -> bool { + let doc = doc_mut!(self, &doc_id); + let transactions = doc.earlier(view_id, kind); + if transactions.is_empty() { + return false; + } + for transaction in transactions { + self.apply_transaction_to_views(&transaction, doc_id); + } + true + } + + pub fn later(&mut self, doc_id: DocumentId, view_id: ViewId, kind: UndoKind) -> bool { + let doc = doc_mut!(self, &doc_id); + let transactions = doc.later(view_id, kind); + if transactions.is_empty() { + return false; + } + for transaction in transactions { + self.apply_transaction_to_views(&transaction, doc_id); + } + true + } + + /// Applies a given [helix_core::Transaction] to the given Document and the focused + /// ViewId. + /// + /// The transaction is also applied to all views which contain the open document so + /// that all jumplist selections are updated by the transaction. + pub fn apply_transaction( + &mut self, + transaction: &helix_core::Transaction, + doc_id: DocumentId, + view_id: ViewId, + ) -> bool { + let doc = doc_mut!(self, &doc_id); + if doc.apply(transaction, view_id) { + self.apply_transaction_to_views(transaction, doc_id); + true + } else { + false + } + } + + fn apply_transaction_to_views( + &mut self, + transaction: &helix_core::Transaction, + doc_id: DocumentId, + ) { + let doc = doc!(self, &doc_id); + for (view, _focused) in self.tree.views_mut() { + view.apply(transaction, doc) + } + } + pub fn resize(&mut self, area: Rect) { if self.tree.resize(area) { self._refresh(); diff --git a/helix-view/src/lib.rs b/helix-view/src/lib.rs index 4c32b356b9eaa..9a98044639531 100644 --- a/helix-view/src/lib.rs +++ b/helix-view/src/lib.rs @@ -66,19 +66,6 @@ pub fn align_view(doc: &Document, view: &mut View, align: Align) { view.offset.row = line.saturating_sub(relative); } -/// Applies a [`helix_core::Transaction`] to the given [`Document`] -/// and [`View`]. -pub fn apply_transaction( - transaction: &helix_core::Transaction, - doc: &mut Document, - view: &mut View, -) -> bool { - // This is a short function but it's easy to call `Document::apply` - // without calling `View::apply` or in the wrong order. The transaction - // must be applied to the document before the view. - doc.apply(transaction, view.id) && view.apply(transaction, doc) -} - pub use document::Document; pub use editor::Editor; pub use theme::Theme; diff --git a/helix-view/src/macros.rs b/helix-view/src/macros.rs index 53ab434622d44..311e65d07777f 100644 --- a/helix-view/src/macros.rs +++ b/helix-view/src/macros.rs @@ -28,6 +28,16 @@ macro_rules! current_ref { }}; } +/// Get the IDs of the current View and Document immutably. +/// Returns `(ViewId, DocumentId)` +#[macro_export] +macro_rules! current_ids { + ($editor:expr) => {{ + let (view, doc) = $crate::current_ref!($editor); + (view.id, doc.id()) + }}; +} + /// Get the current document mutably. /// Returns `&mut Document` #[macro_export] @@ -67,7 +77,7 @@ macro_rules! view { #[macro_export] macro_rules! doc { ($editor:expr, $id:expr) => {{ - $editor.documents[$id] + &$editor.documents[$id] }}; ($editor:expr) => {{ $crate::current_ref!($editor).1 diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 6da4df1f0f031..33e5d6046c038 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -341,11 +341,10 @@ impl View { // } /// Applies a [`Transaction`] to the view. - /// Instead of calling this function directly, use [crate::apply_transaction] - /// which applies a transaction to the [`Document`] and view together. - pub fn apply(&mut self, transaction: &Transaction, doc: &Document) -> bool { + /// Instead of calling this function directly, use [crate::Editor::apply_transaction] + /// which applies a transaction to the [`Document`] and views together. + pub fn apply(&mut self, transaction: &Transaction, doc: &Document) { self.jumps.apply(transaction, doc); - true } }