bug-apl
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Patch: CTRL+R command history substring search


From: Russtopia
Subject: Patch: CTRL+R command history substring search
Date: Thu, 22 Jul 2021 01:32:40 -0700

Hello,

I read in the documentation that some time ago, the line edit logic was re-written to no longer use GNU readline, for better context-aware behaviour. However I miss the ability to jump back in history based on substrings. Holding up-arrow or CTRL-P to sequentially go back through history can be tedious, so I added some logic similar to the bash CTRL+R behaviour.

See patch below. Perhaps it could be improved, suggestions welcomed.

Cheers,
-Russ

---

Index: src/LineInput.cc
===================================================================
--- src/LineInput.cc (revision 1477)
+++ src/LineInput.cc (working copy)
@@ -126,7 +126,9 @@
 LineHistory::LineHistory(int maxl)
    : current_line(0),
      put(0),
-     max_lines(maxl)
+     max_lines(maxl),
+     cur_search_substr( "" ),
+     last_search_line(0)
 {
    UCS_string u("xxx");
    add_line(u);
@@ -135,7 +137,9 @@
 LineHistory::LineHistory(const Nabla & nabla)
    : current_line(0),
      put(0),
-     max_lines(1000)
+     max_lines(1000),
+     cur_search_substr( "" ),
+     last_search_line(0)
 {
    UCS_string u("xxx");
    add_line(u);
@@ -308,6 +312,56 @@
 
    return &hist_lines[current_line];
 }
+//-----------------------------------------------------------------------------
+const void
+LineHistory::clear_search(void)
+{
+    cur_search_substr = "";
+}
+//-----------------------------------------------------------------------------
+const void
+LineHistory::update_search(UCS_string &cur_line)
+{
+    cur_search_substr = cur_line;
+}
+//-----------------------------------------------------------------------------
+const UCS_string *
+LineHistory::search(UCS_string &cur_line)
+{
+    if( hist_lines.size() == 0 ) return 0;  // no history
+
+    // For now, a simple prefix search of hist_lines[]
+    int search_start_line = last_search_line - 1;
+    if( search_start_line < 0) {
+        search_start_line = hist_lines.size()-1;
+    }
+    int idx = search_start_line;
+    bool found = false;
+    do {
+        if( hist_lines[idx].substr_pos(cur_search_substr) >= 0 ) {
+            current_line = idx;
+            found = true;
+            continue;
+        }
+
+        idx--;
+        if( idx < 0 ) {
+            idx = hist_lines.size()-1;
+        }
+        if( idx == search_start_line ) {
+            break;
+        }
+    } while(!found);
+
+    if( !found ) {
+        idx = hist_lines.size()-1;
+    }
+
+    last_search_line = idx;
+    if( idx == 0 ) return 0;
+
+    return &hist_lines[current_line];
+}
 //=============================================================================
 LineEditContext::LineEditContext(LineInputMode mode, int rows, int cols,
                                  LineHistory & hist, const UCS_string & prmt)
@@ -550,6 +604,13 @@
 }
 //-----------------------------------------------------------------------------
 void
+LineEditContext::cursor_CLEAR_SEARCH()
+{
+   Log(LOG_get_line)   history.info(CERR << "cursor_CLEAR_SEARCH()") << endl;
+   history.clear_search();
+}
+//-----------------------------------------------------------------------------
+void
 LineEditContext::cursor_UP()
 {
    Log(LOG_get_line)   history.info(CERR << "cursor_UP()") << endl;
@@ -608,6 +669,35 @@
    move_idx(user_line.size());
    Log(LOG_get_line)   history.info(CERR << "cursor_DOWN() done" << endl);
 }
+//-----------------------------------------------------------------------------
+void
+LineEditContext::update_SEARCH(void)
+{
+    history.update_search(user_line);
+}
+//-----------------------------------------------------------------------------
+void
+LineEditContext::cursor_SEARCH()
+{
+    user_line_before_history = user_line;
+    history_entered = true;
+
+    const UCS_string * ucs = history.search(user_line_before_history);
+    if (ucs == 0)   // no line above
+    {
+        Log(LOG_get_line)   CERR << "hit top of history()" << endl;
+        Log(LOG_get_line)   history.info(CERR << "cursor_SEARCH() done" << endl);
+        return;
+    }
+
+    adjust_allocated_height();
+
+    uidx = 0;
+    user_line = *ucs;
+    refresh_from_cursor();
+    move_idx(user_line.size());
+    Log(LOG_get_line)   history.info(CERR << "cursor_SEARCH() done" << endl);
+}
 //=============================================================================
 LineInput::LineInput(bool do_read_history)
    : history(uprefs.line_history_len),
