From b17a77b8b84b1dfdbc1615a652e9718d847ea0de Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Fri, 11 Sep 2020 14:14:44 +0900 Subject: cleanup: Import tree-sitter-highlight so we can cache trees. --- helix-term/src/editor.rs | 215 ++++++++++++++++++++--------------------------- helix-term/src/main.rs | 1 + helix-term/src/theme.rs | 59 +++++++++++++ 3 files changed, 153 insertions(+), 122 deletions(-) create mode 100644 helix-term/src/theme.rs (limited to 'helix-term/src') diff --git a/helix-term/src/editor.rs b/helix-term/src/editor.rs index f7abc806..af18842d 100644 --- a/helix-term/src/editor.rs +++ b/helix-term/src/editor.rs @@ -1,5 +1,21 @@ -use crate::{keymap, Args}; +use crate::{keymap, theme::Theme, Args}; +use helix_core::{ + language_mode::{HighlightConfiguration, HighlightEvent, Highlighter}, + state::coords_at_pos, + state::Mode, + State, +}; + +use std::{ + io::{self, stdout, Write}, + path::PathBuf, + time::Duration, +}; + +use smol::prelude::*; + use anyhow::Error; + use crossterm::{ cursor, cursor::position, @@ -9,17 +25,7 @@ use crossterm::{ terminal::{self, disable_raw_mode, enable_raw_mode}, }; -use helix_core::{state::coords_at_pos, state::Mode, State}; -use smol::prelude::*; -use std::collections::HashMap; -use std::io::{self, stdout, Write}; -use std::path::PathBuf; -use std::time::Duration; - -use tui::backend::CrosstermBackend; -use tui::buffer::Buffer as Surface; -use tui::layout::Rect; -use tui::style::Style; +use tui::{backend::CrosstermBackend, buffer::Buffer as Surface, layout::Rect, style::Style}; type Terminal = tui::Terminal>; @@ -31,7 +37,10 @@ pub struct Editor { first_line: u16, size: (u16, u16), surface: Surface, - theme: HashMap<&'static str, Style>, + theme: Theme, + highlighter: Highlighter, + highlight_config: HighlightConfiguration, + highlight_names: Vec, } impl Editor { @@ -42,43 +51,60 @@ impl Editor { let size = terminal::size().unwrap(); let area = Rect::new(0, 0, size.0, size.1); - use tui::style::Color; - let theme = hashmap! { - "attribute" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac - "keyword" => Style::default().fg(Color::Rgb(236, 205, 186)), // almond - "punctuation" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender - "punctuation.delimiter" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender - "operator" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac - "property" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender - "variable.parameter" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender - // TODO distinguish type from type.builtin? - "type" => Style::default().fg(Color::Rgb(255, 255, 255)), // white - "type.builtin" => Style::default().fg(Color::Rgb(255, 255, 255)), // white - "constructor" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac - "function" => Style::default().fg(Color::Rgb(255, 255, 255)), // white - "function.macro" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac - "comment" => Style::default().fg(Color::Rgb(105, 124, 129)), // sirocco - "variable.builtin" => Style::default().fg(Color::Rgb(159, 242, 143)), // mint - "constant" => Style::default().fg(Color::Rgb(255, 255, 255)), // white - "constant.builtin" => Style::default().fg(Color::Rgb(255, 255, 255)), // white - "string" => Style::default().fg(Color::Rgb(204, 204, 204)), // silver - "escape" => Style::default().fg(Color::Rgb(239, 186, 93)), // honey - // used for lifetimes - "label" => Style::default().fg(Color::Rgb(239, 186, 93)), // honey - - // TODO: diferentiate number builtin - // TODO: diferentiate doc comment - // TODO: variable as lilac - // TODO: mod/use statements as white - // TODO: mod stuff as chamoise - // TODO: add "(scoped_identifier) @path" for std::mem:: - // - // concat (ERROR) @syntax-error and "MISSING ;" selectors for errors - - "module" => Style::default().fg(Color::Rgb(255, 0, 0)), // white - "variable" => Style::default().fg(Color::Rgb(255, 0, 0)), // white - "function.builtin" => Style::default().fg(Color::Rgb(255, 0, 0)), // white - }; + let highlight_names: Vec = [ + "attribute", + "constant.builtin", + "constant", + "function.builtin", + "function.macro", + "function", + "keyword", + "operator", + "property", + "punctuation", + "comment", + "escape", + "label", + // "punctuation.bracket", + "punctuation.delimiter", + "string", + "string.special", + "tag", + "type", + "type.builtin", + "constructor", + "variable", + "variable.builtin", + "variable.parameter", + "path", + ] + .iter() + .map(|s| s.to_string()) + .collect(); + + // let mut parser = tree_sitter::Parser::new(); + // parser.set_language(language).unwrap(); + // let tree = parser.parse(source_code, None).unwrap(); + + let language = helix_syntax::get_language(&helix_syntax::LANG::Rust); + + let highlighter = Highlighter::new(); + + let mut highlight_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(); + + highlight_config.configure(&highlight_names); let mut editor = Editor { terminal, @@ -86,7 +112,11 @@ impl Editor { first_line: 0, size, surface: Surface::empty(area), - theme, + theme: Theme::default(), + // TODO; move to state + highlighter, + highlight_config, + highlight_names, }; if let Some(file) = args.files.pop() { @@ -108,72 +138,16 @@ impl Editor { let mut surface = Surface::empty(area); let mut stdout = stdout(); - // - use tree_sitter_highlight::{HighlightConfiguration, HighlightEvent, Highlighter}; - - let highlight_names: Vec = [ - "attribute", - "constant.builtin", - "constant", - "function.builtin", - "function.macro", - "function", - "keyword", - "operator", - "property", - "punctuation", - "comment", - "escape", - "label", - // "punctuation.bracket", - "punctuation.delimiter", - "string", - "string.special", - "tag", - "type", - "type.builtin", - "constructor", - "variable", - "variable.builtin", - "variable.parameter", - "path", - ] - .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); - - // TODO: inefficient, should feed chunks.iter() to tree_sitter.parse_with(|offset, - // pos|) + // TODO: inefficient, should feed chunks.iter() to tree_sitter.parse_with(|offset, pos|) let source_code = state.doc.to_string(); // TODO: cache highlight results // TODO: only recalculate when state.doc is actually modified - let highlights = highlighter - .highlight(&config, source_code.as_bytes(), None, |_| None) + let highlights = self + .highlighter + .highlight(&self.highlight_config, source_code.as_bytes(), None, |_| { + None + }) .unwrap(); let mut spans = Vec::new(); @@ -186,12 +160,10 @@ impl Editor { for event in highlights { match event.unwrap() { HighlightEvent::HighlightStart(span) => { - // eprintln!("highlight style started: {:?}", highlight_names[span.0]); spans.push(span); } HighlightEvent::HighlightEnd => { spans.pop(); - // eprintln!("highlight style ended"); } HighlightEvent::Source { start, end } => { // TODO: filter out spans out of viewport for now.. @@ -204,17 +176,16 @@ impl Editor { use helix_core::graphemes::{grapheme_width, RopeGraphemes}; use tui::style::Color; - let style = match spans.first() { - Some(span) => self - .theme - .get(highlight_names[span.0].as_str()) - .map(|style| *style) - .unwrap_or(Style::default().fg(Color::Rgb(0, 0, 255))), + let style = match spans.first() { + Some(span) => self.theme.get(self.highlight_names[span.0].as_str()), None => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender - // None => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac }; + // TODO: we could render the text to a surface, then cache that, that + // way if only the selection/cursor changes we can copy from cache + // and paint the new cursor. + // iterate over range char by char for grapheme in RopeGraphemes::new(&text) { // TODO: track current char_index diff --git a/helix-term/src/main.rs b/helix-term/src/main.rs index e3c16c14..d6c6c499 100644 --- a/helix-term/src/main.rs +++ b/helix-term/src/main.rs @@ -3,6 +3,7 @@ mod macros; mod editor; mod keymap; +mod theme; use editor::Editor; diff --git a/helix-term/src/theme.rs b/helix-term/src/theme.rs new file mode 100644 index 00000000..0353f0e6 --- /dev/null +++ b/helix-term/src/theme.rs @@ -0,0 +1,59 @@ +use std::collections::HashMap; +use tui::style::{Color, Style}; + +/// Color theme for syntax highlighting. +pub struct Theme { + mapping: HashMap<&'static str, Style>, +} + +impl Default for Theme { + fn default() -> Self { + let mapping = hashmap! { + "attribute" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac + "keyword" => Style::default().fg(Color::Rgb(236, 205, 186)), // almond + "punctuation" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender + "punctuation.delimiter" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender + "operator" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac + "property" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender + "variable.parameter" => Style::default().fg(Color::Rgb(164, 160, 232)), // lavender + // TODO distinguish type from type.builtin? + "type" => Style::default().fg(Color::Rgb(255, 255, 255)), // white + "type.builtin" => Style::default().fg(Color::Rgb(255, 255, 255)), // white + "constructor" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac + "function" => Style::default().fg(Color::Rgb(255, 255, 255)), // white + "function.macro" => Style::default().fg(Color::Rgb(219, 191, 239)), // lilac + "comment" => Style::default().fg(Color::Rgb(105, 124, 129)), // sirocco + "variable.builtin" => Style::default().fg(Color::Rgb(159, 242, 143)), // mint + "constant" => Style::default().fg(Color::Rgb(255, 255, 255)), // white + "constant.builtin" => Style::default().fg(Color::Rgb(255, 255, 255)), // white + "string" => Style::default().fg(Color::Rgb(204, 204, 204)), // silver + "escape" => Style::default().fg(Color::Rgb(239, 186, 93)), // honey + // used for lifetimes + "label" => Style::default().fg(Color::Rgb(239, 186, 93)), // honey + + // TODO: diferentiate number builtin + // TODO: diferentiate doc comment + // TODO: variable as lilac + // TODO: mod/use statements as white + // TODO: mod stuff as chamoise + // TODO: add "(scoped_identifier) @path" for std::mem:: + // + // concat (ERROR) @syntax-error and "MISSING ;" selectors for errors + + "module" => Style::default().fg(Color::Rgb(255, 0, 0)), // white + "variable" => Style::default().fg(Color::Rgb(255, 0, 0)), // white + "function.builtin" => Style::default().fg(Color::Rgb(255, 0, 0)), // white + }; + + Self { mapping } + } +} + +impl Theme { + pub fn get(&self, scope: &str) -> Style { + self.mapping + .get(scope) + .copied() + .unwrap_or_else(|| Style::default().fg(Color::Rgb(0, 0, 255))) + } +} -- cgit v1.2.3-70-g09d2