183 changes: 138 additions & 45 deletions lldb/source/Core/IOHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@
using namespace lldb;
using namespace lldb_private;

IOHandler::IOHandler (Debugger &debugger) :
IOHandler::IOHandler (Debugger &debugger, IOHandler::Type type) :
IOHandler (debugger,
type,
StreamFileSP(), // Adopt STDIN from top input reader
StreamFileSP(), // Adopt STDOUT from top input reader
StreamFileSP(), // Adopt STDERR from top input reader
Expand All @@ -49,6 +50,7 @@ IOHandler::IOHandler (Debugger &debugger) :


IOHandler::IOHandler (Debugger &debugger,
IOHandler::Type type,
const lldb::StreamFileSP &input_sp,
const lldb::StreamFileSP &output_sp,
const lldb::StreamFileSP &error_sp,
Expand All @@ -57,7 +59,9 @@ IOHandler::IOHandler (Debugger &debugger,
m_input_sp (input_sp),
m_output_sp (output_sp),
m_error_sp (error_sp),
m_popped (false),
m_flags (flags),
m_type (type),
m_user_data (NULL),
m_done (false),
m_active (false)
Expand Down Expand Up @@ -153,13 +157,28 @@ IOHandler::GetIsRealTerminal ()
return GetInputStreamFile()->GetFile().GetIsRealTerminal();
}

void
IOHandler::SetPopped (bool b)
{
m_popped.SetValue(b, eBroadcastOnChange);
}

void
IOHandler::WaitForPop ()
{
m_popped.WaitForValueEqualTo(true);
}

IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
const char *prompt,
bool default_response) :
IOHandlerEditline(debugger,
IOHandler::Type::Confirm,
NULL, // NULL editline_name means no history loaded/saved
NULL,
NULL, // No prompt
NULL, // No continuation prompt
false, // Multi-line
false, // Don't colorize the prompt (i.e. the confirm message.)
0,
*this),
m_default_response (default_response),
Expand Down Expand Up @@ -312,42 +331,56 @@ IOHandlerDelegate::IOHandlerComplete (IOHandler &io_handler,


IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
IOHandler::Type type,
const char *editline_name, // Used for saving history files
const char *prompt,
const char *continuation_prompt,
bool multi_line,
bool color_prompts,
uint32_t line_number_start,
IOHandlerDelegate &delegate) :
IOHandlerEditline(debugger,
type,
StreamFileSP(), // Inherit input from top input reader
StreamFileSP(), // Inherit output from top input reader
StreamFileSP(), // Inherit error from top input reader
0, // Flags
editline_name, // Used for saving history files
prompt,
continuation_prompt,
multi_line,
color_prompts,
line_number_start,
delegate)
{
}

IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
IOHandler::Type type,
const lldb::StreamFileSP &input_sp,
const lldb::StreamFileSP &output_sp,
const lldb::StreamFileSP &error_sp,
uint32_t flags,
const char *editline_name, // Used for saving history files
const char *prompt,
const char *continuation_prompt,
bool multi_line,
bool color_prompts,
uint32_t line_number_start,
IOHandlerDelegate &delegate) :
IOHandler (debugger, input_sp, output_sp, error_sp, flags),
IOHandler (debugger, type, input_sp, output_sp, error_sp, flags),
#ifndef LLDB_DISABLE_LIBEDIT
m_editline_ap (),
#endif
m_delegate (delegate),
m_prompt (),
m_continuation_prompt(),
m_current_lines_ptr (NULL),
m_base_line_number (line_number_start),
m_multi_line (multi_line)
m_curr_line_idx (UINT32_MAX),
m_multi_line (multi_line),
m_color_prompts (color_prompts),
m_interrupt_exits (true)
{
SetPrompt(prompt);

Expand All @@ -364,17 +397,25 @@ IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
if (use_editline)
{
m_editline_ap.reset(new Editline (editline_name,
prompt ? prompt : "",
multi_line,
GetInputFILE (),
GetOutputFILE (),
GetErrorFILE ()));
if (m_base_line_number > 0)
m_editline_ap->ShowLineNumbers(true, m_base_line_number);
m_editline_ap->SetLineCompleteCallback (LineCompletedCallback, this);
GetErrorFILE (),
m_color_prompts));
m_editline_ap->SetIsInputCompleteCallback (IsInputCompleteCallback, this);
m_editline_ap->SetAutoCompleteCallback (AutoCompleteCallback, this);
// See if the delegate supports fixing indentation
const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters();
if (indent_chars)
{
// The delegate does support indentation, hook it up so when any indentation
// character is typed, the delegate gets a chance to fix it
m_editline_ap->SetFixIndentationCallback (FixIndentationCallback, this, indent_chars);
}
}
#endif
SetBaseLineNumber (m_base_line_number);
SetPrompt(prompt ? prompt : "");
SetContinuationPrompt(continuation_prompt);
}

