gedatsu217 created this revision.
gedatsu217 added reviewers: teemperor, JDevlieghere.
gedatsu217 added a project: LLDB.
Herald added a subscriber: lldb-commits.

I implemented autosuggestion if there is one possible suggestion.
I set the keybinds for every character. When a character is typed, 
Editline::TypedCharacter is called. 
Then, autosuggestion part is displayed in gray, and you can actually input by 
typing C-k.
Editline::Autosuggest is a function for finding completion, and it is like 
Editline::TabCommand now, but I will add more features to it.

Testing does not work well in my environment, so I can't confirm that it goes 
well, sorry. I am dealing with it now.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81001

Files:
  lldb/include/lldb/Host/Editline.h
  lldb/source/Host/common/Editline.cpp

Index: lldb/source/Host/common/Editline.cpp
===================================================================
--- lldb/source/Host/common/Editline.cpp
+++ lldb/source/Host/common/Editline.cpp
@@ -14,6 +14,7 @@
 #include "lldb/Host/Editline.h"
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/Host.h"
+#include "lldb/Utility/AnsiTerminal.h"
 #include "lldb/Utility/CompletionRequest.h"
 #include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/LLDBAssert.h"
@@ -114,22 +115,21 @@
   //  - The H_FIRST returns the most recent entry in the history.
   //
   // The naming of the enum entries match the semantic meaning.
-  switch(op) {
-    case HistoryOperation::Oldest:
-      return H_LAST;
-    case HistoryOperation::Older:
-      return H_NEXT;
-    case HistoryOperation::Current:
-      return H_CURR;
-    case HistoryOperation::Newer:
-      return H_PREV;
-    case HistoryOperation::Newest:
-      return H_FIRST;
+  switch (op) {
+  case HistoryOperation::Oldest:
+    return H_LAST;
+  case HistoryOperation::Older:
+    return H_NEXT;
+  case HistoryOperation::Current:
+    return H_CURR;
+  case HistoryOperation::Newer:
+    return H_PREV;
+  case HistoryOperation::Newest:
+    return H_FIRST;
   }
   llvm_unreachable("Fully covered switch!");
 }
 
-
 EditLineStringType CombineLines(const std::vector<EditLineStringType> &lines) {
   EditLineStringStreamType combined_stream;
   for (EditLineStringType line : lines) {
@@ -296,8 +296,8 @@
                         // to use when loading/saving history
   std::string m_path;   // Path to the history file
 };
-}
-}
+} // namespace line_editor
+} // namespace lldb_private
 
 // Editline private methods
 
