diff options
author | Blaž Hrastnik | 2020-10-09 07:58:43 +0000 |
---|---|---|
committer | Blaž Hrastnik | 2020-10-13 14:13:56 +0000 |
commit | 00e661f600b7465750a9bcce8e89eabd5b17b4af (patch) | |
tree | 59712ddb43fce8992fabbfeb079f17eac433fb33 /helix-core | |
parent | 4a648555ed7a61de615baad551bab8f34a5bad74 (diff) |
Indent draft, linewise paste
Diffstat (limited to 'helix-core')
-rw-r--r-- | helix-core/src/indent.rs | 111 | ||||
-rw-r--r-- | helix-core/src/lib.rs | 1 | ||||
-rw-r--r-- | helix-core/src/selection.rs | 1 | ||||
-rw-r--r-- | helix-core/src/state.rs | 3 | ||||
-rw-r--r-- | helix-core/src/syntax.rs | 4 |
5 files changed, 116 insertions, 4 deletions
diff --git a/helix-core/src/indent.rs b/helix-core/src/indent.rs new file mode 100644 index 00000000..c1a4fd6c --- /dev/null +++ b/helix-core/src/indent.rs @@ -0,0 +1,111 @@ +use crate::{ + syntax::Syntax, + tree_sitter::{Node, Tree}, + Rope, RopeSlice, State, +}; + +const TAB_WIDTH: usize = 4; + +fn indent_level_for_line(line: RopeSlice) -> usize { + let mut len = 0; + for ch in line.chars() { + match ch { + '\t' => len += TAB_WIDTH, + ' ' => len += 1, + _ => break, + } + } + + len / TAB_WIDTH +} + +/// Find the highest syntax node at position. +/// This is to identify the column where this node (e.g., an HTML closing tag) ends. +fn get_highest_syntax_node_at_bytepos(syntax: &Syntax, pos: usize) -> Option<Node> { + let tree = syntax.root_layer.tree.as_ref().unwrap(); + + let mut node = match tree.root_node().named_descendant_for_byte_range(pos, pos) { + Some(node) => node, + None => return None, + }; + + while let Some(parent) = node.parent() { + if parent.start_byte() == node.start_byte() { + node = parent + } else { + break; + } + } + + Some(node) +} + +fn walk(node: Option<Node>) -> usize { + let node = match node { + Some(node) => node, + None => return 0, + }; + + let parent = match node.parent() { + Some(node) => node, + None => return 0, + }; + + let mut increment = 0; + + let not_first_or_last_sibling = node.next_sibling().is_some() && node.prev_sibling().is_some(); + let is_scope = true; + + if not_first_or_last_sibling && is_scope { + increment += 1; + } + + walk(Some(parent)) + increment +} + +// for_line_at_col +fn suggested_indent_for_line(state: &State, line_num: usize) -> usize { + let line = state.doc.line(line_num); + let current = indent_level_for_line(line); + + let mut byte_start = state.doc.line_to_byte(line_num); + + // find first non-whitespace char + for ch in line.chars() { + // TODO: could use memchr with chunks? + if ch != ' ' && ch != '\t' { + break; + } + byte_start += 1; + } + + if let Some(syntax) = &state.syntax { + let node = get_highest_syntax_node_at_bytepos(state.syntax.as_ref().unwrap(), byte_start); + + // let indentation = walk() + // special case for comments + + // if preserve_leading_whitespace + + unimplemented!() + } else { + // TODO: case for non-tree sitter grammars + 0 + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn indent_level() { + let line = Rope::from(" fn new"); // 8 spaces + assert_eq!(indent_level_for_line(line.slice(..)), 2); + let line = Rope::from("\t\t\tfn new"); // 3 tabs + assert_eq!(indent_level_for_line(line.slice(..)), 3); + // mixed indentation + let line = Rope::from("\t \tfn new"); // 1 tab, 4 spaces, tab + assert_eq!(indent_level_for_line(line.slice(..)), 3); + } +} diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs index 4a7a2dd4..ccdc7297 100644 --- a/helix-core/src/lib.rs +++ b/helix-core/src/lib.rs @@ -1,6 +1,7 @@ #![allow(unused)] pub mod graphemes; mod history; +mod indent; pub mod macros; mod position; pub mod register; diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index bc677330..d3806cf3 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -110,7 +110,6 @@ impl Range { #[inline] pub fn fragment<'a>(&'a self, text: &'a RopeSlice) -> Cow<'a, str> { - // end inclusive Cow::from(text.slice(self.from()..self.to() + 1)) } } diff --git a/helix-core/src/state.rs b/helix-core/src/state.rs index fde6a866..7035b27c 100644 --- a/helix-core/src/state.rs +++ b/helix-core/src/state.rs @@ -47,6 +47,7 @@ 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, @@ -56,7 +57,7 @@ impl State { restore_cursor: false, syntax: None, changes, - old_state: None, + old_state, } } diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 3e5927e5..290f2652 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -146,7 +146,7 @@ pub struct Syntax { config: Arc<HighlightConfiguration>, - root_layer: LanguageLayer, + pub(crate) root_layer: LanguageLayer, } impl Syntax { @@ -309,7 +309,7 @@ pub struct LanguageLayer { // mode // grammar // depth - tree: Option<Tree>, + pub(crate) tree: Option<Tree>, } use crate::state::coords_at_pos; |