changeset 21798:12e7456f7619

Tab completion of multiple directory levels. (bug #44095) * cmd-edit.h, cmd-edit.cc (gnu_readline::completer_quote_characters): New static data member. (gnu_readline::completion_hook_fcn): New typedef. (looks_like_filename): New static function. (gnu_readline::do_set_completer_quote_characters): Set octave_quote_characters instead of calling octave_rl_set_completer_quote_characters directly. (gnu_readline::do_completer_word_break_hook): New static function. (gnu_readline::do_set_completer_word_break_hook): New function. (gnu_readline::do_set_completer_word_break_characters): Also set completer_word_break_hook. * oct-rl-edit.h, oct-rl-edit.c (rl_completion_hook_fcn_ptr): New typedef. (octave_rl_get_completer_word_break_characters, octave_rl_set_completion_word_break_hook): New functions.
author Lachlan Andrew <lachlanbis@gmail.com>
date Tue, 31 May 2016 12:51:52 +1000
parents e5f083f9704e
children ddd00394d4fe
files liboctave/util/cmd-edit.cc liboctave/util/cmd-edit.h liboctave/util/oct-rl-edit.c liboctave/util/oct-rl-edit.h
diffstat 4 files changed, 105 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/util/cmd-edit.cc	Mon May 30 10:44:24 2016 -0400
+++ b/liboctave/util/cmd-edit.cc	Tue May 31 12:51:52 2016 +1000
@@ -37,6 +37,7 @@
 #include "cmd-edit.h"
 #include "cmd-hist.h"
 #include "file-ops.h"
+#include "file-stat.h"
 #include "lo-error.h"
 #include "lo-utils.h"
 #include "oct-env.h"
@@ -53,6 +54,8 @@
 
 namespace octave
 {
+  char *do_completer_word_break_hook ();
+
   command_editor *command_editor::instance = 0;
 
   std::set<command_editor::startup_hook_fcn> command_editor::startup_hook_set;
@@ -217,6 +220,8 @@
 
     user_accept_line_fcn user_accept_line_function;
 
+    static std::string completer_quote_characters;
+
     static char *command_generator (const char *text, int state);
 
     static char *command_quoter (char *text, int match_type, char *quote_pointer);
@@ -227,8 +232,12 @@
     static int command_accept_line (int count, int key);
 
     static char **command_completer (const char *text, int start, int end);
+
+    static char *do_completer_word_break_hook ();
   };
 
+  std::string gnu_readline::completer_quote_characters = "";
+
   gnu_readline::gnu_readline ()
     : command_editor (), previous_startup_hook (0),
       previous_pre_input_hook (0),
@@ -401,6 +410,10 @@
   gnu_readline::do_set_completer_word_break_characters (const std::string& s)
   {
     ::octave_rl_set_completer_word_break_characters (s.c_str ());
+
+    ::octave_rl_set_completion_word_break_hook
+      (gnu_readline::do_completer_word_break_hook);
+
   }
 
   void
@@ -418,7 +431,7 @@
   void
   gnu_readline::do_set_completer_quote_characters (const std::string& s)
   {
-    ::octave_rl_set_completer_quote_characters (s.c_str ());
+    completer_quote_characters = s;
   }
 
   void
@@ -514,6 +527,75 @@
     return user_accept_line_function;
   }
 
