mirror of
https://github.com/atuinsh/atuin.git
synced 2024-12-01 20:55:49 +01:00
stash
This commit is contained in:
parent
e1745c7dae
commit
f6ee8fcd2e
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -82,6 +82,7 @@ dependencies = [
|
|||||||
"atuin-client",
|
"atuin-client",
|
||||||
"atuin-common",
|
"atuin-common",
|
||||||
"atuin-server",
|
"atuin-server",
|
||||||
|
"atuin-syntect",
|
||||||
"base64 0.20.0",
|
"base64 0.20.0",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cassowary",
|
"cassowary",
|
||||||
@ -105,7 +106,6 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"syntect",
|
|
||||||
"tiny-bip39",
|
"tiny-bip39",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
@ -189,6 +189,14 @@ dependencies = [
|
|||||||
"whoami",
|
"whoami",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atuin-syntect"
|
||||||
|
version = "14.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"syntect",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -32,7 +32,7 @@ buildflags = ["--release"]
|
|||||||
atuin = { path = "/usr/bin/atuin" }
|
atuin = { path = "/usr/bin/atuin" }
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["./atuin-client", "./atuin-server", "./atuin-common"]
|
members = ["./atuin-client", "./atuin-server", "./atuin-common", "./atuin-syntect"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# TODO(conradludgate)
|
# TODO(conradludgate)
|
||||||
@ -47,6 +47,7 @@ server = ["atuin-server", "tracing-subscriber"]
|
|||||||
atuin-server = { path = "atuin-server", version = "14.0.0", optional = true }
|
atuin-server = { path = "atuin-server", version = "14.0.0", optional = true }
|
||||||
atuin-client = { path = "atuin-client", version = "14.0.0", optional = true, default-features = false }
|
atuin-client = { path = "atuin-client", version = "14.0.0", optional = true, default-features = false }
|
||||||
atuin-common = { path = "atuin-common", version = "14.0.0" }
|
atuin-common = { path = "atuin-common", version = "14.0.0" }
|
||||||
|
atuin-syntect = { path = "atuin-syntect", version = "14.0.0" }
|
||||||
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
env_logger = "0.10.0"
|
env_logger = "0.10.0"
|
||||||
@ -74,7 +75,6 @@ tiny-bip39 = "1"
|
|||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
fuzzy-matcher = "0.3.7"
|
fuzzy-matcher = "0.3.7"
|
||||||
colored = "2.0.0"
|
colored = "2.0.0"
|
||||||
syntect = { version = "5.0.0", default-features = false, features = ["dump-load", "parsing", "regex-fancy"] }
|
|
||||||
|
|
||||||
# ratatui
|
# ratatui
|
||||||
bitflags = "1.3"
|
bitflags = "1.3"
|
||||||
|
15
atuin-syntect/Cargo.toml
Normal file
15
atuin-syntect/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "atuin-syntect"
|
||||||
|
version = "14.0.0"
|
||||||
|
authors = ["Ellie Huxtable <ellie@elliehuxtable.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT"
|
||||||
|
description = "common library for atuin"
|
||||||
|
homepage = "https://atuin.sh"
|
||||||
|
repository = "https://github.com/ellie/atuin"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syntect = { version = "5.0.0", default-features = false, features = ["dump-load", "parsing", "regex-fancy"] }
|
||||||
|
once_cell = "1"
|
@ -1,6 +1,120 @@
|
|||||||
use syntect::parsing::{ParseScopeError, Scope};
|
use once_cell::sync::OnceCell;
|
||||||
|
use syntect::{
|
||||||
|
dumps::from_uncompressed_data,
|
||||||
|
parsing::{
|
||||||
|
BasicScopeStackOp, ParseScopeError, Scope, ScopeStack, ScopeStackOp, SyntaxReference,
|
||||||
|
SyntaxSet,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::ratatui::style::{Color, Style};
|
mod style;
|
||||||
|
pub use style::*;
|
||||||
|
|
||||||
|
impl Theme {
|
||||||
|
// this is a manual/simpler implementation of
|
||||||
|
// syntect::highlight::HighlightIterator
|
||||||
|
// to use a custom theme using `ratatui::Style`.
|
||||||
|
// This is so we don't have to care about RGB and can instead use
|
||||||
|
// terminal colours
|
||||||
|
pub fn highlight(&self, h: &str, parsed: &ParsedSyntax, draw: &mut dyn FnMut(&str, Style)) {
|
||||||
|
let mut stack = ScopeStack::default();
|
||||||
|
let mut styles: Vec<(f64, Style)> = vec![];
|
||||||
|
for (line, parsed_line) in h.lines().zip(parsed) {
|
||||||
|
draw("", Style::default());
|
||||||
|
|
||||||
|
let mut last = 0;
|
||||||
|
for &(index, ref op) in parsed_line {
|
||||||
|
let style = styles.last().copied().unwrap_or_default().1;
|
||||||
|
stack
|
||||||
|
.apply_with_hook(op, |op, stack| {
|
||||||
|
highlight_hook(&op, stack, &self.rules, &mut styles);
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
draw(&line[last..index], style);
|
||||||
|
last = index;
|
||||||
|
}
|
||||||
|
let style = styles.last().copied().unwrap_or_default().1;
|
||||||
|
draw(&line[last..], style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
fn highlight_hook(
|
||||||
|
op: &BasicScopeStackOp,
|
||||||
|
stack: &[Scope],
|
||||||
|
rules: &[ThemeRule],
|
||||||
|
styles: &mut Vec<(f64, Style)>,
|
||||||
|
) {
|
||||||
|
match op {
|
||||||
|
BasicScopeStackOp::Push(scope) => {
|
||||||
|
let mut scored_style = styles
|
||||||
|
.last()
|
||||||
|
.copied()
|
||||||
|
.unwrap_or_else(|| (-1.0, Style::default()));
|
||||||
|
|
||||||
|
for rule in rules.iter().filter(|a| a.scope.is_prefix_of(*scope)) {
|
||||||
|
let single_score =
|
||||||
|
f64::from(rule.scope.len()) * f64::from(3 * ((stack.len() - 1) as u32)).exp2();
|
||||||
|
|
||||||
|
if single_score > scored_style.0 {
|
||||||
|
scored_style.0 = single_score;
|
||||||
|
scored_style.1 = rule.style;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
styles.push(scored_style);
|
||||||
|
}
|
||||||
|
BasicScopeStackOp::Pop => {
|
||||||
|
styles.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_syntax() -> ShellSyntax<'static> {
|
||||||
|
static SYNTAX: OnceCell<SyntaxSet> = OnceCell::new();
|
||||||
|
let syntax = SYNTAX.get_or_init(|| {
|
||||||
|
from_uncompressed_data(include_bytes!("default_nonewlines.packdump")).unwrap()
|
||||||
|
});
|
||||||
|
ShellSyntax {
|
||||||
|
syntax,
|
||||||
|
sh: syntax.find_syntax_by_extension("sh").unwrap(),
|
||||||
|
fish: syntax.find_syntax_by_extension("fish").unwrap(),
|
||||||
|
nu: syntax.find_syntax_by_extension("nu").unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct ShellSyntax<'s> {
|
||||||
|
syntax: &'s SyntaxSet,
|
||||||
|
sh: &'s SyntaxReference,
|
||||||
|
fish: &'s SyntaxReference,
|
||||||
|
nu: &'s SyntaxReference,
|
||||||
|
}
|
||||||
|
pub type ParsedSyntax = Vec<Vec<(usize, ScopeStackOp)>>;
|
||||||
|
|
||||||
|
impl ShellSyntax<'_> {
|
||||||
|
pub fn parse_shell(self, h: &str) -> ParsedSyntax {
|
||||||
|
let mut sh = syntect::parsing::ParseState::new(self.sh);
|
||||||
|
let mut fish = syntect::parsing::ParseState::new(self.fish);
|
||||||
|
let mut nu = syntect::parsing::ParseState::new(self.nu);
|
||||||
|
|
||||||
|
let mut lines = vec![];
|
||||||
|
for line in h.lines() {
|
||||||
|
if let Ok(line) = sh.parse_line(line, self.syntax) {
|
||||||
|
lines.push(line);
|
||||||
|
} else if let Ok(line) = fish.parse_line(line, self.syntax) {
|
||||||
|
lines.push(line);
|
||||||
|
} else if let Ok(line) = nu.parse_line(line, self.syntax) {
|
||||||
|
lines.push(line);
|
||||||
|
} else {
|
||||||
|
lines.push(Vec::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lines
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Theme {
|
pub struct Theme {
|
||||||
pub rules: Vec<ThemeRule>,
|
pub rules: Vec<ThemeRule>,
|
61
atuin-syntect/src/style.rs
Normal file
61
atuin-syntect/src/style.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
//! `style` contains the primitives used to control how your user interface will look.
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Color {
|
||||||
|
Black,
|
||||||
|
Red,
|
||||||
|
Green,
|
||||||
|
Yellow,
|
||||||
|
Blue,
|
||||||
|
Magenta,
|
||||||
|
Cyan,
|
||||||
|
Gray,
|
||||||
|
DarkGray,
|
||||||
|
LightRed,
|
||||||
|
LightGreen,
|
||||||
|
LightYellow,
|
||||||
|
LightBlue,
|
||||||
|
LightMagenta,
|
||||||
|
LightCyan,
|
||||||
|
White,
|
||||||
|
Rgb(u8, u8, u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
pub struct Style {
|
||||||
|
pub fg: Option<Color>,
|
||||||
|
pub bg: Option<Color>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Style {
|
||||||
|
/// Changes the foreground color.
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use ratatui::style::{Color, Style};
|
||||||
|
/// let style = Style::default().fg(Color::Blue);
|
||||||
|
/// let diff = Style::default().fg(Color::Red);
|
||||||
|
/// assert_eq!(style.patch(diff), Style::default().fg(Color::Red));
|
||||||
|
/// ```
|
||||||
|
pub fn fg(mut self, color: Color) -> Style {
|
||||||
|
self.fg = Some(color);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Changes the background color.
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use ratatui::style::{Color, Style};
|
||||||
|
/// let style = Style::default().bg(Color::Blue);
|
||||||
|
/// let diff = Style::default().bg(Color::Red);
|
||||||
|
/// assert_eq!(style.patch(diff), Style::default().bg(Color::Red));
|
||||||
|
/// ```
|
||||||
|
pub fn bg(mut self, color: Color) -> Style {
|
||||||
|
self.bg = Some(color);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,6 @@ mod duration;
|
|||||||
mod engines;
|
mod engines;
|
||||||
mod history_list;
|
mod history_list;
|
||||||
mod interactive;
|
mod interactive;
|
||||||
mod syntax;
|
|
||||||
pub use duration::{format_duration, format_duration_into};
|
pub use duration::{format_duration, format_duration_into};
|
||||||
|
|
||||||
#[allow(clippy::struct_excessive_bools)]
|
#[allow(clippy::struct_excessive_bools)]
|
||||||
|
@ -7,13 +7,9 @@ use crate::ratatui::{
|
|||||||
widgets::{Block, StatefulWidget, Widget},
|
widgets::{Block, StatefulWidget, Widget},
|
||||||
};
|
};
|
||||||
use atuin_client::history::History;
|
use atuin_client::history::History;
|
||||||
use syntect::parsing::{BasicScopeStackOp, Scope, ScopeStack};
|
use atuin_syntect::{ParsedSyntax, Theme};
|
||||||
|
|
||||||
use super::{
|
use super::format_duration;
|
||||||
format_duration,
|
|
||||||
interactive::ParsedSyntax,
|
|
||||||
syntax::{Theme, ThemeRule},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct HistoryList<'a> {
|
pub struct HistoryList<'a> {
|
||||||
history: &'a [History],
|
history: &'a [History],
|
||||||
@ -176,39 +172,22 @@ impl DrawState<'_> {
|
|||||||
let selected = self.y as usize + self.state.offset == self.state.selected;
|
let selected = self.y as usize + self.state.offset == self.state.selected;
|
||||||
let with_select = move |style: Style| {
|
let with_select = move |style: Style| {
|
||||||
if selected {
|
if selected {
|
||||||
style.bg(theme.selection).add_modifier(Modifier::BOLD)
|
style
|
||||||
|
.bg(map_color(theme.selection))
|
||||||
|
.add_modifier(Modifier::BOLD)
|
||||||
} else {
|
} else {
|
||||||
style
|
style
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(parsed) = parsed {
|
if let Some(parsed) = parsed {
|
||||||
// this is a manual/simpler implementation of
|
theme.highlight(&h.command, parsed, &mut |t, style| {
|
||||||
// syntect::highlight::HighlightIterator
|
if t.is_empty() {
|
||||||
// to use a custom theme using `ratatui::Style`.
|
|
||||||
// This is so we don't have to care about RGB and can instead use
|
|
||||||
// terminal colours
|
|
||||||
|
|
||||||
let mut stack = ScopeStack::default();
|
|
||||||
let mut styles: Vec<(f64, Style)> = vec![];
|
|
||||||
for (line, parsed_line) in h.command.lines().zip(parsed) {
|
|
||||||
self.x += 1;
|
self.x += 1;
|
||||||
|
} else {
|
||||||
let mut last = 0;
|
self.draw(t, with_select(map_style(style)));
|
||||||
for &(index, ref op) in parsed_line {
|
|
||||||
let style = styles.last().copied().unwrap_or_default().1;
|
|
||||||
stack
|
|
||||||
.apply_with_hook(op, |op, stack| {
|
|
||||||
highlight_hook(&op, stack, &theme.rules, &mut styles);
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
self.draw(&line[last..index], with_select(style));
|
|
||||||
last = index;
|
|
||||||
}
|
|
||||||
let style = styles.last().copied().unwrap_or_default().1;
|
|
||||||
self.draw(&line[last..], with_select(style));
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
let style = with_select(Style::default());
|
let style = with_select(Style::default());
|
||||||
for section in h.command.split_ascii_whitespace() {
|
for section in h.command.split_ascii_whitespace() {
|
||||||
@ -231,34 +210,33 @@ impl DrawState<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
fn map_color(c: atuin_syntect::Color) -> Color {
|
||||||
fn highlight_hook(
|
match c {
|
||||||
op: &BasicScopeStackOp,
|
atuin_syntect::Color::Black => Color::Black,
|
||||||
stack: &[Scope],
|
atuin_syntect::Color::Red => Color::Red,
|
||||||
rules: &[ThemeRule],
|
atuin_syntect::Color::Green => Color::Green,
|
||||||
styles: &mut Vec<(f64, Style)>,
|
atuin_syntect::Color::Yellow => Color::Yellow,
|
||||||
) {
|
atuin_syntect::Color::Blue => Color::Blue,
|
||||||
match op {
|
atuin_syntect::Color::Magenta => Color::Magenta,
|
||||||
BasicScopeStackOp::Push(scope) => {
|
atuin_syntect::Color::Cyan => Color::Cyan,
|
||||||
let mut scored_style = styles
|
atuin_syntect::Color::Gray => Color::Gray,
|
||||||
.last()
|
atuin_syntect::Color::DarkGray => Color::DarkGray,
|
||||||
.copied()
|
atuin_syntect::Color::LightRed => Color::LightRed,
|
||||||
.unwrap_or_else(|| (-1.0, Style::default()));
|
atuin_syntect::Color::LightGreen => Color::LightGreen,
|
||||||
|
atuin_syntect::Color::LightYellow => Color::LightYellow,
|
||||||
for rule in rules.iter().filter(|a| a.scope.is_prefix_of(*scope)) {
|
atuin_syntect::Color::LightBlue => Color::LightBlue,
|
||||||
let single_score =
|
atuin_syntect::Color::LightMagenta => Color::LightMagenta,
|
||||||
f64::from(rule.scope.len()) * f64::from(3 * ((stack.len() - 1) as u32)).exp2();
|
atuin_syntect::Color::LightCyan => Color::LightCyan,
|
||||||
|
atuin_syntect::Color::White => Color::White,
|
||||||
if single_score > scored_style.0 {
|
atuin_syntect::Color::Rgb(r, g, b) => Color::Rgb(r, g, b),
|
||||||
scored_style.0 = single_score;
|
}
|
||||||
scored_style.1 = rule.style;
|
}
|
||||||
}
|
|
||||||
}
|
fn map_style(c: atuin_syntect::Style) -> Style {
|
||||||
|
Style {
|
||||||
styles.push(scored_style);
|
fg: c.fg.map(map_color),
|
||||||
}
|
bg: c.bg.map(map_color),
|
||||||
BasicScopeStackOp::Pop => {
|
add_modifier: Modifier::empty(),
|
||||||
styles.pop();
|
sub_modifier: Modifier::empty(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use std::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use atuin_syntect::{ParsedSyntax, Theme, ShellSyntax, get_syntax, get_theme};
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{self, Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent},
|
event::{self, Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent},
|
||||||
execute, terminal,
|
execute, terminal,
|
||||||
@ -11,11 +12,10 @@ use crossterm::{
|
|||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use futures_util::FutureExt;
|
use futures_util::FutureExt;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use syntect::{
|
// use syntect::{
|
||||||
dumps::{from_binary, from_uncompressed_data},
|
// dumps::from_uncompressed_data,
|
||||||
highlighting::Highlighter,
|
// parsing::{ScopeStackOp, SyntaxReference, SyntaxSet},
|
||||||
parsing::{ScopeStackOp, SyntaxReference, SyntaxSet},
|
// };
|
||||||
};
|
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use atuin_client::{
|
use atuin_client::{
|
||||||
@ -28,11 +28,9 @@ use super::{
|
|||||||
cursor::Cursor,
|
cursor::Cursor,
|
||||||
engines::{SearchEngine, SearchState},
|
engines::{SearchEngine, SearchState},
|
||||||
history_list::{HistoryList, ListState, PREFIX_LENGTH},
|
history_list::{HistoryList, ListState, PREFIX_LENGTH},
|
||||||
syntax::Theme,
|
|
||||||
};
|
};
|
||||||
use crate::{command::client::search::engines, VERSION};
|
use crate::{command::client::search::engines, VERSION};
|
||||||
use crate::{
|
use crate::{
|
||||||
command::client::search::syntax::get_theme,
|
|
||||||
ratatui::{
|
ratatui::{
|
||||||
backend::{Backend, CrosstermBackend},
|
backend::{Backend, CrosstermBackend},
|
||||||
layout::{Alignment, Constraint, Direction, Layout},
|
layout::{Alignment, Constraint, Direction, Layout},
|
||||||
@ -46,9 +44,8 @@ use crate::{
|
|||||||
const RETURN_ORIGINAL: usize = usize::MAX;
|
const RETURN_ORIGINAL: usize = usize::MAX;
|
||||||
const RETURN_QUERY: usize = usize::MAX - 1;
|
const RETURN_QUERY: usize = usize::MAX - 1;
|
||||||
|
|
||||||
pub type ParsedSyntax = Vec<Vec<(usize, ScopeStackOp)>>;
|
|
||||||
|
|
||||||
struct State<'s> {
|
struct State {
|
||||||
history_count: i64,
|
history_count: i64,
|
||||||
update_needed: Option<Version>,
|
update_needed: Option<Version>,
|
||||||
results_state: ListState,
|
results_state: ListState,
|
||||||
@ -61,17 +58,17 @@ struct State<'s> {
|
|||||||
// highlighting
|
// highlighting
|
||||||
results_parsed: HashMap<String, ParsedSyntax>,
|
results_parsed: HashMap<String, ParsedSyntax>,
|
||||||
theme: Theme,
|
theme: Theme,
|
||||||
syntax: ShellSyntax<'s>,
|
syntax: ShellSyntax<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State<'_> {
|
impl State {
|
||||||
async fn query_results(&mut self, db: &mut dyn Database) -> Result<Vec<History>> {
|
async fn query_results(&mut self, db: &mut dyn Database) -> Result<Vec<History>> {
|
||||||
let results = self.engine.query(&self.search, db).await?;
|
let results = self.engine.query(&self.search, db).await?;
|
||||||
self.results_state.select(0);
|
self.results_state.select(0);
|
||||||
for h in &results {
|
for h in &results {
|
||||||
self.results_parsed
|
self.results_parsed
|
||||||
.entry(h.id.clone())
|
.entry(h.id.clone())
|
||||||
.or_insert_with(|| parse_shell(h, self.syntax));
|
.or_insert_with(|| self.syntax.parse_shell(&h.command));
|
||||||
}
|
}
|
||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
@ -534,14 +531,6 @@ pub async fn history(
|
|||||||
|
|
||||||
let history_count = db.history_count().await?;
|
let history_count = db.history_count().await?;
|
||||||
|
|
||||||
let syntax: SyntaxSet =
|
|
||||||
from_uncompressed_data(include_bytes!("syntax/default_nonewlines.packdump")).unwrap();
|
|
||||||
// let themes: ThemeSet = from_binary(include_bytes!("syntax/default.themedump"));
|
|
||||||
// let highlighter = Highlighter::new(&themes.themes["base16-ocean.dark"]);
|
|
||||||
|
|
||||||
// let syntax = SyntaxSet::load_defaults_nonewlines();
|
|
||||||
// let mut themes = ThemeSet::load_defaults();
|
|
||||||
|
|
||||||
let mut app = State {
|
let mut app = State {
|
||||||
history_count,
|
history_count,
|
||||||
results_state: ListState::default(),
|
results_state: ListState::default(),
|
||||||
@ -563,12 +552,7 @@ pub async fn history(
|
|||||||
|
|
||||||
results_parsed: HashMap::new(),
|
results_parsed: HashMap::new(),
|
||||||
theme: get_theme().unwrap(),
|
theme: get_theme().unwrap(),
|
||||||
syntax: ShellSyntax {
|
syntax: get_syntax(),
|
||||||
syntaxs: &syntax,
|
|
||||||
sh: syntax.find_syntax_by_extension("sh").unwrap(),
|
|
||||||
fish: syntax.find_syntax_by_extension("fish").unwrap(),
|
|
||||||
nu: syntax.find_syntax_by_extension("nu").unwrap(),
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// let mut hi = HighlightLines::new(syntax, &ts.themes["base16-ocean.dark"]);
|
// let mut hi = HighlightLines::new(syntax, &ts.themes["base16-ocean.dark"]);
|
||||||
@ -638,30 +622,3 @@ pub async fn history(
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
struct ShellSyntax<'s> {
|
|
||||||
syntaxs: &'s SyntaxSet,
|
|
||||||
sh: &'s SyntaxReference,
|
|
||||||
fish: &'s SyntaxReference,
|
|
||||||
nu: &'s SyntaxReference,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_shell(h: &History, syntax: ShellSyntax<'_>) -> ParsedSyntax {
|
|
||||||
let mut sh = syntect::parsing::ParseState::new(syntax.sh);
|
|
||||||
let mut fish = syntect::parsing::ParseState::new(syntax.fish);
|
|
||||||
let mut nu = syntect::parsing::ParseState::new(syntax.nu);
|
|
||||||
|
|
||||||
let mut lines = vec![];
|
|
||||||
for line in h.command.lines() {
|
|
||||||
if let Ok(line) = sh.parse_line(line, syntax.syntaxs) {
|
|
||||||
lines.push(line);
|
|
||||||
} else if let Ok(line) = fish.parse_line(line, syntax.syntaxs) {
|
|
||||||
lines.push(line);
|
|
||||||
} else if let Ok(line) = nu.parse_line(line, syntax.syntaxs) {
|
|
||||||
lines.push(line);
|
|
||||||
} else {
|
|
||||||
lines.push(Vec::new());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lines
|
|
||||||
}
|
|
||||||
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user