mirror of
https://github.com/nushell/nushell.git
synced 2024-12-22 07:02:19 +01:00
Syntax highlighting
This commit is contained in:
parent
c523ae0f48
commit
9a639fd27b
@ -14,7 +14,7 @@ use parser::PipelineParser;
|
||||
|
||||
pub fn parse(input: &str, _registry: &dyn CommandRegistry) -> Result<Pipeline, ShellError> {
|
||||
let parser = PipelineParser::new();
|
||||
let tokens = Lexer::new(input);
|
||||
let tokens = Lexer::new(input, false);
|
||||
|
||||
match parser.parse(tokens) {
|
||||
Ok(val) => Ok(val),
|
||||
|
@ -375,14 +375,15 @@ pub enum Token {
|
||||
crate struct Lexer<'source> {
|
||||
lexer: logos::Lexer<TopToken, &'source str>,
|
||||
first: bool,
|
||||
// state: LexerState,
|
||||
whitespace: bool, // state: LexerState
|
||||
}
|
||||
|
||||
impl Lexer<'source> {
|
||||
crate fn new(source: &str) -> Lexer<'_> {
|
||||
crate fn new(source: &str, whitespace: bool) -> Lexer<'_> {
|
||||
Lexer {
|
||||
first: true,
|
||||
lexer: logos::Logos::lexer(source),
|
||||
whitespace
|
||||
// state: LexerState::default(),
|
||||
}
|
||||
}
|
||||
@ -400,7 +401,7 @@ impl Iterator for Lexer<'source> {
|
||||
TopToken::Error => {
|
||||
return Some(Err(lex_error(&self.lexer.range(), self.lexer.source)))
|
||||
}
|
||||
TopToken::Whitespace => return self.next(),
|
||||
TopToken::Whitespace if !self.whitespace => return self.next(),
|
||||
other => {
|
||||
return spanned(other.to_token()?, self.lexer.slice(), &self.lexer.range())
|
||||
}
|
||||
@ -415,7 +416,7 @@ impl Iterator for Lexer<'source> {
|
||||
|
||||
match token {
|
||||
TopToken::Error => return Some(Err(lex_error(&range, self.lexer.source))),
|
||||
TopToken::Whitespace => return self.next(),
|
||||
TopToken::Whitespace if !self.whitespace => return self.next(),
|
||||
other => return spanned(other.to_token()?, slice, &range),
|
||||
}
|
||||
}
|
||||
@ -429,7 +430,7 @@ impl Iterator for Lexer<'source> {
|
||||
AfterMemberDot::Error => {
|
||||
return Some(Err(lex_error(&range, self.lexer.source)))
|
||||
}
|
||||
AfterMemberDot::Whitespace => self.next(),
|
||||
AfterMemberDot::Whitespace if !self.whitespace => self.next(),
|
||||
other => return spanned(other.to_token()?, slice, &range),
|
||||
}
|
||||
}
|
||||
@ -443,7 +444,7 @@ impl Iterator for Lexer<'source> {
|
||||
AfterVariableToken::Error => {
|
||||
return Some(Err(lex_error(&range, self.lexer.source)))
|
||||
}
|
||||
AfterVariableToken::Whitespace => self.next(),
|
||||
AfterVariableToken::Whitespace if !self.whitespace => self.next(),
|
||||
|
||||
other => return spanned(other.to_token()?, slice, &range),
|
||||
}
|
||||
@ -508,7 +509,7 @@ mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
fn assert_lex(source: &str, tokens: &[TestToken<'_>]) {
|
||||
let lex = Lexer::new(source);
|
||||
let lex = Lexer::new(source, false);
|
||||
let mut current = 0;
|
||||
|
||||
let expected_tokens: Vec<SpannedToken> = tokens
|
||||
|
@ -1,15 +1,17 @@
|
||||
use crate::shell::completer::NuCompleter;
|
||||
|
||||
use crate::parser::lexer::SpannedToken;
|
||||
use crate::prelude::*;
|
||||
use ansi_term::Color;
|
||||
use log::debug;
|
||||
use rustyline::completion::{self, Completer, FilenameCompleter};
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::highlight::{Highlighter, MatchingBracketHighlighter};
|
||||
use rustyline::highlight::Highlighter;
|
||||
use rustyline::hint::{Hinter, HistoryHinter};
|
||||
use std::borrow::Cow::{self, Owned};
|
||||
|
||||
crate struct Helper {
|
||||
completer: NuCompleter,
|
||||
highlighter: MatchingBracketHighlighter,
|
||||
hinter: HistoryHinter,
|
||||
}
|
||||
|
||||
@ -20,7 +22,6 @@ impl Helper {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
commands,
|
||||
},
|
||||
highlighter: MatchingBracketHighlighter::new(),
|
||||
hinter: HistoryHinter {},
|
||||
}
|
||||
}
|
||||
@ -54,12 +55,78 @@ impl Highlighter for Helper {
|
||||
Owned("\x1b[1m".to_owned() + hint + "\x1b[m")
|
||||
}
|
||||
|
||||
fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
|
||||
self.highlighter.highlight(line, pos)
|
||||
fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> {
|
||||
let tokens = crate::parser::lexer::Lexer::new(line, true);
|
||||
let tokens: Result<Vec<(usize, SpannedToken, usize)>, _> = tokens.collect();
|
||||
|
||||
match tokens {
|
||||
Err(_) => Cow::Borrowed(line),
|
||||
Ok(v) => {
|
||||
let mut out = String::new();
|
||||
let mut iter = v.iter();
|
||||
|
||||
let mut state = State::Command;
|
||||
|
||||
loop {
|
||||
match iter.next() {
|
||||
None => return Cow::Owned(out),
|
||||
Some((start, token, end)) => {
|
||||
let (style, new_state) = token_style(&token, state);
|
||||
|
||||
debug!("token={:?}", token);
|
||||
debug!("style={:?}", style);
|
||||
debug!("new_state={:?}", new_state);
|
||||
|
||||
state = new_state;
|
||||
let slice = &line[*start..*end];
|
||||
let styled = style.paint(slice);
|
||||
out.push_str(&styled.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn highlight_char(&self, line: &str, pos: usize) -> bool {
|
||||
self.highlighter.highlight_char(line, pos)
|
||||
fn highlight_char(&self, _line: &str, _pos: usize) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum State {
|
||||
Command,
|
||||
Flag,
|
||||
Var,
|
||||
Bare,
|
||||
None,
|
||||
}
|
||||
|
||||
fn token_style(
|
||||
token: &crate::parser::lexer::SpannedToken,
|
||||
state: State,
|
||||
) -> (ansi_term::Style, State) {
|
||||
use crate::parser::lexer::Token::*;
|
||||
|
||||
match (state, &token.token) {
|
||||
(State::Command, Bare) => (Color::Cyan.bold(), State::None),
|
||||
(State::Command, Whitespace) => (Color::White.normal(), State::Command),
|
||||
|
||||
(State::Flag, Bare) => (Color::Black.bold(), State::None),
|
||||
|
||||
(State::Var, Variable) => (Color::Yellow.bold(), State::None),
|
||||
|
||||
(State::Bare, Dot) => (Color::Green.normal(), State::Bare),
|
||||
(State::Bare, Member) => (Color::Green.normal(), State::Bare),
|
||||
|
||||
(_, Dash) | (_, DashDash) => (Color::Black.bold(), State::Flag),
|
||||
(_, Dollar) => (Color::Yellow.bold(), State::Var),
|
||||
(_, Bare) => (Color::Green.normal(), State::Bare),
|
||||
(_, Member) => (Color::Cyan.normal(), State::None),
|
||||
(_, Num) => (Color::Purple.bold(), State::None),
|
||||
(_, DQString) | (_, SQString) => (Color::Green.normal(), State::None),
|
||||
(_, Pipe) => (Color::White.normal(), State::Command),
|
||||
_ => (Color::White.normal(), State::None),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user