@@ -863,7 +953,7 @@
 
    user_line.clear();
 
-LineEditContext lec(mode, 24, Workspace::get_PW(), hist, prompt);
+   LineEditContext lec(mode, 24, Workspace::get_PW(), hist, prompt);
 
    for (;;)
        {
@@ -898,6 +988,10 @@
                    lec.cursor_UP();
                    continue;
 
+              case UNI_DC2:  // ^R - search line history
+                   lec.cursor_SEARCH();
+                   continue;
+
               case UNI_EOF:  // end of file
                    eof = user_line.size() == 0;
                    break;
@@ -916,6 +1010,7 @@
 
               case UNI_EOT:   // ^D
                    lec.delete_char();
+                   lec.update_SEARCH();
                    continue;
 #else
               case UNI_EOT:   // ^D
@@ -926,18 +1021,22 @@
 
               case UNI_BS:    // ^H (backspace)
                    lec.backspc();
+                   lec.update_SEARCH();
                    continue;
 
               case UNI_HT:    // ^I (tab)
                    lec.tab_expansion(mode);
+                   lec.update_SEARCH();
                    continue;
 
               case UNI_VT:    // ^K
                    lec.cut_to_EOL();
+                   lec.update_SEARCH();
                    continue;
 
               case UNI_DELETE:
                    lec.delete_char();
+                   lec.update_SEARCH();
                    continue;
 
               case UNI_CR:   // '\r' : ignore
@@ -944,10 +1043,12 @@
                    continue;
 
               case UNI_LF:   // '\n': done
+                   lec.cursor_CLEAR_SEARCH();
                    break;
 
               case UNI_EM:    // ^Y
                    lec.paste();
+                   lec.update_SEARCH();
                    continue;
 
               case Invalid_Unicode:
@@ -955,6 +1056,7 @@
 
               default:  // regular APL character
                    lec.insert_char(uni);
+                   lec.update_SEARCH();
                    continue;
             }
 
@@ -1104,6 +1206,7 @@
              case UNI_VT:  return UNI_VT;            // ^K
              case UNI_SO:  return UNI_CursorDown;    // ^N
              case UNI_DLE: return UNI_CursorUp;      // ^P
+             case UNI_DC2: return UNI_DC2;           // ^R
              case UNI_EM:  return UNI_EM;            // ^Y
 #ifdef WANT_CTRLD_DEL
              case UNI_SUB: return UNI_SUB;     // ^Z (as alt EOT, allowing ^D as delete-char)
Index: src/LineInput.hh
===================================================================
--- src/LineInput.hh (revision 1477)
+++ src/LineInput.hh (working copy)
@@ -77,6 +77,15 @@
    /// move to next newer entry
    const UCS_string * down();
 
+   /// update history search substring
+   const void clear_search(void);
+
+   /// update search substring (called when current line is edited)
+   const void update_search(UCS_string &cur_line);
+
+   /// find entries like current line in history
+   const UCS_string * search(UCS_string &cur_line);
+
    /// print relevant indices
    ostream &  info(ostream & out) const
       { return out << "   CUR=" << current_line
@@ -108,6 +117,12 @@
    /// the max. history size
    const int max_lines;
 
+   /// the current searched-for substring
+   UCS_string cur_search_substr;
+
+   /// the last searched-for line match
+   int last_search_line;
+
    /// the history
    UCS_string_vector hist_lines;
 };
@@ -153,6 +168,10 @@
    void move_idx(int new_idx)
       { uidx = new_idx;   set_cursor(); }
 
+   /// get current cursor column
+   int get_idx(void)
+      { return uidx; }
+
    /// set the cursor (writing the appropriate ESC sequence to CIN)
    void set_cursor()
       { const int offs = uidx + prompt.size();
@@ -202,6 +221,9 @@
    /// tab expansion
    void tab_expansion(LineInputMode mode);
 
+   /// reset search substring
+   void cursor_CLEAR_SEARCH();
+
    /// move backwards in history
    void cursor_UP();
 
@@ -208,6 +230,11 @@
    /// move forward in history
    void cursor_DOWN();
 
+   void update_SEARCH();
+
+   /// search line history
+   void cursor_SEARCH();
+
    /// return current user input
    const UCS_string & get_user_line() const
       { return user_line; }
@@ -240,7 +267,7 @@
    /// true if history was entered
    bool history_entered;
 
-   /// dito
+   /// ditto
    UCS_string user_line_before_history;
 
    /// a buffer for ^K/^Y


reply via email to

[Prev in Thread] Current Thread [Next in Thread]