aboutsummaryrefslogtreecommitdiff
path: root/helix-core
diff options
context:
space:
mode:
authorBlaž Hrastnik2020-10-22 05:35:07 +0000
committerBlaž Hrastnik2020-12-03 04:10:35 +0000
commitb39849dde1b1277d14dbc4e2e1604e5d020db43d (patch)
treec247d4f605db00248eaa0a4383c5ec65db5f69cc /helix-core
parent81ccca0c6a18de86223b8142b5742e0603b9b230 (diff)
Refactor: Document type as a wrapper around barebones State.
Diffstat (limited to 'helix-core')
-rw-r--r--helix-core/src/indent.rs29
-rw-r--r--helix-core/src/state.rs81
-rw-r--r--helix-core/src/syntax.rs2
-rw-r--r--helix-core/src/transaction.rs36
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