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