Skip to content

Commit

Permalink
Add some basic syntax highlighting for code snippets
Browse files Browse the repository at this point in the history
Issue #4
  • Loading branch information
davidlattimore committed Aug 21, 2023
1 parent 8c04c06 commit e0954fa
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 18 deletions.
47 changes: 29 additions & 18 deletions src/ui/full_term/problems_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ use std::sync::Arc;
use std::sync::MutexGuard;

mod diff;
mod syntax_styling;

pub(super) struct ProblemsUi {
problem_store: ProblemStoreRef,
Expand Down Expand Up @@ -538,29 +539,39 @@ fn usage_source_lines(usage: &dyn DisplayUsage) -> Result<Vec<Line<'static>>> {
"{marker}{:gutter_width$}: ",
line_number
))];
if line_number == target_line {
if let Some(column) = source_location.column() {
let column = column as usize - 1;
spans.push(Span::from(line[..column].to_owned()));
spans.push(Span::styled(
line[column..column + 1].to_owned(),
Style::default().add_modifier(Modifier::REVERSED),
));
spans.push(Span::from(line[column + 1..].to_owned()));
} else {
spans.push(Span::styled(
line.to_owned(),
Style::default().add_modifier(Modifier::UNDERLINED),
));
}
} else {
spans.push(Span::from(line.to_owned()));
}
let column = (line_number == target_line)
.then(|| source_location.column())
.flatten();
format_line(&mut spans, column, line);
lines.push(Line::from(spans));
}
Ok(lines)
}

fn format_line(out: &mut Vec<Span>, column: Option<u32>, line: &str) {
let mut rev = false;
let mut offset = 0;
let column_offset = column.map(|c| (c as usize).saturating_sub(1));
for token in rustc_ap_rustc_lexer::tokenize(line) {
let new_offset = offset + token.len;
let token_text = &line[offset..new_offset];
let mut style = Style::default();
if let Some(colour) = syntax_styling::colour_for_token_kind(token.kind, token_text) {
style = style.fg(colour);
}
if column_offset
.map(|c| (offset..new_offset).contains(&c))
.unwrap_or(false)
{
rev = true;
style = style.add_modifier(Modifier::REVERSED);
}
out.push(Span::styled(token_text.to_owned(), style));
offset = new_offset;
}
log::info!("col={column:?} line.len={} rev={rev:?}", line.len());
}

fn render_help(f: &mut Frame<CrosstermBackend<Stdout>>, mode: Option<&Mode>) {
let mut keys = vec![];
let mut title = "Help";
Expand Down
42 changes: 42 additions & 0 deletions src/ui/full_term/problems_ui/syntax_styling.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use ratatui::style::Color;
use rustc_ap_rustc_lexer::LiteralKind;
use rustc_ap_rustc_lexer::TokenKind;

pub(super) fn colour_for_token_kind(kind: TokenKind, token_text: &str) -> Option<Color> {
match kind {
TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } => Some(Color::LightGreen),
TokenKind::Ident | TokenKind::RawIdent => {
if is_keyword(token_text) {
Some(Color::Blue)
} else {
Some(Color::LightGreen)
}
}
TokenKind::Literal {
kind:
LiteralKind::Str { .. }
| LiteralKind::ByteStr { .. }
| LiteralKind::RawByteStr { .. }
| LiteralKind::RawStr { .. },
..
} => Some(Color::Yellow),
TokenKind::Lifetime { .. } => Some(Color::Blue),
TokenKind::OpenParen | TokenKind::CloseParen => Some(Color::Blue),
TokenKind::OpenBrace | TokenKind::CloseBrace => Some(Color::Magenta),
TokenKind::OpenBracket | TokenKind::CloseBracket => Some(Color::Magenta),
TokenKind::Question => Some(Color::Yellow),
_ => None,
}
}

const KEYWORDS: &[&str] = &[
"as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn", "for",
"if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return",
"self", "Self", "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where",
"while", "async", "await", "dyn", "abstract", "become", "box", "do", "final", "macro",
"override", "priv", "typeof", "unsized", "virtual", "yield", "try",
];

fn is_keyword(token_text: &str) -> bool {
KEYWORDS.contains(&token_text)
}

0 comments on commit e0954fa

Please sign in to comment.