@@ -415,9 +415,10 @@
   const char *unfaint = m_color_prompts ? ANSI_UNFAINT : "";
 
   for (int index = firstIndex; index < line_count; index++) {
-    fprintf(m_output_file, "%s"
-                           "%s"
-                           "%s" EditLineStringFormatSpec " ",
+    fprintf(m_output_file,
+            "%s"
+            "%s"
+            "%s" EditLineStringFormatSpec " ",
             faint, PromptForIndex(index).c_str(), unfaint,
             m_input_lines[index].c_str());
     if (index < line_count - 1)
@@ -532,9 +533,10 @@
   // (will only be requested if colors are supported)
   if (m_needs_prompt_repaint) {
     MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
-    fprintf(m_output_file, "%s"
-                           "%s"
-                           "%s",
+    fprintf(m_output_file,
+            "%s"
+            "%s"
+            "%s",
             ANSI_FAINT, Prompt(), ANSI_UNFAINT);
     MoveCursor(CursorLocation::EditingPrompt, CursorLocation::EditingCursor);
     m_needs_prompt_repaint = false;
@@ -1040,6 +1042,77 @@
   return CC_REDISPLAY;
 }
 
+std::string Editline::AutoSuggest(std::string typed) {
+  const LineInfo *line_info = el_line(m_editline);
+
+  llvm::StringRef line(line_info->buffer,
+                       line_info->lastchar - line_info->buffer);
+  unsigned cursor_index = line_info->cursor - line_info->buffer;
+  CompletionResult result;
+  CompletionRequest request(line, cursor_index, result);
+
+  m_completion_callback(request, m_completion_callback_baton);
+
+  llvm::ArrayRef<CompletionResult::Completion> results = result.GetResults();
+
+  StringList completions;
+  result.GetMatches(completions);
+
+  std::string to_add = "";
+
+  if (results.size() == 1) {
+    CompletionResult::Completion completion = results.front();
+    switch (completion.GetMode()) {
+    case CompletionMode::Normal: {
+      to_add = completion.GetCompletion();
+      to_add = to_add.substr(request.GetCursorArgumentPrefix().size());
+      if (request.GetParsedArg().IsQuoted())
+        to_add.push_back(request.GetParsedArg().GetQuoteChar());
+      to_add.push_back(' ');
+      break;
+    }
+    case CompletionMode::Partial: {
+      std::string to_add = completion.GetCompletion();
+      to_add = to_add.substr(request.GetCursorArgumentPrefix().size());
+      break;
+    }
+    case CompletionMode::RewriteLine: {
+      el_deletestr(m_editline, line_info->cursor - line_info->buffer);
+      el_insertstr(m_editline, completion.GetCompletion().c_str());
+      break;
+    }
+    }
+  }
+
+  return to_add;
+}
+
+unsigned char Editline::ApplyCompleteCommand(int ch) {
+  el_insertstr(m_editline, m_add_completion.c_str());
+  m_add_completion = "";
+  return CC_REDISPLAY;
+}
+
+unsigned char Editline::TypedCharacter(int ch, std::string typed) {
+  el_insertstr(m_editline, typed.c_str());
+  std::string to_add = AutoSuggest(typed);
+  m_add_completion = to_add;
+
+  if (to_add.empty()) {
+    return CC_REDISPLAY;
+  }
+
+  std::string gray_suggestion = ansi::FormatAnsiTerminalCodes("${ansi.faint}") +
+                                to_add +
+                                ansi::FormatAnsiTerminalCodes("${ansi.normal}");
+  printf("%s", typed.c_str());
+  printf("%s", gray_suggestion.c_str());
+  fflush(stdout);
+  MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+
+  return CC_REFRESH;
+}
+
 void Editline::ConfigureEditor(bool multiline) {
   if (m_editline && m_multiline_enabled == multiline)
     return;
@@ -1059,7 +1132,7 @@
 
   if (m_history_sp && m_history_sp->IsValid()) {
     if (!m_history_sp->Load()) {
-        fputs("Could not load history file\n.", m_output_file);
+      fputs("Could not load history file\n.", m_output_file);
     }
     el_wset(m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr());
   }
@@ -1071,10 +1144,11 @@
            return Editline::InstanceFor(editline)->Prompt();
          }));
 
-  el_wset(m_editline, EL_GETCFN, (EditlineGetCharCallbackType)([](
-                                     EditLine *editline, EditLineGetCharType *c) {
-            return Editline::InstanceFor(editline)->GetCharacter(c);
-          }));
+  el_wset(m_editline, EL_GETCFN,
+          (EditlineGetCharCallbackType)(
+              [](EditLine *editline, EditLineGetCharType *c) {
+                return Editline::InstanceFor(editline)->GetCharacter(c);
+              }));
 
   // Commands used for multiline support, registered whether or not they're
   // used
@@ -1159,6 +1233,23 @@
   el_set(m_editline, EL_BIND, "\t", "lldb-complete",
          NULL); // Bind TAB to auto complete
 
+  el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-apply-complete"),
+          EditLineConstString("Apply autocompletion"),
+          (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+            return Editline::InstanceFor(editline)->ApplyCompleteCommand(ch);
+          }));
+
+  el_set(m_editline, EL_BIND, "^k", "lldb-apply-complete",
+         NULL); // Apply a part that is suggested automatically
+
+  el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-typed-character"),
+          EditLineConstString("Typed character"),
+          (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+            std::string typed = std::string(1, ch);
+            typed = typed[0];
+            return Editline::InstanceFor(editline)->TypedCharacter(ch, typed);
+          }));
+
   // Allow ctrl-left-arrow and ctrl-right-arrow for navigation, behave like
   // bash in emacs mode.
   el_set(m_editline, EL_BIND, ESCAPE "[1;5C", "em-next-word", NULL);
@@ -1190,6 +1281,17 @@
     }
   }
 
+  if (true) {
+    char bind_key[2] = {0, 0};
+    const char *indent_chars =
+        "abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXZY1234567890 ";
+    while (*indent_chars) {
+      bind_key[0] = *indent_chars;
+      el_set(m_editline, EL_BIND, bind_key, "lldb-typed-character", NULL);
+      ++indent_chars;
+    }
+  }
+
   // Multi-line editor bindings
   if (multiline) {
     el_set(m_editline, EL_BIND, "\n", "lldb-end-or-add-line", NULL);
Index: lldb/include/lldb/Host/Editline.h
===================================================================
--- lldb/include/lldb/Host/Editline.h
+++ lldb/include/lldb/Host/Editline.h
@@ -135,14 +135,8 @@
 };
 
 /// Operation for the history.
-enum class HistoryOperation {
-  Oldest,
-  Older,
-  Current,
-  Newer,
-  Newest
-};
-}
+enum class HistoryOperation { Oldest, Older, Current, Newer, Newest };
+} // namespace line_editor
 
 using namespace line_editor;
 
@@ -312,6 +306,15 @@
   /// tab key is typed.
   unsigned char TabCommand(int ch);
 
+  /// command to apply autosuggested parts in gray.
+  unsigned char ApplyCompleteCommand(int ch);
+
+  /// Call AutoSuggest and display it in gray when a character is typed.
+  unsigned char TypedCharacter(int ch, std::string typed);
+
+  /// Return autosuggest part in string when there are suggests.
+  std::string AutoSuggest(std::string typed);
+
   /// Respond to normal character insertion by fixing line indentation
   unsigned char FixIndentationCommand(int ch);
 
@@ -361,10 +364,11 @@
   const char *m_fix_indentation_callback_chars = nullptr;
   CompleteCallbackType m_completion_callback = nullptr;
   void *m_completion_callback_baton = nullptr;
+  std::string m_add_completion = "";
 
   std::mutex m_output_mutex;
 };
-}
+} // namespace lldb_private
 
 #endif // #if defined(__cplusplus)
 #endif // LLDB_HOST_EDITLINE_H
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to