diff options
-rw-r--r-- | helix-core/src/comment.rs | 18 | ||||
-rw-r--r-- | helix-core/src/indent.rs | 27 | ||||
-rw-r--r-- | helix-core/src/transaction.rs | 24 | ||||
-rw-r--r-- | helix-lsp/src/lib.rs | 15 | ||||
-rw-r--r-- | helix-term/src/commands.rs | 47 | ||||
-rw-r--r-- | helix-term/src/ui/editor.rs | 2 | ||||
-rw-r--r-- | helix-view/src/document.rs | 2 |
7 files changed, 69 insertions, 66 deletions
diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 969d4d92..35aabda9 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -1,4 +1,6 @@ -use crate::{find_first_non_whitespace_char2, Change, RopeSlice, State, Tendril, Transaction}; +use crate::{ + find_first_non_whitespace_char2, Change, Rope, RopeSlice, Selection, Tendril, Transaction, +}; use core::ops::Range; use std::borrow::Cow; @@ -35,14 +37,14 @@ fn find_line_comment( (commented, skipped, min) } -pub fn toggle_line_comments(state: &State) -> Transaction { - let text = state.doc.slice(..); +pub fn toggle_line_comments(doc: &Rope, selection: &Selection) -> Transaction { + let text = doc.slice(..); let mut changes: Vec<Change> = Vec::new(); let token = "//"; let comment = Tendril::from(format!("{} ", token)); - for selection in state.selection.ranges() { + for selection in selection.ranges() { let start = text.char_to_line(selection.from()); let end = text.char_to_line(selection.to()); let lines = start..end + 1; @@ -67,7 +69,7 @@ pub fn toggle_line_comments(state: &State) -> Transaction { } } } - Transaction::change(&state.doc, changes.into_iter()) + Transaction::change(doc, changes.into_iter()) } #[cfg(test)] @@ -76,7 +78,7 @@ mod test { #[test] fn test_find_line_comment() { - use crate::{Rope, Selection}; + use crate::State; // four lines, two space indented, except for line 1 which is blank. let doc = Rope::from(" 1\n\n 2\n 3"); @@ -92,13 +94,13 @@ mod test { assert_eq!(res, (false, vec![1], 2)); // comment - let transaction = toggle_line_comments(&state); + let transaction = toggle_line_comments(&state.doc, &state.selection); transaction.apply(&mut state); assert_eq!(state.doc, " // 1\n\n // 2\n // 3"); // uncomment - let transaction = toggle_line_comments(&state); + let transaction = toggle_line_comments(&state.doc, &state.selection); transaction.apply(&mut state); assert_eq!(state.doc, " 1\n\n 2\n 3"); diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs index ec0460d5..9b1241e5 100644 --- a/helix-core/src/indent.rs +++ b/helix-core/src/indent.rs @@ -2,7 +2,7 @@ use crate::{ find_first_non_whitespace_char, syntax::Syntax, tree_sitter::{Node, Tree}, - Rope, RopeSlice, State, + Rope, RopeSlice, }; /// To determine indentation of a newly inserted line, figure out the indentation at the last col @@ -162,12 +162,12 @@ fn calculate_indentation(node: Option<Node>, newline: bool) -> usize { increment as usize } -fn suggested_indent_for_line(syntax: Option<&Syntax>, state: &State, line_num: usize) -> usize { - let line = state.doc.line(line_num); +fn suggested_indent_for_line(syntax: Option<&Syntax>, text: RopeSlice, line_num: usize) -> usize { + let line = text.line(line_num); let current = indent_level_for_line(line); - if let Some(start) = find_first_non_whitespace_char(state.doc.slice(..), line_num) { - return suggested_indent_for_pos(syntax, state, start, false); + if let Some(start) = find_first_non_whitespace_char(text, line_num) { + return suggested_indent_for_pos(syntax, text, start, false); }; // if the line is blank, indent should be zero @@ -179,12 +179,12 @@ fn suggested_indent_for_line(syntax: Option<&Syntax>, state: &State, line_num: u // - it should look up the wrapper node and count it too when we press o/O pub fn suggested_indent_for_pos( syntax: Option<&Syntax>, - state: &State, + text: RopeSlice, pos: usize, new_line: bool, ) -> usize { if let Some(syntax) = syntax { - let byte_start = state.doc.char_to_byte(pos); + let byte_start = text.char_to_byte(pos); let node = get_highest_syntax_node_at_bytepos(syntax, byte_start); // TODO: special case for comments @@ -279,7 +279,7 @@ std::panic::set_hook(Box::new(move |info| { 1 }}} -pub fn change<I>(state: &State, changes: I) -> Self +pub fn change<I>(document: &Document, changes: I) -> Self where I: IntoIterator<Item = Change> + ExactSizeIterator, { @@ -288,20 +288,19 @@ where ", ); - let state = State::new(doc); - // TODO: set_language + let doc = Rope::from(doc); let language_config = crate::syntax::LOADER .language_config_for_scope("source.rust") .unwrap(); let highlight_config = language_config.highlight_config(&[]).unwrap(); - let syntax = Syntax::new(&state.doc, highlight_config.clone()); - let text = state.doc.slice(..); + let syntax = Syntax::new(&doc, highlight_config.clone()); + let text = doc.slice(..); - for i in 0..state.doc.len_lines() { + for i in 0..doc.len_lines() { let line = text.line(i); let indent = indent_level_for_line(line); assert_eq!( - suggested_indent_for_line(Some(&syntax), &state, i), + suggested_indent_for_line(Some(&syntax), text, i), indent, "line {}: {}", i, diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index dbc5d588..2bd100e8 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -409,9 +409,9 @@ pub struct Transaction { impl Transaction { /// Create a new, empty transaction. - pub fn new(state: &mut State) -> Self { + pub fn new(doc: &Rope) -> Self { Self { - changes: ChangeSet::new(&state.doc), + changes: ChangeSet::new(doc), selection: None, } } @@ -490,16 +490,18 @@ impl Transaction { } /// Generate a transaction with a change per selection range. - pub fn change_by_selection<F>(state: &State, f: F) -> Self + pub fn change_by_selection<F>(doc: &Rope, selection: &Selection, f: F) -> Self where F: FnMut(&Range) -> Change, { - Self::change(&state.doc, state.selection.ranges().iter().map(f)) + Self::change(doc, selection.ranges().iter().map(f)) } /// Insert text at each selection head. - pub fn insert(state: &State, text: Tendril) -> Self { - Self::change_by_selection(state, |range| (range.head, range.head, Some(text.clone()))) + pub fn insert(doc: &Rope, selection: &Selection, text: Tendril) -> Self { + Self::change_by_selection(doc, selection, |range| { + (range.head, range.head, Some(text.clone())) + }) } } @@ -628,15 +630,15 @@ mod test { #[test] fn optimized_composition() { let mut state = State::new("".into()); - let t1 = Transaction::insert(&state, Tendril::from_char('h')); + let t1 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('h')); t1.apply(&mut state); - let t2 = Transaction::insert(&state, Tendril::from_char('e')); + let t2 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('e')); t2.apply(&mut state); - let t3 = Transaction::insert(&state, Tendril::from_char('l')); + let t3 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('l')); t3.apply(&mut state); - let t4 = Transaction::insert(&state, Tendril::from_char('l')); + let t4 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('l')); t4.apply(&mut state); - let t5 = Transaction::insert(&state, Tendril::from_char('o')); + let t5 = Transaction::insert(&state.doc, &state.selection, Tendril::from_char('o')); t5.apply(&mut state); assert_eq!(state.doc, Rope::from_str("hello")); diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 3dcdeb07..29868e82 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -30,7 +30,7 @@ pub enum Error { pub mod util { use super::*; - use helix_core::{Range, RopeSlice, State, Transaction}; + use helix_core::{Range, Rope, RopeSlice, Transaction}; pub fn lsp_pos_to_pos(doc: RopeSlice, pos: lsp::Position) -> usize { let line = doc.line_to_char(pos.line as usize); @@ -52,13 +52,10 @@ pub mod util { lsp::Range::new(start, end) } - pub fn generate_transaction_from_edits( - state: &State, - edits: Vec<lsp::TextEdit>, - ) -> Transaction { - let doc = state.doc.slice(..); + pub fn generate_transaction_from_edits(doc: &Rope, edits: Vec<lsp::TextEdit>) -> Transaction { + let text = doc.slice(..); // would be unnecessary if Transaction::change took Rope | RopeSlice Transaction::change( - &state.doc, + doc, edits.into_iter().map(|edit| { // simplify "" into None for cleaner changesets let replacement = if !edit.new_text.is_empty() { @@ -67,8 +64,8 @@ pub mod util { None }; - let start = lsp_pos_to_pos(doc, edit.range.start); - let end = lsp_pos_to_pos(doc, edit.range.end); + let start = lsp_pos_to_pos(text, edit.range.start); + let end = lsp_pos_to_pos(text, edit.range.end); (start, end, replacement) }), ) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index e703388d..f3847eda 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4,8 +4,8 @@ use helix_core::{ movement, object, pos_at_coords, regex::{self, Regex}, register, search, selection, - state::{Direction, Granularity, State}, - Change, ChangeSet, Position, Range, RopeSlice, Selection, Tendril, Transaction, + state::{Direction, Granularity}, + Change, ChangeSet, Position, Range, Rope, RopeSlice, Selection, Tendril, Transaction, }; use once_cell::sync::Lazy; @@ -107,7 +107,7 @@ pub fn move_line_down(cx: &mut Context) { pub fn move_line_end(cx: &mut Context) { let doc = cx.doc(); - let lines = selection_lines(&doc.state); + let lines = selection_lines(doc.text(), doc.selection()); let positions = lines .into_iter() @@ -127,7 +127,7 @@ pub fn move_line_end(cx: &mut Context) { pub fn move_line_start(cx: &mut Context) { let doc = cx.doc(); - let lines = selection_lines(&doc.state); + let lines = selection_lines(doc.text(), doc.selection()); let positions = lines .into_iter() @@ -586,8 +586,9 @@ pub fn extend_line(cx: &mut Context) { // heuristic: append changes to history after each command, unless we're in insert mode fn _delete_selection(doc: &mut Document) { - let transaction = - Transaction::change_by_selection(&doc.state, |range| (range.from(), range.to() + 1, None)); + let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| { + (range.from(), range.to() + 1, None) + }); doc.apply(&transaction); } @@ -722,12 +723,11 @@ pub fn buffer_picker(cx: &mut Context) { } // calculate line numbers for each selection range -fn selection_lines(state: &State) -> Vec<usize> { - let mut lines = state - .selection +fn selection_lines(doc: &Rope, selection: &Selection) -> Vec<usize> { + let mut lines = selection .ranges() .iter() - .map(|range| state.doc.char_to_line(range.head)) + .map(|range| doc.char_to_line(range.head)) .collect::<Vec<_>>(); lines.sort_unstable(); // sorting by usize so _unstable is preferred @@ -758,19 +758,21 @@ pub fn open_below(cx: &mut Context) { let doc = cx.doc(); enter_insert_mode(doc); - let lines = selection_lines(&doc.state); + let lines = selection_lines(doc.text(), doc.selection()); let positions = lines.into_iter().map(|index| { // adjust all positions to the end of the line (next line minus one) doc.text().line_to_char(index + 1).saturating_sub(1) }); + let text = doc.text().slice(..); + let changes: Vec<Change> = positions .map(|index| { // TODO: share logic with insert_newline for indentation let indent_level = helix_core::indent::suggested_indent_for_pos( doc.syntax.as_ref(), - &doc.state, + text, index, true, ); @@ -955,7 +957,7 @@ pub mod insert { pub fn insert_char(cx: &mut Context, c: char) { let doc = cx.doc(); let c = Tendril::from_char(c); - let transaction = Transaction::insert(&doc.state, c); + let transaction = Transaction::insert(doc.text(), doc.selection(), c); doc.apply(&transaction); } @@ -966,10 +968,11 @@ pub mod insert { pub fn insert_newline(cx: &mut Context) { let doc = cx.doc(); - let transaction = Transaction::change_by_selection(&doc.state, |range| { + let text = doc.text().slice(..); + let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| { let indent_level = helix_core::indent::suggested_indent_for_pos( doc.syntax.as_ref(), - &doc.state, + text, range.head, true, ); @@ -987,7 +990,7 @@ pub mod insert { let count = cx.count; let doc = cx.doc(); let text = doc.text().slice(..); - let transaction = Transaction::change_by_selection(&doc.state, |range| { + let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| { ( graphemes::nth_prev_grapheme_boundary(text, range.head, count), range.head, @@ -1001,7 +1004,7 @@ pub mod insert { let count = cx.count; let doc = cx.doc(); let text = doc.text().slice(..); - let transaction = Transaction::change_by_selection(&doc.state, |range| { + let transaction = Transaction::change_by_selection(doc.text(), doc.selection(), |range| { ( range.head, graphemes::nth_next_grapheme_boundary(text, range.head, count), @@ -1076,12 +1079,12 @@ pub fn paste(cx: &mut Context) { // paste on the next line // TODO: can simply take a range + modifier and compute the right pos without ifs let text = doc.text(); - Transaction::change_by_selection(&doc.state, |range| { + Transaction::change_by_selection(doc.text(), doc.selection(), |range| { let line_end = text.line_to_char(text.char_to_line(range.head) + 1); (line_end, line_end, Some(values.next().unwrap())) }) } else { - Transaction::change_by_selection(&doc.state, |range| { + Transaction::change_by_selection(doc.text(), doc.selection(), |range| { (range.head + 1, range.head + 1, Some(values.next().unwrap())) }) }; @@ -1190,7 +1193,7 @@ pub fn format_selections(cx: &mut Context) { )) .unwrap_or_default(); - let transaction = helix_lsp::util::generate_transaction_from_edits(&doc.state, edits); + let transaction = helix_lsp::util::generate_transaction_from_edits(doc.text(), edits); doc.apply(&transaction); } @@ -1352,7 +1355,7 @@ pub fn completion(cx: &mut Context) { // TODO: <-- if state has changed by further input, transaction will panic on len let transaction = - util::generate_transaction_from_edits(&doc.state, vec![edit]); + util::generate_transaction_from_edits(doc.text(), vec![edit]); doc.apply(&transaction); // TODO: doc.append_changes_to_history(); if not in insert mode? } @@ -1421,7 +1424,7 @@ pub fn next_view(cx: &mut Context) { // comments pub fn toggle_comments(cx: &mut Context) { let doc = cx.doc(); - let transaction = comment::toggle_line_comments(&doc.state); + let transaction = comment::toggle_line_comments(doc.text(), doc.selection()); doc.apply(&transaction); } diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index b79b05e3..8ba6d901 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -6,7 +6,7 @@ use crate::ui::text_color; use helix_core::{ indent::TAB_WIDTH, syntax::{self, HighlightEvent}, - Position, Range, State, + Position, Range, }; use helix_view::{document::Mode, Document, Editor, Theme, View}; use std::borrow::Cow; diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index eba6478d..ffbe8930 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -346,7 +346,7 @@ mod test { // insert - let transaction = Transaction::insert(&doc.state, " world".into()); + let transaction = Transaction::insert(doc.text(), doc.selection(), " world".into()); let old_doc = doc.state.clone(); doc.apply(&transaction); let changes = Client::changeset_to_changes(&old_doc.doc, doc.text(), transaction.changes()); |