Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Syntax-highlight regex prompts #7738

Merged
merged 4 commits into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions helix-core/src/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ impl Default for History {
revisions: vec![Revision {
parent: 0,
last_child: None,
transaction: Transaction::from(ChangeSet::new(&Rope::new())),
inversion: Transaction::from(ChangeSet::new(&Rope::new())),
transaction: Transaction::from(ChangeSet::new("".into())),
inversion: Transaction::from(ChangeSet::new("".into())),
timestamp: Instant::now(),
}],
current: 0,
Expand Down
29 changes: 16 additions & 13 deletions helix-core/src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
diagnostic::Severity,
regex::Regex,
transaction::{ChangeSet, Operation},
Rope, RopeSlice, Tendril,
RopeSlice, Tendril,
};

use ahash::RandomState;
Expand Down Expand Up @@ -818,7 +818,10 @@ impl Loader {
// TODO: content_regex handling conflict resolution
}

pub fn language_config_for_shebang(&self, source: &Rope) -> Option<Arc<LanguageConfiguration>> {
pub fn language_config_for_shebang(
&self,
source: RopeSlice,
) -> Option<Arc<LanguageConfiguration>> {
let line = Cow::from(source.line(0));
static SHEBANG_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(&["^", SHEBANG].concat()).unwrap());
Expand Down Expand Up @@ -928,7 +931,7 @@ fn byte_range_to_str(range: std::ops::Range<usize>, source: RopeSlice) -> Cow<st

impl Syntax {
pub fn new(
source: &Rope,
source: RopeSlice,
config: Arc<HighlightConfiguration>,
loader: Arc<Loader>,
) -> Option<Self> {
Expand Down Expand Up @@ -967,8 +970,8 @@ impl Syntax {

pub fn update(
&mut self,
old_source: &Rope,
source: &Rope,
old_source: RopeSlice,
source: RopeSlice,
changeset: &ChangeSet,
) -> Result<(), Error> {
let mut queue = VecDeque::new();
Expand Down Expand Up @@ -1387,7 +1390,7 @@ impl LanguageLayer {
self.tree.as_ref().unwrap()
}

fn parse(&mut self, parser: &mut Parser, source: &Rope) -> Result<(), Error> {
fn parse(&mut self, parser: &mut Parser, source: RopeSlice) -> Result<(), Error> {
parser
.set_included_ranges(&self.ranges)
.map_err(|_| Error::InvalidRanges)?;
Expand Down Expand Up @@ -1418,7 +1421,7 @@ impl LanguageLayer {
}

pub(crate) fn generate_edits(
old_text: &Rope,
old_text: RopeSlice,
changeset: &ChangeSet,
) -> Vec<tree_sitter::InputEdit> {
use Operation::*;
Expand All @@ -1434,7 +1437,7 @@ pub(crate) fn generate_edits(

// TODO; this is a lot easier with Change instead of Operation.

fn point_at_pos(text: &Rope, pos: usize) -> (usize, Point) {
fn point_at_pos(text: RopeSlice, pos: usize) -> (usize, Point) {
let byte = text.char_to_byte(pos); // <- attempted to index past end
let line = text.char_to_line(pos);
let line_start_byte = text.line_to_byte(line);
Expand Down Expand Up @@ -2529,7 +2532,7 @@ mod test {
let mut cursor = QueryCursor::new();

let config = HighlightConfiguration::new(language, "", "", "").unwrap();
let syntax = Syntax::new(&source, Arc::new(config), Arc::new(loader)).unwrap();
let syntax = Syntax::new(source.slice(..), Arc::new(config), Arc::new(loader)).unwrap();

let root = syntax.tree().root_node();
let mut test = |capture, range| {
Expand Down Expand Up @@ -2603,7 +2606,7 @@ mod test {
fn main() {}
",
);
let syntax = Syntax::new(&source, Arc::new(config), Arc::new(loader)).unwrap();
let syntax = Syntax::new(source.slice(..), Arc::new(config), Arc::new(loader)).unwrap();
let tree = syntax.tree();
let root = tree.root_node();
assert_eq!(root.kind(), "source_file");
Expand All @@ -2630,7 +2633,7 @@ mod test {
&doc,
vec![(6, 11, Some("test".into())), (12, 17, None)].into_iter(),
);
let edits = generate_edits(&doc, transaction.changes());
let edits = generate_edits(doc.slice(..), transaction.changes());
// transaction.apply(&mut state);

assert_eq!(
Expand Down Expand Up @@ -2659,7 +2662,7 @@ mod test {
let mut doc = Rope::from("fn test() {}");
let transaction =
Transaction::change(&doc, vec![(8, 8, Some("a: u32".into()))].into_iter());
let edits = generate_edits(&doc, transaction.changes());
let edits = generate_edits(doc.slice(..), transaction.changes());
transaction.apply(&mut doc);

assert_eq!(doc, "fn test(a: u32) {}");
Expand Down Expand Up @@ -2693,7 +2696,7 @@ mod test {
let language = get_language(language_name).unwrap();

let config = HighlightConfiguration::new(language, "", "", "").unwrap();
let syntax = Syntax::new(&source, Arc::new(config), Arc::new(loader)).unwrap();
let syntax = Syntax::new(source.slice(..), Arc::new(config), Arc::new(loader)).unwrap();

let root = syntax
.tree()
Expand Down
13 changes: 7 additions & 6 deletions helix-core/src/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use ropey::RopeSlice;
use smallvec::SmallVec;

use crate::{Range, Rope, Selection, Tendril};
Expand Down Expand Up @@ -42,7 +43,7 @@ impl ChangeSet {
}

#[must_use]
pub fn new(doc: &Rope) -> Self {
pub fn new(doc: RopeSlice) -> Self {
let len = doc.len_chars();
Self {
changes: Vec::new(),
Expand Down Expand Up @@ -485,7 +486,7 @@ impl Transaction {
/// Create a new, empty transaction.
pub fn new(doc: &Rope) -> Self {
Self {
changes: ChangeSet::new(doc),
changes: ChangeSet::new(doc.slice(..)),
selection: None,
}
}
Expand Down Expand Up @@ -946,9 +947,9 @@ mod test {
#[test]
fn combine_with_empty() {
let empty = Rope::from("");
let a = ChangeSet::new(&empty);
let a = ChangeSet::new(empty.slice(..));

let mut b = ChangeSet::new(&empty);
let mut b = ChangeSet::new(empty.slice(..));
b.insert("a".into());

let changes = a.compose(b);
Expand All @@ -962,9 +963,9 @@ mod test {
const TEST_CASE: &str = "Hello, これはヘリックスエディターです!";

let empty = Rope::from("");
let a = ChangeSet::new(&empty);
let a = ChangeSet::new(empty.slice(..));

let mut b = ChangeSet::new(&empty);
let mut b = ChangeSet::new(empty.slice(..));
b.insert(TEST_CASE.into());

let changes = a.compose(b);
Expand Down
4 changes: 2 additions & 2 deletions helix-core/tests/indent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ fn test_treesitter_indent(file_name: &str, lang_scope: &str) {

let language_config = loader.language_config_for_scope(lang_scope).unwrap();
let highlight_config = language_config.highlight_config(&[]).unwrap();
let syntax = Syntax::new(&doc, highlight_config, std::sync::Arc::new(loader)).unwrap();
let indent_query = language_config.indent_query().unwrap();
let text = doc.slice(..);
let syntax = Syntax::new(text, highlight_config, std::sync::Arc::new(loader)).unwrap();
let indent_query = language_config.indent_query().unwrap();

for i in 0..doc.len_lines() {
let line = text.line(i);
Expand Down
4 changes: 2 additions & 2 deletions helix-term/src/ui/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl Component for SignatureHelp {
});

let sig_text = crate::ui::markdown::highlighted_code_block(
self.signature.clone(),
&self.signature,
&self.language,
Some(&cx.editor.theme),
Arc::clone(&self.config_loader),
Expand Down Expand Up @@ -109,7 +109,7 @@ impl Component for SignatureHelp {
let max_text_width = (viewport.0 - PADDING).min(120);

let signature_text = crate::ui::markdown::highlighted_code_block(
self.signature.clone(),
&self.signature,
&self.language,
None,
Arc::clone(&self.config_loader),
Expand Down
14 changes: 7 additions & 7 deletions helix-term/src/ui/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ use pulldown_cmark::{CodeBlockKind, Event, HeadingLevel, Options, Parser, Tag};

use helix_core::{
syntax::{self, HighlightEvent, InjectionLanguageMarker, Syntax},
Rope,
RopeSlice,
};
use helix_view::{
graphics::{Margin, Rect, Style},
Theme,
};

fn styled_multiline_text<'a>(text: String, style: Style) -> Text<'a> {
fn styled_multiline_text<'a>(text: &str, style: Style) -> Text<'a> {
let spans: Vec<_> = text
.lines()
.map(|line| Span::styled(line.to_string(), style))
Expand All @@ -27,7 +27,7 @@ fn styled_multiline_text<'a>(text: String, style: Style) -> Text<'a> {
}

pub fn highlighted_code_block<'a>(
text: String,
text: &str,
language: &str,
theme: Option<&Theme>,
config_loader: Arc<syntax::Loader>,
Expand All @@ -45,21 +45,21 @@ pub fn highlighted_code_block<'a>(
None => return styled_multiline_text(text, code_style),
};

let rope = Rope::from(text.as_ref());
let ropeslice = RopeSlice::from(text);
let syntax = config_loader
.language_configuration_for_injection_string(&InjectionLanguageMarker::Name(
language.into(),
))
.and_then(|config| config.highlight_config(theme.scopes()))
.and_then(|config| Syntax::new(&rope, config, Arc::clone(&config_loader)));
.and_then(|config| Syntax::new(ropeslice, config, Arc::clone(&config_loader)));

let syntax = match syntax {
Some(s) => s,
None => return styled_multiline_text(text, code_style),
};

let highlight_iter = syntax
.highlight_iter(rope.slice(..), None, None)
.highlight_iter(ropeslice, None, None)
.map(|e| e.unwrap());
let highlight_iter: Box<dyn Iterator<Item = HighlightEvent>> =
if let Some(spans) = additional_highlight_spans {
Expand Down Expand Up @@ -267,7 +267,7 @@ impl Markdown {
CodeBlockKind::Indented => "",
};
let tui_text = highlighted_code_block(
text.to_string(),
&text,
language,
theme,
Arc::clone(&self.config_loader),
Expand Down
6 changes: 2 additions & 4 deletions helix-term/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,14 @@ pub fn regex_prompt(
};

cx.jobs.callback(callback);
} else {
// Update
// TODO: mark command line as error
}
}
}
}
}
},
);
)
.with_language("regex", std::sync::Arc::clone(&cx.editor.syn_loader));
// Calculate initial completion
prompt.recalculate_completion(cx.editor);
// prompt
Expand Down
6 changes: 3 additions & 3 deletions helix-term/src/ui/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,9 +453,9 @@ impl<T: Item + 'static> Picker<T> {
let text = doc.text().clone();
let loader = cx.editor.syn_loader.clone();
let job = tokio::task::spawn_blocking(move || {
let syntax = language_config
.highlight_config(&loader.scopes())
.and_then(|highlight_config| Syntax::new(&text, highlight_config, loader));
let syntax = language_config.highlight_config(&loader.scopes()).and_then(
|highlight_config| Syntax::new(text.slice(..), highlight_config, loader),
);
let callback = move |editor: &mut Editor, compositor: &mut Compositor| {
let Some(syntax) = syntax else {
log::info!("highlighting picker item failed");
Expand Down
45 changes: 26 additions & 19 deletions helix-term/src/ui/prompt.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::compositor::{Component, Compositor, Context, Event, EventResult};
use crate::{alt, ctrl, key, shift, ui};
use helix_core::syntax;
use helix_view::input::KeyEvent;
use helix_view::keyboard::KeyCode;
use std::sync::Arc;
use std::{borrow::Cow, ops::RangeFrom};
use tui::buffer::Buffer as Surface;
use tui::widgets::{Block, Borders, Widget};
Expand Down Expand Up @@ -32,6 +34,7 @@ pub struct Prompt {
callback_fn: CallbackFn,
pub doc_fn: DocFn,
next_char_handler: Option<PromptCharHandler>,
language: Option<(&'static str, Arc<syntax::Loader>)>,
}

#[derive(Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -83,6 +86,7 @@ impl Prompt {
callback_fn: Box::new(callback_fn),
doc_fn: Box::new(|_| None),
next_char_handler: None,
language: None,
}
}

Expand All @@ -94,6 +98,11 @@ impl Prompt {
self
}

pub fn with_language(mut self, language: &'static str, loader: Arc<syntax::Loader>) -> Self {
self.language = Some((language, loader));
self
}

pub fn line(&self) -> &String {
&self.line
}
Expand Down Expand Up @@ -456,30 +465,28 @@ impl Prompt {
// render buffer text
surface.set_string(area.x, area.y + line, &self.prompt, prompt_color);

let (input, is_suggestion): (Cow<str>, bool) = if self.line.is_empty() {
// latest value in the register list
match self
let line_area = area.clip_left(self.prompt.len() as u16).clip_top(line);
if self.line.is_empty() {
// Show the most recently entered value as a suggestion.
if let Some(suggestion) = self
.history_register
.and_then(|reg| cx.editor.registers.last(reg))
.map(|entry| entry.into())
{
Some(value) => (value, true),
None => (Cow::from(""), false),
surface.set_string(line_area.x, line_area.y, suggestion, suggestion_color);
}
} else if let Some((language, loader)) = self.language.as_ref() {
let mut text: ui::text::Text = crate::ui::markdown::highlighted_code_block(
&self.line,
language,
Some(&cx.editor.theme),
loader.clone(),
None,
)
.into();
text.render(line_area, surface, cx);
} else {
(self.line.as_str().into(), false)
};

surface.set_string(
area.x + self.prompt.len() as u16,
area.y + line,
&input,
if is_suggestion {
suggestion_color
} else {
prompt_color
},
);
surface.set_string(line_area.x, line_area.y, self.line.clone(), prompt_color);
}
}
}

Expand Down
Loading