aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Host/common/Editline.cpp
diff options
context:
space:
mode:
authorKate Stone <katherine.stone@apple.com>2016-09-06 20:57:50 +0000
committerKate Stone <katherine.stone@apple.com>2016-09-06 20:57:50 +0000
commitb9c1b51e45b845debb76d8658edabca70ca56079 (patch)
treedfcb5a13ef2b014202340f47036da383eaee74aa /lldb/source/Host/common/Editline.cpp
parentd5aa73376966339caad04013510626ec2e42c760 (diff)
downloadllvm-b9c1b51e45b845debb76d8658edabca70ca56079.zip
llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.gz
llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.bz2
*** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style. This kind of mass change has *** two obvious implications: Firstly, merging this particular commit into a downstream fork may be a huge effort. Alternatively, it may be worth merging all changes up to this commit, performing the same reformatting operation locally, and then discarding the merge for this particular commit. The commands used to accomplish this reformatting were as follows (with current working directory as the root of the repository): find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} + find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ; The version of clang-format used was 3.9.0, and autopep8 was 1.2.4. Secondly, “blame” style tools will generally point to this commit instead of a meaningful prior commit. There are alternatives available that will attempt to look through this change and find the appropriate prior commit. YMMV. llvm-svn: 280751
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 d23a481..6e12bfb 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);
+ }
}