mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 19:17:44 +02:00
Merge master
This commit is contained in:
@ -1,5 +1,3 @@
|
||||
use crate::context::CommandRegistry;
|
||||
|
||||
use derive_new::new;
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::completion::{self, FilenameCompleter};
|
||||
@ -8,19 +6,32 @@ use rustyline::line_buffer::LineBuffer;
|
||||
#[derive(new)]
|
||||
crate struct NuCompleter {
|
||||
pub file_completer: FilenameCompleter,
|
||||
pub commands: CommandRegistry,
|
||||
//pub commands: indexmap::IndexMap<String, Arc<dyn Command>>,
|
||||
}
|
||||
|
||||
impl Completer for NuCompleter {
|
||||
type Candidate = completion::Pair;
|
||||
pub struct CompletionPair {
|
||||
pub display: String,
|
||||
pub replacement: String,
|
||||
}
|
||||
|
||||
fn complete(
|
||||
impl Into<completion::Pair> for CompletionPair {
|
||||
fn into(self) -> completion::Pair {
|
||||
completion::Pair {
|
||||
display: self.display,
|
||||
replacement: self.replacement,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NuCompleter {
|
||||
/*
|
||||
pub fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
context: &rustyline::Context,
|
||||
) -> rustyline::Result<(usize, Vec<completion::Pair>)> {
|
||||
let commands: Vec<String> = self.commands.names();
|
||||
) -> rustyline::Result<(usize, Vec<CompletionPair>)> {
|
||||
//let commands: Vec<String> = self.commands.keys().cloned().collect();
|
||||
|
||||
let mut completions = self.file_completer.complete(line, pos, context)?.1;
|
||||
|
||||
@ -51,6 +62,7 @@ impl Completer for NuCompleter {
|
||||
replace_pos -= 1;
|
||||
}
|
||||
|
||||
/*
|
||||
for command in commands.iter() {
|
||||
let mut pos = replace_pos;
|
||||
let mut matched = true;
|
||||
@ -68,15 +80,17 @@ impl Completer for NuCompleter {
|
||||
}
|
||||
|
||||
if matched {
|
||||
completions.push(completion::Pair {
|
||||
completions.push(CompletionPair {
|
||||
display: command.clone(),
|
||||
replacement: command.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Ok((replace_pos, completions))
|
||||
}
|
||||
*/
|
||||
|
||||
fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
|
||||
let end = line.pos();
|
||||
|
212
src/shell/filesystem_shell.rs
Normal file
212
src/shell/filesystem_shell.rs
Normal file
@ -0,0 +1,212 @@
|
||||
use crate::commands::command::CallInfo;
|
||||
use crate::object::dir_entry_dict;
|
||||
use crate::prelude::*;
|
||||
use crate::shell::completer::{CompletionPair, NuCompleter};
|
||||
use crate::shell::shell::Shell;
|
||||
use rustyline::completion::{Completer, FilenameCompleter};
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::hint::{Hinter, HistoryHinter};
|
||||
use std::path::{Path, PathBuf};
|
||||
pub struct FilesystemShell {
|
||||
crate path: String,
|
||||
completer: NuCompleter,
|
||||
hinter: HistoryHinter,
|
||||
}
|
||||
|
||||
impl Clone for FilesystemShell {
|
||||
fn clone(&self) -> Self {
|
||||
FilesystemShell {
|
||||
path: self.path.clone(),
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
},
|
||||
hinter: HistoryHinter {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FilesystemShell {
|
||||
pub fn basic() -> Result<FilesystemShell, std::io::Error> {
|
||||
let path = std::env::current_dir()?;
|
||||
|
||||
Ok(FilesystemShell {
|
||||
path: path.to_string_lossy().to_string(),
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
},
|
||||
hinter: HistoryHinter {},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_location(path: String) -> Result<FilesystemShell, std::io::Error> {
|
||||
Ok(FilesystemShell {
|
||||
path,
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
},
|
||||
hinter: HistoryHinter {},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Shell for FilesystemShell {
|
||||
fn name(&self) -> String {
|
||||
"filesystem".to_string()
|
||||
}
|
||||
|
||||
fn ls(&self, call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
let cwd = self.path.clone();
|
||||
let mut full_path = PathBuf::from(&self.path);
|
||||
match &call_info.args.nth(0) {
|
||||
Some(Tagged { item: value, .. }) => full_path.push(Path::new(&value.as_string()?)),
|
||||
_ => {}
|
||||
}
|
||||
let entries = glob::glob(&full_path.to_string_lossy());
|
||||
|
||||
if entries.is_err() {
|
||||
return Err(ShellError::string("Invalid pattern."));
|
||||
}
|
||||
|
||||
let mut shell_entries = VecDeque::new();
|
||||
let entries: Vec<_> = entries.unwrap().collect();
|
||||
|
||||
// If this is a single entry, try to display the contents of the entry if it's a directory
|
||||
if entries.len() == 1 {
|
||||
if let Ok(entry) = &entries[0] {
|
||||
if entry.is_dir() {
|
||||
let entries = std::fs::read_dir(&full_path);
|
||||
|
||||
let entries = match entries {
|
||||
Err(e) => {
|
||||
if let Some(s) = call_info.args.nth(0) {
|
||||
return Err(ShellError::labeled_error(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
s.span(),
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
call_info.name_span,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(o) => o,
|
||||
};
|
||||
for entry in entries {
|
||||
let entry = entry?;
|
||||
let filepath = entry.path();
|
||||
let filename = filepath.strip_prefix(&cwd).unwrap();
|
||||
let value = dir_entry_dict(
|
||||
filename,
|
||||
&entry.metadata()?,
|
||||
Tag::unknown_origin(call_info.name_span),
|
||||
)?;
|
||||
shell_entries.push_back(ReturnSuccess::value(value))
|
||||
}
|
||||
return Ok(shell_entries.to_output_stream());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enumerate the entries from the glob and add each
|
||||
for entry in entries {
|
||||
if let Ok(entry) = entry {
|
||||
let filename = entry.strip_prefix(&cwd).unwrap();
|
||||
let metadata = std::fs::metadata(&entry)?;
|
||||
let value = dir_entry_dict(
|
||||
filename,
|
||||
&metadata,
|
||||
Tag::unknown_origin(call_info.name_span),
|
||||
)?;
|
||||
shell_entries.push_back(ReturnSuccess::value(value))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(shell_entries.to_output_stream())
|
||||
}
|
||||
|
||||
fn cd(&self, call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
let path = match call_info.args.nth(0) {
|
||||
None => match dirs::home_dir() {
|
||||
Some(o) => o,
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can not change to home directory",
|
||||
"can not go to home",
|
||||
call_info.name_span,
|
||||
))
|
||||
}
|
||||
},
|
||||
Some(v) => {
|
||||
let target = v.as_string()?;
|
||||
let path = PathBuf::from(self.path());
|
||||
match dunce::canonicalize(path.join(target).as_path()) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can not change to directory",
|
||||
"directory not found",
|
||||
v.span().clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
match std::env::set_current_dir(&path) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
if call_info.args.len() > 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can not change to directory",
|
||||
"directory not found",
|
||||
call_info.args.nth(0).unwrap().span().clone(),
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string("Can not change to directory"));
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.push_back(ReturnSuccess::change_cwd(
|
||||
path.to_string_lossy().to_string(),
|
||||
));
|
||||
Ok(stream.into())
|
||||
}
|
||||
|
||||
fn path(&self) -> String {
|
||||
self.path.clone()
|
||||
}
|
||||
|
||||
fn set_path(&mut self, path: String) {
|
||||
let pathbuf = PathBuf::from(&path);
|
||||
let path = match dunce::canonicalize(pathbuf.as_path()) {
|
||||
Ok(path) => {
|
||||
let _ = std::env::set_current_dir(&path);
|
||||
path
|
||||
}
|
||||
_ => {
|
||||
// TODO: handle the case where the path cannot be canonicalized
|
||||
pathbuf
|
||||
}
|
||||
};
|
||||
self.path = path.to_string_lossy().to_string();
|
||||
}
|
||||
|
||||
/*
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<CompletionPair>), ReadlineError> {
|
||||
self.completer.complete(line, pos, ctx)
|
||||
}
|
||||
*/
|
||||
|
||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
self.hinter.hint(line, pos, ctx)
|
||||
}
|
||||
}
|
@ -1,50 +1,60 @@
|
||||
use crate::parser::nom_input;
|
||||
use crate::parser::parse::span::Spanned;
|
||||
use crate::parser::parse::token_tree::TokenNode;
|
||||
use crate::parser::parse::tokens::RawToken;
|
||||
use crate::parser::{Pipeline, PipelineElement};
|
||||
use crate::prelude::*;
|
||||
use crate::shell::completer::NuCompleter;
|
||||
use crate::shell::completer::CompletionPair;
|
||||
use crate::shell::shell_manager::ShellManager;
|
||||
use crate::Tagged;
|
||||
use ansi_term::Color;
|
||||
use rustyline::completion::{self, Completer, FilenameCompleter};
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::highlight::Highlighter;
|
||||
use rustyline::hint::{Hinter, HistoryHinter};
|
||||
use rustyline::hint::Hinter;
|
||||
use std::borrow::Cow::{self, Owned};
|
||||
|
||||
crate struct Helper {
|
||||
completer: NuCompleter,
|
||||
hinter: HistoryHinter,
|
||||
helper: ShellManager,
|
||||
}
|
||||
|
||||
impl Helper {
|
||||
crate fn new(commands: CommandRegistry) -> Helper {
|
||||
Helper {
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
commands,
|
||||
},
|
||||
hinter: HistoryHinter {},
|
||||
}
|
||||
crate fn new(helper: ShellManager) -> Helper {
|
||||
Helper { helper }
|
||||
}
|
||||
}
|
||||
|
||||
impl Completer for Helper {
|
||||
type Candidate = completion::Pair;
|
||||
type Candidate = rustyline::completion::Pair;
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), ReadlineError> {
|
||||
//FIXME: Add back completions
|
||||
Ok((0, vec![]))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl Completer for Helper {
|
||||
type Candidate = rustyline::completion::Pair;
|
||||
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<completion::Pair>), ReadlineError> {
|
||||
self.completer.complete(line, pos, ctx)
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), ReadlineError> {
|
||||
let result = self.helper.complete(line, pos, ctx);
|
||||
|
||||
result.map(|(x, y)| (x, y.iter().map(|z| z.into()).collect()))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl Hinter for Helper {
|
||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
self.hinter.hint(line, pos, ctx)
|
||||
self.helper.hint(line, pos, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,23 +117,23 @@ fn paint_token_node(token_node: &TokenNode, line: &str) -> String {
|
||||
TokenNode::Delimited(..) => Color::White.paint(token_node.span().slice(line)),
|
||||
TokenNode::Operator(..) => Color::White.normal().paint(token_node.span().slice(line)),
|
||||
TokenNode::Pipeline(..) => Color::Blue.normal().paint(token_node.span().slice(line)),
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Integer(..),
|
||||
..
|
||||
}) => Color::Purple.bold().paint(token_node.span().slice(line)),
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Size(..),
|
||||
..
|
||||
}) => Color::Purple.bold().paint(token_node.span().slice(line)),
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::String(..),
|
||||
..
|
||||
}) => Color::Green.normal().paint(token_node.span().slice(line)),
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Variable(..),
|
||||
..
|
||||
}) => Color::Yellow.bold().paint(token_node.span().slice(line)),
|
||||
TokenNode::Token(Spanned {
|
||||
TokenNode::Token(Tagged {
|
||||
item: RawToken::Bare,
|
||||
..
|
||||
}) => Color::Green.normal().paint(token_node.span().slice(line)),
|
||||
|
22
src/shell/shell.rs
Normal file
22
src/shell/shell.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use crate::commands::command::CallInfo;
|
||||
use crate::errors::ShellError;
|
||||
use crate::shell::completer::CompletionPair;
|
||||
use crate::stream::{InputStream, OutputStream};
|
||||
use rustyline::error::ReadlineError;
|
||||
|
||||
pub trait Shell {
|
||||
fn name(&self) -> String;
|
||||
fn ls(&self, call_info: CallInfo, input: InputStream) -> Result<OutputStream, ShellError>;
|
||||
fn cd(&self, call_info: CallInfo, input: InputStream) -> Result<OutputStream, ShellError>;
|
||||
fn path(&self) -> String;
|
||||
fn set_path(&mut self, path: String);
|
||||
|
||||
// fn complete(
|
||||
// &self,
|
||||
// line: &str,
|
||||
// pos: usize,
|
||||
// ctx: &rustyline::Context<'_>,
|
||||
// ) -> Result<(usize, Vec<CompletionPair>), ReadlineError>;
|
||||
|
||||
fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String>;
|
||||
}
|
101
src/shell/shell_manager.rs
Normal file
101
src/shell/shell_manager.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use crate::commands::command::CallInfo;
|
||||
use crate::errors::ShellError;
|
||||
use crate::shell::completer::CompletionPair;
|
||||
use crate::shell::filesystem_shell::FilesystemShell;
|
||||
use crate::shell::shell::Shell;
|
||||
use crate::stream::{InputStream, OutputStream};
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::error::ReadlineError;
|
||||
use std::error::Error;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ShellManager {
|
||||
crate shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>,
|
||||
}
|
||||
|
||||
impl ShellManager {
|
||||
pub fn basic() -> Result<ShellManager, Box<dyn Error>> {
|
||||
Ok(ShellManager {
|
||||
shells: Arc::new(Mutex::new(vec![Box::new(FilesystemShell::basic()?)])),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn push(&mut self, shell: Box<dyn Shell + Send>) {
|
||||
self.shells.lock().unwrap().push(shell);
|
||||
self.set_path(self.path());
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) {
|
||||
self.shells.lock().unwrap().pop();
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.shells.lock().unwrap().is_empty()
|
||||
}
|
||||
|
||||
pub fn path(&self) -> String {
|
||||
self.shells.lock().unwrap().last().unwrap().path()
|
||||
}
|
||||
|
||||
pub fn set_path(&mut self, path: String) {
|
||||
self.shells
|
||||
.lock()
|
||||
.unwrap()
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.set_path(path)
|
||||
}
|
||||
|
||||
// pub fn complete(
|
||||
// &self,
|
||||
// line: &str,
|
||||
// pos: usize,
|
||||
// ctx: &rustyline::Context<'_>,
|
||||
// ) -> Result<(usize, Vec<CompletionPair>), ReadlineError> {
|
||||
// self.shells
|
||||
// .lock()
|
||||
// .unwrap()
|
||||
// .last()
|
||||
// .unwrap()
|
||||
// .complete(line, pos, ctx)
|
||||
// }
|
||||
|
||||
pub fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
self.shells
|
||||
.lock()
|
||||
.unwrap()
|
||||
.last()
|
||||
.unwrap()
|
||||
.hint(line, pos, ctx)
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
{
|
||||
let mut x = self.shells.lock().unwrap();
|
||||
let shell = x.pop().unwrap();
|
||||
x.insert(0, shell);
|
||||
}
|
||||
self.set_path(self.path());
|
||||
}
|
||||
|
||||
pub fn prev(&mut self) {
|
||||
{
|
||||
let mut x = self.shells.lock().unwrap();
|
||||
let shell = x.remove(0);
|
||||
x.push(shell);
|
||||
}
|
||||
self.set_path(self.path());
|
||||
}
|
||||
|
||||
pub fn ls(&self, call_info: CallInfo, input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
let env = self.shells.lock().unwrap();
|
||||
|
||||
env.last().unwrap().ls(call_info, input)
|
||||
}
|
||||
pub fn cd(&self, call_info: CallInfo, input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
let env = self.shells.lock().unwrap();
|
||||
|
||||
env.last().unwrap().cd(call_info, input)
|
||||
}
|
||||
}
|
165
src/shell/value_shell.rs
Normal file
165
src/shell/value_shell.rs
Normal file
@ -0,0 +1,165 @@
|
||||
use crate::commands::command::CallInfo;
|
||||
use crate::prelude::*;
|
||||
use crate::shell::completer::CompletionPair;
|
||||
use crate::shell::shell::Shell;
|
||||
use rustyline::error::ReadlineError;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ValueShell {
|
||||
crate path: String,
|
||||
crate value: Tagged<Value>,
|
||||
}
|
||||
|
||||
impl ValueShell {
|
||||
pub fn new(value: Tagged<Value>) -> ValueShell {
|
||||
ValueShell {
|
||||
path: "/".to_string(),
|
||||
value,
|
||||
}
|
||||
}
|
||||
fn members(&self) -> VecDeque<Tagged<Value>> {
|
||||
let mut shell_entries = VecDeque::new();
|
||||
let full_path = PathBuf::from(&self.path);
|
||||
let mut viewed = self.value.clone();
|
||||
let sep_string = std::path::MAIN_SEPARATOR.to_string();
|
||||
let sep = OsStr::new(&sep_string);
|
||||
for p in full_path.iter() {
|
||||
match p {
|
||||
x if x == sep => {}
|
||||
step => match viewed.get_data_by_key(step.to_str().unwrap()) {
|
||||
Some(v) => {
|
||||
viewed = v.clone();
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
match viewed {
|
||||
Tagged {
|
||||
item: Value::List(l),
|
||||
..
|
||||
} => {
|
||||
for item in l {
|
||||
shell_entries.push_back(item.clone());
|
||||
}
|
||||
}
|
||||
x => {
|
||||
shell_entries.push_back(x.clone());
|
||||
}
|
||||
}
|
||||
|
||||
shell_entries
|
||||
}
|
||||
}
|
||||
|
||||
impl Shell for ValueShell {
|
||||
fn name(&self) -> String {
|
||||
"value".to_string()
|
||||
}
|
||||
|
||||
fn ls(&self, _call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
Ok(self
|
||||
.members()
|
||||
.map(|x| ReturnSuccess::value(x))
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
fn cd(&self, call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
let path = match call_info.args.nth(0) {
|
||||
None => "/".to_string(),
|
||||
Some(v) => {
|
||||
let target = v.as_string()?;
|
||||
|
||||
let mut cwd = PathBuf::from(&self.path);
|
||||
match target {
|
||||
x if x == ".." => {
|
||||
cwd.pop();
|
||||
}
|
||||
_ => match target.chars().nth(0) {
|
||||
Some(x) if x == '/' => cwd = PathBuf::from(target),
|
||||
_ => {
|
||||
cwd.push(target);
|
||||
}
|
||||
},
|
||||
}
|
||||
cwd.to_string_lossy().to_string()
|
||||
}
|
||||
};
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(ReturnSuccess::change_cwd(path));
|
||||
Ok(stream.into())
|
||||
}
|
||||
|
||||
fn path(&self) -> String {
|
||||
self.path.clone()
|
||||
}
|
||||
|
||||
fn set_path(&mut self, path: String) {
|
||||
let _ = std::env::set_current_dir(&path);
|
||||
self.path = path.clone();
|
||||
}
|
||||
|
||||
/*
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
_ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<CompletionPair>), ReadlineError> {
|
||||
let mut completions = vec![];
|
||||
|
||||
let mut possible_completion = vec![];
|
||||
let members = self.members();
|
||||
for member in members {
|
||||
match member {
|
||||
Tagged { item, .. } => {
|
||||
for desc in item.data_descriptors() {
|
||||
possible_completion.push(desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let line_chars: Vec<_> = line.chars().collect();
|
||||
let mut replace_pos = pos;
|
||||
while replace_pos > 0 {
|
||||
if line_chars[replace_pos - 1] == ' ' {
|
||||
break;
|
||||
}
|
||||
replace_pos -= 1;
|
||||
}
|
||||
|
||||
for command in possible_completion.iter() {
|
||||
let mut pos = replace_pos;
|
||||
let mut matched = true;
|
||||
if pos < line_chars.len() {
|
||||
for chr in command.chars() {
|
||||
if line_chars[pos] != chr {
|
||||
matched = false;
|
||||
break;
|
||||
}
|
||||
pos += 1;
|
||||
if pos == line_chars.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if matched {
|
||||
completions.push(CompletionPair {
|
||||
display: command.to_string(),
|
||||
replacement: command.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok((replace_pos, completions))
|
||||
}
|
||||
*/
|
||||
|
||||
fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user