summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--assets/monokai-extended-light.theme.binbin0 -> 15762 bytes
-rw-r--r--src/config/mod.rs20
-rw-r--r--src/main.rs13
-rw-r--r--src/render/cmd.rs8
-rw-r--r--src/render/markdown.rs11
-rw-r--r--src/render/mod.rs5
-rw-r--r--src/render/repl.rs11
-rw-r--r--src/repl/handler.rs2
-rw-r--r--src/repl/init.rs33
11 files changed, 81 insertions, 24 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b5de47e..f399a9f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -39,6 +39,7 @@ dependencies = [
"inquire",
"is-terminal",
"lazy_static",
+ "nu-ansi-term",
"parking_lot",
"reedline",
"reqwest",
diff --git a/Cargo.toml b/Cargo.toml
index a40a16d..a144386 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,6 +37,7 @@ fancy-regex = "0.11.0"
base64 = "0.21.0"
rustc-hash = "1.1.0"
bstr = "1.3.0"
+nu-ansi-term = "0.46.0"
[dependencies.reqwest]
version = "0.11.14"
diff --git a/assets/monokai-extended-light.theme.bin b/assets/monokai-extended-light.theme.bin
new file mode 100644
index 0000000..f9e9696
--- /dev/null
+++ b/assets/monokai-extended-light.theme.bin
Binary files differ
diff --git a/src/config/mod.rs b/src/config/mod.rs
index a670d00..96f19db 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -54,6 +54,8 @@ pub struct Config {
pub dry_run: bool,
/// If set ture, start a conversation immediately upon repl
pub conversation_first: bool,
+ /// Is ligth theme
+ pub light_theme: bool,
/// Predefined roles
#[serde(skip)]
pub roles: Vec<Role>,
@@ -75,6 +77,7 @@ impl Default for Config {
proxy: None,
dry_run: false,
conversation_first: false,
+ light_theme: false,
roles: vec![],
role: None,
conversation: None,
@@ -409,11 +412,10 @@ impl Config {
fn merge_env_vars(&mut self) {
if let Ok(value) = env::var(get_env_name("dry_run")) {
- match value.as_str() {
- "1" | "true" => self.dry_run = true,
- "0" | "false" => self.dry_run = false,
- _ => {}
- }
+ set_bool(&mut self.dry_run, &value);
+ }
+ if let Ok(value) = env::var(get_env_name("light_theme")) {
+ set_bool(&mut self.light_theme, &value);
}
}
}
@@ -479,3 +481,11 @@ fn get_env_name(key: &str) -> String {
key.to_ascii_uppercase(),
)
}
+
+fn set_bool(target: &mut bool, value: &str) {
+ match value {
+ "1" | "true" => *target = true,
+ "0" | "false" => *target = false,
+ _ => {}
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 5bcdf11..fa0e64e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -75,10 +75,11 @@ fn start_directive(
no_stream: bool,
) -> Result<()> {
let highlight = config.lock().highlight && stdout().is_terminal();
+ let light_theme = config.lock().light_theme;
let output = if no_stream {
let output = client.send_message(input)?;
if highlight {
- let mut markdown_render = MarkdownRender::new();
+ let mut markdown_render = MarkdownRender::new(light_theme);
println!("{}", markdown_render.render(&output).trim());
} else {
println!("{}", output.trim());
@@ -92,7 +93,15 @@ fn start_directive(
abort_clone.set_ctrlc();
})
.expect("Error setting Ctrl-C handler");
- let output = render_stream(input, &client, highlight, false, abort, wg.clone())?;
+ let output = render_stream(
+ input,
+ &client,
+ highlight,
+ light_theme,
+ false,
+ abort,
+ wg.clone(),
+ )?;
wg.wait();
output
};
diff --git a/src/render/cmd.rs b/src/render/cmd.rs
index 2a25768..62a0a34 100644
--- a/src/render/cmd.rs
+++ b/src/render/cmd.rs
@@ -6,9 +6,13 @@ use crate::repl::{ReplyStreamEvent, SharedAbortSignal};
use anyhow::Result;
use crossbeam::channel::Receiver;
-pub fn cmd_render_stream(rx: Receiver<ReplyStreamEvent>, abort: SharedAbortSignal) -> Result<()> {
+pub fn cmd_render_stream(
+ rx: Receiver<ReplyStreamEvent>,
+ light_theme: bool,
+ abort: SharedAbortSignal,
+) -> Result<()> {
let mut buffer = String::new();
- let mut markdown_render = MarkdownRender::new();
+ let mut markdown_render = MarkdownRender::new(light_theme);
loop {
if abort.aborted() {
return Ok(());
diff --git a/src/render/markdown.rs b/src/render/markdown.rs
index affaf21..5bdca9d 100644
--- a/src/render/markdown.rs
+++ b/src/render/markdown.rs
@@ -7,6 +7,7 @@ use syntect::{easy::HighlightLines, parsing::SyntaxReference};
/// Monokai Extended
const MD_THEME: &[u8] = include_bytes!("../../assets/monokai-extended.theme.bin");
+const MD_THEME_LIGHT: &[u8] = include_bytes!("../../assets/monokai-extended-light.theme.bin");
/// Comes from https://github.com/sharkdp/bat/raw/5e77ca37e89c873e4490b42ff556370dc5c6ba4f/assets/syntaxes.bin
const SYNTAXES: &[u8] = include_bytes!("../../assets/syntaxes.bin");
@@ -29,10 +30,14 @@ pub struct MarkdownRender {
}
impl MarkdownRender {
- pub fn new() -> Self {
+ pub fn new(light_theme: bool) -> Self {
let syntax_set: SyntaxSet =
bincode::deserialize_from(SYNTAXES).expect("invalid syntaxes binary");
- let md_theme: Theme = bincode::deserialize_from(MD_THEME).expect("invalid md_theme binary");
+ let md_theme: Theme = if light_theme {
+ bincode::deserialize_from(MD_THEME_LIGHT).expect("invalid theme binary")
+ } else {
+ bincode::deserialize_from(MD_THEME).expect("invalid theme binary")
+ };
let code_color = get_code_color(&md_theme);
let md_syntax = syntax_set.find_syntax_by_extension("md").unwrap().clone();
let line_type = LineType::Normal;
@@ -223,7 +228,7 @@ mod tests {
#[test]
fn test_render() {
- let render = MarkdownRender::new();
+ let render = MarkdownRender::new(true);
assert!(render.find_syntax("csharp").is_some());
}
}
diff --git a/src/render/mod.rs b/src/render/mod.rs
index 4d5c6d3..d200087 100644
--- a/src/render/mod.rs
+++ b/src/render/mod.rs
@@ -19,6 +19,7 @@ pub fn render_stream(
input: &str,
client: &ChatGptClient,
highlight: bool,
+ light_theme: bool,
repl: bool,
abort: SharedAbortSignal,
wg: WaitGroup,
@@ -28,9 +29,9 @@ pub fn render_stream(
let abort_clone = abort.clone();
spawn(move || {
let err = if repl {
- repl_render_stream(rx, abort)
+ repl_render_stream(rx, light_theme, abort)
} else {
- cmd_render_stream(rx, abort)
+ cmd_render_stream(rx, light_theme, abort)
};
if let Err(err) = err {
let err = format!("{err:?}");
diff --git a/src/render/repl.rs b/src/render/repl.rs
index d7ccbc1..04dee73 100644
--- a/src/render/repl.rs
+++ b/src/render/repl.rs
@@ -16,11 +16,15 @@ use std::{
};
use unicode_width::UnicodeWidthStr;
-pub fn repl_render_stream(rx: Receiver<ReplyStreamEvent>, abort: SharedAbortSignal) -> Result<()> {
+pub fn repl_render_stream(
+ rx: Receiver<ReplyStreamEvent>,
+ light_theme: bool,
+ abort: SharedAbortSignal,
+) -> Result<()> {
enable_raw_mode()?;
let mut stdout = io::stdout();
- let ret = repl_render_stream_inner(rx, abort, &mut stdout);
+ let ret = repl_render_stream_inner(rx, light_theme, abort, &mut stdout);
disable_raw_mode()?;
@@ -29,13 +33,14 @@ pub fn repl_render_stream(rx: Receiver<ReplyStreamEvent>, abort: SharedAbortSign
fn repl_render_stream_inner(
rx: Receiver<ReplyStreamEvent>,
+ light_theme: bool,
abort: SharedAbortSignal,
writer: &mut Stdout,
) -> Result<()> {
let mut last_tick = Instant::now();
let tick_rate = Duration::from_millis(100);
let mut buffer = String::new();
- let mut markdown_render = MarkdownRender::new();
+ let mut markdown_render = MarkdownRender::new(light_theme);
let terminal_columns = terminal::size()?.0;
loop {
if abort.aborted() {
diff --git a/src/repl/handler.rs b/src/repl/handler.rs
index ce95855..a7f4b08 100644
--- a/src/repl/handler.rs
+++ b/src/repl/handler.rs
@@ -51,11 +51,13 @@ impl ReplCmdHandler {
return Ok(());
}
let highlight = self.config.lock().highlight;
+ let light_theme = self.config.lock().light_theme;
let wg = WaitGroup::new();
let ret = render_stream(
&input,
&self.client,
highlight,
+ light_theme,
true,
self.abort.clone(),
wg.clone(),
diff --git a/src/repl/init.rs b/src/repl/init.rs
index 7d0c2bb..ff75eff 100644
--- a/src/repl/init.rs
+++ b/src/repl/init.rs
@@ -3,12 +3,17 @@ use super::REPL_COMMANDS;
use crate::config::{Config, SharedConfig};
use anyhow::{Context, Result};
+use nu_ansi_term::Color;
use reedline::{
default_emacs_keybindings, ColumnarMenu, DefaultCompleter, DefaultValidator, Emacs,
- FileBackedHistory, KeyCode, KeyModifiers, Keybindings, Reedline, ReedlineEvent, ReedlineMenu,
+ ExampleHighlighter, FileBackedHistory, KeyCode, KeyModifiers, Keybindings, Reedline,
+ ReedlineEvent, ReedlineMenu,
};
const MENU_NAME: &str = "completion_menu";
+const MATCH_COLOR: Color = Color::Green;
+const NEUTRAL_COLOR: Color = Color::White;
+const NEUTRAL_COLOR_LIGHT: Color = Color::Black;
pub struct Repl {
pub editor: Reedline,
@@ -16,13 +21,20 @@ pub struct Repl {
impl Repl {
pub fn init(config: SharedConfig) -> Result<Self> {
- let completer = Self::create_completer(config);
+ let commands: Vec<String> = REPL_COMMANDS
+ .into_iter()
+ .map(|(v, _)| v.to_string())
+ .collect();
+
+ let completer = Self::create_completer(config.clone(), &commands);
+ let highlighter = Self::create_highlighter(config, &commands);
let keybindings = Self::create_keybindings();
let history = Self::create_history()?;
let menu = Self::create_menu();
let edit_mode = Box::new(Emacs::new(keybindings));
let editor = Reedline::create()
.with_completer(Box::new(completer))
+ .with_highlighter(Box::new(highlighter))
.with_history(history)
.with_menu(menu)
.with_edit_mode(edit_mode)
@@ -33,17 +45,24 @@ impl Repl {
Ok(Self { editor })
}
- fn create_completer(config: SharedConfig) -> DefaultCompleter {
- let mut completion: Vec<String> = REPL_COMMANDS
- .into_iter()
- .map(|(v, _)| v.to_string())
- .collect();
+ fn create_completer(config: SharedConfig, commands: &[String]) -> DefaultCompleter {
+ let mut completion = commands.to_vec();
completion.extend(config.lock().repl_completions());
let mut completer = DefaultCompleter::with_inclusions(&['.', '-', '_']).set_min_word_len(2);
completer.insert(completion.clone());
completer
}
+ fn create_highlighter(config: SharedConfig, commands: &[String]) -> ExampleHighlighter {
+ let mut highlighter = ExampleHighlighter::new(commands.to_vec());
+ if config.lock().light_theme {
+ highlighter.change_colors(MATCH_COLOR, NEUTRAL_COLOR_LIGHT, NEUTRAL_COLOR_LIGHT);
+ } else {
+ highlighter.change_colors(MATCH_COLOR, NEUTRAL_COLOR, NEUTRAL_COLOR);
+ }
+ highlighter
+ }
+
fn create_keybindings() -> Keybindings {
let mut keybindings = default_emacs_keybindings();
keybindings.add_binding(