gedatsu217 updated this revision to Diff 272479. gedatsu217 added a comment.
Change the name and return of the function( bool UseAutosuggestion() -> void SetShowAutosuggestion (bool) ) (ll. 1447 in Editline.cpp and ll.194 in Editline.h). int -> size_t (ll. 1009 in Editline.cpp). Fix for normal setter (ll. 269 in IOHandler.cpp). > The Editline instance isn't recreated when you change the settings, so you > need to restart LLDB for this to work. However, settings aren't automatically > saved, so I think the right way to do this by putting the settings set > show-autosuggestion true into the ~/.lldbinit file (which will be > automatically executed before LLDB's command line frontend starts). It > probably requires a bunch of work to get that working without a restart, so I > think this can be fixed as a follow-up. There is no ~/.lldbinit in my environment (I do not why). Instead, there is ~/.lldb directory (but there are just command history file there.). > On a more general note: I'm not sure why we need m_current_autosuggestion. > There is a bunch of code that tries to keep that variable up-to-date with > what is typed, but unless I'm missing something this is just the text the > user has entered so far? If yes, then you can also just get the current user > input from Editline (see the first few lines of the Editline::TabCommand > function for how to do that). I think "m_current_autosuggestion" is needed. That is because it keeps the characters for the suggestion, not just user input. For example, when "b" is typed, "reakpoint" is saved in m_current_autosuggestion (when "breakpoint" is typed before). When a character is typed, Editline::TypedCharacter is called and m_current_autosuggestion is renewed every time. On the other hand, Editline::ApplyCompleteCommand, which execute suggestion actually, is not called unless C^f is typed. Therefore I think the suggestion parts should be saved until it is called. Indeed, I can get current user input by the first few lines of the Editline::TabCommand function, but it cannot save the suggestion parts probably. However, I noticed that "to_add" in Editline::TypedCharacter is unnecessary, so removeed it. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D81001/new/ https://reviews.llvm.org/D81001 Files: lldb/include/lldb/Core/Debugger.h lldb/include/lldb/Core/IOHandler.h lldb/include/lldb/Host/Editline.h lldb/include/lldb/Interpreter/CommandInterpreter.h lldb/source/Core/CoreProperties.td lldb/source/Core/Debugger.cpp lldb/source/Core/IOHandler.cpp lldb/source/Host/common/Editline.cpp lldb/source/Interpreter/CommandInterpreter.cpp
Index: lldb/source/Interpreter/CommandInterpreter.cpp =================================================================== --- lldb/source/Interpreter/CommandInterpreter.cpp +++ lldb/source/Interpreter/CommandInterpreter.cpp @@ -1866,6 +1866,21 @@ HandleCompletionMatches(request); } +llvm::Optional<std::string> +CommandInterpreter::GetAutoSuggestionForCommand(llvm::StringRef line, + std::string &result) { + const size_t s = m_command_history.GetSize(); + for (size_t i = 0; i < s; ++i) { + llvm::StringRef entry = m_command_history.GetStringAtIndex(i); + if (entry.startswith(line)) { + llvm::StringRef res = entry.substr(line.size()); + result = res.str(); + return result; + } + } + return llvm::None; +} + CommandInterpreter::~CommandInterpreter() {} void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) { 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" @@ -1004,6 +1005,17 @@ to_add = to_add.substr(request.GetCursorArgumentPrefix().size()); if (request.GetParsedArg().IsQuoted()) to_add.push_back(request.GetParsedArg().GetQuoteChar()); + if (m_use_autosuggestion && !to_add.empty()) { + size_t length = to_add.length(); + if (m_current_autosuggestion.length() > length && + to_add == m_current_autosuggestion.substr(0, length)) { + to_add.push_back(' '); + el_insertstr(m_editline, to_add.c_str()); + m_current_autosuggestion = + m_current_autosuggestion.substr(length + 1); + return CC_REFRESH; + } + } to_add.push_back(' '); el_insertstr(m_editline, to_add.c_str()); break; @@ -1020,6 +1032,7 @@ break; } } + m_current_autosuggestion = ""; return CC_REDISPLAY; } @@ -1040,6 +1053,36 @@ return CC_REDISPLAY; } +unsigned char Editline::ApplyCompleteCommand(int ch) { + el_insertstr(m_editline, m_current_autosuggestion.c_str()); + m_current_autosuggestion = ""; + return CC_REDISPLAY; +} + +unsigned char Editline::TypedCharacter(int ch) { + std::string typed = std::string(1, ch); + el_insertstr(m_editline, typed.c_str()); + const LineInfo *line_info = el_line(m_editline); + llvm::StringRef line(line_info->buffer, + line_info->lastchar - line_info->buffer); + + m_current_autosuggestion = ""; + m_suggestion_callback(line, m_current_autosuggestion, + m_suggestion_callback_baton); + + if (m_current_autosuggestion.empty()) + return CC_REDISPLAY; + + std::string to_add_color = ansi::FormatAnsiTerminalCodes("${ansi.faint}") + + m_current_autosuggestion + + ansi::FormatAnsiTerminalCodes("${ansi.normal}"); + fputs(typed.c_str(), m_output_file); + fputs(to_add_color.c_str(), m_output_file); + MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt); + + return CC_REFRESH; +} + void Editline::ConfigureEditor(bool multiline) { if (m_editline && m_multiline_enabled == multiline) return; @@ -1153,7 +1196,38 @@ if (!multiline) { el_set(m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string + + if (m_use_autosuggestion) { + el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-apply-complete"), + EditLineConstString("Adopt autocompletion"), + (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->ApplyCompleteCommand( + ch); + })); + + el_set(m_editline, EL_BIND, "^f", "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) { + return Editline::InstanceFor(editline)->TypedCharacter(ch); + })); + + char bind_key[2] = {0, 0}; + llvm::StringRef indent_chars = + "abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXZY1234567890!\"#$%" + "&'()*+,./:;<=>?@[]_`{|}~ "; + for (char c : indent_chars) { + bind_key[0] = c; + el_set(m_editline, EL_BIND, bind_key, "lldb-typed-character", NULL); + } + el_set(m_editline, EL_BIND, "\\-", "lldb-typed-character", NULL); + el_set(m_editline, EL_BIND, "\\^", "lldb-typed-character", NULL); + el_set(m_editline, EL_BIND, "\\\\", "lldb-typed-character", NULL); + } } + el_set(m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash in emacs mode el_set(m_editline, EL_BIND, "\t", "lldb-complete", @@ -1364,6 +1438,19 @@ return result; } +void Editline::SetSuggestionCallback(SuggestionCallbackType callback, + void *baton) { + m_suggestion_callback = callback; + m_suggestion_callback_baton = baton; +} + +void Editline::SetShowAutosuggestion(bool autosuggestion) { + if (autosuggestion) + m_use_autosuggestion = true; + else + m_use_autosuggestion = false; +} + void Editline::SetAutoCompleteCallback(CompleteCallbackType callback, void *baton) { m_completion_callback = callback; Index: lldb/source/Core/IOHandler.cpp =================================================================== --- lldb/source/Core/IOHandler.cpp +++ lldb/source/Core/IOHandler.cpp @@ -195,6 +195,13 @@ } } +void IOHandlerDelegate::IOHandlerSuggestion(IOHandler &io_handler, + llvm::StringRef line, + std::string &result) { + io_handler.GetDebugger().GetCommandInterpreter().GetAutoSuggestionForCommand( + line, result); +} + void IOHandlerDelegate::IOHandlerComplete(IOHandler &io_handler, CompletionRequest &request) { switch (m_completion) { @@ -257,7 +264,9 @@ GetOutputFILE(), GetErrorFILE(), m_color_prompts)); m_editline_up->SetIsInputCompleteCallback(IsInputCompleteCallback, this); + m_editline_up->SetSuggestionCallback(SuggestionCallback, this); m_editline_up->SetAutoCompleteCallback(AutoCompleteCallback, this); + m_editline_up->SetShowAutosuggestion(debugger.GetUseAutosuggestion()); // See if the delegate supports fixing indentation const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters(); if (indent_chars) { @@ -429,6 +438,14 @@ *editline_reader, lines, cursor_position); } +void IOHandlerEditline::SuggestionCallback(llvm::StringRef line, + std::string &result, void *baton) { + IOHandlerEditline *editline_reader = static_cast<IOHandlerEditline *>(baton); + if (editline_reader) + editline_reader->m_delegate.IOHandlerSuggestion(*editline_reader, line, + result); +} + void IOHandlerEditline::AutoCompleteCallback(CompletionRequest &request, void *baton) { IOHandlerEditline *editline_reader = (IOHandlerEditline *)baton; Index: lldb/source/Core/Debugger.cpp =================================================================== --- lldb/source/Core/Debugger.cpp +++ lldb/source/Core/Debugger.cpp @@ -346,6 +346,12 @@ return ret; } +bool Debugger::GetUseAutosuggestion() const { + const uint32_t idx = ePropertyShowAutosuggestion; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); +} + bool Debugger::GetUseSourceCache() const { const uint32_t idx = ePropertyUseSourceCache; return m_collection_sp->GetPropertyAtIndexAsBoolean( Index: lldb/source/Core/CoreProperties.td =================================================================== --- lldb/source/Core/CoreProperties.td +++ lldb/source/Core/CoreProperties.td @@ -131,4 +131,8 @@ Global, DefaultStringValue<"frame #${frame.index}: ${ansi.fg.yellow}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}{${function.is-optimized} [opt]}{${frame.is-artificial} [artificial]}\\\\n">, Desc<"The default frame format string to use when displaying stack frameinformation for threads from thread backtrace unique.">; + def ShowAutosuggestion: Property<"show-autosuggestion", "Boolean">, + Global, + DefaultFalse, + Desc<"If true, LLDB will show suggestions on possible commands the user might want to type.">; } Index: lldb/include/lldb/Interpreter/CommandInterpreter.h =================================================================== --- lldb/include/lldb/Interpreter/CommandInterpreter.h +++ lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -350,6 +350,11 @@ CommandObject *GetCommandObjectForCommand(llvm::StringRef &command_line); + /// Returns the auto-suggestion string that should be added to the given + /// command line. + llvm::Optional<std::string> GetAutoSuggestionForCommand(llvm::StringRef line, + std::string &result); + // This handles command line completion. void HandleCompletion(CompletionRequest &request); Index: lldb/include/lldb/Host/Editline.h =================================================================== --- lldb/include/lldb/Host/Editline.h +++ lldb/include/lldb/Host/Editline.h @@ -98,6 +98,9 @@ const StringList &lines, int cursor_position, void *baton); +typedef void (*SuggestionCallbackType)(llvm::StringRef line, + std::string &result, void *baton); + typedef void (*CompleteCallbackType)(CompletionRequest &request, void *baton); /// Status used to decide when and how to start editing another line in @@ -184,6 +187,12 @@ /// Cancel this edit and oblitarate all trace of it bool Cancel(); + /// Register a callback for autosuggestion. + void SetSuggestionCallback(SuggestionCallbackType callback, void *baton); + + /// Set autosuggestion if user set it valid. + void SetShowAutosuggestion(bool autosuggestion); + /// Register a callback for the tab key void SetAutoCompleteCallback(CompleteCallbackType callback, void *baton); @@ -312,6 +321,12 @@ /// tab key is typed. unsigned char TabCommand(int ch); + /// Apply autosuggestion part in gray as editline. + unsigned char ApplyCompleteCommand(int ch); + + /// Command used when a character is typed. + unsigned char TypedCharacter(int ch); + /// Respond to normal character insertion by fixing line indentation unsigned char FixIndentationCommand(int ch); @@ -359,9 +374,12 @@ FixIndentationCallbackType m_fix_indentation_callback = nullptr; void *m_fix_indentation_callback_baton = nullptr; const char *m_fix_indentation_callback_chars = nullptr; + SuggestionCallbackType m_suggestion_callback = nullptr; + void *m_suggestion_callback_baton = nullptr; CompleteCallbackType m_completion_callback = nullptr; void *m_completion_callback_baton = nullptr; - + std::string m_current_autosuggestion = ""; + bool m_use_autosuggestion = false; std::mutex m_output_mutex; }; } Index: lldb/include/lldb/Core/IOHandler.h =================================================================== --- lldb/include/lldb/Core/IOHandler.h +++ lldb/include/lldb/Core/IOHandler.h @@ -202,6 +202,9 @@ virtual void IOHandlerDeactivated(IOHandler &io_handler) {} + virtual void IOHandlerSuggestion(IOHandler &io_handler, llvm::StringRef line, + std::string &result); + virtual void IOHandlerComplete(IOHandler &io_handler, CompletionRequest &request); @@ -419,6 +422,9 @@ static int FixIndentationCallback(Editline *editline, const StringList &lines, int cursor_position, void *baton); + static void SuggestionCallback(llvm::StringRef line, std::string &result, + void *baton); + static void AutoCompleteCallback(CompletionRequest &request, void *baton); #endif Index: lldb/include/lldb/Core/Debugger.h =================================================================== --- lldb/include/lldb/Core/Debugger.h +++ lldb/include/lldb/Core/Debugger.h @@ -273,6 +273,8 @@ bool SetUseColor(bool use_color); + bool GetUseAutosuggestion() const; + bool GetUseSourceCache() const; bool SetUseSourceCache(bool use_source_cache);
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits