forked from OSchip/llvm-project
Complete rewrite of interactive editing support for single- and multi-line input.
Improvements include: * Use of libedit's wide character support, which is imperfect but a distinct improvement over ASCII-only * Fallback for ASCII editing path * Support for a "faint" prompt clearly distinguished from input * Breaking lines and insert new lines in the middle of a batch by simply pressing return * Joining lines with forward and backward character deletion * Detection of paste to suppress automatic formatting and statement completion tests * Correctly reformatting when lines grow or shrink to occupy different numbers of rows * Saving multi-line history, and correctly preserving the "tip" of history during editing * Displaying visible ^C and ^D indications when interrupting input or sending EOF * Fledgling VI support for multi-line editing * General correctness and reliability improvements llvm-svn: 222163
This commit is contained in:
parent
278ddec22c
commit
e30f11d9ee
|
@ -19,9 +19,11 @@
|
|||
#include "lldb/Core/ConstString.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/Flags.h"
|
||||
#include "lldb/Core/Stream.h"
|
||||
#include "lldb/Core/StringList.h"
|
||||
#include "lldb/Core/ValueObjectList.h"
|
||||
#include "lldb/Host/Mutex.h"
|
||||
#include "lldb/Host/Predicate.h"
|
||||
|
||||
namespace curses
|
||||
{
|
||||
|
@ -34,9 +36,23 @@ namespace lldb_private {
|
|||
class IOHandler
|
||||
{
|
||||
public:
|
||||
IOHandler (Debugger &debugger);
|
||||
enum class Type {
|
||||
CommandInterpreter,
|
||||
CommandList,
|
||||
Confirm,
|
||||
Curses,
|
||||
Expression,
|
||||
ProcessIO,
|
||||
PythonInterpreter,
|
||||
PythonCode,
|
||||
Other
|
||||
};
|
||||
|
||||
IOHandler (Debugger &debugger,
|
||||
IOHandler::Type type);
|
||||
|
||||
IOHandler (Debugger &debugger,
|
||||
IOHandler::Type type,
|
||||
const lldb::StreamFileSP &input_sp,
|
||||
const lldb::StreamFileSP &output_sp,
|
||||
const lldb::StreamFileSP &error_sp,
|
||||
|
@ -97,6 +113,12 @@ namespace lldb_private {
|
|||
return m_done;
|
||||
}
|
||||
|
||||
Type
|
||||
GetType () const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
virtual void
|
||||
Activate ()
|
||||
{
|
||||
|
@ -128,7 +150,19 @@ namespace lldb_private {
|
|||
{
|
||||
return ConstString();
|
||||
}
|
||||
|
||||
virtual const char *
|
||||
GetCommandPrefix ()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual const char *
|
||||
GetHelpPrologue()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
GetInputFD();
|
||||
|
||||
|
@ -206,13 +240,21 @@ namespace lldb_private {
|
|||
//------------------------------------------------------------------
|
||||
bool
|
||||
GetIsRealTerminal ();
|
||||
|
||||
|
||||
void
|
||||
SetPopped (bool b);
|
||||
|
||||
void
|
||||
WaitForPop ();
|
||||
|
||||
protected:
|
||||
Debugger &m_debugger;
|
||||
lldb::StreamFileSP m_input_sp;
|
||||
lldb::StreamFileSP m_output_sp;
|
||||
lldb::StreamFileSP m_error_sp;
|
||||
Predicate<bool> m_popped;
|
||||
Flags m_flags;
|
||||
Type m_type;
|
||||
void *m_user_data;
|
||||
bool m_done;
|
||||
bool m_active;
|
||||
|
@ -254,7 +296,12 @@ namespace lldb_private {
|
|||
IOHandlerActivated (IOHandler &io_handler)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual void
|
||||
IOHandlerDeactivated (IOHandler &io_handler)
|
||||
{
|
||||
}
|
||||
|
||||
virtual int
|
||||
IOHandlerComplete (IOHandler &io_handler,
|
||||
const char *current_line,
|
||||
|
@ -264,6 +311,44 @@ namespace lldb_private {
|
|||
int max_matches,
|
||||
StringList &matches);
|
||||
|
||||
virtual const char *
|
||||
IOHandlerGetFixIndentationCharacters ()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Called when a new line is created or one of an identifed set of
|
||||
/// indentation characters is typed.
|
||||
///
|
||||
/// This function determines how much indentation should be added
|
||||
/// or removed to match the recommended amount for the final line.
|
||||
///
|
||||
/// @param[in] io_handler
|
||||
/// The IOHandler that responsible for input.
|
||||
///
|
||||
/// @param[in] lines
|
||||
/// The current input up to the line to be corrected. Lines
|
||||
/// following the line containing the cursor are not included.
|
||||
///
|
||||
/// @param[in] cursor_position
|
||||
/// The number of characters preceeding the cursor on the final
|
||||
/// line at the time.
|
||||
///
|
||||
/// @return
|
||||
/// Returns an integer describing the number of spaces needed
|
||||
/// to correct the indentation level. Positive values indicate
|
||||
/// that spaces should be added, while negative values represent
|
||||
/// spaces that should be removed.
|
||||
//------------------------------------------------------------------
|
||||
virtual int
|
||||
IOHandlerFixIndentation (IOHandler &io_handler,
|
||||
const StringList &lines,
|
||||
int cursor_position)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Called when a line or lines have been retrieved.
|
||||
///
|
||||
|
@ -275,40 +360,55 @@ namespace lldb_private {
|
|||
//------------------------------------------------------------------
|
||||
virtual void
|
||||
IOHandlerInputComplete (IOHandler &io_handler, std::string &data) = 0;
|
||||
|
||||
|
||||
virtual void
|
||||
IOHandlerInputInterrupted (IOHandler &io_handler, std::string &data)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Called when a line in \a lines has been updated when doing
|
||||
/// multi-line input.
|
||||
/// Called to determine whether typing enter after the last line in
|
||||
/// \a lines should end input. This function will not be called on
|
||||
/// IOHandler objects that are getting single lines.
|
||||
/// @param[in] io_handler
|
||||
/// The IOHandler that responsible for updating the lines.
|
||||
///
|
||||
/// @param[in] lines
|
||||
/// The current multi-line content. May be altered to provide
|
||||
/// alternative input when complete.
|
||||
///
|
||||
/// @return
|
||||
/// Return an enumeration to indicate the status of the current
|
||||
/// line:
|
||||
/// Success - The line is good and should be added to the
|
||||
/// multiple lines
|
||||
/// Error - There is an error with the current line and it
|
||||
/// need to be re-edited before it is acceptable
|
||||
/// Done - The lines collection is complete and ready to be
|
||||
/// returned.
|
||||
/// Return an boolean to indicate whether input is complete,
|
||||
/// true indicates that no additional input is necessary, while
|
||||
/// false indicates that more input is required.
|
||||
//------------------------------------------------------------------
|
||||
virtual LineStatus
|
||||
IOHandlerLinesUpdated (IOHandler &io_handler,
|
||||
StringList &lines,
|
||||
uint32_t line_idx,
|
||||
Error &error)
|
||||
virtual bool
|
||||
IOHandlerIsInputComplete (IOHandler &io_handler,
|
||||
StringList &lines)
|
||||
{
|
||||
return LineStatus::Done; // Stop getting lines on the first line that is updated
|
||||
// subclasses should do something more intelligent here.
|
||||
// This function will not be called on IOHandler objects
|
||||
// that are getting single lines.
|
||||
// Impose no requirements for input to be considered
|
||||
// complete. subclasses should do something more intelligent.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
virtual ConstString
|
||||
IOHandlerGetControlSequence (char ch)
|
||||
{
|
||||
return ConstString();
|
||||
}
|
||||
|
||||
virtual const char *
|
||||
IOHandlerGetCommandPrefix ()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual const char *
|
||||
IOHandlerGetHelpPrologue ()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Intercept the IOHandler::Interrupt() calls and do something.
|
||||
//
|
||||
|
@ -356,30 +456,21 @@ namespace lldb_private {
|
|||
return ConstString();
|
||||
}
|
||||
|
||||
virtual LineStatus
|
||||
IOHandlerLinesUpdated (IOHandler &io_handler,
|
||||
StringList &lines,
|
||||
uint32_t line_idx,
|
||||
Error &error)
|
||||
virtual bool
|
||||
IOHandlerIsInputComplete (IOHandler &io_handler,
|
||||
StringList &lines)
|
||||
{
|
||||
if (line_idx == UINT32_MAX)
|
||||
// Determine whether the end of input signal has been entered
|
||||
const size_t num_lines = lines.GetSize();
|
||||
if (num_lines > 0 && lines[num_lines - 1] == m_end_line)
|
||||
{
|
||||
// Remove the last empty line from "lines" so it doesn't appear
|
||||
// in our final expression and return true to indicate we are done
|
||||
// Remove the terminal line from "lines" so it doesn't appear in
|
||||
// the resulting input and return true to indicate we are done
|
||||
// getting lines
|
||||
lines.PopBack();
|
||||
return LineStatus::Done;
|
||||
return true;
|
||||
}
|
||||
else if (line_idx + 1 == lines.GetSize())
|
||||
{
|
||||
// The last line was edited, if this line is empty, then we are done
|
||||
// getting our multiple lines.
|
||||
if (lines[line_idx] == m_end_line)
|
||||
{
|
||||
return LineStatus::Done;
|
||||
}
|
||||
}
|
||||
return LineStatus::Success;
|
||||
return false;
|
||||
}
|
||||
protected:
|
||||
const std::string m_end_line;
|
||||
|
@ -390,20 +481,26 @@ namespace lldb_private {
|
|||
{
|
||||
public:
|
||||
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, // If non-zero show line numbers starting at 'line_number_start'
|
||||
IOHandlerDelegate &delegate);
|
||||
|
||||
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, // If non-zero show line numbers starting at 'line_number_start'
|
||||
IOHandlerDelegate &delegate);
|
||||
|
||||
|
@ -429,11 +526,10 @@ namespace lldb_private {
|
|||
GotEOF();
|
||||
|
||||
virtual void
|
||||
Activate ()
|
||||
{
|
||||
IOHandler::Activate();
|
||||
m_delegate.IOHandlerActivated(*this);
|
||||
}
|
||||
Activate ();
|
||||
|
||||
virtual void
|
||||
Deactivate ();
|
||||
|
||||
virtual ConstString
|
||||
GetControlSequence (char ch)
|
||||
|
@ -441,12 +537,30 @@ namespace lldb_private {
|
|||
return m_delegate.IOHandlerGetControlSequence (ch);
|
||||
}
|
||||
|
||||
virtual const char *
|
||||
GetCommandPrefix ()
|
||||
{
|
||||
return m_delegate.IOHandlerGetCommandPrefix ();
|
||||
}
|
||||
|
||||
virtual const char *
|
||||
GetHelpPrologue ()
|
||||
{
|
||||
return m_delegate.IOHandlerGetHelpPrologue ();
|
||||
}
|
||||
|
||||
virtual const char *
|
||||
GetPrompt ();
|
||||
|
||||
virtual bool
|
||||
SetPrompt (const char *prompt);
|
||||
|
||||
|
||||
const char *
|
||||
GetContinuationPrompt ();
|
||||
|
||||
void
|
||||
SetContinuationPrompt (const char *prompt);
|
||||
|
||||
bool
|
||||
GetLine (std::string &line, bool &interrupted);
|
||||
|
||||
|
@ -456,15 +570,40 @@ namespace lldb_private {
|
|||
void
|
||||
SetBaseLineNumber (uint32_t line);
|
||||
|
||||
bool
|
||||
GetInterruptExits ()
|
||||
{
|
||||
return m_interrupt_exits;
|
||||
}
|
||||
|
||||
void
|
||||
SetInterruptExits (bool b)
|
||||
{
|
||||
m_interrupt_exits = b;
|
||||
}
|
||||
|
||||
const StringList *
|
||||
GetCurrentLines () const
|
||||
{
|
||||
return m_current_lines_ptr;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GetCurrentLineIndex () const;
|
||||
|
||||
private:
|
||||
#ifndef LLDB_DISABLE_LIBEDIT
|
||||
static LineStatus
|
||||
LineCompletedCallback (Editline *editline,
|
||||
StringList &lines,
|
||||
uint32_t line_idx,
|
||||
Error &error,
|
||||
void *baton);
|
||||
|
||||
static bool
|
||||
IsInputCompleteCallback (Editline *editline,
|
||||
StringList &lines,
|
||||
void *baton);
|
||||
|
||||
static int
|
||||
FixIndentationCallback (Editline *editline,
|
||||
const StringList &lines,
|
||||
int cursor_position,
|
||||
void *baton);
|
||||
|
||||
static int AutoCompleteCallback (const char *current_line,
|
||||
const char *cursor,
|
||||
const char *last_char,
|
||||
|
@ -480,8 +619,13 @@ namespace lldb_private {
|
|||
#endif
|
||||
IOHandlerDelegate &m_delegate;
|
||||
std::string m_prompt;
|
||||
std::string m_continuation_prompt;
|
||||
StringList *m_current_lines_ptr;
|
||||
uint32_t m_base_line_number; // If non-zero, then show line numbers in prompt
|
||||
bool m_multi_line;
|
||||
uint32_t m_curr_line_idx;
|
||||
bool m_multi_line;
|
||||
bool m_color_prompts;
|
||||
bool m_interrupt_exits;
|
||||
};
|
||||
|
||||
class IOHandlerConfirm :
|
||||
|
@ -611,7 +755,8 @@ namespace lldb_private {
|
|||
if (sp)
|
||||
{
|
||||
Mutex::Locker locker (m_mutex);
|
||||
m_stack.push (sp);
|
||||
sp->SetPopped (false);
|
||||
m_stack.push_back (sp);
|
||||
// Set m_top the non-locking IsTop() call
|
||||
m_top = sp.get();
|
||||
}
|
||||
|
@ -631,7 +776,7 @@ namespace lldb_private {
|
|||
{
|
||||
Mutex::Locker locker (m_mutex);
|
||||
if (!m_stack.empty())
|
||||
sp = m_stack.top();
|
||||
sp = m_stack.back();
|
||||
}
|
||||
return sp;
|
||||
}
|
||||
|
@ -641,12 +786,16 @@ namespace lldb_private {
|
|||
{
|
||||
Mutex::Locker locker (m_mutex);
|
||||
if (!m_stack.empty())
|
||||
m_stack.pop();
|
||||
{
|
||||
lldb::IOHandlerSP sp (m_stack.back());
|
||||
m_stack.pop_back();
|
||||
sp->SetPopped (true);
|
||||
}
|
||||
// Set m_top the non-locking IsTop() call
|
||||
if (m_stack.empty())
|
||||
m_top = NULL;
|
||||
else
|
||||
m_top = m_stack.top().get();
|
||||
m_top = m_stack.back().get();
|
||||
}
|
||||
|
||||
Mutex &
|
||||
|
@ -661,6 +810,19 @@ namespace lldb_private {
|
|||
return m_top == io_handler_sp.get();
|
||||
}
|
||||
|
||||
bool
|
||||
CheckTopIOHandlerTypes (IOHandler::Type top_type, IOHandler::Type second_top_type)
|
||||
{
|
||||
Mutex::Locker locker (m_mutex);
|
||||
const size_t num_io_handlers = m_stack.size();
|
||||
if (num_io_handlers >= 2 &&
|
||||
m_stack[num_io_handlers-1]->GetType() == top_type &&
|
||||
m_stack[num_io_handlers-2]->GetType() == second_top_type)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ConstString
|
||||
GetTopIOHandlerControlSequence (char ch)
|
||||
{
|
||||
|
@ -669,9 +831,26 @@ namespace lldb_private {
|
|||
return ConstString();
|
||||
}
|
||||
|
||||
protected:
|
||||
const char *
|
||||
GetTopIOHandlerCommandPrefix()
|
||||
{
|
||||
if (m_top)
|
||||
return m_top->GetCommandPrefix();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::stack<lldb::IOHandlerSP> m_stack;
|
||||
const char *
|
||||
GetTopIOHandlerHelpPrologue()
|
||||
{
|
||||
if (m_top)
|
||||
return m_top->GetHelpPrologue();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
typedef std::vector<lldb::IOHandlerSP> collection;
|
||||
collection m_stack;
|
||||
mutable Mutex m_mutex;
|
||||
IOHandler *m_top;
|
||||
|
||||
|
|
|
@ -7,13 +7,40 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
//TODO: wire up window size changes
|
||||
|
||||
// If we ever get a private copy of libedit, there are a number of defects that would be nice to fix;
|
||||
// a) Sometimes text just disappears while editing. In an 80-column editor paste the following text, without
|
||||
// the quotes:
|
||||
// "This is a test of the input system missing Hello, World! Do you disappear when it gets to a particular length?"
|
||||
// Now press ^A to move to the start and type 3 characters, and you'll see a good amount of the text will
|
||||
// disappear. It's still in the buffer, just invisible.
|
||||
// b) The prompt printing logic for dealing with ANSI formatting characters is broken, which is why we're
|
||||
// working around it here.
|
||||
// c) When resizing the terminal window, if the cursor moves between rows libedit will get confused.
|
||||
// d) The incremental search uses escape to cancel input, so it's confused by ANSI sequences starting with escape.
|
||||
// e) Emoji support is fairly terrible, presumably it doesn't understand composed characters?
|
||||
|
||||
#ifndef liblldb_Editline_h_
|
||||
#define liblldb_Editline_h_
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#include "lldb/lldb-private.h"
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
// components needed to handle wide characters ( <codecvt>, codecvt_utf8, libedit built with '--enable-widec' )
|
||||
// are not consistenly available on non-OSX platforms. The wchar_t versions of libedit functions will only be
|
||||
// used in cases where this is true. This is a compile time dependecy, for now selected per target Platform
|
||||
#if defined (__APPLE__)
|
||||
#define LLDB_EDITLINE_USE_WCHAR 1
|
||||
#include <codecvt>
|
||||
#else
|
||||
#define LLDB_EDITLINE_USE_WCHAR 0
|
||||
#endif
|
||||
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Host/ConnectionFileDescriptor.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#if defined(_WIN32)
|
||||
#include "lldb/Host/windows/editlinewin.h"
|
||||
#else
|
||||
|
@ -32,179 +59,308 @@
|
|||
#include "lldb/Host/Predicate.h"
|
||||
|
||||
namespace lldb_private {
|
||||
namespace line_editor {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// @class Editline Editline.h "lldb/Host/Editline.h"
|
||||
/// @brief A class that encapsulates editline functionality.
|
||||
//----------------------------------------------------------------------
|
||||
class EditlineHistory;
|
||||
|
||||
typedef std::shared_ptr<EditlineHistory> EditlineHistorySP;
|
||||
|
||||
class Editline
|
||||
{
|
||||
public:
|
||||
typedef LineStatus (*LineCompletedCallbackType) (
|
||||
Editline *editline,
|
||||
StringList &lines,
|
||||
uint32_t line_idx,
|
||||
Error &error,
|
||||
void *baton);
|
||||
|
||||
typedef int (*CompleteCallbackType) (
|
||||
const char *current_line,
|
||||
const char *cursor,
|
||||
const char *last_char,
|
||||
int skip_first_n_matches,
|
||||
int max_matches,
|
||||
StringList &matches,
|
||||
void *baton);
|
||||
// type alias's to help manage 8 bit and wide character versions of libedit
|
||||
#if LLDB_EDITLINE_USE_WCHAR
|
||||
using EditLineStringType = std::wstring;
|
||||
using EditLineStringStreamType = std::wstringstream;
|
||||
using EditLineCharType = wchar_t;
|
||||
#else
|
||||
using EditLineStringType=std::string;
|
||||
using EditLineStringStreamType = std::stringstream;
|
||||
using EditLineCharType = char;
|
||||
#endif
|
||||
|
||||
typedef int (*GetCharCallbackType) (
|
||||
::EditLine *,
|
||||
char *c);
|
||||
|
||||
Editline(const char *prog, // Used for the history file and for editrc program name
|
||||
const char *prompt,
|
||||
bool configure_for_multiline,
|
||||
FILE *fin,
|
||||
FILE *fout,
|
||||
FILE *ferr);
|
||||
typedef int (* EditlineGetCharCallbackType)(::EditLine * editline, EditLineCharType * c);
|
||||
typedef unsigned char (* EditlineCommandCallbackType)(::EditLine * editline, int ch);
|
||||
typedef const char * (* EditlinePromptCallbackType)(::EditLine * editline);
|
||||
|
||||
~Editline();
|
||||
class EditlineHistory;
|
||||
|
||||
typedef std::shared_ptr<EditlineHistory> EditlineHistorySP;
|
||||
|
||||
Error
|
||||
GetLine (std::string &line,
|
||||
bool &interrupted);
|
||||
typedef bool (* IsInputCompleteCallbackType) (
|
||||
Editline * editline,
|
||||
StringList & lines,
|
||||
void * baton);
|
||||
|
||||
typedef int (* FixIndentationCallbackType) (
|
||||
Editline * editline,
|
||||
const StringList & lines,
|
||||
int cursor_position,
|
||||
void * baton);
|
||||
|
||||
typedef int (* CompleteCallbackType) (
|
||||
const char * current_line,
|
||||
const char * cursor,
|
||||
const char * last_char,
|
||||
int skip_first_n_matches,
|
||||
int max_matches,
|
||||
StringList & matches,
|
||||
void * baton);
|
||||
|
||||
/// Status used to decide when and how to start editing another line in multi-line sessions
|
||||
enum class EditorStatus
|
||||
{
|
||||
|
||||
/// The default state proceeds to edit the current line
|
||||
Editing,
|
||||
|
||||
/// Editing complete, returns the complete set of edited lines
|
||||
Complete,
|
||||
|
||||
/// End of input reported
|
||||
EndOfInput,
|
||||
|
||||
Error
|
||||
GetLines (const std::string &end_line,
|
||||
StringList &lines,
|
||||
bool &interrupted);
|
||||
|
||||
bool
|
||||
LoadHistory ();
|
||||
|
||||
bool
|
||||
SaveHistory ();
|
||||
|
||||
FILE *
|
||||
GetInputFile ();
|
||||
|
||||
FILE *
|
||||
GetOutputFile ();
|
||||
|
||||
FILE *
|
||||
GetErrorFile ();
|
||||
|
||||
bool
|
||||
GettingLine () const
|
||||
{
|
||||
return m_getting_line;
|
||||
}
|
||||
|
||||
void
|
||||
Hide ();
|
||||
|
||||
void
|
||||
Refresh();
|
||||
|
||||
bool
|
||||
Interrupt ();
|
||||
|
||||
void
|
||||
SetAutoCompleteCallback (CompleteCallbackType callback,
|
||||
void *baton)
|
||||
{
|
||||
m_completion_callback = callback;
|
||||
m_completion_callback_baton = baton;
|
||||
}
|
||||
|
||||
void
|
||||
SetLineCompleteCallback (LineCompletedCallbackType callback,
|
||||
void *baton)
|
||||
{
|
||||
m_line_complete_callback = callback;
|
||||
m_line_complete_callback_baton = baton;
|
||||
}
|
||||
|
||||
size_t
|
||||
Push (const char *bytes, size_t len);
|
||||
|
||||
static int
|
||||
GetCharFromInputFileCallback (::EditLine *e, char *c);
|
||||
|
||||
void
|
||||
SetGetCharCallback (GetCharCallbackType callback);
|
||||
|
||||
const char *
|
||||
GetPrompt();
|
||||
|
||||
void
|
||||
SetPrompt (const char *p);
|
||||
|
||||
void
|
||||
ShowLineNumbers (bool enable, uint32_t line_offset)
|
||||
{
|
||||
m_prompt_with_line_numbers = enable;
|
||||
m_line_offset = line_offset;
|
||||
/// Editing interrupted
|
||||
Interrupted
|
||||
};
|
||||
|
||||
/// Established locations that can be easily moved among with MoveCursor
|
||||
enum class CursorLocation
|
||||
{
|
||||
/// The start of the first line in a multi-line edit session
|
||||
BlockStart,
|
||||
|
||||
/// The start of the current line in a multi-line edit session
|
||||
EditingPrompt,
|
||||
|
||||
/// The location of the cursor on the current line in a multi-line edit session
|
||||
EditingCursor,
|
||||
|
||||
/// The location immediately after the last character in a multi-line edit session
|
||||
BlockEnd
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Error
|
||||
PrivateGetLine(std::string &line);
|
||||
using namespace line_editor;
|
||||
|
||||
unsigned char
|
||||
HandleCompletion (int ch);
|
||||
|
||||
static unsigned char
|
||||
CallbackEditPrevLine (::EditLine *e, int ch);
|
||||
|
||||
static unsigned char
|
||||
CallbackEditNextLine (::EditLine *e, int ch);
|
||||
|
||||
static unsigned char
|
||||
CallbackComplete (::EditLine *e, int ch);
|
||||
|
||||
static const char *
|
||||
GetPromptCallback (::EditLine *e);
|
||||
|
||||
static Editline *
|
||||
GetClientData (::EditLine *e);
|
||||
|
||||
static FILE *
|
||||
GetFilePointer (::EditLine *e, int fd);
|
||||
|
||||
enum class Command
|
||||
/// Instances of Editline provide an abstraction over libedit's EditLine facility. Both
|
||||
/// single- and multi-line editing are supported.
|
||||
class Editline
|
||||
{
|
||||
None = 0,
|
||||
EditPrevLine,
|
||||
EditNextLine,
|
||||
public:
|
||||
Editline (const char * editor_name, FILE * input_file, FILE * output_file, FILE * error_file, bool color_prompts);
|
||||
|
||||
~Editline();
|
||||
|
||||
/// Uses the user data storage of EditLine to retrieve an associated instance of Editline.
|
||||
static Editline *
|
||||
InstanceFor (::EditLine * editline);
|
||||
|
||||
/// Sets a string to be used as a prompt, or combined with a line number to form a prompt.
|
||||
void
|
||||
SetPrompt (const char * prompt);
|
||||
|
||||
/// Sets an alternate string to be used as a prompt for the second line and beyond in multi-line
|
||||
/// editing scenarios.
|
||||
void
|
||||
SetContinuationPrompt (const char * continuation_prompt);
|
||||
|
||||
/// Required to update the width of the terminal registered for I/O. It is critical that this
|
||||
/// be correct at all times.
|
||||
void
|
||||
TerminalSizeChanged();
|
||||
|
||||
/// Returns the prompt established by SetPrompt()
|
||||
const char *
|
||||
GetPrompt();
|
||||
|
||||
/// Returns the index of the line currently being edited
|
||||
uint32_t
|
||||
GetCurrentLine();
|
||||
|
||||
/// Hides the current input session in preparation for output
|
||||
void
|
||||
Hide();
|
||||
|
||||
/// Prepare to return to editing after a call to Hide()
|
||||
void
|
||||
Refresh();
|
||||
|
||||
/// Interrupt the current edit as if ^C was pressed
|
||||
bool
|
||||
Interrupt();
|
||||
|
||||
/// Register a callback for the tab key
|
||||
void
|
||||
SetAutoCompleteCallback (CompleteCallbackType callback, void * baton);
|
||||
|
||||
/// Register a callback for testing whether multi-line input is complete
|
||||
void
|
||||
SetIsInputCompleteCallback (IsInputCompleteCallbackType callback, void * baton);
|
||||
|
||||
/// Register a callback for determining the appropriate indentation for a line
|
||||
/// when creating a newline. An optional set of insertable characters can also
|
||||
/// trigger the callback.
|
||||
bool
|
||||
SetFixIndentationCallback (FixIndentationCallbackType callback,
|
||||
void * baton,
|
||||
const char * indent_chars);
|
||||
|
||||
/// Prompts for and reads a single line of user input.
|
||||
bool
|
||||
GetLine (std::string &line, bool &interrupted);
|
||||
|
||||
/// Prompts for and reads a multi-line batch of user input.
|
||||
bool
|
||||
GetLines (int first_line_number, StringList &lines, bool &interrupted);
|
||||
|
||||
private:
|
||||
|
||||
/// Sets the lowest line number for multi-line editing sessions. A value of zero suppresses
|
||||
/// line number printing in the prompt.
|
||||
void
|
||||
SetBaseLineNumber (int line_number);
|
||||
|
||||
/// Returns the complete prompt by combining the prompt or continuation prompt with line numbers
|
||||
/// as appropriate. The line index is a zero-based index into the current multi-line session.
|
||||
std::string
|
||||
PromptForIndex (int line_index);
|
||||
|
||||
/// Sets the current line index between line edits to allow free movement between lines. Updates
|
||||
/// the prompt to match.
|
||||
void
|
||||
SetCurrentLine (int line_index);
|
||||
|
||||
/// Determines the width of the prompt in characters. The width is guaranteed to be the same for
|
||||
/// all lines of the current multi-line session.
|
||||
int
|
||||
GetPromptWidth();
|
||||
|
||||
/// Returns true if the underlying EditLine session's keybindings are Emacs-based, or false if
|
||||
/// they are VI-based.
|
||||
bool
|
||||
IsEmacs();
|
||||
|
||||
/// Returns true if the current EditLine buffer contains nothing but spaces, or is empty.
|
||||
bool
|
||||
IsOnlySpaces();
|
||||
|
||||
/// Helper method used by MoveCursor to determine relative line position.
|
||||
int
|
||||
GetLineIndexForLocation (CursorLocation location, int cursor_row);
|
||||
|
||||
/// Move the cursor from one well-established location to another using relative line positioning
|
||||
/// and absolute column positioning.
|
||||
void
|
||||
MoveCursor (CursorLocation from, CursorLocation to);
|
||||
|
||||
/// Clear from cursor position to bottom of screen and print input lines including prompts, optionally
|
||||
/// starting from a specific line. Lines are drawn with an extra space at the end to reserve room for
|
||||
/// the rightmost cursor position.
|
||||
void
|
||||
DisplayInput (int firstIndex = 0);
|
||||
|
||||
/// Counts the number of rows a given line of content will end up occupying, taking into account both
|
||||
/// the preceding prompt and a single trailing space occupied by a cursor when at the end of the line.
|
||||
int
|
||||
CountRowsForLine (const EditLineStringType & content);
|
||||
|
||||
/// Save the line currently being edited
|
||||
void
|
||||
SaveEditedLine();
|
||||
|
||||
/// Convert the current input lines into a UTF8 StringList
|
||||
StringList
|
||||
GetInputAsStringList(int line_count = UINT32_MAX);
|
||||
|
||||
/// Replaces the current multi-line session with the next entry from history. When the parameter is
|
||||
/// true it will take the next earlier entry from history, when it is false it takes the next most
|
||||
/// recent.
|
||||
unsigned char
|
||||
RecallHistory (bool earlier);
|
||||
|
||||
/// Character reading implementation for EditLine that supports our multi-line editing trickery.
|
||||
int
|
||||
GetCharacter (EditLineCharType * c);
|
||||
|
||||
/// Prompt implementation for EditLine.
|
||||
const char *
|
||||
Prompt();
|
||||
|
||||
/// Line break command used when return is pressed in multi-line mode.
|
||||
unsigned char
|
||||
BreakLineCommand (int ch);
|
||||
|
||||
/// Delete command used when delete is pressed in multi-line mode.
|
||||
unsigned char
|
||||
DeleteNextCharCommand (int ch);
|
||||
|
||||
/// Delete command used when backspace is pressed in multi-line mode.
|
||||
unsigned char
|
||||
DeletePreviousCharCommand (int ch);
|
||||
|
||||
/// Line navigation command used when ^P or up arrow are pressed in multi-line mode.
|
||||
unsigned char
|
||||
PreviousLineCommand (int ch);
|
||||
|
||||
/// Line navigation command used when ^N or down arrow are pressed in multi-line mode.
|
||||
unsigned char
|
||||
NextLineCommand (int ch);
|
||||
|
||||
/// Buffer start command used when Esc < is typed in multi-line emacs mode.
|
||||
unsigned char
|
||||
BufferStartCommand (int ch);
|
||||
|
||||
/// Buffer end command used when Esc > is typed in multi-line emacs mode.
|
||||
unsigned char
|
||||
BufferEndCommand (int ch);
|
||||
|
||||
/// Context-sensitive tab insertion or code completion command used when the tab key is typed.
|
||||
unsigned char
|
||||
TabCommand (int ch);
|
||||
|
||||
/// Respond to normal character insertion by fixing line indentation
|
||||
unsigned char
|
||||
FixIndentationCommand (int ch);
|
||||
|
||||
/// Revert line command used when moving between lines.
|
||||
unsigned char
|
||||
RevertLineCommand (int ch);
|
||||
|
||||
/// Ensures that the current EditLine instance is properly configured for single or multi-line editing.
|
||||
void
|
||||
ConfigureEditor (bool multiline);
|
||||
|
||||
private:
|
||||
#if LLDB_EDITLINE_USE_WCHAR
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> m_utf8conv;
|
||||
#endif
|
||||
::EditLine * m_editline = nullptr;
|
||||
EditlineHistorySP m_history_sp;
|
||||
bool m_in_history = false;
|
||||
std::vector<EditLineStringType> m_live_history_lines;
|
||||
bool m_multiline_enabled = false;
|
||||
std::vector<EditLineStringType> m_input_lines;
|
||||
EditorStatus m_editor_status;
|
||||
bool m_editor_getting_char = false;
|
||||
bool m_color_prompts = true;
|
||||
int m_terminal_width = 0;
|
||||
int m_base_line_number = 0;
|
||||
unsigned m_current_line_index = 0;
|
||||
int m_current_line_rows = -1;
|
||||
int m_revert_cursor_index = 0;
|
||||
int m_line_number_digits = 3;
|
||||
std::string m_set_prompt;
|
||||
std::string m_set_continuation_prompt;
|
||||
std::string m_current_prompt;
|
||||
bool m_needs_prompt_repaint = false;
|
||||
std::string m_editor_name;
|
||||
FILE * m_input_file;
|
||||
FILE * m_output_file;
|
||||
FILE * m_error_file;
|
||||
ConnectionFileDescriptor m_input_connection;
|
||||
IsInputCompleteCallbackType m_is_input_complete_callback = nullptr;
|
||||
void * m_is_input_complete_callback_baton = nullptr;
|
||||
FixIndentationCallbackType m_fix_indentation_callback = nullptr;
|
||||
void * m_fix_indentation_callback_baton = nullptr;
|
||||
const char * m_fix_indentation_callback_chars = nullptr;
|
||||
CompleteCallbackType m_completion_callback = nullptr;
|
||||
void * m_completion_callback_baton = nullptr;
|
||||
};
|
||||
::EditLine *m_editline;
|
||||
EditlineHistorySP m_history_sp;
|
||||
std::string m_prompt;
|
||||
std::string m_lines_prompt;
|
||||
lldb_private::Predicate<bool> m_getting_char;
|
||||
CompleteCallbackType m_completion_callback;
|
||||
void *m_completion_callback_baton;
|
||||
LineCompletedCallbackType m_line_complete_callback;
|
||||
void *m_line_complete_callback_baton;
|
||||
Command m_lines_command;
|
||||
uint32_t m_line_offset;
|
||||
uint32_t m_lines_curr_line;
|
||||
uint32_t m_lines_max_line;
|
||||
ConnectionFileDescriptor m_file;
|
||||
bool m_prompt_with_line_numbers;
|
||||
bool m_getting_line;
|
||||
bool m_got_eof; // Set to true when we detect EOF
|
||||
bool m_interrupted;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Editline);
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
}
|
||||
|
||||
#endif // #if defined(__cplusplus)
|
||||
#endif // liblldb_Host_h_
|
||||
#endif // liblldb_Editline_h_
|
||||
|
|
|
@ -627,6 +627,9 @@ public:
|
|||
return m_quit_requested;
|
||||
}
|
||||
|
||||
lldb::IOHandlerSP
|
||||
GetIOHandler(bool force_create = false, CommandInterpreterRunOptions *options = NULL);
|
||||
|
||||
bool
|
||||
GetStoppedForCrash () const
|
||||
{
|
||||
|
|
|
@ -1030,11 +1030,15 @@ protected:
|
|||
if (argc == 1)
|
||||
{
|
||||
Debugger &debugger = m_interpreter.GetDebugger();
|
||||
bool color_prompt = debugger.GetUseColor();
|
||||
const bool multiple_lines = true; // Get multiple lines
|
||||
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
|
||||
IOHandler::Type::Other,
|
||||
"lldb-regex", // Name of input reader for history
|
||||
"\033[K> ", // Prompt and clear line
|
||||
NULL, // Continuation prompt
|
||||
multiple_lines,
|
||||
color_prompt,
|
||||
0, // Don't show line numbers
|
||||
*this));
|
||||
|
||||
|
|
|
@ -425,11 +425,15 @@ CommandObjectExpression::GetMultilineExpression ()
|
|||
m_expr_line_count = 0;
|
||||
|
||||
Debugger &debugger = GetCommandInterpreter().GetDebugger();
|
||||
bool color_prompt = debugger.GetUseColor();
|
||||
const bool multiple_lines = true; // Get multiple lines
|
||||
IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger,
|
||||
IOHandler::Type::Expression,
|
||||
"lldb-expr", // Name of input reader for history
|
||||
NULL, // No prompt
|
||||
NULL, // Continuation prompt
|
||||
multiple_lines,
|
||||
color_prompt,
|
||||
1, // Show line numbers starting at 1
|
||||
*this));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 ()
|
||||
|
@ -384,6 +425,20 @@ 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)
|
||||
|
@ -391,7 +446,7 @@ 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
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
if (m_editline_ap)
|
||||
m_editline_ap->ShowLineNumbers (true, line);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
uint32_t
|
||||
IOHandlerEditline::GetCurrentLineIndex () const
|
||||
{
|
||||
#ifdef LLDB_DISABLE_LIBEDIT
|
||||
if (m_editline_ap)
|
||||
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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -5375,7 +5468,7 @@ protected:
|
|||
DisplayOptions ValueObjectListDelegate::g_options = { true };
|
||||
|
||||
IOHandlerCursesGUI::IOHandlerCursesGUI (Debugger &debugger) :
|
||||
IOHandler (debugger)
|
||||
IOHandler (debugger, IOHandler::Type::Curses)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -3281,10 +3308,10 @@ CommandInterpreter::RunCommandInterpreter(bool auto_handle_events,
|
|||
else
|
||||
{
|
||||
m_debugger.ExecuteIOHanders();
|
||||
|
||||
|
||||
if (auto_handle_events)
|
||||
m_debugger.StopEventHandlerThread();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -728,7 +728,7 @@ public:
|
|||
|
||||
IOHandlerPythonInterpreter (Debugger &debugger,
|
||||
ScriptInterpreterPython *python) :
|
||||
IOHandler (debugger),
|
||||
IOHandler (debugger, IOHandler::Type::PythonInterpreter),
|
||||
m_python(python)
|
||||
{
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Reference in New Issue