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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits