From d237ec42b8180dadd6d117bc63e9b979c956415d Mon Sep 17 00:00:00 2001 From: Steven Stanfield <stanfield@scarecrowtech.com> Date: Thu, 4 Jul 2019 21:49:09 +0000 Subject: [PATCH] Formatted and fixed some tab complete issues for commands. - If directories in PATH did not end in / then command complete would not work. - Also complete commands if previous item ended in '|', '&' or ';'. This does not handle cases when a space does not follow the special character. - Do not include the full path when completing commands. --- src/binary/completer.rs | 55 +++++++++++++++++++++++------------------ src/binary/mod.rs | 8 +++--- src/lib/lib.rs | 8 +++--- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/binary/completer.rs b/src/binary/completer.rs index 9224356b..42500b9a 100644 --- a/src/binary/completer.rs +++ b/src/binary/completer.rs @@ -96,7 +96,14 @@ impl<'a, 'b> Completer for IonCompleter<'a, 'b> { // in the environment's **$PATH** variable. let file_completers: Vec<_> = if let Some(paths) = env::var_os("PATH") { env::split_paths(&paths) - .map(|s| IonFileCompleter::new(Some(s), &self.shell, true)) + .map(|s| { + let s = if !s.to_string_lossy().ends_with("/") { + PathBuf::from(format!("{}/", s.to_string_lossy())) + } else { + s + }; + IonFileCompleter::new(Some(s), &self.shell, true) + }) .collect() } else { vec![IonFileCompleter::new(Some("/bin/".into()), &self.shell, true)] @@ -106,35 +113,36 @@ impl<'a, 'b> Completer for IonCompleter<'a, 'b> { } CompletionType::Nothing => (), } - + completions } fn on_event<W: std::io::Write>(&mut self, event: Event<'_, '_, W>) { if let EventKind::BeforeComplete = event.kind { let (words, pos) = event.editor.get_words_and_cursor_position(); - -/* self.complete_commands = match pos { - CursorPosition::InWord(_) => false, - CursorPosition::InSpace(Some(_), _) => false, - CursorPosition::InSpace(None, _) => false, - CursorPosition::OnWordLeftEdge(_) => false, - CursorPosition::OnWordRightEdge(index) => if index == 0 { - true - } else { - words - .into_iter() - .nth(index - 1) - .map(|(start, end)| event.editor.current_buffer().range(start, end)) - .filter(|filename| filename.ends_with("|")) - .is_some() - }, - }; - }*/ self.completion = match pos { _ if words.is_empty() => CompletionType::Nothing, - CursorPosition::InWord(0) | CursorPosition::OnWordRightEdge(0) => { - CompletionType::Command + CursorPosition::InWord(0) => CompletionType::Command, + CursorPosition::OnWordRightEdge(index) => { + if index == 0 { + CompletionType::Command + } else { + let is_pipe = words + .into_iter() + .nth(index - 1) + .map(|(start, end)| event.editor.current_buffer().range(start, end)) + .filter(|filename| { + filename.ends_with("|") + || filename.ends_with("&") + || filename.ends_with(";") + }) + .is_some(); + if is_pipe { + CompletionType::Command + } else { + CompletionType::VariableAndFiles + } + } } _ => CompletionType::VariableAndFiles, }; @@ -184,7 +192,6 @@ impl<'a, 'b> Completer for IonFileCompleter<'a, 'b> { // Now we obtain completions for the `expanded` form of the `start` value. let completions = filename_completion(&expanded, &self.path); if expanded == start { - //return completions.map(|s| s.rsplit('/').nth(0).unwrap_or(&s).to_string()).collect(); return if self.for_command { completions.map(|s| s.rsplit('/').nth(0).unwrap_or(&s).to_string()).collect() } else { @@ -253,7 +260,7 @@ fn filename_completion<'a>(start: &'a str, path: &'a PathBuf) -> impl Iterator<I let globs = glob_with( &string, MatchOptions { - case_sensitive: false, //true, + case_sensitive: true, require_literal_separator: true, require_literal_leading_dot: false, }, diff --git a/src/binary/mod.rs b/src/binary/mod.rs index 07c953a0..f9d1351f 100644 --- a/src/binary/mod.rs +++ b/src/binary/mod.rs @@ -18,8 +18,7 @@ use liner::{Buffer, Context, KeyBindings}; use std::{ cell::{Cell, RefCell}, fs::{self, OpenOptions}, - io, - io::Write, + io::{self, Write}, path::Path, rc::Rc, }; @@ -191,7 +190,10 @@ impl<'a> InteractiveShell<'a> { context_bis.borrow_mut().history.load_duplicates = false; } Some(_) => { - Status::error("Invalid history option. Choices are [+|-] inc_append and share (implies inc_append)."); + Status::error( + "Invalid history option. Choices are [+|-] inc_append, duplicates and \ + share (implies inc_append).", + ); } None => { print!("{}", context_bis.borrow().history.buffers.iter().format("\n")); diff --git a/src/lib/lib.rs b/src/lib/lib.rs index c2459cd8..fe05dd92 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -18,8 +18,8 @@ //! ## Demo //! //! ```rust -//! use ion_shell::{builtins::Status, Value, types, BuiltinFunction, BuiltinMap, Shell}; -//! use std::{cell::RefCell, rc::Rc, thread, time, fs::File}; +//! use ion_shell::{builtins::Status, types, BuiltinFunction, BuiltinMap, Shell, Value}; +//! use std::{cell::RefCell, fs::File, rc::Rc, thread, time}; //! //! enum Layout { //! Simple, @@ -57,7 +57,9 @@ //! i += 1; //! // call a user-defined callback function named on_update //! if let Some(Value::Function(function)) = shell.variables().get("on_update") { -//! if let Err(why) = shell.execute_function(&function.clone(), &["ion", &i.to_string()]) { +//! if let Err(why) = +//! shell.execute_function(&function.clone(), &["ion", &i.to_string()]) +//! { //! println!("ERROR: my-application: error in on_update callback: {}", why); //! } //! } -- GitLab