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