aboutsummaryrefslogtreecommitdiff
path: root/helix-core/src
diff options
context:
space:
mode:
authorBlaž Hrastnik2020-10-09 07:58:43 +0000
committerBlaž Hrastnik2020-10-13 14:13:56 +0000
commit00e661f600b7465750a9bcce8e89eabd5b17b4af (patch)
tree59712ddb43fce8992fabbfeb079f17eac433fb33 /helix-core/src
parent4a648555ed7a61de615baad551bab8f34a5bad74 (diff)
Indent draft, linewise paste
Diffstat (limited to 'helix-core/src')
-rw-r--r--helix-core/src/indent.rs111
-rw-r--r--helix-core/src/lib.rs1
-rw-r--r--helix-core/src/selection.rs1
-rw-r--r--helix-core/src/state.rs3
-rw-r--r--helix-core/src/syntax.rs4
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;