mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 00:13:21 +01:00
Refactor the repl loop
This commit is contained in:
parent
34a866df99
commit
98ab5e63fc
9
src/env/host.rs
vendored
9
src/env/host.rs
vendored
@ -1,11 +1,16 @@
|
|||||||
pub trait Host {
|
pub trait Host {
|
||||||
fn stdout(&mut self, out: &str);
|
fn stdout(&mut self, out: &str);
|
||||||
|
fn stderr(&mut self, out: &str);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Host for Box<dyn Host> {
|
impl Host for Box<dyn Host> {
|
||||||
fn stdout(&mut self, out: &str) {
|
fn stdout(&mut self, out: &str) {
|
||||||
(**self).stdout(out)
|
(**self).stdout(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn stderr(&mut self, out: &str) {
|
||||||
|
(**self).stderr(out)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate struct BasicHost;
|
crate struct BasicHost;
|
||||||
@ -14,4 +19,8 @@ impl Host for BasicHost {
|
|||||||
fn stdout(&mut self, out: &str) {
|
fn stdout(&mut self, out: &str) {
|
||||||
println!("{}", out)
|
println!("{}", out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn stderr(&mut self, out: &str) {
|
||||||
|
eprintln!("{}", out)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,10 @@ impl ShellError {
|
|||||||
error: self.error.copy(),
|
error: self.error.copy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate fn description(&self) -> String {
|
||||||
|
self.title.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for ShellError {
|
impl std::fmt::Display for ShellError {
|
||||||
|
179
src/main.rs
179
src/main.rs
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::borrow::Cow::{self, Borrowed, Owned};
|
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
mod context;
|
mod context;
|
||||||
@ -13,6 +12,7 @@ mod format;
|
|||||||
mod object;
|
mod object;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod prelude;
|
mod prelude;
|
||||||
|
mod shell;
|
||||||
|
|
||||||
use crate::commands::command::ReturnValue;
|
use crate::commands::command::ReturnValue;
|
||||||
crate use crate::commands::command::{Command, CommandAction, CommandBlueprint};
|
crate use crate::commands::command::{Command, CommandAction, CommandBlueprint};
|
||||||
@ -21,13 +21,9 @@ crate use crate::env::{Environment, Host};
|
|||||||
crate use crate::errors::ShellError;
|
crate use crate::errors::ShellError;
|
||||||
crate use crate::format::{EntriesListView, GenericView};
|
crate use crate::format::{EntriesListView, GenericView};
|
||||||
use crate::object::Value;
|
use crate::object::Value;
|
||||||
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
|
||||||
use rustyline::highlight::{Highlighter, MatchingBracketHighlighter};
|
|
||||||
use rustyline::hint::{Hinter, HistoryHinter};
|
|
||||||
|
|
||||||
use ansi_term::Color;
|
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use rustyline::{ColorMode, Config, Editor, Helper, self};
|
use rustyline::{self, ColorMode, Config, Editor};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@ -48,54 +44,10 @@ impl<T> MaybeOwned<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MyHelper(FilenameCompleter, MatchingBracketHighlighter, HistoryHinter);
|
|
||||||
impl Completer for MyHelper {
|
|
||||||
type Candidate = Pair;
|
|
||||||
|
|
||||||
fn complete(
|
|
||||||
&self,
|
|
||||||
line: &str,
|
|
||||||
pos: usize,
|
|
||||||
ctx: &rustyline::Context<'_>,
|
|
||||||
) -> Result<(usize, Vec<Pair>), ReadlineError> {
|
|
||||||
self.0.complete(line, pos, ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hinter for MyHelper {
|
|
||||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
|
||||||
self.2.hint(line, pos, ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Highlighter for MyHelper {
|
|
||||||
fn highlight_prompt<'p>(&self, prompt: &'p str) -> Cow<'p, str> {
|
|
||||||
Owned("\x1b[32m".to_owned() + &prompt[0..prompt.len() - 2] + "\x1b[m> ")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
|
|
||||||
Owned("\x1b[1m".to_owned() + hint + "\x1b[m")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn highlight<'l>(&self, line: &'l str, pos: usize) -> Cow<'l, str> {
|
|
||||||
self.1.highlight(line, pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn highlight_char(&self, line: &str, pos: usize) -> bool {
|
|
||||||
self.1.highlight_char(line, pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Helper for MyHelper {}
|
|
||||||
|
|
||||||
fn main() -> Result<(), Box<Error>> {
|
fn main() -> Result<(), Box<Error>> {
|
||||||
let config = Config::builder().color_mode(ColorMode::Forced).build();
|
let config = Config::builder().color_mode(ColorMode::Forced).build();
|
||||||
let h = MyHelper(
|
let h = crate::shell::Helper::new();
|
||||||
FilenameCompleter::new(),
|
let mut rl: Editor<crate::shell::Helper> = Editor::with_config(config);
|
||||||
MatchingBracketHighlighter::new(),
|
|
||||||
HistoryHinter {},
|
|
||||||
);
|
|
||||||
let mut rl: Editor<MyHelper> = Editor::with_config(config);
|
|
||||||
rl.set_helper(Some(h));
|
rl.set_helper(Some(h));
|
||||||
if rl.load_history("history.txt").is_err() {
|
if rl.load_history("history.txt").is_err() {
|
||||||
println!("No previous history.");
|
println!("No previous history.");
|
||||||
@ -125,48 +77,25 @@ fn main() -> Result<(), Box<Error>> {
|
|||||||
context.lock().unwrap().env.cwd().display().to_string()
|
context.lock().unwrap().env.cwd().display().to_string()
|
||||||
));
|
));
|
||||||
|
|
||||||
match readline {
|
match process_line(readline, context.clone()) {
|
||||||
Ok(ref line) if line.trim() == "exit" => {
|
LineResult::Success(line) => {
|
||||||
break;
|
|
||||||
}
|
|
||||||
Ok(line) => {
|
|
||||||
let result = crate::parser::shell_parser(&line)
|
|
||||||
.map_err(|e| ShellError::string(format!("{:?}", e)))?;
|
|
||||||
|
|
||||||
let parsed = result.1;
|
|
||||||
|
|
||||||
rl.add_history_entry(line.as_ref());
|
rl.add_history_entry(line.as_ref());
|
||||||
|
|
||||||
let mut input = VecDeque::new();
|
|
||||||
|
|
||||||
for item in parsed {
|
|
||||||
input = process_command(
|
|
||||||
crate::parser::print_items(&item),
|
|
||||||
item.clone(),
|
|
||||||
input,
|
|
||||||
context.clone(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.len() > 0 {
|
|
||||||
if equal_shapes(&input) {
|
|
||||||
format(crate::commands::to_array(input), context.clone());
|
|
||||||
} else {
|
|
||||||
format(input, context.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(ReadlineError::Interrupted) => {
|
|
||||||
println!("CTRL-C");
|
LineResult::Error(err) => {
|
||||||
|
context.lock().unwrap().host.stdout(&err);
|
||||||
|
}
|
||||||
|
|
||||||
|
LineResult::Break => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Err(ReadlineError::Eof) => {
|
|
||||||
println!("CTRL-D");
|
LineResult::FatalError(err) => {
|
||||||
break;
|
context
|
||||||
}
|
.lock()
|
||||||
Err(err) => {
|
.unwrap()
|
||||||
println!("Error: {:?}", err);
|
.host
|
||||||
break;
|
.stdout(&format!("A surprising fatal error occurred.\n{:?}", err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,13 +104,81 @@ fn main() -> Result<(), Box<Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum LineResult {
|
||||||
|
Success(String),
|
||||||
|
Error(String),
|
||||||
|
Break,
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
FatalError(ShellError),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_line(
|
||||||
|
readline: Result<String, ReadlineError>,
|
||||||
|
context: Arc<Mutex<Context>>,
|
||||||
|
) -> LineResult {
|
||||||
|
match &readline {
|
||||||
|
Ok(line) if line.trim() == "exit" => LineResult::Break,
|
||||||
|
|
||||||
|
Ok(line) if line.trim() == "" => LineResult::Success(line.clone()),
|
||||||
|
|
||||||
|
Ok(line) => {
|
||||||
|
let result = match crate::parser::shell_parser(&line) {
|
||||||
|
Err(err) => {
|
||||||
|
return LineResult::Error(format!("{:?}", err));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(val) => val,
|
||||||
|
};
|
||||||
|
|
||||||
|
let parsed = result.1;
|
||||||
|
|
||||||
|
let mut input = VecDeque::new();
|
||||||
|
|
||||||
|
for item in parsed {
|
||||||
|
input = match process_command(
|
||||||
|
crate::parser::print_items(&item),
|
||||||
|
item.clone(),
|
||||||
|
input,
|
||||||
|
context.clone(),
|
||||||
|
) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(err) => return LineResult::Error(format!("{}", err.description())),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.len() > 0 {
|
||||||
|
if equal_shapes(&input) {
|
||||||
|
format(crate::commands::to_array(input), context.clone());
|
||||||
|
} else {
|
||||||
|
format(input, context.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LineResult::Success(line.to_string())
|
||||||
|
}
|
||||||
|
Err(ReadlineError::Interrupted) => {
|
||||||
|
println!("CTRL-C");
|
||||||
|
LineResult::Break
|
||||||
|
}
|
||||||
|
Err(ReadlineError::Eof) => {
|
||||||
|
println!("CTRL-D");
|
||||||
|
LineResult::Break
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
println!("Error: {:?}", err);
|
||||||
|
LineResult::Break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn process_command(
|
fn process_command(
|
||||||
line: String,
|
line: String,
|
||||||
parsed: Vec<crate::parser::Item>,
|
parsed: Vec<crate::parser::Item>,
|
||||||
input: VecDeque<Value>,
|
input: VecDeque<Value>,
|
||||||
context: Arc<Mutex<Context>>,
|
context: Arc<Mutex<Context>>,
|
||||||
) -> Result<VecDeque<Value>, ShellError> {
|
) -> Result<VecDeque<Value>, ShellError> {
|
||||||
let command = &parsed[0].name();
|
let command = &parsed[0].name()?;
|
||||||
let arg_list = parsed[1..].iter().map(|i| i.as_value()).collect();
|
let arg_list = parsed[1..].iter().map(|i| i.as_value()).collect();
|
||||||
|
|
||||||
if command == &"format" {
|
if command == &"format" {
|
||||||
|
@ -120,6 +120,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
crate fn as_bool(&self) -> Result<bool, ShellError> {
|
crate fn as_bool(&self) -> Result<bool, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Primitive(Primitive::Boolean(b)) => Ok(*b),
|
Value::Primitive(Primitive::Boolean(b)) => Ok(*b),
|
||||||
@ -143,6 +144,7 @@ impl Value {
|
|||||||
Value::Primitive(Primitive::Int(s.into()))
|
Value::Primitive(Primitive::Int(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
crate fn bool(s: impl Into<bool>) -> Value {
|
crate fn bool(s: impl Into<bool>) -> Value {
|
||||||
Value::Primitive(Primitive::Boolean(s.into()))
|
Value::Primitive(Primitive::Boolean(s.into()))
|
||||||
}
|
}
|
||||||
@ -213,74 +215,34 @@ crate fn find(obj: &Value, field: &str, op: &str, rhs: &Value) -> bool {
|
|||||||
//println!("'{:?}' '{}' '{:?}'", v, op, rhs);
|
//println!("'{:?}' '{}' '{:?}'", v, op, rhs);
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
Value::Primitive(Primitive::Boolean(b)) => {
|
Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) {
|
||||||
match (op, rhs) {
|
("-eq", Value::Primitive(Primitive::Boolean(b2))) => b == *b2,
|
||||||
("-eq", Value::Primitive(Primitive::Boolean(b2))) => {
|
("-ne", Value::Primitive(Primitive::Boolean(b2))) => b != *b2,
|
||||||
b == *b2
|
_ => false,
|
||||||
}
|
},
|
||||||
("-ne", Value::Primitive(Primitive::Boolean(b2))) => {
|
Value::Primitive(Primitive::Bytes(i)) => match (op, rhs) {
|
||||||
b != *b2
|
("-lt", Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u128),
|
||||||
}
|
("-gt", Value::Primitive(Primitive::Int(i2))) => i > (*i2 as u128),
|
||||||
_ => false
|
("-le", Value::Primitive(Primitive::Int(i2))) => i <= (*i2 as u128),
|
||||||
}
|
("-ge", Value::Primitive(Primitive::Int(i2))) => i >= (*i2 as u128),
|
||||||
}
|
("-eq", Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u128),
|
||||||
Value::Primitive(Primitive::Bytes(i)) => {
|
("-ne", Value::Primitive(Primitive::Int(i2))) => i != (*i2 as u128),
|
||||||
match (op, rhs) {
|
_ => false,
|
||||||
("-lt", Value::Primitive(Primitive::Int(i2))) => {
|
},
|
||||||
i < (*i2 as u128)
|
Value::Primitive(Primitive::Int(i)) => match (op, rhs) {
|
||||||
}
|
("-lt", Value::Primitive(Primitive::Int(i2))) => i < *i2,
|
||||||
("-gt", Value::Primitive(Primitive::Int(i2))) => {
|
("-gt", Value::Primitive(Primitive::Int(i2))) => i > *i2,
|
||||||
i > (*i2 as u128)
|
("-le", Value::Primitive(Primitive::Int(i2))) => i <= *i2,
|
||||||
}
|
("-ge", Value::Primitive(Primitive::Int(i2))) => i >= *i2,
|
||||||
("-le", Value::Primitive(Primitive::Int(i2))) => {
|
("-eq", Value::Primitive(Primitive::Int(i2))) => i == *i2,
|
||||||
i <= (*i2 as u128)
|
("-ne", Value::Primitive(Primitive::Int(i2))) => i != *i2,
|
||||||
}
|
_ => false,
|
||||||
("-ge", Value::Primitive(Primitive::Int(i2))) => {
|
},
|
||||||
i >= (*i2 as u128)
|
Value::Primitive(Primitive::String(s)) => match (op, rhs) {
|
||||||
}
|
("-eq", Value::Primitive(Primitive::String(s2))) => s == *s2,
|
||||||
("-eq", Value::Primitive(Primitive::Int(i2))) => {
|
("-ne", Value::Primitive(Primitive::String(s2))) => s != *s2,
|
||||||
i == (*i2 as u128)
|
_ => false,
|
||||||
}
|
},
|
||||||
("-ne", Value::Primitive(Primitive::Int(i2))) => {
|
|
||||||
i != (*i2 as u128)
|
|
||||||
}
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value::Primitive(Primitive::Int(i)) => {
|
|
||||||
match (op, rhs) {
|
|
||||||
("-lt", Value::Primitive(Primitive::Int(i2))) => {
|
|
||||||
i < *i2
|
|
||||||
}
|
|
||||||
("-gt", Value::Primitive(Primitive::Int(i2))) => {
|
|
||||||
i > *i2
|
|
||||||
}
|
|
||||||
("-le", Value::Primitive(Primitive::Int(i2))) => {
|
|
||||||
i <= *i2
|
|
||||||
}
|
|
||||||
("-ge", Value::Primitive(Primitive::Int(i2))) => {
|
|
||||||
i >= *i2
|
|
||||||
}
|
|
||||||
("-eq", Value::Primitive(Primitive::Int(i2))) => {
|
|
||||||
i == *i2
|
|
||||||
}
|
|
||||||
("-ne", Value::Primitive(Primitive::Int(i2))) => {
|
|
||||||
i != *i2
|
|
||||||
}
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value::Primitive(Primitive::String(s)) => {
|
|
||||||
match (op, rhs) {
|
|
||||||
("-eq", Value::Primitive(Primitive::String(s2))) => {
|
|
||||||
s == *s2
|
|
||||||
}
|
|
||||||
("-ne", Value::Primitive(Primitive::String(s2))) => {
|
|
||||||
s != *s2
|
|
||||||
}
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,12 @@ crate fn print_items(items: &[Item]) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
crate fn name(&self) -> &str {
|
crate fn name(&self) -> Result<&str, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
Item::Quoted(s) => s,
|
Item::Quoted(s) => Ok(s),
|
||||||
Item::Bare(s) => s,
|
Item::Bare(s) => Ok(s),
|
||||||
Item::Boolean(_) | Item::Int(_) => unimplemented!(),
|
Item::Boolean(i) => Err(ShellError::string(format!("{} is not a valid command", i))),
|
||||||
|
Item::Int(i) => Err(ShellError::string(format!("{} is not a valid command", i))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
src/shell.rs
Normal file
4
src/shell.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
crate mod completer;
|
||||||
|
crate mod helper;
|
||||||
|
|
||||||
|
crate use helper::Helper;
|
41
src/shell/completer.rs
Normal file
41
src/shell/completer.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use rustyline::completion::{Candidate, Completer};
|
||||||
|
use rustyline::line_buffer::LineBuffer;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
crate struct NuCompleter;
|
||||||
|
|
||||||
|
impl Completer for NuCompleter {
|
||||||
|
type Candidate = NuPair;
|
||||||
|
|
||||||
|
fn complete(
|
||||||
|
&self,
|
||||||
|
_line: &str,
|
||||||
|
_pos: usize,
|
||||||
|
_context: &rustyline::Context,
|
||||||
|
) -> rustyline::Result<(usize, Vec<NuPair>)> {
|
||||||
|
Ok((
|
||||||
|
0,
|
||||||
|
vec![
|
||||||
|
NuPair("exit", "exit"),
|
||||||
|
NuPair("ls", "ls"),
|
||||||
|
NuPair("ps", "ps"),
|
||||||
|
],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
|
||||||
|
let end = line.pos();
|
||||||
|
line.replace(start..end, elected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate struct NuPair(&'static str, &'static str);
|
||||||
|
|
||||||
|
impl Candidate for NuPair {
|
||||||
|
fn display(&self) -> &str {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
fn replacement(&self) -> &str {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
}
|
62
src/shell/helper.rs
Normal file
62
src/shell/helper.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use crate::shell::completer::{NuCompleter, NuPair};
|
||||||
|
|
||||||
|
use rustyline::completion::Completer;
|
||||||
|
use rustyline::error::ReadlineError;
|
||||||
|
use rustyline::highlight::{Highlighter, MatchingBracketHighlighter};
|
||||||
|
use rustyline::hint::{Hinter, HistoryHinter};
|
||||||
|
use std::borrow::Cow::{self, Owned};
|
||||||
|
|
||||||
|
crate struct Helper {
|
||||||
|
completer: NuCompleter,
|
||||||
|
highlighter: MatchingBracketHighlighter,
|
||||||
|
hinter: HistoryHinter,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Helper {
|
||||||
|
crate fn new() -> Helper {
|
||||||
|
Helper {
|
||||||
|
completer: NuCompleter,
|
||||||
|
highlighter: MatchingBracketHighlighter::new(),
|
||||||
|
hinter: HistoryHinter {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Completer for Helper {
|
||||||
|
type Candidate = NuPair;
|
||||||
|
|
||||||
|
fn complete(
|
||||||
|
&self,
|
||||||
|
line: &str,
|
||||||
|
pos: usize,
|
||||||
|
ctx: &rustyline::Context<'_>,
|
||||||
|
) -> Result<(usize, Vec<NuPair>), ReadlineError> {
|
||||||
|
self.completer.complete(line, pos, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hinter for Helper {
|
||||||
|
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||||
|
self.hinter.hint(line, pos, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Highlighter for Helper {
|
||||||
|
fn highlight_prompt<'p>(&self, prompt: &'p str) -> Cow<'p, str> {
|
||||||
|
Owned("\x1b[32m".to_owned() + &prompt[0..prompt.len() - 2] + "\x1b[m> ")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
|
||||||
|
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_char(&self, line: &str, pos: usize) -> bool {
|
||||||
|
self.highlighter.highlight_char(line, pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl rustyline::Helper for Helper {}
|
Loading…
Reference in New Issue
Block a user