Show completion hints for built-in values
This commit is contained in:
parent
848a0cadb6
commit
f2e7badf4b
@ -1,5 +1,6 @@
|
|||||||
use std::{collections::BTreeMap, env::args, sync::OnceLock};
|
use std::{collections::BTreeMap, env::args, sync::OnceLock};
|
||||||
|
|
||||||
|
use enum_iterator::{all, Sequence};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -13,7 +14,11 @@ static JSON: OnceLock<Value> = OnceLock::new();
|
|||||||
static RANDOM: OnceLock<Value> = OnceLock::new();
|
static RANDOM: OnceLock<Value> = OnceLock::new();
|
||||||
static STRING: OnceLock<Value> = OnceLock::new();
|
static STRING: OnceLock<Value> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
pub fn built_in_values() -> impl Iterator<Item = BuiltInValue> {
|
||||||
|
all()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Sequence, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum BuiltInValue {
|
pub enum BuiltInValue {
|
||||||
Args,
|
Args,
|
||||||
AssertEqual,
|
AssertEqual,
|
||||||
@ -39,7 +44,7 @@ impl BuiltInValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
pub fn r#type(&self) -> Type {
|
||||||
match self {
|
match self {
|
||||||
BuiltInValue::Args => Type::list(Type::String),
|
BuiltInValue::Args => Type::list(Type::String),
|
||||||
BuiltInValue::AssertEqual => BuiltInFunction::AssertEqual.r#type(),
|
BuiltInValue::AssertEqual => BuiltInFunction::AssertEqual.r#type(),
|
||||||
@ -52,7 +57,7 @@ impl BuiltInValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self) -> &Value {
|
pub fn get(&self) -> &Value {
|
||||||
match self {
|
match self {
|
||||||
BuiltInValue::Args => ARGS.get_or_init(|| {
|
BuiltInValue::Args => ARGS.get_or_init(|| {
|
||||||
let args = args().map(|arg| Value::string(arg.to_string())).collect();
|
let args = args().map(|arg| Value::string(arg.to_string())).collect();
|
||||||
|
@ -142,6 +142,14 @@ impl Type {
|
|||||||
pub fn is_function(&self) -> bool {
|
pub fn is_function(&self) -> bool {
|
||||||
matches!(self, Type::Function { .. })
|
matches!(self, Type::Function { .. })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_list(&self) -> bool {
|
||||||
|
matches!(self, Type::List(_))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_map(&self) -> bool {
|
||||||
|
matches!(self, Type::Map(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Type {
|
impl AbstractTree for Type {
|
||||||
|
59
src/main.rs
59
src/main.rs
@ -3,16 +3,17 @@
|
|||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use rustyline::{
|
use rustyline::{
|
||||||
completion::FilenameCompleter,
|
completion::FilenameCompleter,
|
||||||
|
config::Builder,
|
||||||
error::ReadlineError,
|
error::ReadlineError,
|
||||||
highlight::Highlighter,
|
highlight::Highlighter,
|
||||||
hint::{Hint, Hinter, HistoryHinter},
|
hint::{Hint, Hinter, HistoryHinter},
|
||||||
history::DefaultHistory,
|
history::DefaultHistory,
|
||||||
Completer, Context, Editor, Helper, Validator,
|
ColorMode, Completer, CompletionType, Context, Editor, Helper, Validator,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{borrow::Cow, fs::read_to_string};
|
use std::{borrow::Cow, fs::read_to_string};
|
||||||
|
|
||||||
use dust_lang::{Interpreter, Map, Value};
|
use dust_lang::{built_in_values, Interpreter, Map, Value};
|
||||||
|
|
||||||
/// Command-line arguments to be parsed.
|
/// Command-line arguments to be parsed.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@ -112,7 +113,7 @@ struct DustReadline {
|
|||||||
#[rustyline(Completer)]
|
#[rustyline(Completer)]
|
||||||
completer: FilenameCompleter,
|
completer: FilenameCompleter,
|
||||||
|
|
||||||
tool_hints: Vec<ToolHint>,
|
hints: Vec<ToolHint>,
|
||||||
|
|
||||||
#[rustyline(Hinter)]
|
#[rustyline(Hinter)]
|
||||||
_hinter: HistoryHinter,
|
_hinter: HistoryHinter,
|
||||||
@ -120,10 +121,49 @@ struct DustReadline {
|
|||||||
|
|
||||||
impl DustReadline {
|
impl DustReadline {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
|
let mut hints = Vec::new();
|
||||||
|
|
||||||
|
for built_in_value in built_in_values() {
|
||||||
|
let mut display = built_in_value.name().to_string();
|
||||||
|
|
||||||
|
if built_in_value.r#type().is_function() {
|
||||||
|
display.push_str("()");
|
||||||
|
}
|
||||||
|
|
||||||
|
if built_in_value.r#type().is_map() {
|
||||||
|
let value = built_in_value.get();
|
||||||
|
|
||||||
|
if let Value::Map(map) = value {
|
||||||
|
for (key, (value, _)) in map.variables().unwrap().iter() {
|
||||||
|
let display = if value.is_function() {
|
||||||
|
format!("{display}:{key}()")
|
||||||
|
} else {
|
||||||
|
format!("{display}:{key}")
|
||||||
|
};
|
||||||
|
|
||||||
|
hints.push(ToolHint {
|
||||||
|
complete_to: display.len(),
|
||||||
|
display,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hints.push(ToolHint {
|
||||||
|
complete_to: display.len(),
|
||||||
|
display,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
hints.push(ToolHint {
|
||||||
|
display: "output".to_string(),
|
||||||
|
complete_to: 0,
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
completer: FilenameCompleter::new(),
|
completer: FilenameCompleter::new(),
|
||||||
_hinter: HistoryHinter {},
|
_hinter: HistoryHinter {},
|
||||||
tool_hints: Vec::new(),
|
hints,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,7 +204,7 @@ impl Hinter for DustReadline {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tool_hints.iter().find_map(|tool_hint| {
|
self.hints.iter().find_map(|tool_hint| {
|
||||||
if tool_hint.display.starts_with(line) {
|
if tool_hint.display.starts_with(line) {
|
||||||
Some(tool_hint.suffix(pos))
|
Some(tool_hint.suffix(pos))
|
||||||
} else {
|
} else {
|
||||||
@ -176,7 +216,7 @@ impl Hinter for DustReadline {
|
|||||||
|
|
||||||
impl Highlighter for DustReadline {
|
impl Highlighter for DustReadline {
|
||||||
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
|
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
|
||||||
let highlighted = ansi_term::Colour::Red.paint(hint).to_string();
|
let highlighted = ansi_term::Colour::Yellow.paint(hint).to_string();
|
||||||
|
|
||||||
Cow::Owned(highlighted)
|
Cow::Owned(highlighted)
|
||||||
}
|
}
|
||||||
@ -184,7 +224,12 @@ impl Highlighter for DustReadline {
|
|||||||
|
|
||||||
fn run_cli_shell(context: Map) {
|
fn run_cli_shell(context: Map) {
|
||||||
let mut interpreter = Interpreter::new(context);
|
let mut interpreter = Interpreter::new(context);
|
||||||
let mut rl: Editor<DustReadline, DefaultHistory> = Editor::new().unwrap();
|
let config = Builder::new()
|
||||||
|
.color_mode(ColorMode::Enabled)
|
||||||
|
.completion_type(CompletionType::List)
|
||||||
|
.build();
|
||||||
|
let mut rl: Editor<DustReadline, DefaultHistory> =
|
||||||
|
Editor::with_config(config).expect("Line editor could not be configured properly.");
|
||||||
|
|
||||||
rl.set_helper(Some(DustReadline::new()));
|
rl.set_helper(Some(DustReadline::new()));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user