summaryrefslogtreecommitdiffstats
path: root/lldb/source/Host/common/Editline.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Host/common/Editline.cpp')
-rw-r--r--lldb/source/Host/common/Editline.cpp2392
1 files changed, 1128 insertions, 1264 deletions
diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp
index d23a481d168..6e12bfb8972 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -11,11 +11,11 @@
#include <iostream>
#include <limits.h>
-#include "lldb/Host/Editline.h"
-#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Core/Error.h"
-#include "lldb/Core/StringList.h"
#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Editline.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
@@ -34,14 +34,17 @@ using namespace lldb_private::line_editor;
// the function declaraction has been hoisted here.
#if defined(__APPLE__)
extern "C" {
- int setupterm(char *term, int fildes, int *errret);
+int setupterm(char *term, int fildes, int *errret);
}
#define USE_SETUPTERM_WORKAROUND
#endif
-// Editline uses careful cursor management to achieve the illusion of editing a multi-line block of text
-// with a single line editor. Preserving this illusion requires fairly careful management of cursor
-// state. Read and understand the relationship between DisplayInput(), MoveCursor(), SetCurrentLine(),
+// Editline uses careful cursor management to achieve the illusion of editing a
+// multi-line block of text
+// with a single line editor. Preserving this illusion requires fairly careful
+// management of cursor
+// state. Read and understand the relationship between DisplayInput(),
+// MoveCursor(), SetCurrentLine(),
// and SaveEditedLine() before making changes.
#define ESCAPE "\x1b"
@@ -63,7 +66,8 @@ extern "C" {
#define EditLineConstString(str) str
#define EditLineStringFormatSpec "%s"
-// use #defines so wide version functions and structs will resolve to old versions
+// use #defines so wide version functions and structs will resolve to old
+// versions
// for case of libedit not built with wide char support
#define history_w history
#define history_winit history_init
@@ -76,1430 +80,1290 @@ extern "C" {
#define el_wgetc el_getc
#define el_wpush el_push
#define el_wparse el_parse
-#define el_wset el_set
-#define el_wget el_get
+#define el_wset el_set
+#define el_wget el_get
#define el_wline el_line
#define el_winsertstr el_insertstr
-#define el_wdeletestr el_deletestr
+#define el_wdeletestr el_deletestr
#endif // #if LLDB_EDITLINE_USE_WCHAR
-bool
-IsOnlySpaces (const EditLineStringType & content)
-{
- for (wchar_t ch : content)
- {
- if (ch != EditLineCharType(' '))
- return false;
- }
- return true;
+bool IsOnlySpaces(const EditLineStringType &content) {
+ for (wchar_t ch : content) {
+ if (ch != EditLineCharType(' '))
+ return false;
+ }
+ return true;
}
-EditLineStringType
-CombineLines (const std::vector<EditLineStringType> & lines)
-{
- EditLineStringStreamType combined_stream;
- for (EditLineStringType line : lines)
- {
- combined_stream << line.c_str() << "\n";
- }
- return combined_stream.str();
+EditLineStringType CombineLines(const std::vector<EditLineStringType> &lines) {
+ EditLineStringStreamType combined_stream;
+ for (EditLineStringType line : lines) {
+ combined_stream << line.c_str() << "\n";
+ }
+ return combined_stream.str();
}
-std::vector<EditLineStringType>
-SplitLines (const EditLineStringType & input)
-{
- std::vector<EditLineStringType> result;
- size_t start = 0;
- while (start < input.length())
- {
- size_t end = input.find ('\n', start);
- if (end == std::string::npos)
- {
- result.insert (result.end(), input.substr (start));
- break;
- }
- result.insert (result.end(), input.substr (start, end - start));
- start = end + 1;
+std::vector<EditLineStringType> SplitLines(const EditLineStringType &input) {
+ std::vector<EditLineStringType> result;
+ size_t start = 0;
+ while (start < input.length()) {
+ size_t end = input.find('\n', start);
+ if (end == std::string::npos) {
+ result.insert(result.end(), input.substr(start));
+ break;
}
- return result;
+ result.insert(result.end(), input.substr(start, end - start));
+ start = end + 1;
+ }
+ return result;
}
-EditLineStringType
-FixIndentation (const EditLineStringType & line, int indent_correction)
-{
- if (indent_correction == 0)
- return line;
- if (indent_correction < 0)
- return line.substr (-indent_correction);
- return EditLineStringType (indent_correction, EditLineCharType(' ')) + line;
+EditLineStringType FixIndentation(const EditLineStringType &line,
+ int indent_correction) {
+ if (indent_correction == 0)
+ return line;
+ if (indent_correction < 0)
+ return line.substr(-indent_correction);
+ return EditLineStringType(indent_correction, EditLineCharType(' ')) + line;
}
-int
-GetIndentation (const EditLineStringType & line)
-{
- int space_count = 0;
- for (EditLineCharType ch : line)
- {
- if (ch != EditLineCharType(' '))
- break;
- ++space_count;
- }
- return space_count;
+int GetIndentation(const EditLineStringType &line) {
+ int space_count = 0;
+ for (EditLineCharType ch : line) {
+ if (ch != EditLineCharType(' '))
+ break;
+ ++space_count;
+ }
+ return space_count;
}
-bool
-IsInputPending (FILE * file)
-{
- // FIXME: This will be broken on Windows if we ever re-enable Editline. You can't use select
- // on something that isn't a socket. This will have to be re-written to not use a FILE*, but
- // instead use some kind of yet-to-be-created abstraction that select-like functionality on
- // non-socket objects.
- const int fd = fileno (file);
- SelectHelper select_helper;
- select_helper.SetTimeout(std::chrono::microseconds(0));
- select_helper.FDSetRead(fd);
- return select_helper.Select().Success();
+bool IsInputPending(FILE *file) {
+ // FIXME: This will be broken on Windows if we ever re-enable Editline. You
+ // can't use select
+ // on something that isn't a socket. This will have to be re-written to not
+ // use a FILE*, but
+ // instead use some kind of yet-to-be-created abstraction that select-like
+ // functionality on
+ // non-socket objects.
+ const int fd = fileno(file);
+ SelectHelper select_helper;
+ select_helper.SetTimeout(std::chrono::microseconds(0));
+ select_helper.FDSetRead(fd);
+ return select_helper.Select().Success();
}
-namespace lldb_private
-{
- namespace line_editor
- {
- typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP;
-
- // EditlineHistory objects are sometimes shared between multiple
- // Editline instances with the same program name.
-
- class EditlineHistory
- {
- private:
- // Use static GetHistory() function to get a EditlineHistorySP to one of these objects
- EditlineHistory (const std::string &prefix, uint32_t size, bool unique_entries) :
- m_history (NULL),
- m_event (),
- m_prefix (prefix),
- m_path ()
- {
- m_history = history_winit();
- history_w (m_history, &m_event, H_SETSIZE, size);
- if (unique_entries)
- history_w (m_history, &m_event, H_SETUNIQUE, 1);
- }
-
- const char *
- GetHistoryFilePath()
- {
- if (m_path.empty() && m_history && !m_prefix.empty())
- {
- FileSpec parent_path{"~/.lldb", true};
- char history_path[PATH_MAX];
- if (FileSystem::MakeDirectory(parent_path, lldb::eFilePermissionsDirectoryDefault).Success())
- {
- snprintf (history_path, sizeof (history_path), "~/.lldb/%s-history", m_prefix.c_str());
- }
- else
- {
- snprintf (history_path, sizeof (history_path), "~/%s-widehistory", m_prefix.c_str());
- }
- m_path = FileSpec (history_path, true).GetPath();
- }
- if (m_path.empty())
- return NULL;
- return m_path.c_str();
- }
-
- public:
-
- ~EditlineHistory()
- {
- Save();
-
- if (m_history)
- {
- history_wend (m_history);
- m_history = NULL;
- }
- }
-
- static EditlineHistorySP
- GetHistory (const std::string &prefix)
- {
- typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap;
- static std::recursive_mutex g_mutex;
- static WeakHistoryMap g_weak_map;
- std::lock_guard<std::recursive_mutex> guard(g_mutex);
- WeakHistoryMap::const_iterator pos = g_weak_map.find (prefix);
- EditlineHistorySP history_sp;
- if (pos != g_weak_map.end())
- {
- history_sp = pos->second.lock();
- if (history_sp)
- return history_sp;
- g_weak_map.erase (pos);
- }
- history_sp.reset (new EditlineHistory (prefix, 800, true));
- g_weak_map[prefix] = history_sp;
- return history_sp;
- }
-
- bool IsValid() const
- {
- return m_history != NULL;
- }
-
- HistoryW *
- GetHistoryPtr ()
- {
- return m_history;
- }
-
- void
- Enter (const EditLineCharType *line_cstr)
- {
- if (m_history)
- history_w (m_history, &m_event, H_ENTER, line_cstr);
- }
-
- bool
- Load ()
- {
- if (m_history)
- {
- const char *path = GetHistoryFilePath();
- if (path)
- {
- history_w (m_history, &m_event, H_LOAD, path);
- return true;
- }
- }
- return false;
- }
-
- bool
- Save ()
- {
- if (m_history)
- {
- const char *path = GetHistoryFilePath();
- if (path)
- {
- history_w (m_history, &m_event, H_SAVE, path);
- return true;
- }
- }
- return false;
- }
-
- protected:
- HistoryW * m_history; // The history object
- HistEventW m_event; // The history event needed to contain all history events
- std::string m_prefix; // The prefix name (usually the editline program name) to use when loading/saving history
- std::string m_path; // Path to the history file
- };
+namespace lldb_private {
+namespace line_editor {
+typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP;
+
+// EditlineHistory objects are sometimes shared between multiple
+// Editline instances with the same program name.
+
+class EditlineHistory {
+private:
+ // Use static GetHistory() function to get a EditlineHistorySP to one of these
+ // objects
+ EditlineHistory(const std::string &prefix, uint32_t size, bool unique_entries)
+ : m_history(NULL), m_event(), m_prefix(prefix), m_path() {
+ m_history = history_winit();
+ history_w(m_history, &m_event, H_SETSIZE, size);
+ if (unique_entries)
+ history_w(m_history, &m_event, H_SETUNIQUE, 1);
+ }
+
+ const char *GetHistoryFilePath() {
+ if (m_path.empty() && m_history && !m_prefix.empty()) {
+ FileSpec parent_path{"~/.lldb", true};
+ char history_path[PATH_MAX];
+ if (FileSystem::MakeDirectory(parent_path,
+ lldb::eFilePermissionsDirectoryDefault)
+ .Success()) {
+ snprintf(history_path, sizeof(history_path), "~/.lldb/%s-history",
+ m_prefix.c_str());
+ } else {
+ snprintf(history_path, sizeof(history_path), "~/%s-widehistory",
+ m_prefix.c_str());
+ }
+ m_path = FileSpec(history_path, true).GetPath();
+ }
+ if (m_path.empty())
+ return NULL;
+ return m_path.c_str();
+ }
+
+public:
+ ~EditlineHistory() {
+ Save();
+
+ if (m_history) {
+ history_wend(m_history);
+ m_history = NULL;
+ }
+ }
+
+ static EditlineHistorySP GetHistory(const std::string &prefix) {
+ typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap;
+ static std::recursive_mutex g_mutex;
+ static WeakHistoryMap g_weak_map;
+ std::lock_guard<std::recursive_mutex> guard(g_mutex);
+ WeakHistoryMap::const_iterator pos = g_weak_map.find(prefix);
+ EditlineHistorySP history_sp;
+ if (pos != g_weak_map.end()) {
+ history_sp = pos->second.lock();
+ if (history_sp)
+ return history_sp;
+ g_weak_map.erase(pos);
+ }
+ history_sp.reset(new EditlineHistory(prefix, 800, true));
+ g_weak_map[prefix] = history_sp;
+ return history_sp;
+ }
+
+ bool IsValid() const { return m_history != NULL; }
+
+ HistoryW *GetHistoryPtr() { return m_history; }
+
+ void Enter(const EditLineCharType *line_cstr) {
+ if (m_history)
+ history_w(m_history, &m_event, H_ENTER, line_cstr);
+ }
+
+ bool Load() {
+ if (m_history) {
+ const char *path = GetHistoryFilePath();
+ if (path) {
+ history_w(m_history, &m_event, H_LOAD, path);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool Save() {
+ if (m_history) {
+ const char *path = GetHistoryFilePath();
+ if (path) {
+ history_w(m_history, &m_event, H_SAVE, path);
+ return true;
+ }
}
+ return false;
+ }
+
+protected:
+ HistoryW *m_history; // The history object
+ HistEventW m_event; // The history event needed to contain all history events
+ std::string m_prefix; // The prefix name (usually the editline program name)
+ // to use when loading/saving history
+ std::string m_path; // Path to the history file
+};
+}
}
//------------------------------------------------------------------
// Editline private methods
//------------------------------------------------------------------
-void
-Editline::SetBaseLineNumber (int line_number)
-{
- std::stringstream line_number_stream;
- line_number_stream << line_number;
- m_base_line_number = line_number;
- m_line_number_digits = std::max (3, (int)line_number_stream.str().length() + 1);
+void Editline::SetBaseLineNumber(int line_number) {
+ std::stringstream line_number_stream;
+ line_number_stream << line_number;
+ m_base_line_number = line_number;
+ m_line_number_digits =
+ std::max(3, (int)line_number_stream.str().length() + 1);
}
-std::string
-Editline::PromptForIndex (int line_index)
-{
- bool use_line_numbers = m_multiline_enabled && m_base_line_number > 0;
- std::string prompt = m_set_prompt;
- if (use_line_numbers && prompt.length() == 0)
- {
- prompt = ": ";
- }
- std::string continuation_prompt = prompt;
- if (m_set_continuation_prompt.length() > 0)
- {
- continuation_prompt = m_set_continuation_prompt;
-
- // Ensure that both prompts are the same length through space padding
- while (continuation_prompt.length() < prompt.length())
- {
- continuation_prompt += ' ';
- }
- while (prompt.length() < continuation_prompt.length())
- {
- prompt += ' ';
- }
+std::string Editline::PromptForIndex(int line_index) {
+ bool use_line_numbers = m_multiline_enabled && m_base_line_number > 0;
+ std::string prompt = m_set_prompt;
+ if (use_line_numbers && prompt.length() == 0) {
+ prompt = ": ";
+ }
+ std::string continuation_prompt = prompt;
+ if (m_set_continuation_prompt.length() > 0) {
+ continuation_prompt = m_set_continuation_prompt;
+
+ // Ensure that both prompts are the same length through space padding
+ while (continuation_prompt.length() < prompt.length()) {
+ continuation_prompt += ' ';
}
-
- if (use_line_numbers)
- {
- StreamString prompt_stream;
- prompt_stream.Printf("%*d%s", m_line_number_digits, m_base_line_number + line_index,
- (line_index == 0) ? prompt.c_str() : continuation_prompt.c_str());
- return std::move (prompt_stream.GetString());
+ while (prompt.length() < continuation_prompt.length()) {
+ prompt += ' ';
}
- return (line_index == 0) ? prompt : continuation_prompt;
+ }
+
+ if (use_line_numbers) {
+ StreamString prompt_stream;
+ prompt_stream.Printf(
+ "%*d%s", m_line_number_digits, m_base_line_number + line_index,
+ (line_index == 0) ? prompt.c_str() : continuation_prompt.c_str());
+ return std::move(prompt_stream.GetString());
+ }
+ return (line_index == 0) ? prompt : continuation_prompt;
}
-void
-Editline::SetCurrentLine (int line_index)
-{
- m_current_line_index = line_index;
- m_current_prompt = PromptForIndex (line_index);
+void Editline::SetCurrentLine(int line_index) {
+ m_current_line_index = line_index;
+ m_current_prompt = PromptForIndex(line_index);
}
-int
-Editline::GetPromptWidth()
-{
- return (int)PromptForIndex (0).length();
-}
+int Editline::GetPromptWidth() { return (int)PromptForIndex(0).length(); }
-bool
-Editline::IsEmacs()
-{
- const char * editor;
- el_get (m_editline, EL_EDITOR, &editor);
- return editor[0] == 'e';
+bool Editline::IsEmacs() {
+ const char *editor;
+ el_get(m_editline, EL_EDITOR, &editor);
+ return editor[0] == 'e';
}
-bool
-Editline::IsOnlySpaces()
-{
- const LineInfoW * info = el_wline (m_editline);
- for (const EditLineCharType * character = info->buffer; character < info->lastchar; character++)
- {
- if (*character != ' ')
- return false;
- }
- return true;
+bool Editline::IsOnlySpaces() {
+ const LineInfoW *info = el_wline(m_editline);
+ for (const EditLineCharType *character = info->buffer;
+ character < info->lastchar; character++) {
+ if (*character != ' ')
+ return false;
+ }
+ return true;
}
-int
-Editline::GetLineIndexForLocation (CursorLocation location, int cursor_row)
-{
- int line = 0;
- if (location == CursorLocation::EditingPrompt || location == CursorLocation::BlockEnd ||
- location == CursorLocation::EditingCursor)
- {
- for (unsigned index = 0; index < m_current_line_index; index++)
- {
- line += CountRowsForLine (m_input_lines[index]);
- }
- if (location == CursorLocation::EditingCursor)
- {
- line += cursor_row;
- }
- else if (location == CursorLocation::BlockEnd)
- {
- for (unsigned index = m_current_line_index; index < m_input_lines.size(); index++)
- {
- line += CountRowsForLine (m_input_lines[index]);
- }
- --line;
- }
+int Editline::GetLineIndexForLocation(CursorLocation location, int cursor_row) {
+ int line = 0;
+ if (location == CursorLocation::EditingPrompt ||
+ location == CursorLocation::BlockEnd ||
+ location == CursorLocation::EditingCursor) {
+ for (unsigned index = 0; index < m_current_line_index; index++) {
+ line += CountRowsForLine(m_input_lines[index]);
}
- return line;
-}
-
-void
-Editline::MoveCursor (CursorLocation from, CursorLocation to)
-{
- const LineInfoW * info = el_wline (m_editline);
- int editline_cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth());
- int editline_cursor_row = editline_cursor_position / m_terminal_width;
-
- // Determine relative starting and ending lines
- int fromLine = GetLineIndexForLocation (from, editline_cursor_row);
- int toLine = GetLineIndexForLocation (to, editline_cursor_row);
- if (toLine != fromLine)
- {
- fprintf (m_output_file, (toLine > fromLine) ? ANSI_DOWN_N_ROWS : ANSI_UP_N_ROWS, std::abs (toLine - fromLine));
+ if (location == CursorLocation::EditingCursor) {
+ line += cursor_row;
+ } else if (location == CursorLocation::BlockEnd) {
+ for (unsigned index = m_current_line_index; index < m_input_lines.size();
+ index++) {
+ line += CountRowsForLine(m_input_lines[index]);
+ }
+ --line;
}
-
- // Determine target column
- int toColumn = 1;
- if (to == CursorLocation::EditingCursor)
- {
- toColumn = editline_cursor_position - (editline_cursor_row * m_terminal_width) + 1;
- }
- else if (to == CursorLocation::BlockEnd)
- {
- toColumn = ((m_input_lines[m_input_lines.size() - 1].length() + GetPromptWidth()) % 80) + 1;
- }
- fprintf (m_output_file, ANSI_SET_COLUMN_N, toColumn);
+ }
+ return line;
}
-void
-Editline::DisplayInput (int firstIndex)
-{
- fprintf (m_output_file, ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW, 1);
- int line_count = (int)m_input_lines.size();
- const char *faint = m_color_prompts ? ANSI_FAINT : "";
- const char *unfaint = m_color_prompts ? ANSI_UNFAINT : "";
-
- for (int index = firstIndex; index < line_count; index++)
- {
- fprintf (m_output_file, "%s" "%s" "%s" EditLineStringFormatSpec " ",
- faint,
- PromptForIndex (index).c_str(),
- unfaint,
- m_input_lines[index].c_str());
- if (index < line_count - 1)
- fprintf (m_output_file, "\n");
- }
+void Editline::MoveCursor(CursorLocation from, CursorLocation to) {
+ const LineInfoW *info = el_wline(m_editline);
+ int editline_cursor_position =
+ (int)((info->cursor - info->buffer) + GetPromptWidth());
+ int editline_cursor_row = editline_cursor_position / m_terminal_width;
+
+ // Determine relative starting and ending lines
+ int fromLine = GetLineIndexForLocation(from, editline_cursor_row);
+ int toLine = GetLineIndexForLocation(to, editline_cursor_row);
+ if (toLine != fromLine) {
+ fprintf(m_output_file,
+ (toLine > fromLine) ? ANSI_DOWN_N_ROWS : ANSI_UP_N_ROWS,
+ std::abs(toLine - fromLine));
+ }
+
+ // Determine target column
+ int toColumn = 1;
+ if (to == CursorLocation::EditingCursor) {
+ toColumn =
+ editline_cursor_position - (editline_cursor_row * m_terminal_width) + 1;
+ } else if (to == CursorLocation::BlockEnd) {
+ toColumn =
+ ((m_input_lines[m_input_lines.size() - 1].length() + GetPromptWidth()) %
+ 80) +
+ 1;
+ }
+ fprintf(m_output_file, ANSI_SET_COLUMN_N, toColumn);
}
+void Editline::DisplayInput(int firstIndex) {
+ fprintf(m_output_file, ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW, 1);
+ int line_count = (int)m_input_lines.size();
+ const char *faint = m_color_prompts ? ANSI_FAINT : "";
+ const char *unfaint = m_color_prompts ? ANSI_UNFAINT : "";
+
+ for (int index = firstIndex; index < line_count; index++) {
+ fprintf(m_output_file, "%s"
+ "%s"
+ "%s" EditLineStringFormatSpec " ",
+ faint, PromptForIndex(index).c_str(), unfaint,
+ m_input_lines[index].c_str());
+ if (index < line_count - 1)
+ fprintf(m_output_file, "\n");
+ }
+}
-int
-Editline::CountRowsForLine (const EditLineStringType & content)
-{
- auto prompt = PromptForIndex (0); // Prompt width is constant during an edit session
- int line_length = (int)(content.length() + prompt.length());
- return (line_length / m_terminal_width) + 1;
+int Editline::CountRowsForLine(const EditLineStringType &content) {
+ auto prompt =
+ PromptForIndex(0); // Prompt width is constant during an edit session
+ int line_length = (int)(content.length() + prompt.length());
+ return (line_length / m_terminal_width) + 1;
}
-void
-Editline::SaveEditedLine()
-{
- const LineInfoW * info = el_wline (m_editline);
- m_input_lines[m_current_line_index] = EditLineStringType (info->buffer, info->lastchar - info->buffer);
+void Editline::SaveEditedLine() {
+ const LineInfoW *info = el_wline(m_editline);
+ m_input_lines[m_current_line_index] =
+ EditLineStringType(info->buffer, info->lastchar - info->buffer);
}
-StringList
-Editline::GetInputAsStringList(int line_count)
-{
- StringList lines;
- for (EditLineStringType line : m_input_lines)
- {
- if (line_count == 0)
- break;
+StringList Editline::GetInputAsStringList(int line_count) {
+ StringList lines;
+ for (EditLineStringType line : m_input_lines) {
+ if (line_count == 0)
+ break;
#if LLDB_EDITLINE_USE_WCHAR
- lines.AppendString (m_utf8conv.to_bytes (line));
+ lines.AppendString(m_utf8conv.to_bytes(line));
#else
- lines.AppendString(line);
+ lines.AppendString(line);
#endif
- --line_count;
- }
- return lines;
+ --line_count;
+ }
+ return lines;
}
-unsigned char
-Editline::RecallHistory (bool earlier)
-{
- if (!m_history_sp || !m_history_sp->IsValid())
+unsigned char Editline::RecallHistory(bool earlier) {
+ if (!m_history_sp || !m_history_sp->IsValid())
+ return CC_ERROR;
+
+ HistoryW *pHistory = m_history_sp->GetHistoryPtr();
+ HistEventW history_event;
+ std::vector<EditLineStringType> new_input_lines;
+
+ // Treat moving from the "live" entry differently
+ if (!m_in_history) {
+ if (earlier == false)
+ return CC_ERROR; // Can't go newer than the "live" entry
+ if (history_w(pHistory, &history_event, H_FIRST) == -1)
+ return CC_ERROR;
+
+ // Save any edits to the "live" entry in case we return by moving forward in
+ // history
+ // (it would be more bash-like to save over any current entry, but libedit
+ // doesn't
+ // offer the ability to add entries anywhere except the end.)
+ SaveEditedLine();
+ m_live_history_lines = m_input_lines;
+ m_in_history = true;
+ } else {
+ if (history_w(pHistory, &history_event, earlier ? H_NEXT : H_PREV) == -1) {
+ // Can't move earlier than the earliest entry
+ if (earlier)
return CC_ERROR;
-
- HistoryW * pHistory = m_history_sp->GetHistoryPtr();
- HistEventW history_event;
- std::vector<EditLineStringType> new_input_lines;
-
- // Treat moving from the "live" entry differently
- if (!m_in_history)
- {
- if (earlier == false)
- return CC_ERROR; // Can't go newer than the "live" entry
- if (history_w (pHistory, &history_event, H_FIRST) == -1)
- return CC_ERROR;
-
- // Save any edits to the "live" entry in case we return by moving forward in history
- // (it would be more bash-like to save over any current entry, but libedit doesn't
- // offer the ability to add entries anywhere except the end.)
- SaveEditedLine();
- m_live_history_lines = m_input_lines;
- m_in_history = true;
- }
- else
- {
- if (history_w (pHistory, &history_event, earlier ? H_NEXT : H_PREV) == -1)
- {
- // Can't move earlier than the earliest entry
- if (earlier)
- return CC_ERROR;
-
- // ... but moving to newer than the newest yields the "live" entry
- new_input_lines = m_live_history_lines;
- m_in_history = false;
- }
+
+ // ... but moving to newer than the newest yields the "live" entry
+ new_input_lines = m_live_history_lines;
+ m_in_history = false;
}
-
- // If we're pulling the lines from history, split them apart
- if (m_in_history)
- new_input_lines = SplitLines (history_event.str);
-
- // Erase the current edit session and replace it with a new one
- MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockStart);
- m_input_lines = new_input_lines;
- DisplayInput();
-
- // Prepare to edit the last line when moving to previous entry, or the first line
- // when moving to next entry
- SetCurrentLine (m_current_line_index = earlier ? (int)m_input_lines.size() - 1 : 0);
- MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
- return CC_NEWLINE;
+ }
+
+ // If we're pulling the lines from history, split them apart
+ if (m_in_history)
+ new_input_lines = SplitLines(history_event.str);
+
+ // Erase the current edit session and replace it with a new one
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ m_input_lines = new_input_lines;
+ DisplayInput();
+
+ // Prepare to edit the last line when moving to previous entry, or the first
+ // line
+ // when moving to next entry
+ SetCurrentLine(m_current_line_index =
+ earlier ? (int)m_input_lines.size() - 1 : 0);
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ return CC_NEWLINE;
}
-int
-Editline::GetCharacter (EditLineCharType * c)
-{
- const LineInfoW * info = el_wline (m_editline);
-
- // Paint a faint version of the desired prompt over the version libedit draws
- // (will only be requested if colors are supported)
- if (m_needs_prompt_repaint)
- {
- MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
- fprintf (m_output_file, "%s" "%s" "%s", ANSI_FAINT, Prompt(), ANSI_UNFAINT);
- MoveCursor (CursorLocation::EditingPrompt, CursorLocation::EditingCursor);
- m_needs_prompt_repaint = false;
+int Editline::GetCharacter(EditLineCharType *c) {
+ const LineInfoW *info = el_wline(m_editline);
+
+ // Paint a faint version of the desired prompt over the version libedit draws
+ // (will only be requested if colors are supported)
+ if (m_needs_prompt_repaint) {
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ fprintf(m_output_file, "%s"
+ "%s"
+ "%s",
+ ANSI_FAINT, Prompt(), ANSI_UNFAINT);
+ MoveCursor(CursorLocation::EditingPrompt, CursorLocation::EditingCursor);
+ m_needs_prompt_repaint = false;
+ }
+
+ if (m_multiline_enabled) {
+ // Detect when the number of rows used for this input line changes due to an
+ // edit
+ int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth());
+ int new_line_rows = (lineLength / m_terminal_width) + 1;
+ if (m_current_line_rows != -1 && new_line_rows != m_current_line_rows) {
+ // Respond by repainting the current state from this line on
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ SaveEditedLine();
+ DisplayInput(m_current_line_index);
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
}
-
- if (m_multiline_enabled)
- {
- // Detect when the number of rows used for this input line changes due to an edit
- int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth());
- int new_line_rows = (lineLength / m_terminal_width) + 1;
- if (m_current_line_rows != -1 && new_line_rows != m_current_line_rows)
- {
- // Respond by repainting the current state from this line on
- MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
- SaveEditedLine();
- DisplayInput (m_current_line_index);
- MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingCursor);
- }
- m_current_line_rows = new_line_rows;
+ m_current_line_rows = new_line_rows;
+ }
+
+ // Read an actual character
+ while (true) {
+ lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
+ char ch = 0;
+
+ // This mutex is locked by our caller (GetLine). Unlock it while we read a
+ // character
+ // (blocking operation), so we do not hold the mutex indefinitely. This
+ // gives a chance
+ // for someone to interrupt us. After Read returns, immediately lock the
+ // mutex again and
+ // check if we were interrupted.
+ m_output_mutex.unlock();
+ int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
+ m_output_mutex.lock();
+ if (m_editor_status == EditorStatus::Interrupted) {
+ while (read_count > 0 && status == lldb::eConnectionStatusSuccess)
+ read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
+ lldbassert(status == lldb::eConnectionStatusInterrupted);
+ return 0;
}
-
- // Read an actual character
- while (true)
- {
- lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
- char ch = 0;
-
- // This mutex is locked by our caller (GetLine). Unlock it while we read a character
- // (blocking operation), so we do not hold the mutex indefinitely. This gives a chance
- // for someone to interrupt us. After Read returns, immediately lock the mutex again and
- // check if we were interrupted.
- m_output_mutex.unlock();
- int read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
- m_output_mutex.lock();
- if (m_editor_status == EditorStatus::Interrupted)
- {
- while (read_count > 0 && status == lldb::eConnectionStatusSuccess)
- read_count = m_input_connection.Read(&ch, 1, UINT32_MAX, status, NULL);
- lldbassert(status == lldb::eConnectionStatusInterrupted);
- return 0;
- }
- if (read_count)
- {
+ if (read_count) {
#if LLDB_EDITLINE_USE_WCHAR
- // After the initial interruptible read, this is guaranteed not to block
- ungetc (ch, m_input_file);
- *c = fgetwc (m_input_file);
- if (*c != WEOF)
- return 1;
+ // After the initial interruptible read, this is guaranteed not to block
+ ungetc(ch, m_input_file);
+ *c = fgetwc(m_input_file);
+ if (*c != WEOF)
+ return 1;
#else
- *c = ch;
- if(ch != (char)EOF)
- return 1;
+ *c = ch;
+ if (ch != (char)EOF)
+ return 1;
#endif
- }
- else
- {
- switch (status)
- {
- case lldb::eConnectionStatusSuccess: // Success
- break;
-
- case lldb::eConnectionStatusInterrupted:
- lldbassert(0 && "Interrupts should have been handled above.");
-
- case lldb::eConnectionStatusError: // Check GetError() for details
- case lldb::eConnectionStatusTimedOut: // Request timed out
- case lldb::eConnectionStatusEndOfFile: // End-of-file encountered
- case lldb::eConnectionStatusNoConnection: // No connection
- case lldb::eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
- m_editor_status = EditorStatus::EndOfInput;
- return 0;
- }
- }
+ } else {
+ switch (status) {
+ case lldb::eConnectionStatusSuccess: // Success
+ break;
+
+ case lldb::eConnectionStatusInterrupted:
+ lldbassert(0 && "Interrupts should have been handled above.");
+
+ case lldb::eConnectionStatusError: // Check GetError() for details
+ case lldb::eConnectionStatusTimedOut: // Request timed out
+ case lldb::eConnectionStatusEndOfFile: // End-of-file encountered
+ case lldb::eConnectionStatusNoConnection: // No connection
+ case lldb::eConnectionStatusLostConnection: // Lost connection while
+ // connected to a valid
+ // connection
+ m_editor_status = EditorStatus::EndOfInput;
+ return 0;
+ }
}
+ }
}
-const char *
-Editline::Prompt()
-{
- if (m_color_prompts)
- m_needs_prompt_repaint = true;
- return m_current_prompt.c_str();
+const char *Editline::Prompt() {
+ if (m_color_prompts)
+ m_needs_prompt_repaint = true;
+ return m_current_prompt.c_str();
}
-unsigned char
-Editline::BreakLineCommand (int ch)
-{
- // Preserve any content beyond the cursor, truncate and save the current line
- const LineInfoW * info = el_wline (m_editline);
- auto current_line = EditLineStringType (info->buffer, info->cursor - info->buffer);
- auto new_line_fragment = EditLineStringType (info->cursor, info->lastchar - info->cursor);
- m_input_lines[m_current_line_index] = current_line;
-
- // Ignore whitespace-only extra fragments when breaking a line
- if (::IsOnlySpaces (new_line_fragment))
- new_line_fragment = EditLineConstString("");
-
- // Establish the new cursor position at the start of a line when inserting a line break
- m_revert_cursor_index = 0;
-
- // Don't perform automatic formatting when pasting
- if (!IsInputPending (m_input_file))
- {
- // Apply smart indentation
- if (m_fix_indentation_callback)
- {
- StringList lines = GetInputAsStringList (m_current_line_index + 1);
+unsigned char Editline::BreakLineCommand(int ch) {
+ // Preserve any content beyond the cursor, truncate and save the current line
+ const LineInfoW *info = el_wline(m_editline);
+ auto current_line =
+ EditLineStringType(info->buffer, info->cursor - info->buffer);
+ auto new_line_fragment =
+ EditLineStringType(info->cursor, info->lastchar - info->cursor);
+ m_input_lines[m_current_line_index] = current_line;
+
+ // Ignore whitespace-only extra fragments when breaking a line
+ if (::IsOnlySpaces(new_line_fragment))
+ new_line_fragment = EditLineConstString("");
+
+ // Establish the new cursor position at the start of a line when inserting a
+ // line break
+ m_revert_cursor_index = 0;
+
+ // Don't perform automatic formatting when pasting
+ if (!IsInputPending(m_input_file)) {
+ // Apply smart indentation
+ if (m_fix_indentation_callback) {
+ StringList lines = GetInputAsStringList(m_current_line_index + 1);
#if LLDB_EDITLINE_USE_WCHAR
- lines.AppendString (m_utf8conv.to_bytes (new_line_fragment));
+ lines.AppendString(m_utf8conv.to_bytes(new_line_fragment));
#else
- lines.AppendString (new_line_fragment);
+ lines.AppendString(new_line_fragment);
#endif
-
- int indent_correction = m_fix_indentation_callback (this, lines, 0, m_fix_indentation_callback_baton);
- new_line_fragment = FixIndentation(new_line_fragment, indent_correction);
- m_revert_cursor_index = GetIndentation(new_line_fragment);
- }
+
+ int indent_correction = m_fix_indentation_callback(
+ this, lines, 0, m_fix_indentation_callback_baton);
+ new_line_fragment = FixIndentation(new_line_fragment, indent_correction);
+ m_revert_cursor_index = GetIndentation(new_line_fragment);
}
-
- // Insert the new line and repaint everything from the split line on down
- m_input_lines.insert (m_input_lines.begin() + m_current_line_index + 1, new_line_fragment);
- MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
- DisplayInput (m_current_line_index);
-
- // Reposition the cursor to the right line and prepare to edit the new line
- SetCurrentLine (m_current_line_index + 1);
- MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
- return CC_NEWLINE;
+ }
+
+ // Insert the new line and repaint everything from the split line on down
+ m_input_lines.insert(m_input_lines.begin() + m_current_line_index + 1,
+ new_line_fragment);
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ DisplayInput(m_current_line_index);
+
+ // Reposition the cursor to the right line and prepare to edit the new line
+ SetCurrentLine(m_current_line_index + 1);
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ return CC_NEWLINE;
}
-unsigned char
-Editline::EndOrAddLineCommand(int ch)
-{
- // Don't perform end of input detection when pasting, always treat this as a line break
- if (IsInputPending(m_input_file))
- {
+unsigned char Editline::EndOrAddLineCommand(int ch) {
+ // Don't perform end of input detection when pasting, always treat this as a
+ // line break
+ if (IsInputPending(m_input_file)) {
+ return BreakLineCommand(ch);
+ }
+
+ // Save any edits to this line
+ SaveEditedLine();
+
+ // If this is the end of the last line, consider whether to add a line instead
+ const LineInfoW *info = el_wline(m_editline);
+ if (m_current_line_index == m_input_lines.size() - 1 &&
+ info->cursor == info->lastchar) {
+ if (m_is_input_complete_callback) {
+ auto lines = GetInputAsStringList();
+ if (!m_is_input_complete_callback(this, lines,
+ m_is_input_complete_callback_baton)) {
return BreakLineCommand(ch);
- }
-
- // Save any edits to this line
- SaveEditedLine();
+ }
- // If this is the end of the last line, consider whether to add a line instead
- const LineInfoW *info = el_wline(m_editline);
- if (m_current_line_index == m_input_lines.size() - 1 && info->cursor == info->lastchar)
- {
- if (m_is_input_complete_callback)
- {
- auto lines = GetInputAsStringList();
- if (!m_is_input_complete_callback(this, lines, m_is_input_complete_callback_baton))
- {
- return BreakLineCommand(ch);
- }
-
- // The completion test is allowed to change the input lines when complete
- m_input_lines.clear();
- for (unsigned index = 0; index < lines.GetSize(); index++)
- {
+ // The completion test is allowed to change the input lines when complete
+ m_input_lines.clear();
+ for (unsigned index = 0; index < lines.GetSize(); index++) {
#if LLDB_EDITLINE_USE_WCHAR
- m_input_lines.insert(m_input_lines.end(), m_utf8conv.from_bytes(lines[index]));
+ m_input_lines.insert(m_input_lines.end(),
+ m_utf8conv.from_bytes(lines[index]));
#else
- m_input_lines.insert(m_input_lines.end(), lines[index]);
+ m_input_lines.insert(m_input_lines.end(), lines[index]);
#endif
- }
- }
+ }
}
- MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd);
- fprintf(m_output_file, "\n");
- m_editor_status = EditorStatus::Complete;
- return CC_NEWLINE;
+ }
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd);
+ fprintf(m_output_file, "\n");
+ m_editor_status = EditorStatus::Complete;
+ return CC_NEWLINE;
}
-unsigned char
-Editline::DeleteNextCharCommand(int ch)
-{
- LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
-
- // Just delete the next character normally if possible
- if (info->cursor < info->lastchar)
- {
- info->cursor++;
- el_deletestr (m_editline, 1);
- return CC_REFRESH;
- }
+unsigned char Editline::DeleteNextCharCommand(int ch) {
+ LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline));
- // Fail when at the end of the last line, except when ^D is pressed on
- // the line is empty, in which case it is treated as EOF
- if (m_current_line_index == m_input_lines.size() - 1)
- {
- if (ch == 4 && info->buffer == info->lastchar)
- {
- fprintf (m_output_file, "^D\n");
- m_editor_status = EditorStatus::EndOfInput;
- return CC_EOF;
- }
- return CC_ERROR;
- }
-
- // Prepare to combine this line with the one below
- MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
-
- // Insert the next line of text at the cursor and restore the cursor position
- const EditLineCharType * cursor = info->cursor;
- el_winsertstr (m_editline, m_input_lines[m_current_line_index + 1].c_str());
- info->cursor = cursor;
- SaveEditedLine();
-
- // Delete the extra line
- m_input_lines.erase (m_input_lines.begin() + m_current_line_index + 1);
-
- // Clear and repaint from this line on down
- DisplayInput (m_current_line_index);
- MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ // Just delete the next character normally if possible
+ if (info->cursor < info->lastchar) {
+ info->cursor++;
+ el_deletestr(m_editline, 1);
return CC_REFRESH;
+ }
+
+ // Fail when at the end of the last line, except when ^D is pressed on
+ // the line is empty, in which case it is treated as EOF
+ if (m_current_line_index == m_input_lines.size() - 1) {
+ if (ch == 4 && info->buffer == info->lastchar) {
+ fprintf(m_output_file, "^D\n");
+ m_editor_status = EditorStatus::EndOfInput;
+ return CC_EOF;
+ }
+ return CC_ERROR;
+ }
+
+ // Prepare to combine this line with the one below
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+
+ // Insert the next line of text at the cursor and restore the cursor position
+ const EditLineCharType *cursor = info->cursor;
+ el_winsertstr(m_editline, m_input_lines[m_current_line_index + 1].c_str());
+ info->cursor = cursor;
+ SaveEditedLine();
+
+ // Delete the extra line
+ m_input_lines.erase(m_input_lines.begin() + m_current_line_index + 1);
+
+ // Clear and repaint from this line on down
+ DisplayInput(m_current_line_index);
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ return CC_REFRESH;
}
-unsigned char
-Editline::DeletePreviousCharCommand (int ch)
-{
- LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
-
- // Just delete the previous character normally when not at the start of a line
- if (info->cursor > info->buffer)
- {
- el_deletestr (m_editline, 1);
- return CC_REFRESH;
- }
-
- // No prior line and no prior character? Let the user know
- if (m_current_line_index == 0)
- return CC_ERROR;
-
- // No prior character, but prior line? Combine with the line above
- SaveEditedLine();
- SetCurrentLine (m_current_line_index - 1);
- auto priorLine = m_input_lines[m_current_line_index];
- m_input_lines.erase (m_input_lines.begin() + m_current_line_index);
- m_input_lines[m_current_line_index] = priorLine + m_input_lines[m_current_line_index];
-
- // Repaint from the new line down
- fprintf (m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N, CountRowsForLine (priorLine), 1);
- DisplayInput (m_current_line_index);
-
- // Put the cursor back where libedit expects it to be before returning to editing
- // by telling libedit about the newly inserted text
- MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
- el_winsertstr (m_editline, priorLine.c_str());
- return CC_REDISPLAY;
+unsigned char Editline::DeletePreviousCharCommand(int ch) {
+ LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline));
+
+ // Just delete the previous character normally when not at the start of a line
+ if (info->cursor > info->buffer) {
+ el_deletestr(m_editline, 1);
+ return CC_REFRESH;
+ }
+
+ // No prior line and no prior character? Let the user know
+ if (m_current_line_index == 0)
+ return CC_ERROR;
+
+ // No prior character, but prior line? Combine with the line above
+ SaveEditedLine();
+ SetCurrentLine(m_current_line_index - 1);
+ auto priorLine = m_input_lines[m_current_line_index];
+ m_input_lines.erase(m_input_lines.begin() + m_current_line_index);
+ m_input_lines[m_current_line_index] =
+ priorLine + m_input_lines[m_current_line_index];
+
+ // Repaint from the new line down
+ fprintf(m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N,
+ CountRowsForLine(priorLine), 1);
+ DisplayInput(m_current_line_index);
+
+ // Put the cursor back where libedit expects it to be before returning to
+ // editing
+ // by telling libedit about the newly inserted text
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ el_winsertstr(m_editline, priorLine.c_str());
+ return CC_REDISPLAY;
}
-unsigned char
-Editline::PreviousLineCommand (int ch)
-{
- SaveEditedLine();
+unsigned char Editline::PreviousLineCommand(int ch) {
+ SaveEditedLine();
- if (m_current_line_index == 0) {
- return RecallHistory (true);
- }
-
- // Start from a known location
- MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
-
- // Treat moving up from a blank last line as a deletion of that line
- if (m_current_line_index == m_input_lines.size() - 1 && IsOnlySpaces())
- {
- m_input_lines.erase (m_input_lines.begin() + m_current_line_index);
- fprintf (m_output_file, ANSI_CLEAR_BELOW);
- }
-
- SetCurrentLine (m_current_line_index - 1);
- fprintf (m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N,
- CountRowsForLine (m_input_lines[m_current_line_index]), 1);
- return CC_NEWLINE;
+ if (m_current_line_index == 0) {
+ return RecallHistory(true);
+ }
+
+ // Start from a known location
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+
+ // Treat moving up from a blank last line as a deletion of that line
+ if (m_current_line_index == m_input_lines.size() - 1 && IsOnlySpaces()) {
+ m_input_lines.erase(m_input_lines.begin() + m_current_line_index);
+ fprintf(m_output_file, ANSI_CLEAR_BELOW);
+ }
+
+ SetCurrentLine(m_current_line_index - 1);
+ fprintf(m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N,
+ CountRowsForLine(m_input_lines[m_current_line_index]), 1);
+ return CC_NEWLINE;
}
-unsigned char
-Editline::NextLineCommand (int ch)
-{
- SaveEditedLine();
+unsigned char Editline::NextLineCommand(int ch) {
+ SaveEditedLine();
- // Handle attempts to move down from the last line
- if (m_current_line_index == m_input_lines.size() - 1)
- {
- // Don't add an extra line if the existing last line is blank, move through history instead
- if (IsOnlySpaces())
- {
- return RecallHistory (false);
- }
-
- // Determine indentation for the new line
- int indentation = 0;
- if (m_fix_indentation_callback)
- {
- StringList lines = GetInputAsStringList();
- lines.AppendString("");
- indentation = m_fix_indentation_callback (this, lines, 0, m_fix_indentation_callback_baton);
- }
- m_input_lines.insert (m_input_lines.end(), EditLineStringType (indentation, EditLineCharType(' ')));
+ // Handle attempts to move down from the last line
+ if (m_current_line_index == m_input_lines.size() - 1) {
+ // Don't add an extra line if the existing last line is blank, move through
+ // history instead
+ if (IsOnlySpaces()) {
+ return RecallHistory(false);
}
-
- // Move down past the current line using newlines to force scrolling if needed
- SetCurrentLine (m_current_line_index + 1);
- const LineInfoW * info = el_wline (m_editline);
- int cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth());
- int cursor_row = cursor_position / m_terminal_width;
- for (int line_count = 0; line_count < m_current_line_rows - cursor_row; line_count++)
- {
- fprintf (m_output_file, "\n");
+
+ // Determine indentation for the new line
+ int indentation = 0;
+ if (m_fix_indentation_callback) {
+ StringList lines = GetInputAsStringList();
+ lines.AppendString("");
+ indentation = m_fix_indentation_callback(
+ this, lines, 0, m_fix_indentation_callback_baton);
}
- return CC_NEWLINE;
+ m_input_lines.insert(
+ m_input_lines.end(),
+ EditLineStringType(indentation, EditLineCharType(' ')));
+ }
+
+ // Move down past the current line using newlines to force scrolling if needed
+ SetCurrentLine(m_current_line_index + 1);
+ const LineInfoW *info = el_wline(m_editline);
+ int cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth());
+ int cursor_row = cursor_position / m_terminal_width;
+ for (int line_count = 0; line_count < m_current_line_rows - cursor_row;
+ line_count++) {
+ fprintf(m_output_file, "\n");
+ }
+ return CC_NEWLINE;
}
-unsigned char
-Editline::PreviousHistoryCommand(int ch)
-{
- SaveEditedLine();
+unsigned char Editline::PreviousHistoryCommand(int ch) {
+ SaveEditedLine();
- return RecallHistory(true);
+ return RecallHistory(true);
}
-unsigned char
-Editline::NextHistoryCommand(int ch)
-{
- SaveEditedLine();
+unsigned char Editline::NextHistoryCommand(int ch) {
+ SaveEditedLine();
- return RecallHistory(false);
+ return RecallHistory(false);
}
-unsigned char
-Editline::FixIndentationCommand(int ch)
-{
- if (!m_fix_indentation_callback)
- return CC_NORM;
+unsigned char Editline::FixIndentationCommand(int ch) {
+ if (!m_fix_indentation_callback)
+ return CC_NORM;
- // Insert the character typed before proceeding
- EditLineCharType inserted[] = { (EditLineCharType)ch, 0 };
- el_winsertstr (m_editline, inserted);
- LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
- int cursor_position = info->cursor - info->buffer;
+ // Insert the character typed before proceeding
+ EditLineCharType inserted[] = {(EditLineCharType)ch, 0};
+ el_winsertstr(m_editline, inserted);
+ LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline));
+ int cursor_position = info->cursor - info->buffer;
- // Save the edits and determine the correct indentation level
- SaveEditedLine();
- StringList lines = GetInputAsStringList (m_current_line_index + 1);
- int indent_correction = m_fix_indentation_callback (this, lines, cursor_position, m_fix_indentation_callback_baton);
-
- // If it is already correct no special work is needed
- if (indent_correction == 0)
- return CC_REFRESH;
-
- // Change the indentation level of the line
- std::string currentLine = lines.GetStringAtIndex (m_current_line_index);
- if (indent_correction > 0)
- {
- currentLine = currentLine.insert (0, indent_correction, ' ');
- }
- else
- {
- currentLine = currentLine.erase (0, -indent_correction);
- }
+ // Save the edits and determine the correct indentation level
+ SaveEditedLine();
+ StringList lines = GetInputAsStringList(m_current_line_index + 1);
+ int indent_correction = m_fix_indentation_callback(
+ this, lines, cursor_position, m_fix_indentation_callback_baton);
+
+ // If it is already correct no special work is needed
+ if (indent_correction == 0)
+ return CC_REFRESH;
+
+ // Change the indentation level of the line
+ std::string currentLine = lines.GetStringAtIndex(m_current_line_index);
+ if (indent_correction > 0) {
+ currentLine = currentLine.insert(0, indent_correction, ' ');
+ } else {
+ currentLine = currentLine.erase(0, -indent_correction);
+ }
#if LLDB_EDITLINE_USE_WCHAR
- m_input_lines[m_current_line_index] = m_utf8conv.from_bytes (currentLine);
+ m_input_lines[m_current_line_index] = m_utf8conv.from_bytes(currentLine);
#else
- m_input_lines[m_current_line_index] = currentLine;
+ m_input_lines[m_current_line_index] = currentLine;
#endif
- // Update the display to reflect the change
- MoveCursor (CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
- DisplayInput (m_current_line_index);
-
- // Reposition the cursor back on the original line and prepare to restart editing
- // with a new cursor position
- SetCurrentLine (m_current_line_index);
- MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
- m_revert_cursor_index = cursor_position + indent_correction;
- return CC_NEWLINE;
+ // Update the display to reflect the change
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
+ DisplayInput(m_current_line_index);
+
+ // Reposition the cursor back on the original line and prepare to restart
+ // editing
+ // with a new cursor position
+ SetCurrentLine(m_current_line_index);
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ m_revert_cursor_index = cursor_position + indent_correction;
+ return CC_NEWLINE;
}
-unsigned char
-Editline::RevertLineCommand (int ch)
-{
- el_winsertstr (m_editline, m_input_lines[m_current_line_index].c_str());
- if (m_revert_cursor_index >= 0)
- {
- LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline));
- info->cursor = info->buffer + m_revert_cursor_index;
- if (info->cursor > info->lastchar)
- {
- info->cursor = info->lastchar;
- }
- m_revert_cursor_index = -1;
+unsigned char Editline::RevertLineCommand(int ch) {
+ el_winsertstr(m_editline, m_input_lines[m_current_line_index].c_str());
+ if (m_revert_cursor_index >= 0) {
+ LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline));
+ info->cursor = info->buffer + m_revert_cursor_index;
+ if (info->cursor > info->lastchar) {
+ info->cursor = info->lastchar;
}
- return CC_REFRESH;
+ m_revert_cursor_index = -1;
+ }
+ return CC_REFRESH;
}
-unsigned char
-Editline::BufferStartCommand (int ch)
-{
- SaveEditedLine();
- MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockStart);
- SetCurrentLine (0);
- m_revert_cursor_index = 0;
- return CC_NEWLINE;
+unsigned char Editline::BufferStartCommand(int ch) {
+ SaveEditedLine();
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ SetCurrentLine(0);
+ m_revert_cursor_index = 0;
+ return CC_NEWLINE;
}
-unsigned char
-Editline::BufferEndCommand (int ch)
-{
- SaveEditedLine();
- MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockEnd);
- SetCurrentLine ((int)m_input_lines.size() - 1);
- MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
- return CC_NEWLINE;
+unsigned char Editline::BufferEndCommand(int ch) {
+ SaveEditedLine();
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd);
+ SetCurrentLine((int)m_input_lines.size() - 1);
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
+ return CC_NEWLINE;
}
-unsigned char
-Editline::TabCommand (int ch)
-{
- if (m_completion_callback == nullptr)
- return CC_ERROR;
-
- const LineInfo *line_info = el_line (m_editline);
- StringList completions;
- int page_size = 40;
-
- const int num_completions = m_completion_callback (line_info->buffer,
- line_info->cursor,
- line_info->lastchar,
- 0, // Don't skip any matches (start at match zero)
- -1, // Get all the matches
- completions,
- m_completion_callback_baton);
-
- if (num_completions == 0)
- return CC_ERROR;
- // if (num_completions == -1)
- // {
- // el_insertstr (m_editline, m_completion_key);
- // return CC_REDISPLAY;
- // }
- // else
- if (num_completions == -2)
- {
- // Replace the entire line with the first string...
- el_deletestr (m_editline, line_info->cursor - line_info->buffer);
- el_insertstr (m_editline, completions.GetStringAtIndex (0));
- return CC_REDISPLAY;
- }
-
- // If we get a longer match display that first.
- const char *completion_str = completions.GetStringAtIndex (0);
- if (completion_str != nullptr && *completion_str != '\0')
- {
- el_insertstr (m_editline, completion_str);
- return CC_REDISPLAY;
- }
-
- if (num_completions > 1)
- {
- int num_elements = num_completions + 1;
- fprintf (m_output_file, "\n" ANSI_CLEAR_BELOW "Available completions:");
- if (num_completions < page_size)
- {
- for (int i = 1; i < num_elements; i++)
- {
- completion_str = completions.GetStringAtIndex (i);
- fprintf (m_output_file, "\n\t%s", completion_str);
- }
- fprintf (m_output_file, "\n");
+unsigned char Editline::TabCommand(int ch) {
+ if (m_completion_callback == nullptr)
+ return CC_ERROR;
+
+ const LineInfo *line_info = el_line(m_editline);
+ StringList completions;
+ int page_size = 40;
+
+ const int num_completions = m_completion_callback(
+ line_info->buffer, line_info->cursor, line_info->lastchar,
+ 0, // Don't skip any matches (start at match zero)
+ -1, // Get all the matches
+ completions, m_completion_callback_baton);
+
+ if (num_completions == 0)
+ return CC_ERROR;
+ // if (num_completions == -1)
+ // {
+ // el_insertstr (m_editline, m_completion_key);
+ // return CC_REDISPLAY;
+ // }
+ // else
+ if (num_completions == -2) {
+ // Replace the entire line with the first string...
+ el_deletestr(m_editline, line_info->cursor - line_info->buffer);
+ el_insertstr(m_editline, completions.GetStringAtIndex(0));
+ return CC_REDISPLAY;
+ }
+
+ // If we get a longer match display that first.
+ const char *completion_str = completions.GetStringAtIndex(0);
+ if (completion_str != nullptr && *completion_str != '\0') {
+ el_insertstr(m_editline, completion_str);
+ return CC_REDISPLAY;
+ }
+
+ if (num_completions > 1) {
+ int num_elements = num_completions + 1;
+ fprintf(m_output_file, "\n" ANSI_CLEAR_BELOW "Available completions:");
+ if (num_completions < page_size) {
+ for (int i = 1; i < num_elements; i++) {
+ completion_str = completions.GetStringAtIndex(i);
+ fprintf(m_output_file, "\n\t%s", completion_str);
+ }
+ fprintf(m_output_file, "\n");
+ } else {
+ int cur_pos = 1;
+ char reply;
+ int got_char;
+ while (cur_pos < num_elements) {
+ int endpoint = cur_pos + page_size;
+ if (endpoint > num_elements)
+ endpoint = num_elements;
+ for (; cur_pos < endpoint; cur_pos++) {
+ completion_str = completions.GetStringAtIndex(cur_pos);
+ fprintf(m_output_file, "\n\t%s", completion_str);
}
- else
- {
- int cur_pos = 1;
- char reply;
- int got_char;
- while (cur_pos < num_elements)
- {
- int endpoint = cur_pos + page_size;
- if (endpoint > num_elements)
- endpoint = num_elements;
- for (; cur_pos < endpoint; cur_pos++)
- {
- completion_str = completions.GetStringAtIndex (cur_pos);
- fprintf (m_output_file, "\n\t%s", completion_str);
- }
-
- if (cur_pos >= num_elements)
- {
- fprintf (m_output_file, "\n");
- break;
- }
-
- fprintf (m_output_file, "\nMore (Y/n/a): ");
- reply = 'n';
- got_char = el_getc(m_editline, &reply);
- if (got_char == -1 || reply == 'n')
- break;
- if (reply == 'a')
- page_size = num_elements - cur_pos;
- }
+
+ if (cur_pos >= num_elements) {
+ fprintf(m_output_file, "\n");
+ break;
}
- DisplayInput();
- MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+
+ fprintf(m_output_file, "\nMore (Y/n/a): ");
+ reply = 'n';
+ got_char = el_getc(m_editline, &reply);
+ if (got_char == -1 || reply == 'n')
+ break;
+ if (reply == 'a')
+ page_size = num_elements - cur_pos;
+ }
}
- return CC_REDISPLAY;
+ DisplayInput();
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ }
+ return CC_REDISPLAY;
}
-void
-Editline::ConfigureEditor (bool multiline)
-{
- if (m_editline && m_multiline_enabled == multiline)
- return;
- m_multiline_enabled = multiline;
-
- if (m_editline)
- {
- // Disable edit mode to stop the terminal from flushing all input
- // during the call to el_end() since we expect to have multiple editline
- // instances in this program.
- el_set (m_editline, EL_EDITMODE, 0);
- el_end (m_editline);
- }
-
- m_editline = el_init (m_editor_name.c_str(), m_input_file, m_output_file, m_error_file);
- TerminalSizeChanged();
-
- if (m_history_sp && m_history_sp->IsValid())
- {
- m_history_sp->Load();
- el_wset (m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr());
- }
- el_set (m_editline, EL_CLIENTDATA, this);
- el_set (m_editline, EL_SIGNAL, 0);
- el_set (m_editline, EL_EDITOR, "emacs");
- el_set (m_editline, EL_PROMPT, (EditlinePromptCallbackType)([] (EditLine *editline) {
- return Editline::InstanceFor (editline)->Prompt();
- }));
-
- el_wset (m_editline, EL_GETCFN,
- (EditlineGetCharCallbackType)([] (EditLine * editline, EditLineCharType * c) {
- return Editline::InstanceFor (editline)->GetCharacter (c);
- }));
-
- // Commands used for multiline support, registered whether or not they're used
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-break-line"), EditLineConstString("Insert a line break"),
- (EditlineCommandCallbackType)(
- [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->BreakLineCommand(ch); }));
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-end-or-add-line"),
- EditLineConstString("End editing or continue when incomplete"),
- (EditlineCommandCallbackType)(
- [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->EndOrAddLineCommand(ch); }));
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-next-char"),
- EditLineConstString("Delete next character"), (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
- return Editline::InstanceFor(editline)->DeleteNextCharCommand(ch);
- }));
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-previous-char"),
- EditLineConstString("Delete previous character"),
- (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
- return Editline::InstanceFor(editline)->DeletePreviousCharCommand(ch);
- }));
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-line"),
- EditLineConstString("Move to previous line"), (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
- return Editline::InstanceFor(editline)->PreviousLineCommand(ch);
- }));
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-line"), EditLineConstString("Move to next line"),
- (EditlineCommandCallbackType)(
- [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->NextLineCommand(ch); }));
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-history"),
- EditLineConstString("Move to previous history"),
- (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
- return Editline::InstanceFor(editline)->PreviousHistoryCommand(ch);
- }));
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-history"), EditLineConstString("Move to next history"),
- (EditlineCommandCallbackType)(
- [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->NextHistoryCommand(ch); }));
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-start"),
- EditLineConstString("Move to start of buffer"),
- (EditlineCommandCallbackType)(
- [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->BufferStartCommand(ch); }));
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-end"), EditLineConstString("Move to end of buffer"),
- (EditlineCommandCallbackType)(
- [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->BufferEndCommand(ch); }));
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-fix-indentation"),
- EditLineConstString("Fix line indentation"), (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
- return Editline::InstanceFor (editline)->FixIndentationCommand (ch);
- }));
-
- // Register the complete callback under two names for compatibility with older clients using
- // custom .editrc files (largely because libedit has a bad bug where if you have a bind command
- // that tries to bind to a function name that doesn't exist, it can corrupt the heap and
- // crash your process later.)
- EditlineCommandCallbackType complete_callback = [] (EditLine * editline, int ch) {
- return Editline::InstanceFor (editline)->TabCommand (ch);
- };
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-complete"), EditLineConstString("Invoke completion"),
- complete_callback);
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb_complete"), EditLineConstString("Invoke completion"),
- complete_callback);
-
- // General bindings we don't mind being overridden
- if (!multiline) {
- el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string
- }
- el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash in emacs mode
- el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to auto complete
-
- // Allow user-specific customization prior to registering bindings we absolutely require
- el_source (m_editline, NULL);
-
- // Register an internal binding that external developers shouldn't use
- el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-revert-line"),
- EditLineConstString("Revert line to saved state"),
- (EditlineCommandCallbackType)(
- [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->RevertLineCommand(ch); }));
-
- // Register keys that perform auto-indent correction
- if (m_fix_indentation_callback && m_fix_indentation_callback_chars)
- {
- char bind_key[2] = { 0, 0 };
- const char * indent_chars = m_fix_indentation_callback_chars;
- while (*indent_chars)
- {
- bind_key[0] = *indent_chars;
- el_set (m_editline, EL_BIND, bind_key, "lldb-fix-indentation", NULL);
- ++indent_chars;
- }
+void Editline::ConfigureEditor(bool multiline) {
+ if (m_editline && m_multiline_enabled == multiline)
+ return;
+ m_multiline_enabled = multiline;
+
+ if (m_editline) {
+ // Disable edit mode to stop the terminal from flushing all input
+ // during the call to el_end() since we expect to have multiple editline
+ // instances in this program.
+ el_set(m_editline, EL_EDITMODE, 0);
+ el_end(m_editline);
+ }
+
+ m_editline =
+ el_init(m_editor_name.c_str(), m_input_file, m_output_file, m_error_file);
+ TerminalSizeChanged();
+
+ if (m_history_sp && m_history_sp->IsValid()) {
+ m_history_sp->Load();
+ el_wset(m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr());
+ }
+ el_set(m_editline, EL_CLIENTDATA, this);
+ el_set(m_editline, EL_SIGNAL, 0);
+ el_set(m_editline, EL_EDITOR, "emacs");
+ el_set(m_editline, EL_PROMPT,
+ (EditlinePromptCallbackType)([](EditLine *editline) {
+ return Editline::InstanceFor(editline)->Prompt();
+ }));
+
+ el_wset(m_editline, EL_GETCFN, (EditlineGetCharCallbackType)([](
+ EditLine *editline, EditLineCharType *c) {
+ return Editline::InstanceFor(editline)->GetCharacter(c);
+ }));
+
+ // Commands used for multiline support, registered whether or not they're used
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-break-line"),
+ EditLineConstString("Insert a line break"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->BreakLineCommand(ch);
+ }));
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-end-or-add-line"),
+ EditLineConstString("End editing or continue when incomplete"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->EndOrAddLineCommand(ch);
+ }));
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-next-char"),
+ EditLineConstString("Delete next character"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->DeleteNextCharCommand(ch);
+ }));
+ el_wset(
+ m_editline, EL_ADDFN, EditLineConstString("lldb-delete-previous-char"),
+ EditLineConstString("Delete previous character"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->DeletePreviousCharCommand(ch);
+ }));
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-line"),
+ EditLineConstString("Move to previous line"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->PreviousLineCommand(ch);
+ }));
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-line"),
+ EditLineConstString("Move to next line"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->NextLineCommand(ch);
+ }));
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-history"),
+ EditLineConstString("Move to previous history"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->PreviousHistoryCommand(ch);
+ }));
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-history"),
+ EditLineConstString("Move to next history"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->NextHistoryCommand(ch);
+ }));
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-start"),
+ EditLineConstString("Move to start of buffer"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->BufferStartCommand(ch);
+ }));
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-end"),
+ EditLineConstString("Move to end of buffer"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->BufferEndCommand(ch);
+ }));
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-fix-indentation"),
+ EditLineConstString("Fix line indentation"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->FixIndentationCommand(ch);
+ }));
+
+ // Register the complete callback under two names for compatibility with older
+ // clients using
+ // custom .editrc files (largely because libedit has a bad bug where if you
+ // have a bind command
+ // that tries to bind to a function name that doesn't exist, it can corrupt
+ // the heap and
+ // crash your process later.)
+ EditlineCommandCallbackType complete_callback = [](EditLine *editline,
+ int ch) {
+ return Editline::InstanceFor(editline)->TabCommand(ch);
+ };
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-complete"),
+ EditLineConstString("Invoke completion"), complete_callback);
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb_complete"),
+ EditLineConstString("Invoke completion"), complete_callback);
+
+ // General bindings we don't mind being overridden
+ if (!multiline) {
+ el_set(m_editline, EL_BIND, "^r", "em-inc-search-prev",
+ NULL); // Cycle through backwards search, entering string
+ }
+ el_set(m_editline, EL_BIND, "^w", "ed-delete-prev-word",
+ NULL); // Delete previous word, behave like bash in emacs mode
+ el_set(m_editline, EL_BIND, "\t", "lldb-complete",
+ NULL); // Bind TAB to auto complete
+
+ // Allow user-specific customization prior to registering bindings we
+ // absolutely require
+ el_source(m_editline, NULL);
+
+ // Register an internal binding that external developers shouldn't use
+ el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-revert-line"),
+ EditLineConstString("Revert line to saved state"),
+ (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
+ return Editline::InstanceFor(editline)->RevertLineCommand(ch);
+ }));
+
+ // Register keys that perform auto-indent correction
+ if (m_fix_indentation_callback && m_fix_indentation_callback_chars) {
+ char bind_key[2] = {0, 0};
+ const char *indent_chars = m_fix_indentation_callback_chars;
+ while (*indent_chars) {
+ bind_key[0] = *indent_chars;
+ el_set(m_editline, EL_BIND, bind_key, "lldb-fix-indentation", NULL);
+ ++indent_chars;
}
-
- // Multi-line editor bindings
- if (multiline)
- {
- el_set(m_editline, EL_BIND, "\n", "lldb-end-or-add-line", NULL);
- el_set(m_editline, EL_BIND, "\r", "lldb-end-or-add-line", NULL);
- el_set(m_editline, EL_BIND, ESCAPE "\n", "lldb-break-line", NULL);
- el_set(m_editline, EL_BIND, ESCAPE "\r", "lldb-break-line", NULL);
- el_set (m_editline, EL_BIND, "^p", "lldb-previous-line", NULL);
- el_set (m_editline, EL_BIND, "^n", "lldb-next-line", NULL);
- el_set (m_editline, EL_BIND, "^?", "lldb-delete-previous-char", NULL);
- el_set (m_editline, EL_BIND, "^d", "lldb-delete-next-char", NULL);
- el_set (m_editline, EL_BIND, ESCAPE "[3~", "lldb-delete-next-char", NULL);
- el_set (m_editline, EL_BIND, ESCAPE "[\\^", "lldb-revert-line", NULL);
-
- // Editor-specific bindings
- if (IsEmacs())
- {
- el_set (m_editline, EL_BIND, ESCAPE "<", "lldb-buffer-start", NULL);
- el_set (m_editline, EL_BIND, ESCAPE ">", "lldb-buffer-end", NULL);
- el_set (m_editline, EL_BIND, ESCAPE "[A", "lldb-previous-line", NULL);
- el_set (m_editline, EL_BIND, ESCAPE "[B", "lldb-next-line", NULL);
- el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[A", "lldb-previous-history", NULL);
- el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[B", "lldb-next-history", NULL);
- el_set(m_editline, EL_BIND, ESCAPE "[1;3A", "lldb-previous-history", NULL);
- el_set(m_editline, EL_BIND, ESCAPE "[1;3B", "lldb-next-history", NULL);
- }
- else
- {
- el_set (m_editline, EL_BIND, "^H", "lldb-delete-previous-char", NULL);
-
- el_set (m_editline, EL_BIND, "-a", ESCAPE "[A", "lldb-previous-line", NULL);
- el_set (m_editline, EL_BIND, "-a", ESCAPE "[B", "lldb-next-line", NULL);
- el_set (m_editline, EL_BIND, "-a", "x", "lldb-delete-next-char", NULL);
- el_set (m_editline, EL_BIND, "-a", "^H", "lldb-delete-previous-char", NULL);
- el_set (m_editline, EL_BIND, "-a", "^?", "lldb-delete-previous-char", NULL);
-
- // Escape is absorbed exiting edit mode, so re-register important sequences
- // without the prefix
- el_set (m_editline, EL_BIND, "-a", "[A", "lldb-previous-line", NULL);
- el_set (m_editline, EL_BIND, "-a", "[B", "lldb-next-line", NULL);
- el_set (m_editline, EL_BIND, "-a", "[\\^", "lldb-revert-line", NULL);
- }
+ }
+
+ // Multi-line editor bindings
+ if (multiline) {
+ el_set(m_editline, EL_BIND, "\n", "lldb-end-or-add-line", NULL);
+ el_set(m_editline, EL_BIND, "\r", "lldb-end-or-add-line", NULL);
+ el_set(m_editline, EL_BIND, ESCAPE "\n", "lldb-break-line", NULL);
+ el_set(m_editline, EL_BIND, ESCAPE "\r", "lldb-break-line", NULL);
+ el_set(m_editline, EL_BIND, "^p", "lldb-previous-line", NULL);
+ el_set(m_editline, EL_BIND, "^n", "lldb-next-line", NULL);
+ el_set(m_editline, EL_BIND, "^?", "lldb-delete-previous-char", NULL);
+ el_set(m_editline, EL_BIND, "^d", "lldb-delete-next-char", NULL);
+ el_set(m_editline, EL_BIND, ESCAPE "[3~", "lldb-delete-next-char", NULL);
+ el_set(m_editline, EL_BIND, ESCAPE "[\\^", "lldb-revert-line", NULL);
+
+ // Editor-specific bindings
+ if (IsEmacs()) {
+ el_set(m_editline, EL_BIND, ESCAPE "<", "lldb-buffer-start", NULL);
+ el_set(m_editline, EL_BIND, ESCAPE ">", "lldb-buffer-end", NULL);
+ el_set(m_editline, EL_BIND, ESCAPE "[A", "lldb-previous-line", NULL);
+ el_set(m_editline, EL_BIND, ESCAPE "[B", "lldb-next-line", NULL);
+ el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[A", "lldb-previous-history",
+ NULL);
+ el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[B", "lldb-next-history",
+ NULL);
+ el_set(m_editline, EL_BIND, ESCAPE "[1;3A", "lldb-previous-history",
+ NULL);
+ el_set(m_editline, EL_BIND, ESCAPE "[1;3B", "lldb-next-history", NULL);
+ } else {
+ el_set(m_editline, EL_BIND, "^H", "lldb-delete-previous-char", NULL);
+
+ el_set(m_editline, EL_BIND, "-a", ESCAPE "[A", "lldb-previous-line",
+ NULL);
+ el_set(m_editline, EL_BIND, "-a", ESCAPE "[B", "lldb-next-line", NULL);
+ el_set(m_editline, EL_BIND, "-a", "x", "lldb-delete-next-char", NULL);
+ el_set(m_editline, EL_BIND, "-a", "^H", "lldb-delete-previous-char",
+ NULL);
+ el_set(m_editline, EL_BIND, "-a", "^?", "lldb-delete-previous-char",
+ NULL);
+
+ // Escape is absorbed exiting edit mode, so re-register important
+ // sequences
+ // without the prefix
+ el_set(m_editline, EL_BIND, "-a", "[A", "lldb-previous-line", NULL);
+ el_set(m_editline, EL_BIND, "-a", "[B", "lldb-next-line", NULL);
+ el_set(m_editline, EL_BIND, "-a", "[\\^", "lldb-revert-line", NULL);
}
+ }
}
//------------------------------------------------------------------
// Editline public methods
//------------------------------------------------------------------
-Editline *
-Editline::InstanceFor (EditLine * editline)
-{
- Editline * editor;
- el_get (editline, EL_CLIENTDATA, &editor);
- return editor;
+Editline *Editline::InstanceFor(EditLine *editline) {
+ Editline *editor;
+ el_get(editline, EL_CLIENTDATA, &editor);
+ return editor;
}
-Editline::Editline (const char * editline_name, FILE * input_file, FILE * output_file, FILE * error_file, bool color_prompts) :
- m_editor_status (EditorStatus::Complete),
- m_color_prompts(color_prompts),
- m_input_file (input_file),
- m_output_file (output_file),
- m_error_file (error_file),
- m_input_connection (fileno(input_file), false)
-{
- // Get a shared history instance
- m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name;
- m_history_sp = EditlineHistory::GetHistory (m_editor_name);
+Editline::Editline(const char *editline_name, FILE *input_file,
+ FILE *output_file, FILE *error_file, bool color_prompts)
+ : m_editor_status(EditorStatus::Complete), m_color_prompts(color_prompts),
+ m_input_file(input_file), m_output_file(output_file),
+ m_error_file(error_file), m_input_connection(fileno(input_file), false) {
+ // Get a shared history instance
+ m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name;
+ m_history_sp = EditlineHistory::GetHistory(m_editor_name);
#ifdef USE_SETUPTERM_WORKAROUND
- if (m_output_file)
- {
- const int term_fd = fileno(m_output_file);
- if (term_fd != -1)
- {
- static std::mutex *g_init_terminal_fds_mutex_ptr = nullptr;
- static std::set<int> *g_init_terminal_fds_ptr = nullptr;
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, [&]() {
- g_init_terminal_fds_mutex_ptr = new std::mutex(); // NOTE: Leak to avoid C++ destructor chain issues
- g_init_terminal_fds_ptr = new std::set<int>(); // NOTE: Leak to avoid C++ destructor chain issues
- });
-
- // We must make sure to initialize the terminal a given file descriptor
- // only once. If we do this multiple times, we start leaking memory.
- std::lock_guard<std::mutex> guard(*g_init_terminal_fds_mutex_ptr);
- if (g_init_terminal_fds_ptr->find(term_fd) == g_init_terminal_fds_ptr->end())
- {
- g_init_terminal_fds_ptr->insert(term_fd);
- setupterm((char *)0, term_fd, (int *)0);
- }
- }
+ if (m_output_file) {
+ const int term_fd = fileno(m_output_file);
+ if (term_fd != -1) {
+ static std::mutex *g_init_terminal_fds_mutex_ptr = nullptr;
+ static std::set<int> *g_init_terminal_fds_ptr = nullptr;
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, [&]() {
+ g_init_terminal_fds_mutex_ptr =
+ new std::mutex(); // NOTE: Leak to avoid C++ destructor chain issues
+ g_init_terminal_fds_ptr = new std::set<int>(); // NOTE: Leak to avoid
+ // C++ destructor chain
+ // issues
+ });
+
+ // We must make sure to initialize the terminal a given file descriptor
+ // only once. If we do this multiple times, we start leaking memory.
+ std::lock_guard<std::mutex> guard(*g_init_terminal_fds_mutex_ptr);
+ if (g_init_terminal_fds_ptr->find(term_fd) ==
+ g_init_terminal_fds_ptr->end()) {
+ g_init_terminal_fds_ptr->insert(term_fd);
+ setupterm((char *)0, term_fd, (int *)0);
+ }
}
+ }
#endif
}
-Editline::~Editline()
-{
- if (m_editline)
- {
- // Disable edit mode to stop the terminal from flushing all input
- // during the call to el_end() since we expect to have multiple editline
- // instances in this program.
- el_set (m_editline, EL_EDITMODE, 0);
- el_end (m_editline);
- m_editline = nullptr;
- }
-
- // EditlineHistory objects are sometimes shared between multiple
- // Editline instances with the same program name. So just release
- // our shared pointer and if we are the last owner, it will save the
- // history to the history save file automatically.
- m_history_sp.reset();
+Editline::~Editline() {
+ if (m_editline) {
+ // Disable edit mode to stop the terminal from flushing all input
+ // during the call to el_end() since we expect to have multiple editline
+ // instances in this program.
+ el_set(m_editline, EL_EDITMODE, 0);
+ el_end(m_editline);
+ m_editline = nullptr;
+ }
+
+ // EditlineHistory objects are sometimes shared between multiple
+ // Editline instances with the same program name. So just release
+ // our shared pointer and if we are the last owner, it will save the
+ // history to the history save file automatically.
+ m_history_sp.reset();
}
-void
-Editline::SetPrompt (const char * prompt)
-{
- m_set_prompt = prompt == nullptr ? "" : prompt;
+void Editline::SetPrompt(const char *prompt) {
+ m_set_prompt = prompt == nullptr ? "" : prompt;
}
-void
-Editline::SetContinuationPrompt (const char * continuation_prompt)
-{
- m_set_continuation_prompt = continuation_prompt == nullptr ? "" : continuation_prompt;
+void Editline::SetContinuationPrompt(const char *continuation_prompt) {
+ m_set_continuation_prompt =
+ continuation_prompt == nullptr ? "" : continuation_prompt;
}
-void
-Editline::TerminalSizeChanged()
-{
- if (m_editline != nullptr)
- {
- el_resize (m_editline);
- int columns;
- // Despite the man page claiming non-zero indicates success, it's actually zero
- if (el_get (m_editline, EL_GETTC, "co", &columns) == 0)
- {
- m_terminal_width = columns;
- if (m_current_line_rows != -1)
- {
- const LineInfoW * info = el_wline (m_editline);
- int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth());
- m_current_line_rows = (lineLength / columns) + 1;
- }
- }
- else
- {
- m_terminal_width = INT_MAX;
- m_current_line_rows = 1;
- }
+void Editline::TerminalSizeChanged() {
+ if (m_editline != nullptr) {
+ el_resize(m_editline);
+ int columns;
+ // Despite the man page claiming non-zero indicates success, it's actually
+ // zero
+ if (el_get(m_editline, EL_GETTC, "co", &columns) == 0) {
+ m_terminal_width = columns;
+ if (m_current_line_rows != -1) {
+ const LineInfoW *info = el_wline(m_editline);
+ int lineLength =
+ (int)((info->lastchar - info->buffer) + GetPromptWidth());
+ m_current_line_rows = (lineLength / columns) + 1;
+ }
+ } else {
+ m_terminal_width = INT_MAX;
+ m_current_line_rows = 1;
}
+ }
}
-const char *
-Editline::GetPrompt()
-{
- return m_set_prompt.c_str();
-}
+const char *Editline::GetPrompt() { return m_set_prompt.c_str(); }
-uint32_t
-Editline::GetCurrentLine()
-{
- return m_current_line_index;
-}
+uint32_t Editline::GetCurrentLine() { return m_current_line_index; }
-bool
-Editline::Interrupt()
-{
- bool result = true;
- std::lock_guard<std::mutex> guard(m_output_mutex);
- if (m_editor_status == EditorStatus::Editing) {
- fprintf(m_output_file, "^C\n");
- result = m_input_connection.InterruptRead();
- }
- m_editor_status = EditorStatus::Interrupted;
- return result;
+bool Editline::Interrupt() {
+ bool result = true;
+ std::lock_guard<std::mutex> guard(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing) {
+ fprintf(m_output_file, "^C\n");
+ result = m_input_connection.InterruptRead();
+ }
+ m_editor_status = EditorStatus::Interrupted;
+ return result;
}
-bool
-Editline::Cancel()
-{
- bool result = true;
- std::lock_guard<std::mutex> guard(m_output_mutex);
- if (m_editor_status == EditorStatus::Editing) {
- MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
- fprintf(m_output_file, ANSI_CLEAR_BELOW);
- result = m_input_connection.InterruptRead();
- }
- m_editor_status = EditorStatus::Interrupted;
- return result;
+bool Editline::Cancel() {
+ bool result = true;
+ std::lock_guard<std::mutex> guard(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing) {
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ fprintf(m_output_file, ANSI_CLEAR_BELOW);
+ result = m_input_connection.InterruptRead();
+ }
+ m_editor_status = EditorStatus::Interrupted;
+ return result;
}
-void
-Editline::SetAutoCompleteCallback (CompleteCallbackType callback, void * baton)
-{
- m_completion_callback = callback;
- m_completion_callback_baton = baton;
+void Editline::SetAutoCompleteCallback(CompleteCallbackType callback,
+ void *baton) {
+ m_completion_callback = callback;
+ m_completion_callback_baton = baton;
}
-void
-Editline::SetIsInputCompleteCallback (IsInputCompleteCallbackType callback, void * baton)
-{
- m_is_input_complete_callback = callback;
- m_is_input_complete_callback_baton = baton;
+void Editline::SetIsInputCompleteCallback(IsInputCompleteCallbackType callback,
+ void *baton) {
+ m_is_input_complete_callback = callback;
+ m_is_input_complete_callback_baton = baton;
}
-bool
-Editline::SetFixIndentationCallback (FixIndentationCallbackType callback,
- void * baton,
- const char * indent_chars)
-{
- m_fix_indentation_callback = callback;
- m_fix_indentation_callback_baton = baton;
- m_fix_indentation_callback_chars = indent_chars;
- return false;
+bool Editline::SetFixIndentationCallback(FixIndentationCallbackType callback,
+ void *baton,
+ const char *indent_chars) {
+ m_fix_indentation_callback = callback;
+ m_fix_indentation_callback_baton = baton;
+ m_fix_indentation_callback_chars = indent_chars;
+ return false;
}
-bool
-Editline::GetLine (std::string &line, bool &interrupted)
-{
- ConfigureEditor (false);
- m_input_lines = std::vector<EditLineStringType>();
- m_input_lines.insert (m_input_lines.begin(), EditLineConstString(""));
+bool Editline::GetLine(std::string &line, bool &interrupted) {
+ ConfigureEditor(false);
+ m_input_lines = std::vector<EditLineStringType>();
+ m_input_lines.insert(m_input_lines.begin(), EditLineConstString(""));
- std::lock_guard<std::mutex> guard(m_output_mutex);
+ std::lock_guard<std::mutex> guard(m_output_mutex);
- lldbassert(m_editor_status != EditorStatus::Editing);
- if (m_editor_status == EditorStatus::Interrupted)
- {
- m_editor_status = EditorStatus::Complete;
- interrupted = true;
- return true;
- }
-
- SetCurrentLine (0);
- m_in_history = false;
- m_editor_status = EditorStatus::Editing;
- m_revert_cursor_index = -1;
-
- int count;
- auto input = el_wgets (m_editline, &count);
-
- interrupted = m_editor_status == EditorStatus::Interrupted;
- if (!interrupted)
- {
- if (input == nullptr)
- {
- fprintf (m_output_file, "\n");
- m_editor_status = EditorStatus::EndOfInput;
- }
- else
- {
- m_history_sp->Enter (input);
+ lldbassert(m_editor_status != EditorStatus::Editing);
+ if (m_editor_status == EditorStatus::Interrupted) {
+ m_editor_status = EditorStatus::Complete;
+ interrupted = true;
+ return true;
+ }
+
+ SetCurrentLine(0);
+ m_in_history = false;
+ m_editor_status = EditorStatus::Editing;
+ m_revert_cursor_index = -1;
+
+ int count;
+ auto input = el_wgets(m_editline, &count);
+
+ interrupted = m_editor_status == EditorStatus::Interrupted;
+ if (!interrupted) {
+ if (input == nullptr) {
+ fprintf(m_output_file, "\n");
+ m_editor_status = EditorStatus::EndOfInput;
+ } else {
+ m_history_sp->Enter(input);
#if LLDB_EDITLINE_USE_WCHAR
- line = m_utf8conv.to_bytes (SplitLines (input)[0]);
+ line = m_utf8conv.to_bytes(SplitLines(input)[0]);
#else
- line = SplitLines (input)[0];
+ line = SplitLines(input)[0];
#endif
- m_editor_status = EditorStatus::Complete;
- }
+ m_editor_status = EditorStatus::Complete;
}
- return m_editor_status != EditorStatus::EndOfInput;
+ }
+ return m_editor_status != EditorStatus::EndOfInput;
}
-bool
-Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted)
-{
- ConfigureEditor (true);
-
- // Print the initial input lines, then move the cursor back up to the start of input
- SetBaseLineNumber (first_line_number);
- m_input_lines = std::vector<EditLineStringType>();
- m_input_lines.insert (m_input_lines.begin(), EditLineConstString(""));
-
- std::lock_guard<std::mutex> guard(m_output_mutex);
- // Begin the line editing loop
- DisplayInput();
- SetCurrentLine (0);
- MoveCursor (CursorLocation::BlockEnd, CursorLocation::BlockStart);
- m_editor_status = EditorStatus::Editing;
- m_in_history = false;
-
- m_revert_cursor_index = -1;
- while (m_editor_status == EditorStatus::Editing)
- {
- int count;
- m_current_line_rows = -1;
- el_wpush (m_editline, EditLineConstString("\x1b[^")); // Revert to the existing line content
- el_wgets (m_editline, &count);
- }
-
- interrupted = m_editor_status == EditorStatus::Interrupted;
- if (!interrupted)
- {
- // Save the completed entry in history before returning
- m_history_sp->Enter (CombineLines (m_input_lines).c_str());
-
- lines = GetInputAsStringList();
- }
- return m_editor_status != EditorStatus::EndOfInput;
+bool Editline::GetLines(int first_line_number, StringList &lines,
+ bool &interrupted) {
+ ConfigureEditor(true);
+
+ // Print the initial input lines, then move the cursor back up to the start of
+ // input
+ SetBaseLineNumber(first_line_number);
+ m_input_lines = std::vector<EditLineStringType>();
+ m_input_lines.insert(m_input_lines.begin(), EditLineConstString(""));
+
+ std::lock_guard<std::mutex> guard(m_output_mutex);
+ // Begin the line editing loop
+ DisplayInput();
+ SetCurrentLine(0);
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::BlockStart);
+ m_editor_status = EditorStatus::Editing;
+ m_in_history = false;
+
+ m_revert_cursor_index = -1;
+ while (m_editor_status == EditorStatus::Editing) {
+ int count;
+ m_current_line_rows = -1;
+ el_wpush(m_editline, EditLineConstString(
+ "\x1b[^")); // Revert to the existing line content
+ el_wgets(m_editline, &count);
+ }
+
+ interrupted = m_editor_status == EditorStatus::Interrupted;
+ if (!interrupted) {
+ // Save the completed entry in history before returning
+ m_history_sp->Enter(CombineLines(m_input_lines).c_str());
+
+ lines = GetInputAsStringList();
+ }
+ return m_editor_status != EditorStatus::EndOfInput;
}
-void
-Editline::PrintAsync (Stream *stream, const char *s, size_t len)
-{
- std::lock_guard<std::mutex> guard(m_output_mutex);
- if (m_editor_status == EditorStatus::Editing)
- {
- MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
- fprintf(m_output_file, ANSI_CLEAR_BELOW);
- }
- stream->Write (s, len);
- stream->Flush();
- if (m_editor_status == EditorStatus::Editing)
- {
- DisplayInput();
- MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
- }
+void Editline::PrintAsync(Stream *stream, const char *s, size_t len) {
+ std::lock_guard<std::mutex> guard(m_output_mutex);
+ if (m_editor_status == EditorStatus::Editing) {
+ MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
+ fprintf(m_output_file, ANSI_CLEAR_BELOW);
+ }
+ stream->Write(s, len);
+ stream->Flush();
+ if (m_editor_status == EditorStatus::Editing) {
+ DisplayInput();
+ MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
+ }
}
OpenPOWER on IntegriCloud