aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2020-09-09 06:48:25 +0000
committerBlaž Hrastnik2020-09-09 06:48:25 +0000
commit25b3f98e3d200ae7f0f08b10be50552359502494 (patch)
tree65954db941916fe6d892ef9201d0c1a43351aa48
parent7eac12a4bb02aaa96f63de612077a12df1d5fedc (diff)
draft: tree-sitter highlighting
-rw-r--r--Cargo.lock13
-rw-r--r--helix-core/src/state.rs11
-rw-r--r--helix-term/Cargo.toml2
-rw-r--r--helix-term/src/editor.rs115
4 files changed, 141 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0385b9d3..6334ee8b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -393,8 +393,11 @@ dependencies = [
"argh",
"crossterm",
"helix-core",
+ "helix-syntax",
"num_cpus",
"smol",
+ "tree-sitter",
+ "tree-sitter-highlight",
"tui",
]
@@ -717,6 +720,16 @@ dependencies = [
]
[[package]]
+name = "tree-sitter-highlight"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6e3c800ac0db1562a045a4893cbbd7c484eb93426cae5632f9e5d24dd588cd1"
+dependencies = [
+ "regex",
+ "tree-sitter",
+]
+
+[[package]]
name = "tui"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/helix-core/src/state.rs b/helix-core/src/state.rs
index 67f23009..5f941fb5 100644
--- a/helix-core/src/state.rs
+++ b/helix-core/src/state.rs
@@ -81,6 +81,17 @@ impl State {
// foldable
// changeFilter/transactionFilter
+ // TODO: move that accepts a boundary matcher fn/list, we keep incrementing until we hit
+ // a boundary
+
+ // TODO: edits, does each keypress trigger a full command? I guess it's adding to the same
+ // transaction
+ // There should be three pieces of the state: current transaction, the original doc, "preview"
+ // of the new state.
+ // 1. apply the newly generated keypress as a transaction
+ // 2. compose onto a ongoing transaction
+ // 3. on insert mode leave, that transaction gets stored into undo history
+
pub fn move_pos(
&self,
pos: usize,
diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml
index ce3add5c..dcb01c1d 100644
--- a/helix-term/Cargo.toml
+++ b/helix-term/Cargo.toml
@@ -24,3 +24,5 @@ crossterm = { version = "0.17", features = ["event-stream"] }
smol = "1"
num_cpus = "1.13.0"
tui = { version = "0.10.0", default-features = false, features = ["crossterm"] }
+tree-sitter = "0.16.1"
+tree-sitter-highlight = "0.2.0"
diff --git a/helix-term/src/editor.rs b/helix-term/src/editor.rs
index e019b5ba..1b58c46d 100644
--- a/helix-term/src/editor.rs
+++ b/helix-term/src/editor.rs
@@ -216,3 +216,118 @@ impl Editor {
Ok(())
}
}
+
+// TODO: language configs:
+// tabSize, fileExtension etc, mapping to tree sitter parser
+// themes:
+// map tree sitter highlights to color values
+//
+// TODO: expand highlight thing so we're able to render only viewport range
+// TODO: async: maybe pre-cache scopes as empty so we render all graphemes initially as regular
+////text until calc finishes
+// TODO: scope matching: biggest union match? [string] & [html, string], [string, html] & [ string, html]
+// can do this by sorting our theme matches based on array len (longest first) then stopping at the
+// first rule that matches (rule.all(|scope| scopes.contains(scope)))
+//
+// let visual_x = 0;
+// let line = ?;
+// for span in spans {
+// start(scope) => scopes.push(scope)
+// span =>
+// let text = rope.slice(span.start..span.end);
+// let style = calculate_style(scopes);
+// for each grapheme in text.graphemes() {
+// // if newline += lines, continue
+//
+// if state.selection.ranges().any(|range| range.contains(char_index)) {
+// if exactly on cursor {
+// }
+// if on primary cursor? {
+// }
+// modify style temporarily
+// }
+//
+// // if in bounds
+//
+// // if tab, draw tab width
+// // draw(visual_x, line, grapheme, style)
+// // increment visual_x by grapheme_width(grapheme)
+// // increment char_index by grapheme.len_chars()
+// }
+// end => scopes.pop()
+// }
+#[test]
+fn test_parser() {
+ use tree_sitter_highlight::{HighlightConfiguration, HighlightEvent, Highlighter};
+
+ let source_code = include_str!("./main.rs");
+
+ let highlight_names: Vec<String> = [
+ "attribute",
+ "constant",
+ "function.builtin",
+ "function",
+ "keyword",
+ "operator",
+ "property",
+ "punctuation",
+ "punctuation.bracket",
+ "punctuation.delimiter",
+ "string",
+ "string.special",
+ "tag",
+ "type",
+ "type.builtin",
+ "variable",
+ "variable.builtin",
+ "variable.parameter",
+ ]
+ .iter()
+ .cloned()
+ .map(String::from)
+ .collect();
+
+ let language = helix_syntax::get_language(&helix_syntax::LANG::Rust);
+ // let mut parser = tree_sitter::Parser::new();
+ // parser.set_language(language).unwrap();
+ // let tree = parser.parse(source_code, None).unwrap();
+
+ let mut highlighter = Highlighter::new();
+
+ let mut config = HighlightConfiguration::new(
+ language,
+ &std::fs::read_to_string(
+ "../helix-syntax/languages/tree-sitter-rust/queries/highlights.scm",
+ )
+ .unwrap(),
+ &std::fs::read_to_string(
+ "../helix-syntax/languages/tree-sitter-rust/queries/injections.scm",
+ )
+ .unwrap(),
+ "", // locals.scm
+ )
+ .unwrap();
+
+ config.configure(&highlight_names);
+
+ let highlights = highlighter
+ .highlight(&config, source_code.as_bytes(), None, |_| None)
+ .unwrap();
+
+ for event in highlights {
+ match event.unwrap() {
+ HighlightEvent::Source { start, end } => {
+ eprintln!("source: {}-{}", start, end);
+ // iterate over range char by char
+ }
+ HighlightEvent::HighlightStart(s) => {
+ eprintln!("highlight style started: {:?}", highlight_names[s.0]);
+ // store/push highlight styles
+ }
+ HighlightEvent::HighlightEnd => {
+ eprintln!("highlight style ended");
+ // pop highlight styles
+ }
+ }
+ }
+}