on master help sign in
Optimize LSP snippet parsing
commite973b71c83dcefbdb3a748f28ce3bfd51e9cd842 authorUrgau <urgau@numericable.fr> dateTue 7 Feb 2023, 20:15 (4 years ago) parent9c12e0f
4 files changed+57−19
Cargo.lock−1 helix-lsp/Cargo.toml−1 helix-lsp/src/snippet.rs+28−17 helix-parsec/src/lib.rs+29
Cargo.lock−1
@@ -1141,7 +1141,6 @@ dependencies = [
11411141 "helix-loader",
11421142 "log",
11431143 "lsp-types",
1144− "once_cell",
11451144 "serde",
11461145 "serde_json",
11471146 "thiserror",
helix-lsp/Cargo.toml−1
@@ -27,4 +27,3 @@ thiserror = "1.0"
2727tokio = { version = "1.26", features = ["rt", "rt-multi-thread", "io-util", "io-std", "time", "process", "macros", "fs", "parking_lot", "sync"] }
2828tokio-stream = "0.1.12"
2929which = "4.4"
30−once_cell = "1.15"
helix-lsp/src/snippet.rs+28−17
@@ -50,14 +50,11 @@ pub struct Snippet<'a> {
5050 elements: Vec<SnippetElement<'a>>,
5151}
5252
53−pub fn parse<'a>(s: &'a str) -> Result<Snippet<'a>> {
53+pub fn parse(s: &str) -> Result<Snippet<'_>> {
5454 parser::parse(s).map_err(|rest| anyhow!("Failed to parse snippet. Remaining input: {}", rest))
5555}
5656
5757mod parser {
58− use helix_core::regex;
59− use once_cell::sync::Lazy;
60−
6158 use helix_parsec::*;
6259
6360 use super::{CaseChange, FormatItem, Regex, Snippet, SnippetElement};
@@ -86,17 +83,34 @@ mod parser {
8683 else ::= text
8784 */
8885
89− static DIGIT: Lazy<regex::Regex> = Lazy::new(|| regex::Regex::new(r"^[0-9]+").unwrap());
90− static VARIABLE: Lazy<regex::Regex> =
91− Lazy::new(|| regex::Regex::new(r"^[_a-zA-Z][_a-zA-Z0-9]*").unwrap());
92− static TEXT: Lazy<regex::Regex> = Lazy::new(|| regex::Regex::new(r"^[^\$]+").unwrap());
93−
9486 fn var<'a>() -> impl Parser<'a, Output = &'a str> {
95− pattern(&VARIABLE)
87+ // var = [_a-zA-Z][_a-zA-Z0-9]*
88+ move |input: &'a str| match input
89+ .char_indices()
90+ .take_while(|(p, c)| {
91+ *c == '_'
92+ || if *p == 0 {
93+ c.is_ascii_alphabetic()
94+ } else {
95+ c.is_ascii_alphanumeric()
96+ }
97+ })
98+ .last()
99+ {
100+ Some((index, c)) if index >= 1 => {
101+ let index = index + c.len_utf8();
102+ Ok((&input[index..], &input[0..index]))
103+ }
104+ _ => Err(input),
105+ }
106+ }
107+
108+ fn text<'a>() -> impl Parser<'a, Output = &'a str> {
109+ take_while(|c| c != '$')
96110 }
97111
98112 fn digit<'a>() -> impl Parser<'a, Output = usize> {
99− filter_map(pattern(&DIGIT), |s| s.parse().ok())
113+ filter_map(take_while(|c| c.is_ascii_digit()), |s| s.parse().ok())
100114 }
101115
102116 fn case_change<'a>() -> impl Parser<'a, Output = CaseChange> {
@@ -152,7 +166,7 @@ mod parser {
152166 |seq| { Conditional(seq.1, None, Some(seq.4)) }
153167 ),
154168 // Any text
155− map(pattern(&TEXT), Text),
169+ map(text(), Text),
156170 )
157171 }
158172
@@ -245,12 +259,9 @@ mod parser {
245259 )
246260 }
247261
248− fn text<'a>() -> impl Parser<'a, Output = SnippetElement<'a>> {
249− map(pattern(&TEXT), SnippetElement::Text)
250− }
251−
252262 fn anything<'a>() -> impl Parser<'a, Output = SnippetElement<'a>> {
253− choice!(tabstop(), placeholder(), choice(), variable(), text())
263+ let text = map(text(), SnippetElement::Text);
264+ choice!(tabstop(), placeholder(), choice(), variable(), text)
254265 }
255266
256267 fn snippet<'a>() -> impl Parser<'a, Output = Snippet<'a>> {
helix-parsec/src/lib.rs+29
@@ -157,6 +157,35 @@ where
157157 }
158158}
159159
160+/// A parser which matches all values until the specified pattern no longer match.
161+///
162+/// This parser only ever fails if the input has a length of zero.
163+///
164+/// # Examples
165+///
166+/// ```
167+/// use helix_parsec::{take_while, Parser};
168+/// let parser = take_while(|c| c == '1');
169+/// assert_eq!(Ok(("2", "11")), parser.parse("112"));
170+/// assert_eq!(Err("22"), parser.parse("22"));
171+/// ```
172+pub fn take_while<'a, F>(pattern: F) -> impl Parser<'a, Output = &'a str>
173+where
174+ F: Fn(char) -> bool,
175+{
176+ move |input: &'a str| match input
177+ .char_indices()
178+ .take_while(|(_p, c)| pattern(*c))
179+ .last()
180+ {
181+ Some((index, c)) => {
182+ let index = index + c.len_utf8();
183+ Ok((&input[index..], &input[0..index]))
184+ }
185+ _ => Err(input),
186+ }
187+}
188+
160189// Variadic parser combinators
161190
162191/// A parser combinator which matches a sequence of parsers in an all-or-nothing fashion.