+  // True if the last "word" of the string line (delimited by delim) is
+  // an existing directory.  Used by do_completer_word_break_hook.
+
+  static bool
+  looks_like_filename (const char *line, char delim)
+  {
+    bool retval = false;
+
+    const char *s = strrchr (line, delim);
+
+    if (s)
+      {
+        // Remove incomplete component.
+        const char *f = strrchr (line, octave::sys::file_ops::dir_sep_char ());
+
+        if (s[1] == '~' || (f && f != s))
+          {
+            // For something like "A /b", f==s; don't assume a file.
+
+            std::string candidate_filename = s+1;
+
+            candidate_filename = candidate_filename.substr (0, f - s);
+
+            // Handles any complete ~<username>, but doesn't expand usernames.
+
+            if (candidate_filename[0] == '~')
+              candidate_filename
+                = octave::sys::file_ops::tilde_expand (candidate_filename);
+
+            octave::sys::file_stat fs (candidate_filename);
+
+            retval = fs.is_dir ();
+          }
+      }
+
+    return retval;
+  }
+
+  // Decide whether to interpret partial commands like "abc/def" as a
+  // filename or division.  Return the set of delimiters appropriate for
+  // the decision.
+
+  char *
+  gnu_readline::do_completer_word_break_hook ()
+  {
+    static char *dir_sep = strdup (" '\"");
+
+    std::string word;
+    std::string line = get_line_buffer ();
+
+    // For now, assume space or quote delimiter for file names.
+    const char *l = line.c_str ();
+
+    if (looks_like_filename (l, ' ') || looks_like_filename (l, '\'')
+        || looks_like_filename (l, '"'))
+      {
+        ::octave_rl_set_completer_quote_characters (completer_quote_characters.c_str ());
+
+        return dir_sep;
+      }
+    else
+      {
+        ::octave_rl_set_completer_quote_characters ("");
+
+        return octave_rl_get_completer_word_break_characters ();
+      }
+  }
+
+
   string_vector
   gnu_readline::do_generate_filename_completions (const std::string& text)
   {
--- a/liboctave/util/cmd-edit.h	Mon May 30 10:44:24 2016 -0400
+++ b/liboctave/util/cmd-edit.h	Tue May 31 12:51:52 2016 +1000
@@ -53,6 +53,8 @@
 
     typedef std::string (*completion_fcn) (const std::string&, int);
 
+    typedef char * (*completion_hook_fcn) ();
+
     typedef std::string (*quoting_fcn) (const std::string&, int, char);
 
     typedef std::string (*dequoting_fcn) (const std::string&, int);
@@ -276,6 +278,8 @@
 
     virtual void do_set_completer_word_break_characters (const std::string&) { }
 
+    virtual void do_set_completer_word_break_hook (completion_hook_fcn) { }
+
     virtual void do_set_basic_quote_characters (const std::string&) { }
 
     virtual void do_set_filename_quote_characters (const std::string&) { }
--- a/liboctave/util/oct-rl-edit.c	Mon May 30 10:44:24 2016 -0400
+++ b/liboctave/util/oct-rl-edit.c	Tue May 31 12:51:52 2016 +1000
@@ -297,6 +297,18 @@
   rl_completer_word_break_characters = ss;
 }
 
+char *
+octave_rl_get_completer_word_break_characters (void)
+{
+  return rl_completer_word_break_characters;
+}
+
+void
+octave_rl_set_completion_word_break_hook (rl_completion_hook_fcn_ptr f)
+{
+  rl_completion_word_break_hook = f;
+}
+
 void
 octave_rl_set_basic_quote_characters (const char *s)
 {
--- a/liboctave/util/oct-rl-edit.h	Mon May 30 10:44:24 2016 -0400
+++ b/liboctave/util/oct-rl-edit.h	Tue May 31 12:51:52 2016 +1000
@@ -37,6 +37,8 @@
 
 typedef char * (*rl_completer_fcn_ptr) (const char *, int);
 
+typedef char * (*rl_completion_hook_fcn_ptr) (void);
+
 typedef char * (*rl_quoting_fcn_ptr) (char *, int, char *);
 
 typedef char * (*rl_dequoting_fcn_ptr) (char *, int);
@@ -118,6 +120,10 @@
 
 extern void octave_rl_set_completer_word_break_characters (const char *);
 
+extern char *octave_rl_get_completer_word_break_characters (void);
+
+extern void octave_rl_set_completion_word_break_hook (rl_completion_hook_fcn_ptr);
+
 extern void octave_rl_set_basic_quote_characters (const char *);
 
 extern void octave_rl_set_filename_quote_characters (const char *);