[lldb][NFC] Fix all formatting errors in .cpp file headers
Summary:
A *.cpp file header in LLDB (and in LLDB) should like this:
```
//===-- TestUtilities.cpp -------------------------------------------------===//
```
However in LLDB most of our source files have arbitrary changes to this format and
these changes are spreading through LLDB as folks usually just use the existing
source files as templates for their new files (most notably the unnecessary
editor language indicator `-*- C++ -*-` is spreading and in every review
someone is pointing out that this is wrong, resulting in people pointing out that this
is done in the same way in other files).
This patch removes most of these inconsistencies including the editor language indicators,
all the different missing/additional '-' characters, files that center the file name, missing
trailing `===//` (mostly caused by clang-format breaking the line).
Reviewers: aprantl, espindola, jfb, shafik, JDevlieghere
Reviewed By: JDevlieghere
Subscribers: dexonsmith, wuzish, emaste, sdardis, nemanjai, kbarton, MaskRay, atanasyan, arphaman, jfb, abidh, jsji, JDevlieghere, usaxena95, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D73258
2020-01-24 08:23:27 +01:00
|
|
|
//===-- REPL.cpp ----------------------------------------------------------===//
|
2015-10-19 23:11:07 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2015-10-19 23:11:07 +00:00
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
|
#include "lldb/Expression/REPL.h"
|
|
|
|
|
#include "lldb/Core/Debugger.h"
|
|
|
|
|
#include "lldb/Core/PluginManager.h"
|
|
|
|
|
#include "lldb/Expression/ExpressionVariable.h"
|
|
|
|
|
#include "lldb/Expression/UserExpression.h"
|
|
|
|
|
#include "lldb/Host/HostInfo.h"
|
2023-08-08 17:18:47 -07:00
|
|
|
#include "lldb/Host/StreamFile.h"
|
2015-10-19 23:11:07 +00:00
|
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
|
|
|
|
#include "lldb/Interpreter/CommandReturnObject.h"
|
|
|
|
|
#include "lldb/Target/Thread.h"
|
|
|
|
|
#include "lldb/Utility/AnsiTerminal.h"
|
|
|
|
|
|
2019-02-11 23:13:08 +00:00
|
|
|
#include <memory>
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
using namespace lldb_private;
|
|
|
|
|
|
2023-05-10 15:41:07 -05:00
|
|
|
char REPL::ID;
|
|
|
|
|
|
|
|
|
|
REPL::REPL(Target &target) : m_target(target) {
|
2015-10-31 00:43:59 +00:00
|
|
|
// Make sure all option values have sane defaults
|
|
|
|
|
Debugger &debugger = m_target.GetDebugger();
|
2022-04-11 10:42:59 -07:00
|
|
|
debugger.SetShowProgress(false);
|
2016-08-11 23:51:28 +00:00
|
|
|
auto exe_ctx = debugger.GetCommandInterpreter().GetExecutionContext();
|
|
|
|
|
m_format_options.OptionParsingStarting(&exe_ctx);
|
|
|
|
|
m_varobj_options.OptionParsingStarting(&exe_ctx);
|
2015-10-31 00:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
REPL::~REPL() = default;
|
|
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
lldb::REPLSP REPL::Create(Status &err, lldb::LanguageType language,
|
2015-10-21 00:28:44 +00:00
|
|
|
Debugger *debugger, Target *target,
|
|
|
|
|
const char *repl_options) {
|
2015-10-19 23:11:07 +00:00
|
|
|
uint32_t idx = 0;
|
|
|
|
|
lldb::REPLSP ret;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
while (REPLCreateInstance create_instance =
|
2021-12-14 12:04:28 -08:00
|
|
|
PluginManager::GetREPLCreateCallbackAtIndex(idx)) {
|
|
|
|
|
LanguageSet supported_languages =
|
|
|
|
|
PluginManager::GetREPLSupportedLanguagesAtIndex(idx++);
|
|
|
|
|
if (!supported_languages[language])
|
|
|
|
|
continue;
|
2015-10-21 00:28:44 +00:00
|
|
|
ret = (*create_instance)(err, language, debugger, target, repl_options);
|
2015-10-19 23:11:07 +00:00
|
|
|
if (ret) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string REPL::GetSourcePath() {
|
2023-06-01 18:37:37 -07:00
|
|
|
llvm::StringRef file_basename = GetSourceFileBasename();
|
2018-06-19 15:09:07 +00:00
|
|
|
FileSpec tmpdir_file_spec = HostInfo::GetProcessTempDir();
|
|
|
|
|
if (tmpdir_file_spec) {
|
2022-07-25 23:29:30 -07:00
|
|
|
tmpdir_file_spec.SetFilename(file_basename);
|
2015-10-31 00:43:59 +00:00
|
|
|
m_repl_source_path = tmpdir_file_spec.GetPath();
|
2015-10-19 23:11:07 +00:00
|
|
|
} else {
|
2018-11-01 21:05:36 +00:00
|
|
|
tmpdir_file_spec = FileSpec("/tmp");
|
2023-06-01 18:37:37 -07:00
|
|
|
tmpdir_file_spec.AppendPathComponent(file_basename);
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
return tmpdir_file_spec.GetPath();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lldb::IOHandlerSP REPL::GetIOHandler() {
|
|
|
|
|
if (!m_io_handler_sp) {
|
|
|
|
|
Debugger &debugger = m_target.GetDebugger();
|
2019-02-11 23:13:08 +00:00
|
|
|
m_io_handler_sp = std::make_shared<IOHandlerEditline>(
|
|
|
|
|
debugger, IOHandler::Type::REPL,
|
2019-03-02 00:20:26 +00:00
|
|
|
"lldb-repl", // Name of input reader for history
|
|
|
|
|
llvm::StringRef("> "), // prompt
|
|
|
|
|
llvm::StringRef(". "), // Continuation prompt
|
|
|
|
|
true, // Multi-line
|
|
|
|
|
true, // The REPL prompt is always colored
|
|
|
|
|
1, // Line number
|
2022-09-19 10:47:09 -07:00
|
|
|
*this);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Don't exit if CTRL+C is pressed
|
|
|
|
|
static_cast<IOHandlerEditline *>(m_io_handler_sp.get())
|
|
|
|
|
->SetInterruptExits(false);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (m_io_handler_sp->GetIsInteractive() &&
|
|
|
|
|
m_io_handler_sp->GetIsRealTerminal()) {
|
|
|
|
|
m_indent_str.assign(debugger.GetTabSize(), ' ');
|
|
|
|
|
m_enable_auto_indent = debugger.GetAutoIndent();
|
|
|
|
|
} else {
|
|
|
|
|
m_indent_str.clear();
|
|
|
|
|
m_enable_auto_indent = false;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
return m_io_handler_sp;
|
|
|
|
|
}
|
|
|
|
|
|
Quiet command regex instructions during batch execution
Summary:
Within .lldbinit, regex commands can be structured as a list of substitutions over
multiple lines. It's possible that this is uninentional, but it works and has
benefits.
For example:
command regex <command-name>
s/pat1/repl1/
s/pat2/repl2/
...
I use this form of `command regex` in my `~/.lldbinit`, because it makes it
clearer to write and read compared to a single line definition, because
multiline substitutions don't need to be quoted, and are broken up one per line.
However, multiline definitions result in usage instructions being printed for
each use. The result is that every time I run `lldb`, I get a dozen or more
lines of noise. With this change, the instructions are only printed when
`command regex` is invoked interactively, or from a terminal, neither of which
are true when lldb is sourcing `~/.lldbinit`.
Reviewers: clayborg, jingham
Reviewed By: clayborg
Subscribers: jdoerfert, kastiglione, xiaobai, keith, lldb-commits
Differential Revision: https://reviews.llvm.org/D48752
llvm-svn: 355793
2019-03-10 23:15:48 +00:00
|
|
|
void REPL::IOHandlerActivated(IOHandler &io_handler, bool interactive) {
|
2015-10-19 23:11:07 +00:00
|
|
|
lldb::ProcessSP process_sp = m_target.GetProcessSP();
|
|
|
|
|
if (process_sp && process_sp->IsAlive())
|
|
|
|
|
return;
|
2025-02-19 20:32:00 -08:00
|
|
|
LockedStreamFile locked_stream = io_handler.GetErrorStreamFileSP()->Lock();
|
|
|
|
|
locked_stream.Printf("REPL requires a running target process.\n");
|
2015-10-19 23:11:07 +00:00
|
|
|
io_handler.SetIsDone(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool REPL::IOHandlerInterrupt(IOHandler &io_handler) { return false; }
|
|
|
|
|
|
|
|
|
|
void REPL::IOHandlerInputInterrupted(IOHandler &io_handler, std::string &line) {
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-31 00:43:59 +00:00
|
|
|
const char *REPL::IOHandlerGetFixIndentationCharacters() {
|
|
|
|
|
return (m_enable_auto_indent ? GetAutoIndentCharacters() : nullptr);
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-26 15:50:26 -07:00
|
|
|
llvm::StringRef REPL::IOHandlerGetControlSequence(char ch) {
|
|
|
|
|
static constexpr llvm::StringLiteral control_sequence(":quit\n");
|
2015-10-19 23:11:07 +00:00
|
|
|
if (ch == 'd')
|
2023-05-26 15:50:26 -07:00
|
|
|
return control_sequence;
|
|
|
|
|
return {};
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *REPL::IOHandlerGetCommandPrefix() { return ":"; }
|
|
|
|
|
|
|
|
|
|
const char *REPL::IOHandlerGetHelpPrologue() {
|
|
|
|
|
return "\nThe REPL (Read-Eval-Print-Loop) acts like an interpreter. "
|
|
|
|
|
"Valid statements, expressions, and declarations are immediately "
|
|
|
|
|
"compiled and executed.\n\n"
|
|
|
|
|
"The complete set of LLDB debugging commands are also available as "
|
2020-07-30 14:43:46 -07:00
|
|
|
"described below.\n\nCommands "
|
2015-10-19 23:11:07 +00:00
|
|
|
"must be prefixed with a colon at the REPL prompt (:quit for "
|
|
|
|
|
"example.) Typing just a colon "
|
2020-07-30 14:43:46 -07:00
|
|
|
"followed by return will switch to the LLDB prompt.\n\n"
|
|
|
|
|
"Type “< path” to read in code from a text file “path”.\n\n";
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool REPL::IOHandlerIsInputComplete(IOHandler &io_handler, StringList &lines) {
|
|
|
|
|
// Check for meta command
|
|
|
|
|
const size_t num_lines = lines.GetSize();
|
|
|
|
|
if (num_lines == 1) {
|
|
|
|
|
const char *first_line = lines.GetStringAtIndex(0);
|
|
|
|
|
if (first_line[0] == ':')
|
|
|
|
|
return true; // Meta command is a single line where that starts with ':'
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Check if REPL input is done
|
|
|
|
|
std::string source_string(lines.CopyList());
|
|
|
|
|
return SourceIsComplete(source_string);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int REPL::CalculateActualIndentation(const StringList &lines) {
|
|
|
|
|
std::string last_line = lines[lines.GetSize() - 1];
|
|
|
|
|
|
|
|
|
|
int actual_indent = 0;
|
|
|
|
|
for (char &ch : last_line) {
|
|
|
|
|
if (ch != ' ')
|
|
|
|
|
break;
|
|
|
|
|
++actual_indent;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
return actual_indent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int REPL::IOHandlerFixIndentation(IOHandler &io_handler,
|
|
|
|
|
const StringList &lines,
|
|
|
|
|
int cursor_position) {
|
|
|
|
|
if (!m_enable_auto_indent)
|
|
|
|
|
return 0;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (!lines.GetSize()) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
int tab_size = io_handler.GetDebugger().GetTabSize();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
lldb::offset_t desired_indent =
|
|
|
|
|
GetDesiredIndentation(lines, cursor_position, tab_size);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
int actual_indent = REPL::CalculateActualIndentation(lines);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (desired_indent == LLDB_INVALID_OFFSET)
|
|
|
|
|
return 0;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
return (int)desired_indent - actual_indent;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 14:43:46 -07:00
|
|
|
static bool ReadCode(const std::string &path, std::string &code,
|
|
|
|
|
lldb::StreamFileSP &error_sp) {
|
|
|
|
|
auto &fs = FileSystem::Instance();
|
|
|
|
|
llvm::Twine pathTwine(path);
|
|
|
|
|
if (!fs.Exists(pathTwine)) {
|
|
|
|
|
error_sp->Printf("no such file at path '%s'\n", path.c_str());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!fs.Readable(pathTwine)) {
|
|
|
|
|
error_sp->Printf("could not read file at path '%s'\n", path.c_str());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
const size_t file_size = fs.GetByteSize(pathTwine);
|
|
|
|
|
const size_t max_size = code.max_size();
|
|
|
|
|
if (file_size > max_size) {
|
|
|
|
|
error_sp->Printf("file at path '%s' too large: "
|
2020-09-16 15:52:50 -07:00
|
|
|
"file_size = %zu, max_size = %zu\n",
|
2020-07-30 14:43:46 -07:00
|
|
|
path.c_str(), file_size, max_size);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
auto data_sp = fs.CreateDataBuffer(pathTwine);
|
|
|
|
|
if (data_sp == nullptr) {
|
|
|
|
|
error_sp->Printf("could not create buffer for file at path '%s'\n",
|
|
|
|
|
path.c_str());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
code.assign((const char *)data_sp->GetBytes(), data_sp->GetByteSize());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) {
|
2025-02-19 20:32:00 -08:00
|
|
|
lldb::StreamFileSP output_sp = std::make_shared<StreamFile>(
|
|
|
|
|
io_handler.GetOutputStreamFileSP()->GetUnlockedFileSP());
|
|
|
|
|
lldb::StreamFileSP error_sp = std::make_shared<StreamFile>(
|
|
|
|
|
io_handler.GetErrorStreamFileSP()->GetUnlockedFileSP());
|
2015-10-19 23:11:07 +00:00
|
|
|
bool extra_line = false;
|
|
|
|
|
bool did_quit = false;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (code.empty()) {
|
|
|
|
|
m_code.AppendString("");
|
|
|
|
|
static_cast<IOHandlerEditline &>(io_handler)
|
|
|
|
|
.SetBaseLineNumber(m_code.GetSize() + 1);
|
|
|
|
|
} else {
|
|
|
|
|
Debugger &debugger = m_target.GetDebugger();
|
|
|
|
|
CommandInterpreter &ci = debugger.GetCommandInterpreter();
|
|
|
|
|
extra_line = ci.GetSpaceReplPrompts();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
ExecutionContext exe_ctx(m_target.GetProcessSP()
|
|
|
|
|
->GetThreadList()
|
|
|
|
|
.GetSelectedThread()
|
2023-04-21 13:49:01 -07:00
|
|
|
->GetSelectedFrame(DoNoSelectMostRelevantFrame)
|
2015-10-19 23:11:07 +00:00
|
|
|
.get());
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
lldb::ProcessSP process_sp(exe_ctx.GetProcessSP());
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (code[0] == ':') {
|
|
|
|
|
// Meta command
|
|
|
|
|
// Strip the ':'
|
|
|
|
|
code.erase(0, 1);
|
2019-09-06 08:40:31 +00:00
|
|
|
if (!llvm::StringRef(code).trim().empty()) {
|
2015-10-19 23:11:07 +00:00
|
|
|
// "lldb" was followed by arguments, so just execute the command dump
|
|
|
|
|
// the results
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Turn off prompt on quit in case the user types ":quit"
|
|
|
|
|
const bool saved_prompt_on_quit = ci.GetPromptOnQuit();
|
|
|
|
|
if (saved_prompt_on_quit)
|
|
|
|
|
ci.SetPromptOnQuit(false);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Execute the command
|
2020-06-09 10:21:09 -07:00
|
|
|
CommandReturnObject result(debugger.GetUseColor());
|
2015-10-19 23:11:07 +00:00
|
|
|
result.SetImmediateOutputStream(output_sp);
|
|
|
|
|
result.SetImmediateErrorStream(error_sp);
|
|
|
|
|
ci.HandleCommand(code.c_str(), eLazyBoolNo, result);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (saved_prompt_on_quit)
|
|
|
|
|
ci.SetPromptOnQuit(true);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (result.GetStatus() == lldb::eReturnStatusQuit) {
|
|
|
|
|
did_quit = true;
|
|
|
|
|
io_handler.SetIsDone(true);
|
|
|
|
|
if (debugger.CheckTopIOHandlerTypes(
|
|
|
|
|
IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) {
|
|
|
|
|
// We typed "quit" or an alias to quit so we need to check if the
|
|
|
|
|
// command interpreter is above us and tell it that it is done as
|
2018-04-30 16:49:04 +00:00
|
|
|
// well so we don't drop back into the command interpreter if we
|
|
|
|
|
// have already quit
|
2015-10-19 23:11:07 +00:00
|
|
|
lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
|
|
|
|
|
if (io_handler_sp)
|
|
|
|
|
io_handler_sp->SetIsDone(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// ":" was followed by no arguments, so push the LLDB command prompt
|
|
|
|
|
if (debugger.CheckTopIOHandlerTypes(
|
|
|
|
|
IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter)) {
|
|
|
|
|
// If the user wants to get back to the command interpreter and the
|
|
|
|
|
// command interpreter is what launched the REPL, then just let the
|
|
|
|
|
// REPL exit and fall back to the command interpreter.
|
|
|
|
|
io_handler.SetIsDone(true);
|
|
|
|
|
} else {
|
|
|
|
|
// The REPL wasn't launched the by the command interpreter, it is the
|
|
|
|
|
// base IOHandler, so we need to get the command interpreter and
|
|
|
|
|
lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
|
|
|
|
|
if (io_handler_sp) {
|
|
|
|
|
io_handler_sp->SetIsDone(false);
|
2020-01-15 14:56:28 -08:00
|
|
|
debugger.RunIOHandlerAsync(ci.GetIOHandler());
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2020-07-30 14:43:46 -07:00
|
|
|
if (code[0] == '<') {
|
|
|
|
|
// User wants to read code from a file.
|
|
|
|
|
// Interpret rest of line as a literal path.
|
|
|
|
|
auto path = llvm::StringRef(code.substr(1)).trim().str();
|
|
|
|
|
if (!ReadCode(path, code, error_sp)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Unwind any expression we might have been running in case our REPL
|
|
|
|
|
// expression crashed and the user was looking around
|
|
|
|
|
if (m_dedicated_repl_mode) {
|
|
|
|
|
Thread *thread = exe_ctx.GetThreadPtr();
|
|
|
|
|
if (thread && thread->UnwindInnermostExpression().Success()) {
|
|
|
|
|
thread->SetSelectedFrameByIndex(0, false);
|
2023-04-21 13:49:01 -07:00
|
|
|
exe_ctx.SetFrameSP(
|
|
|
|
|
thread->GetSelectedFrame(DoNoSelectMostRelevantFrame));
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2019-03-09 00:10:52 +00:00
|
|
|
EvaluateExpressionOptions expr_options = m_expr_options;
|
2015-10-19 23:11:07 +00:00
|
|
|
expr_options.SetCoerceToId(m_varobj_options.use_objc);
|
|
|
|
|
expr_options.SetKeepInMemory(true);
|
|
|
|
|
expr_options.SetUseDynamic(m_varobj_options.use_dynamic);
|
|
|
|
|
expr_options.SetGenerateDebugInfo(true);
|
|
|
|
|
expr_options.SetREPLEnabled(true);
|
|
|
|
|
expr_options.SetColorizeErrors(colorize_err);
|
|
|
|
|
expr_options.SetPoundLine(m_repl_source_path.c_str(),
|
|
|
|
|
m_code.GetSize() + 1);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
expr_options.SetLanguage(GetLanguage());
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
PersistentExpressionState *persistent_state =
|
|
|
|
|
m_target.GetPersistentExpressionStateForLanguage(GetLanguage());
|
2020-01-08 14:18:47 -08:00
|
|
|
if (!persistent_state)
|
|
|
|
|
return;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
const size_t var_count_before = persistent_state->GetSize();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
const char *expr_prefix = nullptr;
|
|
|
|
|
lldb::ValueObjectSP result_valobj_sp;
|
2024-11-21 15:37:04 -08:00
|
|
|
lldb::ExpressionResults execution_results = UserExpression::Evaluate(
|
|
|
|
|
exe_ctx, expr_options, code.c_str(), expr_prefix, result_valobj_sp);
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error;
|
2023-05-02 21:40:12 -05:00
|
|
|
if (llvm::Error err = OnExpressionEvaluated(exe_ctx, code, expr_options,
|
|
|
|
|
execution_results,
|
|
|
|
|
result_valobj_sp, error)) {
|
|
|
|
|
*error_sp << llvm::toString(std::move(err)) << "\n";
|
|
|
|
|
} else if (process_sp && process_sp->IsAlive()) {
|
2015-10-19 23:11:07 +00:00
|
|
|
bool add_to_code = true;
|
|
|
|
|
bool handled = false;
|
|
|
|
|
if (result_valobj_sp) {
|
|
|
|
|
lldb::Format format = m_format_options.GetFormat();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (result_valobj_sp->GetError().Success()) {
|
|
|
|
|
handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp);
|
|
|
|
|
} else if (result_valobj_sp->GetError().GetError() ==
|
2018-10-18 03:10:43 +00:00
|
|
|
UserExpression::kNoResult) {
|
2015-10-19 23:11:07 +00:00
|
|
|
if (format != lldb::eFormatVoid && debugger.GetNotifyVoid()) {
|
|
|
|
|
error_sp->PutCString("(void)\n");
|
|
|
|
|
handled = true;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (debugger.GetPrintDecls()) {
|
|
|
|
|
for (size_t vi = var_count_before, ve = persistent_state->GetSize();
|
2016-09-06 20:57:50 +00:00
|
|
|
vi != ve; ++vi) {
|
2015-10-19 23:11:07 +00:00
|
|
|
lldb::ExpressionVariableSP persistent_var_sp =
|
|
|
|
|
persistent_state->GetVariableAtIndex(vi);
|
|
|
|
|
lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
PrintOneVariable(debugger, output_sp, valobj_sp,
|
|
|
|
|
persistent_var_sp.get());
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!handled) {
|
|
|
|
|
bool useColors = error_sp->GetFile().GetIsTerminalWithColors();
|
|
|
|
|
switch (execution_results) {
|
|
|
|
|
case lldb::eExpressionSetupError:
|
|
|
|
|
case lldb::eExpressionParseError:
|
|
|
|
|
add_to_code = false;
|
2022-08-08 11:31:49 -07:00
|
|
|
[[fallthrough]];
|
2015-10-19 23:11:07 +00:00
|
|
|
case lldb::eExpressionDiscarded:
|
|
|
|
|
error_sp->Printf("%s\n", error.AsCString());
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
case lldb::eExpressionCompleted:
|
|
|
|
|
break;
|
|
|
|
|
case lldb::eExpressionInterrupted:
|
|
|
|
|
if (useColors) {
|
|
|
|
|
error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
|
|
|
|
|
error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
error_sp->Printf("Execution interrupted. ");
|
|
|
|
|
if (useColors)
|
|
|
|
|
error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
|
|
|
|
|
error_sp->Printf("Enter code to recover and continue.\nEnter LLDB "
|
|
|
|
|
"commands to investigate (type :help for "
|
|
|
|
|
"assistance.)\n");
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
case lldb::eExpressionHitBreakpoint:
|
|
|
|
|
// Breakpoint was hit, drop into LLDB command interpreter
|
|
|
|
|
if (useColors) {
|
|
|
|
|
error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
|
|
|
|
|
error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
|
|
|
|
|
}
|
|
|
|
|
output_sp->Printf("Execution stopped at breakpoint. ");
|
|
|
|
|
if (useColors)
|
|
|
|
|
error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
|
|
|
|
|
output_sp->Printf("Enter LLDB commands to investigate (type help "
|
|
|
|
|
"for assistance.)\n");
|
|
|
|
|
{
|
|
|
|
|
lldb::IOHandlerSP io_handler_sp(ci.GetIOHandler());
|
|
|
|
|
if (io_handler_sp) {
|
|
|
|
|
io_handler_sp->SetIsDone(false);
|
2020-01-15 14:56:28 -08:00
|
|
|
debugger.RunIOHandlerAsync(ci.GetIOHandler());
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
case lldb::eExpressionTimedOut:
|
|
|
|
|
error_sp->Printf("error: timeout\n");
|
|
|
|
|
if (error.AsCString())
|
|
|
|
|
error_sp->Printf("error: %s\n", error.AsCString());
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
2015-10-19 23:11:07 +00:00
|
|
|
case lldb::eExpressionResultUnavailable:
|
|
|
|
|
// Shoulnd't happen???
|
|
|
|
|
error_sp->Printf("error: could not fetch result -- %s\n",
|
|
|
|
|
error.AsCString());
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
2015-10-19 23:11:07 +00:00
|
|
|
case lldb::eExpressionStoppedForDebug:
|
|
|
|
|
// Shoulnd't happen???
|
|
|
|
|
error_sp->Printf("error: stopped for debug -- %s\n",
|
|
|
|
|
error.AsCString());
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
2020-05-21 23:22:16 -07:00
|
|
|
case lldb::eExpressionThreadVanished:
|
|
|
|
|
// Shoulnd't happen???
|
|
|
|
|
error_sp->Printf("error: expression thread vanished -- %s\n",
|
|
|
|
|
error.AsCString());
|
|
|
|
|
break;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (add_to_code) {
|
|
|
|
|
const uint32_t new_default_line = m_code.GetSize() + 1;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
m_code.SplitIntoLines(code);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Update our code on disk
|
|
|
|
|
if (!m_repl_source_path.empty()) {
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
auto file = FileSystem::Instance().Open(
|
|
|
|
|
FileSpec(m_repl_source_path),
|
2021-07-28 20:07:03 +02:00
|
|
|
File::eOpenOptionWriteOnly | File::eOpenOptionTruncate |
|
remove File::SetStream(), make new files instead.
Summary:
This patch removes File::SetStream() and File::SetDescriptor(),
and replaces most direct uses of File with pointers to File.
Instead of calling SetStream() on a file, we make a new file and
replace it.
My ultimate goal here is to introduce a new API class SBFile, which
has full support for python io.IOStream file objects. These can
redirect read() and write() to python code, so lldb::Files will
need a way to dispatch those methods. Additionally it will need some
form of sharing and assigning files, as a SBFile will be passed in and
assigned to the main IO streams of the debugger.
In my prototype patch queue, I make File itself copyable and add a
secondary class FileOps to manage the sharing and dispatch. In that
case SBFile was a unique_ptr<File>.
(here: https://github.com/smoofra/llvm-project/tree/files)
However in review, Pavel Labath suggested that it be shared_ptr instead.
(here: https://reviews.llvm.org/D67793)
In order for SBFile to use shared_ptr<File>, everything else should
as well.
If this patch is accepted, I will make SBFile use a shared_ptr
I will remove FileOps from future patches and use subclasses of File
instead.
Reviewers: JDevlieghere, jasonmolenda, zturner, jingham, labath
Reviewed By: labath
Subscribers: lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D67891
llvm-svn: 373090
2019-09-27 14:33:35 +00:00
|
|
|
File::eOpenOptionCanCreate,
|
|
|
|
|
lldb::eFilePermissionsFileDefault);
|
2019-09-26 17:54:59 +00:00
|
|
|
if (file) {
|
|
|
|
|
std::string code(m_code.CopyList());
|
|
|
|
|
code.append(1, '\n');
|
|
|
|
|
size_t bytes_written = code.size();
|
|
|
|
|
file.get()->Write(code.c_str(), bytes_written);
|
|
|
|
|
file.get()->Close();
|
|
|
|
|
} else {
|
|
|
|
|
std::string message = llvm::toString(file.takeError());
|
|
|
|
|
error_sp->Printf("error: couldn't open %s: %s\n",
|
|
|
|
|
m_repl_source_path.c_str(), message.c_str());
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Now set the default file and line to the REPL source file
|
|
|
|
|
m_target.GetSourceManager().SetDefaultFileAndLine(
|
2024-08-30 10:58:32 -07:00
|
|
|
std::make_shared<SupportFile>(FileSpec(m_repl_source_path)),
|
|
|
|
|
new_default_line);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
static_cast<IOHandlerEditline &>(io_handler)
|
|
|
|
|
.SetBaseLineNumber(m_code.GetSize() + 1);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
if (extra_line) {
|
2019-10-09 21:50:52 +00:00
|
|
|
output_sp->Printf("\n");
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
2018-04-30 16:49:04 +00:00
|
|
|
// Don't complain about the REPL process going away if we are in the
|
|
|
|
|
// process of quitting.
|
2015-10-19 23:11:07 +00:00
|
|
|
if (!did_quit && (!process_sp || !process_sp->IsAlive())) {
|
|
|
|
|
error_sp->Printf(
|
|
|
|
|
"error: REPL process is no longer alive, exiting REPL\n");
|
|
|
|
|
io_handler.SetIsDone(true);
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
|
|
|
|
|
[lldb][NFC] Remove WordComplete mode, make result array indexed from 0 and remove any undocumented/redundant return values
Summary:
We still have some leftovers of the old completion API in the internals of
LLDB that haven't been replaced by the new CompletionRequest. These leftovers
are:
* The return values (int/size_t) in all completion functions.
* Our result array that starts indexing at 1.
* `WordComplete` mode.
I didn't replace them back then because it's tricky to figure out what exactly they
are used for and the completion code is relatively untested. I finally got around
to writing more tests for the API and understanding the semantics, so I think it's
a good time to get rid of them.
A few words why those things should be removed/replaced:
* The return values are really cryptic, partly redundant and rarely documented.
They are also completely ignored by Xcode, so whatever information they contain will end up
breaking Xcode's completion mechanism. They are also partly impossible to even implement
as we assign negative values special meaning and our completion API sometimes returns size_t.
Completion functions are supposed to return -2 to rewrite the current line. We seem to use this
in some untested code path to expand the history repeat character to the full command, but
I haven't figured out why that doesn't work at the moment.
Completion functions return -1 to 'insert the completion character', but that isn't implemented
(even though we seem to activate this feature in LLDB sometimes).
All positive values have to match the number of results. This is obviously just redundant information
as the user can just look at the result list to get that information (which is what Xcode does).
* The result array that starts indexing at 1 is obviously unexpected. The first element of the array is
reserved for the common prefix of all completions (e.g. "foobar" and "footar" -> "foo"). The idea is
that we calculate this to make the life of the API caller easier, but obviously forcing people to have
1-based indices is not helpful (or even worse, forces them to manually copy the results to make it
0-based like Xcode has to do).
* The `WordComplete` mode indicates that LLDB should enter a space behind the completion. The
idea is that we let the top-level API know that we just provided a full completion. Interestingly we
`WordComplete` is just a single bool that somehow represents all N completions. And we always
provide full completions in LLDB, so in theory it should always be true.
The only use it currently serves is providing redundant information about whether we have a single
definitive completion or not (which we already know from the number of results we get).
This patch essentially removes `WordComplete` mode and makes the result array indexed from 0.
It also removes all return values from all internal completion functions. The only non-redundant information
they contain is about rewriting the current line (which is broken), so that functionality was moved
to the CompletionRequest API. So you can now do `addCompletion("blub", "description", CompletionMode::RewriteLine)`
to do the same.
For the SB API we emulate the old behaviour by making the array indexed from 1 again with the common
prefix at index 0. I didn't keep the special negative return codes as we either never sent them before (e.g. -2) or we
didn't even implement them in the Editline handler (e.g. -1).
I tried to keep this patch minimal and I'm aware we can probably now even further simplify a bunch of related code,
but I would prefer doing this in follow-up NFC commits
Reviewers: JDevlieghere
Reviewed By: JDevlieghere
Subscribers: arphaman, abidh, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D66536
llvm-svn: 369624
2019-08-22 07:41:23 +00:00
|
|
|
void REPL::IOHandlerComplete(IOHandler &io_handler,
|
|
|
|
|
CompletionRequest &request) {
|
2015-10-19 23:11:07 +00:00
|
|
|
// Complete an LLDB command if the first character is a colon...
|
2023-12-16 14:39:37 -08:00
|
|
|
if (request.GetRawLine().starts_with(":")) {
|
2015-10-19 23:11:07 +00:00
|
|
|
Debugger &debugger = m_target.GetDebugger();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// auto complete LLDB commands
|
2019-08-15 13:14:10 +00:00
|
|
|
llvm::StringRef new_line = request.GetRawLine().drop_front();
|
|
|
|
|
CompletionResult sub_result;
|
|
|
|
|
CompletionRequest sub_request(new_line, request.GetRawCursorPos() - 1,
|
|
|
|
|
sub_result);
|
[lldb][NFC] Remove WordComplete mode, make result array indexed from 0 and remove any undocumented/redundant return values
Summary:
We still have some leftovers of the old completion API in the internals of
LLDB that haven't been replaced by the new CompletionRequest. These leftovers
are:
* The return values (int/size_t) in all completion functions.
* Our result array that starts indexing at 1.
* `WordComplete` mode.
I didn't replace them back then because it's tricky to figure out what exactly they
are used for and the completion code is relatively untested. I finally got around
to writing more tests for the API and understanding the semantics, so I think it's
a good time to get rid of them.
A few words why those things should be removed/replaced:
* The return values are really cryptic, partly redundant and rarely documented.
They are also completely ignored by Xcode, so whatever information they contain will end up
breaking Xcode's completion mechanism. They are also partly impossible to even implement
as we assign negative values special meaning and our completion API sometimes returns size_t.
Completion functions are supposed to return -2 to rewrite the current line. We seem to use this
in some untested code path to expand the history repeat character to the full command, but
I haven't figured out why that doesn't work at the moment.
Completion functions return -1 to 'insert the completion character', but that isn't implemented
(even though we seem to activate this feature in LLDB sometimes).
All positive values have to match the number of results. This is obviously just redundant information
as the user can just look at the result list to get that information (which is what Xcode does).
* The result array that starts indexing at 1 is obviously unexpected. The first element of the array is
reserved for the common prefix of all completions (e.g. "foobar" and "footar" -> "foo"). The idea is
that we calculate this to make the life of the API caller easier, but obviously forcing people to have
1-based indices is not helpful (or even worse, forces them to manually copy the results to make it
0-based like Xcode has to do).
* The `WordComplete` mode indicates that LLDB should enter a space behind the completion. The
idea is that we let the top-level API know that we just provided a full completion. Interestingly we
`WordComplete` is just a single bool that somehow represents all N completions. And we always
provide full completions in LLDB, so in theory it should always be true.
The only use it currently serves is providing redundant information about whether we have a single
definitive completion or not (which we already know from the number of results we get).
This patch essentially removes `WordComplete` mode and makes the result array indexed from 0.
It also removes all return values from all internal completion functions. The only non-redundant information
they contain is about rewriting the current line (which is broken), so that functionality was moved
to the CompletionRequest API. So you can now do `addCompletion("blub", "description", CompletionMode::RewriteLine)`
to do the same.
For the SB API we emulate the old behaviour by making the array indexed from 1 again with the common
prefix at index 0. I didn't keep the special negative return codes as we either never sent them before (e.g. -2) or we
didn't even implement them in the Editline handler (e.g. -1).
I tried to keep this patch minimal and I'm aware we can probably now even further simplify a bunch of related code,
but I would prefer doing this in follow-up NFC commits
Reviewers: JDevlieghere
Reviewed By: JDevlieghere
Subscribers: arphaman, abidh, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D66536
llvm-svn: 369624
2019-08-22 07:41:23 +00:00
|
|
|
debugger.GetCommandInterpreter().HandleCompletion(sub_request);
|
2019-08-15 13:14:10 +00:00
|
|
|
StringList matches, descriptions;
|
|
|
|
|
sub_result.GetMatches(matches);
|
2020-07-03 11:36:34 +02:00
|
|
|
// Prepend command prefix that was excluded in the completion request.
|
|
|
|
|
if (request.GetCursorIndex() == 0)
|
|
|
|
|
for (auto &match : matches)
|
|
|
|
|
match.insert(0, 1, ':');
|
2019-08-15 13:14:10 +00:00
|
|
|
sub_result.GetDescriptions(descriptions);
|
|
|
|
|
request.AddCompletions(matches, descriptions);
|
[lldb][NFC] Remove WordComplete mode, make result array indexed from 0 and remove any undocumented/redundant return values
Summary:
We still have some leftovers of the old completion API in the internals of
LLDB that haven't been replaced by the new CompletionRequest. These leftovers
are:
* The return values (int/size_t) in all completion functions.
* Our result array that starts indexing at 1.
* `WordComplete` mode.
I didn't replace them back then because it's tricky to figure out what exactly they
are used for and the completion code is relatively untested. I finally got around
to writing more tests for the API and understanding the semantics, so I think it's
a good time to get rid of them.
A few words why those things should be removed/replaced:
* The return values are really cryptic, partly redundant and rarely documented.
They are also completely ignored by Xcode, so whatever information they contain will end up
breaking Xcode's completion mechanism. They are also partly impossible to even implement
as we assign negative values special meaning and our completion API sometimes returns size_t.
Completion functions are supposed to return -2 to rewrite the current line. We seem to use this
in some untested code path to expand the history repeat character to the full command, but
I haven't figured out why that doesn't work at the moment.
Completion functions return -1 to 'insert the completion character', but that isn't implemented
(even though we seem to activate this feature in LLDB sometimes).
All positive values have to match the number of results. This is obviously just redundant information
as the user can just look at the result list to get that information (which is what Xcode does).
* The result array that starts indexing at 1 is obviously unexpected. The first element of the array is
reserved for the common prefix of all completions (e.g. "foobar" and "footar" -> "foo"). The idea is
that we calculate this to make the life of the API caller easier, but obviously forcing people to have
1-based indices is not helpful (or even worse, forces them to manually copy the results to make it
0-based like Xcode has to do).
* The `WordComplete` mode indicates that LLDB should enter a space behind the completion. The
idea is that we let the top-level API know that we just provided a full completion. Interestingly we
`WordComplete` is just a single bool that somehow represents all N completions. And we always
provide full completions in LLDB, so in theory it should always be true.
The only use it currently serves is providing redundant information about whether we have a single
definitive completion or not (which we already know from the number of results we get).
This patch essentially removes `WordComplete` mode and makes the result array indexed from 0.
It also removes all return values from all internal completion functions. The only non-redundant information
they contain is about rewriting the current line (which is broken), so that functionality was moved
to the CompletionRequest API. So you can now do `addCompletion("blub", "description", CompletionMode::RewriteLine)`
to do the same.
For the SB API we emulate the old behaviour by making the array indexed from 1 again with the common
prefix at index 0. I didn't keep the special negative return codes as we either never sent them before (e.g. -2) or we
didn't even implement them in the Editline handler (e.g. -1).
I tried to keep this patch minimal and I'm aware we can probably now even further simplify a bunch of related code,
but I would prefer doing this in follow-up NFC commits
Reviewers: JDevlieghere
Reviewed By: JDevlieghere
Subscribers: arphaman, abidh, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D66536
llvm-svn: 369624
2019-08-22 07:41:23 +00:00
|
|
|
return;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Strip spaces from the line and see if we had only spaces
|
2019-09-25 12:55:30 +00:00
|
|
|
if (request.GetRawLine().trim().empty()) {
|
2015-10-19 23:11:07 +00:00
|
|
|
// Only spaces on this line, so just indent
|
2019-08-15 13:14:10 +00:00
|
|
|
request.AddCompletion(m_indent_str);
|
[lldb][NFC] Remove WordComplete mode, make result array indexed from 0 and remove any undocumented/redundant return values
Summary:
We still have some leftovers of the old completion API in the internals of
LLDB that haven't been replaced by the new CompletionRequest. These leftovers
are:
* The return values (int/size_t) in all completion functions.
* Our result array that starts indexing at 1.
* `WordComplete` mode.
I didn't replace them back then because it's tricky to figure out what exactly they
are used for and the completion code is relatively untested. I finally got around
to writing more tests for the API and understanding the semantics, so I think it's
a good time to get rid of them.
A few words why those things should be removed/replaced:
* The return values are really cryptic, partly redundant and rarely documented.
They are also completely ignored by Xcode, so whatever information they contain will end up
breaking Xcode's completion mechanism. They are also partly impossible to even implement
as we assign negative values special meaning and our completion API sometimes returns size_t.
Completion functions are supposed to return -2 to rewrite the current line. We seem to use this
in some untested code path to expand the history repeat character to the full command, but
I haven't figured out why that doesn't work at the moment.
Completion functions return -1 to 'insert the completion character', but that isn't implemented
(even though we seem to activate this feature in LLDB sometimes).
All positive values have to match the number of results. This is obviously just redundant information
as the user can just look at the result list to get that information (which is what Xcode does).
* The result array that starts indexing at 1 is obviously unexpected. The first element of the array is
reserved for the common prefix of all completions (e.g. "foobar" and "footar" -> "foo"). The idea is
that we calculate this to make the life of the API caller easier, but obviously forcing people to have
1-based indices is not helpful (or even worse, forces them to manually copy the results to make it
0-based like Xcode has to do).
* The `WordComplete` mode indicates that LLDB should enter a space behind the completion. The
idea is that we let the top-level API know that we just provided a full completion. Interestingly we
`WordComplete` is just a single bool that somehow represents all N completions. And we always
provide full completions in LLDB, so in theory it should always be true.
The only use it currently serves is providing redundant information about whether we have a single
definitive completion or not (which we already know from the number of results we get).
This patch essentially removes `WordComplete` mode and makes the result array indexed from 0.
It also removes all return values from all internal completion functions. The only non-redundant information
they contain is about rewriting the current line (which is broken), so that functionality was moved
to the CompletionRequest API. So you can now do `addCompletion("blub", "description", CompletionMode::RewriteLine)`
to do the same.
For the SB API we emulate the old behaviour by making the array indexed from 1 again with the common
prefix at index 0. I didn't keep the special negative return codes as we either never sent them before (e.g. -2) or we
didn't even implement them in the Editline handler (e.g. -1).
I tried to keep this patch minimal and I'm aware we can probably now even further simplify a bunch of related code,
but I would prefer doing this in follow-up NFC commits
Reviewers: JDevlieghere
Reviewed By: JDevlieghere
Subscribers: arphaman, abidh, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D66536
llvm-svn: 369624
2019-08-22 07:41:23 +00:00
|
|
|
return;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
std::string current_code;
|
|
|
|
|
current_code.append(m_code.CopyList());
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler);
|
2023-08-30 10:27:07 -04:00
|
|
|
StringList current_lines = editline.GetCurrentLines();
|
|
|
|
|
const uint32_t current_line_idx = editline.GetCurrentLineIndex();
|
|
|
|
|
|
|
|
|
|
if (current_line_idx < current_lines.GetSize()) {
|
|
|
|
|
for (uint32_t i = 0; i < current_line_idx; ++i) {
|
|
|
|
|
const char *line_cstr = current_lines.GetStringAtIndex(i);
|
|
|
|
|
if (line_cstr) {
|
|
|
|
|
current_code.append("\n");
|
|
|
|
|
current_code.append(line_cstr);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2019-08-15 13:14:10 +00:00
|
|
|
current_code.append("\n");
|
2019-09-25 12:55:30 +00:00
|
|
|
current_code += request.GetRawLine();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2020-01-27 21:24:39 +01:00
|
|
|
CompleteCode(current_code, request);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
bool QuitCommandOverrideCallback(void *baton, const char **argv) {
|
|
|
|
|
Target *target = (Target *)baton;
|
|
|
|
|
lldb::ProcessSP process_sp(target->GetProcessSP());
|
|
|
|
|
if (process_sp) {
|
|
|
|
|
process_sp->Destroy(false);
|
|
|
|
|
process_sp->GetTarget().GetDebugger().ClearIOHandlers();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-10-19 23:11:07 +00:00
|
|
|
return false;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status REPL::RunLoop() {
|
|
|
|
|
Status error;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
error = DoInitialization();
|
|
|
|
|
m_repl_source_path = GetSourcePath();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (!error.Success())
|
|
|
|
|
return error;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
Debugger &debugger = m_target.GetDebugger();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
lldb::IOHandlerSP io_handler_sp(GetIOHandler());
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2024-08-30 10:58:32 -07:00
|
|
|
std::optional<SourceManager::SupportFileAndLine> default_file_line;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (!m_repl_source_path.empty()) {
|
|
|
|
|
// Save the current default file and line
|
2024-08-30 10:58:32 -07:00
|
|
|
default_file_line = m_target.GetSourceManager().GetDefaultFileAndLine();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2020-01-15 14:56:28 -08:00
|
|
|
debugger.RunIOHandlerAsync(io_handler_sp);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2018-04-30 16:49:04 +00:00
|
|
|
// Check if we are in dedicated REPL mode where LLDB was start with the "--
|
|
|
|
|
// repl" option from the command line. Currently we know this by checking if
|
|
|
|
|
// the debugger already has a IOHandler thread.
|
2015-10-19 23:11:07 +00:00
|
|
|
if (!debugger.HasIOHandlerThread()) {
|
|
|
|
|
// The debugger doesn't have an existing IOHandler thread, so this must be
|
|
|
|
|
// dedicated REPL mode...
|
|
|
|
|
m_dedicated_repl_mode = true;
|
|
|
|
|
debugger.StartIOHandlerThread();
|
2016-10-05 21:14:56 +00:00
|
|
|
llvm::StringRef command_name_str("quit");
|
2015-10-19 23:11:07 +00:00
|
|
|
CommandObject *cmd_obj =
|
|
|
|
|
debugger.GetCommandInterpreter().GetCommandObjectForCommand(
|
|
|
|
|
command_name_str);
|
2016-09-06 20:57:50 +00:00
|
|
|
if (cmd_obj) {
|
2015-10-19 23:11:07 +00:00
|
|
|
assert(command_name_str.empty());
|
|
|
|
|
cmd_obj->SetOverrideCallback(QuitCommandOverrideCallback, &m_target);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Wait for the REPL command interpreter to get popped
|
|
|
|
|
io_handler_sp->WaitForPop();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
if (m_dedicated_repl_mode) {
|
2018-04-30 16:49:04 +00:00
|
|
|
// If we were in dedicated REPL mode we would have started the IOHandler
|
|
|
|
|
// thread, and we should kill our process
|
2015-10-19 23:11:07 +00:00
|
|
|
lldb::ProcessSP process_sp = m_target.GetProcessSP();
|
|
|
|
|
if (process_sp && process_sp->IsAlive())
|
|
|
|
|
process_sp->Destroy(false);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Wait for the IO handler thread to exit (TODO: don't do this if the IO
|
|
|
|
|
// handler thread already exists...)
|
|
|
|
|
debugger.JoinIOHandlerThread();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-19 23:11:07 +00:00
|
|
|
// Restore the default file and line
|
2024-08-30 10:58:32 -07:00
|
|
|
if (default_file_line)
|
|
|
|
|
m_target.GetSourceManager().SetDefaultFileAndLine(
|
|
|
|
|
default_file_line->support_file_sp, default_file_line->line);
|
2015-10-19 23:11:07 +00:00
|
|
|
return error;
|
|
|
|
|
}
|