diff options
author | Blaž Hrastnik | 2020-10-22 05:35:07 +0000 |
---|---|---|
committer | Blaž Hrastnik | 2020-12-03 04:10:35 +0000 |
commit | b39849dde1b1277d14dbc4e2e1604e5d020db43d (patch) | |
tree | c247d4f605db00248eaa0a4383c5ec65db5f69cc /helix-core | |
parent | 81ccca0c6a18de86223b8142b5742e0603b9b230 (diff) |
Refactor: Document type as a wrapper around barebones State.
Diffstat (limited to 'helix-core')
-rw-r--r-- | helix-core/src/indent.rs | 29 | ||||
-rw-r--r-- | helix-core/src/state.rs | 81 | ||||
-rw-r--r-- | helix-core/src/syntax.rs | 2 | ||||
-rw-r--r-- | helix-core/src/transaction.rs | 36 |
4 files changed, 24 insertions, 124 deletions
diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs index 2e1a095e..6b9a1ab1 100644 --- a/helix-core/src/indent.rs +++ b/helix-core/src/indent.rs @@ -111,17 +111,17 @@ fn find_first_non_whitespace_char(state: &State, line_num: usize) -> usize { start } -fn suggested_indent_for_line(state: &State, line_num: usize) -> usize { +fn suggested_indent_for_line(syntax: Option<&Syntax>, state: &State, line_num: usize) -> usize { let line = state.doc.line(line_num); let current = indent_level_for_line(line); let start = find_first_non_whitespace_char(state, line_num); - suggested_indent_for_pos(state, start) + suggested_indent_for_pos(syntax, state, start) } -pub fn suggested_indent_for_pos(state: &State, pos: usize) -> usize { - if let Some(syntax) = &state.syntax { +pub fn suggested_indent_for_pos(syntax: Option<&Syntax>, state: &State, pos: usize) -> usize { + if let Some(syntax) = syntax { let byte_start = state.doc.char_to_byte(pos); let node = get_highest_syntax_node_at_bytepos(syntax, byte_start); @@ -163,13 +163,18 @@ mod test { ", ); - let mut state = State::new(doc); - state.set_language("source.rust", &[]); - - assert_eq!(suggested_indent_for_line(&state, 0), 0); // mod - assert_eq!(suggested_indent_for_line(&state, 1), 1); // fn - assert_eq!(suggested_indent_for_line(&state, 2), 2); // 1 + 1 - assert_eq!(suggested_indent_for_line(&state, 4), 1); // } - assert_eq!(suggested_indent_for_line(&state, 5), 0); // } + let state = State::new(doc); + // TODO: set_language + let language_config = crate::syntax::LOADER + .language_config_for_scope("source.rust") + .unwrap(); + let highlight_config = language_config.highlight_config(&[]).unwrap().unwrap(); + let syntax = Syntax::new(&state.doc, highlight_config.clone()); + + assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 0), 0); // mod + assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 1), 1); // fn + assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 2), 2); // 1 + 1 + assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 4), 1); // } + assert_eq!(suggested_indent_for_line(Some(&syntax), &state, 5), 0); // } } } diff --git a/helix-core/src/state.rs b/helix-core/src/state.rs index 75e5cd40..7fd620a5 100644 --- a/helix-core/src/state.rs +++ b/helix-core/src/state.rs @@ -3,34 +3,11 @@ use crate::syntax::LOADER; use crate::{ChangeSet, Diagnostic, Position, Range, Rope, RopeSlice, Selection, Syntax}; use anyhow::Error; -use std::path::PathBuf; - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub enum Mode { - Normal, - Insert, - Goto, -} - /// A state represents the current editor state of a single buffer. pub struct State { // TODO: fields should be private but we need to refactor commands.rs first - /// Path to file on disk. - pub path: Option<PathBuf>, pub doc: Rope, pub selection: Selection, - pub mode: Mode, - - pub restore_cursor: bool, - - // TODO: move these to a Document wrapper? - pub syntax: Option<Syntax>, - /// Pending changes since last history commit. - pub changes: ChangeSet, - pub old_state: Option<(Rope, Selection)>, - - pub version: i64, - pub diagnostics: Vec<Diagnostic>, } #[derive(Copy, Clone, PartialEq, Eq)] @@ -49,60 +26,12 @@ pub enum Granularity { impl State { #[must_use] pub fn new(doc: Rope) -> Self { - let changes = ChangeSet::new(&doc); - let old_state = Some((doc.clone(), Selection::single(0, 0))); - Self { - path: None, doc, selection: Selection::single(0, 0), - mode: Mode::Normal, - restore_cursor: false, - syntax: None, - changes, - old_state, - diagnostics: Vec::new(), - version: 0, } } - // TODO: passing scopes here is awkward - pub fn load(path: PathBuf, scopes: &[String]) -> Result<Self, Error> { - use std::{env, fs::File, io::BufReader}; - let _current_dir = env::current_dir()?; - - let doc = Rope::from_reader(BufReader::new(File::open(path.clone())?))?; - - // TODO: create if not found - - let mut state = Self::new(doc); - - if let Some(language_config) = LOADER.language_config_for_file_name(path.as_path()) { - let highlight_config = language_config.highlight_config(scopes).unwrap().unwrap(); - // TODO: config.configure(scopes) is now delayed, is that ok? - - let syntax = Syntax::new(&state.doc, highlight_config.clone()); - - state.syntax = Some(syntax); - }; - - // canonicalize path to absolute value - state.path = Some(std::fs::canonicalize(path)?); - - Ok(state) - } - - pub fn set_language(&mut self, scope: &str, scopes: &[String]) { - if let Some(language_config) = LOADER.language_config_for_scope(scope) { - let highlight_config = language_config.highlight_config(scopes).unwrap().unwrap(); - // TODO: config.configure(scopes) is now delayed, is that ok? - - let syntax = Syntax::new(&self.doc, highlight_config.clone()); - - self.syntax = Some(syntax); - }; - } - // TODO: doc/selection accessors // TODO: be able to take either Rope or RopeSlice @@ -116,16 +45,6 @@ impl State { &self.selection } - #[inline] - pub fn mode(&self) -> Mode { - self.mode - } - - #[inline] - pub fn path(&self) -> Option<&PathBuf> { - self.path.as_ref() - } - // pub fn doc<R>(&self, range: R) -> RopeSlice // where // R: std::ops::RangeBounds<usize>, diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 02903637..f4826fb4 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -66,7 +66,7 @@ impl LanguageConfiguration { use once_cell::sync::Lazy; -pub(crate) static LOADER: Lazy<Loader> = Lazy::new(Loader::init); +pub static LOADER: Lazy<Loader> = Lazy::new(Loader::init); pub struct Loader { // highlight_names ? diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs index 6f3956aa..9bd8c615 100644 --- a/helix-core/src/transaction.rs +++ b/helix-core/src/transaction.rs @@ -351,22 +351,6 @@ pub struct Transaction { // scroll_into_view } -/// Like std::mem::replace() except it allows the replacement value to be mapped from the -/// original value. -pub fn take_with<T, F>(mut_ref: &mut T, closure: F) -where - F: FnOnce(T) -> T, -{ - use std::{panic, ptr}; - - unsafe { - let old_t = ptr::read(mut_ref); - let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| closure(old_t))) - .unwrap_or_else(|_| ::std::process::abort()); - ptr::write(mut_ref, new_t); - } -} - impl Transaction { /// Create a new, empty transaction. pub fn new(state: &mut State) -> Self { @@ -376,29 +360,21 @@ impl Transaction { } } + pub fn changes(&self) -> &ChangeSet { + &self.changes + } + /// Returns true if applied successfully. pub fn apply(&self, state: &mut State) -> bool { if !self.changes.is_empty() { - // TODO: also avoid mapping the selection if not necessary - - let old_doc = state.doc().clone(); - // apply changes to the document if !self.changes.apply(&mut state.doc) { return false; } - - // Compose this transaction with the previous one - take_with(&mut state.changes, |changes| { - changes.compose(self.changes.clone()).unwrap() - }); - - if let Some(syntax) = &mut state.syntax { - // TODO: no unwrap - syntax.update(&old_doc, &state.doc, &self.changes).unwrap(); - } } + // TODO: also avoid mapping the selection if not necessary + // update the selection: either take the selection specified in the transaction, or map the // current selection through changes. state.selection = self |