IOHandlerEditline::~IOHandlerEditline ()
Expand All @@ -384,14 +425,28 @@ IOHandlerEditline::~IOHandlerEditline ()
#endif
}

void
IOHandlerEditline::Activate ()
{
IOHandler::Activate();
m_delegate.IOHandlerActivated(*this);
}

void
IOHandlerEditline::Deactivate ()
{
IOHandler::Deactivate();
m_delegate.IOHandlerDeactivated(*this);
}


bool
IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
{
#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
{
return m_editline_ap->GetLine(line, interrupted).Success();
return m_editline_ap->GetLine (line, interrupted);
}
else
{
Expand All @@ -403,7 +458,14 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted)
{
if (GetIsInteractive())
{
const char *prompt = GetPrompt();
const char *prompt = NULL;

if (m_multi_line && m_curr_line_idx > 0)
prompt = GetContinuationPrompt();

if (prompt == NULL)
prompt = GetPrompt();

if (prompt && prompt[0])
{
FILE *out = GetOutputFILE();
Expand Down Expand Up @@ -468,15 +530,23 @@ IOHandlerEditline::GetLine (std::string &line, bool &interrupted)


#ifndef LLDB_DISABLE_LIBEDIT
LineStatus
IOHandlerEditline::LineCompletedCallback (Editline *editline,
bool
IOHandlerEditline::IsInputCompleteCallback (Editline *editline,
StringList &lines,
uint32_t line_idx,
Error &error,
void *baton)
{
IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
return editline_reader->m_delegate.IOHandlerLinesUpdated(*editline_reader, lines, line_idx, error);
return editline_reader->m_delegate.IOHandlerIsInputComplete(*editline_reader, lines);
}

int
IOHandlerEditline::FixIndentationCallback (Editline *editline,
const StringList &lines,
int cursor_position,
void *baton)
{
IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
return editline_reader->m_delegate.IOHandlerFixIndentation(*editline_reader, lines, cursor_position);
}

int
Expand Down Expand Up @@ -534,33 +604,62 @@ IOHandlerEditline::SetPrompt (const char *p)
return true;
}

const char *
IOHandlerEditline::GetContinuationPrompt ()
{
if (m_continuation_prompt.empty())
return NULL;
return m_continuation_prompt.c_str();
}


void
IOHandlerEditline::SetContinuationPrompt (const char *p)
{
if (p && p[0])
m_continuation_prompt = p;
else
m_continuation_prompt.clear();

if (m_editline_ap)
m_editline_ap->SetContinuationPrompt (m_continuation_prompt.empty() ? NULL : m_continuation_prompt.c_str());
}


void
IOHandlerEditline::SetBaseLineNumber (uint32_t line)
{
m_base_line_number = line;
#ifndef LLDB_DISABLE_LIBEDIT
}

uint32_t
IOHandlerEditline::GetCurrentLineIndex () const
{
#ifdef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
m_editline_ap->ShowLineNumbers (true, line);
return m_editline_ap->GetCurrentLine();
#endif

return m_curr_line_idx;
}

bool
IOHandlerEditline::GetLines (StringList &lines, bool &interrupted)
{
m_current_lines_ptr = &lines;

bool success = false;
#ifndef LLDB_DISABLE_LIBEDIT
if (m_editline_ap)
{
std::string end_token;
success = m_editline_ap->GetLines(end_token, lines, interrupted).Success();
return m_editline_ap->GetLines (m_base_line_number, lines, interrupted);
}
else
{
#endif
LineStatus lines_status = LineStatus::Success;
bool done = false;
Error error;

while (lines_status == LineStatus::Success)
while (!done)
{
// Show line numbers if we are asked to
std::string line;
Expand All @@ -571,29 +670,19 @@ IOHandlerEditline::GetLines (StringList &lines, bool &interrupted)
::fprintf(out, "%u%s", m_base_line_number + (uint32_t)lines.GetSize(), GetPrompt() == NULL ? " " : "");
}

m_curr_line_idx = lines.GetSize();

bool interrupted = false;
if (GetLine(line, interrupted))
if (GetLine(line, interrupted) && !interrupted)
{
if (interrupted)
{
lines_status = LineStatus::Done;
}
else
{
lines.AppendString(line);
lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error);
}
lines.AppendString(line);
done = m_delegate.IOHandlerIsInputComplete(*this, lines);
}
else
{
lines_status = LineStatus::Done;
done = true;
}
}

// Call the IOHandlerLinesUpdated function with UINT32_MAX as the line
// number to indicate all lines are complete
m_delegate.IOHandlerLinesUpdated(*this, lines, UINT32_MAX, error);

success = lines.GetSize() > 0;
#ifndef LLDB_DISABLE_LIBEDIT
}
Expand All @@ -618,12 +707,14 @@ IOHandlerEditline::Run ()
{
if (interrupted)
{
m_done = true;
m_done = m_interrupt_exits;
m_delegate.IOHandlerInputInterrupted (*this, line);

}
else
{
line = lines.CopyList();
m_delegate.IOHandlerInputComplete(*this, line);
m_delegate.IOHandlerInputComplete (*this, line);
}
}
else
Expand All @@ -635,8 +726,10 @@ IOHandlerEditline::Run ()
{
if (GetLine(line, interrupted))
{
if (!interrupted)
m_delegate.IOHandlerInputComplete(*this, line);
if (interrupted)
m_delegate.IOHandlerInputInterrupted (*this, line);
else
m_delegate.IOHandlerInputComplete (*this, line);
}
else
{
Expand Down Expand Up @@ -5375,7 +5468,7 @@ class SourceFileWindowDelegate : public WindowDelegate
DisplayOptions ValueObjectListDelegate::g_options = { true };

IOHandlerCursesGUI::IOHandlerCursesGUI (Debugger &debugger) :
IOHandler (debugger)
IOHandler (debugger, IOHandler::Type::Curses)
{
}

Expand Down
1,707 changes: 1,097 additions & 610 deletions lldb/source/Host/common/Editline.cpp

Large diffs are not rendered by default.

99 changes: 63 additions & 36 deletions lldb/source/Interpreter/CommandInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2737,13 +2737,16 @@ CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
lldb::StreamFileSP empty_stream_sp;
m_command_source_flags.push_back(flags);
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
IOHandler::Type::CommandInterpreter,
input_file_sp,
empty_stream_sp, // Pass in an empty stream so we inherit the top input reader output stream
empty_stream_sp, // Pass in an empty stream so we inherit the top input reader error stream
flags,
nullptr, // Pass in NULL for "editline_name" so no history is saved, or written
debugger.GetPrompt(),
NULL,
false, // Not multi-line
debugger.GetUseColor(),
0,
*this));
const bool old_async_execution = debugger.GetAsyncExecution();
Expand Down Expand Up @@ -3181,9 +3184,12 @@ CommandInterpreter::GetLLDBCommandsFromIOHandler (const char *prompt,
{
Debugger &debugger = GetDebugger();
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
IOHandler::Type::CommandList,
"lldb", // Name of input reader for history
prompt, // Prompt
NULL, // Continuation prompt
true, // Get multiple lines
debugger.GetUseColor(),
0, // Don't show line numbers
delegate)); // IOHandlerDelegate

Expand All @@ -3207,9 +3213,12 @@ CommandInterpreter::GetPythonCommandsFromIOHandler (const char *prompt,
{
Debugger &debugger = GetDebugger();
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
IOHandler::Type::PythonCode,
"lldb-python", // Name of input reader for history
prompt, // Prompt
NULL, // Continuation prompt
true, // Get multiple lines
debugger.GetUseColor(),
0, // Don't show line numbers
delegate)); // IOHandlerDelegate

Expand All @@ -3230,47 +3239,65 @@ CommandInterpreter::IsActive ()
return m_debugger.IsTopIOHandler (m_command_io_handler_sp);
}

lldb::IOHandlerSP
CommandInterpreter::GetIOHandler(bool force_create, CommandInterpreterRunOptions *options)
{
// Always re-create the IOHandlerEditline in case the input
// changed. The old instance might have had a non-interactive
// input and now it does or vice versa.
if (force_create || !m_command_io_handler_sp)
{
// Always re-create the IOHandlerEditline in case the input
// changed. The old instance might have had a non-interactive
// input and now it does or vice versa.
uint32_t flags = 0;

if (options)
{
if (options->m_stop_on_continue == eLazyBoolYes)
flags |= eHandleCommandFlagStopOnContinue;
if (options->m_stop_on_error == eLazyBoolYes)
flags |= eHandleCommandFlagStopOnError;
if (options->m_stop_on_crash == eLazyBoolYes)
flags |= eHandleCommandFlagStopOnCrash;
if (options->m_echo_commands != eLazyBoolNo)
flags |= eHandleCommandFlagEchoCommand;
if (options->m_print_results != eLazyBoolNo)
flags |= eHandleCommandFlagPrintResult;
}
else
{
flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult;
}

m_command_io_handler_sp.reset(new IOHandlerEditline (m_debugger,
IOHandler::Type::CommandInterpreter,
m_debugger.GetInputFile(),
m_debugger.GetOutputFile(),
m_debugger.GetErrorFile(),
flags,
"lldb",
m_debugger.GetPrompt(),
NULL, // Continuation prompt
false, // Don't enable multiple line input, just single line commands
m_debugger.GetUseColor(),
0, // Don't show line numbers
*this));
}
return m_command_io_handler_sp;
}

void
CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
bool spawn_thread,
CommandInterpreterRunOptions &options)
{
// Only get one line at a time
const bool multiple_lines = false;
m_num_errors = 0;
m_quit_requested = false;
// Always re-create the command intepreter when we run it in case
// any file handles have changed.
bool force_create = true;
m_debugger.PushIOHandler(GetIOHandler(force_create, &options));
m_stopped_for_crash = false;

// Always re-create the IOHandlerEditline in case the input
// changed. The old instance might have had a non-interactive
// input and now it does or vice versa.
uint32_t flags= 0;

if (options.m_stop_on_continue == eLazyBoolYes)
flags |= eHandleCommandFlagStopOnContinue;
if (options.m_stop_on_error == eLazyBoolYes)
flags |= eHandleCommandFlagStopOnError;
if (options.m_stop_on_crash == eLazyBoolYes)
flags |= eHandleCommandFlagStopOnCrash;
if (options.m_echo_commands != eLazyBoolNo)
flags |= eHandleCommandFlagEchoCommand;
if (options.m_print_results != eLazyBoolNo)
flags |= eHandleCommandFlagPrintResult;


m_command_io_handler_sp.reset(new IOHandlerEditline (m_debugger,
m_debugger.GetInputFile(),
m_debugger.GetOutputFile(),
m_debugger.GetErrorFile(),
flags,
"lldb",
m_debugger.GetPrompt(),
multiple_lines,
0, // Don't show line numbers
*this));

m_debugger.PushIOHandler(m_command_io_handler_sp);

if (auto_handle_events)
m_debugger.StartEventHandlerThread();

Expand All @@ -3281,10 +3308,10 @@ CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
else
{
m_debugger.ExecuteIOHanders();

if (auto_handle_events)
m_debugger.StopEventHandlerThread();
}

}

2 changes: 1 addition & 1 deletion lldb/source/Interpreter/ScriptInterpreterPython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ class IOHandlerPythonInterpreter :

IOHandlerPythonInterpreter (Debugger &debugger,
ScriptInterpreterPython *python) :
IOHandler (debugger),
IOHandler (debugger, IOHandler::Type::PythonInterpreter),
m_python(python)
{

Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4893,7 +4893,7 @@ class IOHandlerProcessSTDIO :
public:
IOHandlerProcessSTDIO (Process *process,
int write_fd) :
IOHandler(process->GetTarget().GetDebugger()),
IOHandler(process->GetTarget().GetDebugger(), IOHandler::Type::ProcessIO),
m_process (process),
m_read_file (),
m_write_file (write_fd, false),
Expand Down