1 //===-- Editline.cpp ------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
13 #include "lldb/Host/ConnectionFileDescriptor.h"
14 #include "lldb/Host/Editline.h"
15 #include "lldb/Host/FileSystem.h"
16 #include "lldb/Host/Host.h"
17 #include "lldb/Utility/CompletionRequest.h"
18 #include "lldb/Utility/FileSpec.h"
19 #include "lldb/Utility/LLDBAssert.h"
20 #include "lldb/Utility/SelectHelper.h"
21 #include "lldb/Utility/Status.h"
22 #include "lldb/Utility/StreamString.h"
23 #include "lldb/Utility/StringList.h"
24 #include "lldb/Utility/Timeout.h"
25 #include "llvm/Support/ConvertUTF.h"
27 #include "llvm/Support/FileSystem.h"
28 #include "llvm/Support/Locale.h"
29 #include "llvm/Support/Threading.h"
31 using namespace lldb_private
;
32 using namespace lldb_private::line_editor
;
34 // Editline uses careful cursor management to achieve the illusion of editing a
35 // multi-line block of text with a single line editor. Preserving this
36 // illusion requires fairly careful management of cursor state. Read and
37 // understand the relationship between DisplayInput(), MoveCursor(),
38 // SetCurrentLine(), and SaveEditedLine() before making changes.
40 /// https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
42 #define ANSI_CLEAR_BELOW ESCAPE "[J"
43 #define ANSI_CLEAR_RIGHT ESCAPE "[K"
44 #define ANSI_SET_COLUMN_N ESCAPE "[%dG"
45 #define ANSI_UP_N_ROWS ESCAPE "[%dA"
46 #define ANSI_DOWN_N_ROWS ESCAPE "[%dB"
48 #if LLDB_EDITLINE_USE_WCHAR
50 #define EditLineConstString(str) L##str
51 #define EditLineStringFormatSpec "%ls"
55 #define EditLineConstString(str) str
56 #define EditLineStringFormatSpec "%s"
58 // use #defines so wide version functions and structs will resolve to old
59 // versions for case of libedit not built with wide char support
60 #define history_w history
61 #define history_winit history_init
62 #define history_wend history_end
63 #define HistoryW History
64 #define HistEventW HistEvent
65 #define LineInfoW LineInfo
67 #define el_wgets el_gets
68 #define el_wgetc el_getc
69 #define el_wpush el_push
70 #define el_wparse el_parse
71 #define el_wset el_set
72 #define el_wget el_get
73 #define el_wline el_line
74 #define el_winsertstr el_insertstr
75 #define el_wdeletestr el_deletestr
77 #endif // #if LLDB_EDITLINE_USE_WCHAR
79 bool IsOnlySpaces(const EditLineStringType
&content
) {
80 for (wchar_t ch
: content
) {
81 if (ch
!= EditLineCharType(' '))
87 static size_t ColumnWidth(llvm::StringRef str
) {
88 return llvm::sys::locale::columnWidth(str
);
91 static int GetOperation(HistoryOperation op
) {
92 // The naming used by editline for the history operations is counter
93 // intuitive to how it's used in LLDB's editline implementation.
95 // - The H_LAST returns the oldest entry in the history.
97 // - The H_PREV operation returns the previous element in the history, which
98 // is newer than the current one.
100 // - The H_CURR returns the current entry in the history.
102 // - The H_NEXT operation returns the next element in the history, which is
103 // older than the current one.
105 // - The H_FIRST returns the most recent entry in the history.
107 // The naming of the enum entries match the semantic meaning.
109 case HistoryOperation::Oldest
:
111 case HistoryOperation::Older
:
113 case HistoryOperation::Current
:
115 case HistoryOperation::Newer
:
117 case HistoryOperation::Newest
:
120 llvm_unreachable("Fully covered switch!");
124 EditLineStringType
CombineLines(const std::vector
<EditLineStringType
> &lines
) {
125 EditLineStringStreamType combined_stream
;
126 for (EditLineStringType line
: lines
) {
127 combined_stream
<< line
.c_str() << "\n";
129 return combined_stream
.str();
132 std::vector
<EditLineStringType
> SplitLines(const EditLineStringType
&input
) {
133 std::vector
<EditLineStringType
> result
;
135 while (start
< input
.length()) {
136 size_t end
= input
.find('\n', start
);
137 if (end
== std::string::npos
) {
138 result
.push_back(input
.substr(start
));
141 result
.push_back(input
.substr(start
, end
- start
));
144 // Treat an empty history session as a single command of zero-length instead
145 // of returning an empty vector.
146 if (result
.empty()) {
147 result
.emplace_back();
152 EditLineStringType
FixIndentation(const EditLineStringType
&line
,
153 int indent_correction
) {
154 if (indent_correction
== 0)
156 if (indent_correction
< 0)
157 return line
.substr(-indent_correction
);
158 return EditLineStringType(indent_correction
, EditLineCharType(' ')) + line
;
161 int GetIndentation(const EditLineStringType
&line
) {
163 for (EditLineCharType ch
: line
) {
164 if (ch
!= EditLineCharType(' '))
171 bool IsInputPending(FILE *file
) {
172 // FIXME: This will be broken on Windows if we ever re-enable Editline. You
174 // on something that isn't a socket. This will have to be re-written to not
175 // use a FILE*, but instead use some kind of yet-to-be-created abstraction
176 // that select-like functionality on non-socket objects.
177 const int fd
= fileno(file
);
178 SelectHelper select_helper
;
179 select_helper
.SetTimeout(std::chrono::microseconds(0));
180 select_helper
.FDSetRead(fd
);
181 return select_helper
.Select().Success();
184 namespace lldb_private
{
185 namespace line_editor
{
186 typedef std::weak_ptr
<EditlineHistory
> EditlineHistoryWP
;
188 // EditlineHistory objects are sometimes shared between multiple Editline
189 // instances with the same program name.
191 class EditlineHistory
{
193 // Use static GetHistory() function to get a EditlineHistorySP to one of
195 EditlineHistory(const std::string
&prefix
, uint32_t size
, bool unique_entries
)
197 m_history
= history_winit();
198 history_w(m_history
, &m_event
, H_SETSIZE
, size
);
200 history_w(m_history
, &m_event
, H_SETUNIQUE
, 1);
203 const char *GetHistoryFilePath() {
204 // Compute the history path lazily.
205 if (m_path
.empty() && m_history
&& !m_prefix
.empty()) {
206 llvm::SmallString
<128> lldb_history_file
;
207 FileSystem::Instance().GetHomeDirectory(lldb_history_file
);
208 llvm::sys::path::append(lldb_history_file
, ".lldb");
210 // LLDB stores its history in ~/.lldb/. If for some reason this directory
211 // isn't writable or cannot be created, history won't be available.
212 if (!llvm::sys::fs::create_directory(lldb_history_file
)) {
213 #if LLDB_EDITLINE_USE_WCHAR
214 std::string filename
= m_prefix
+ "-widehistory";
216 std::string filename
= m_prefix
+ "-history";
218 llvm::sys::path::append(lldb_history_file
, filename
);
219 m_path
= std::string(lldb_history_file
.str());
226 return m_path
.c_str();
234 history_wend(m_history
);
239 static EditlineHistorySP
GetHistory(const std::string
&prefix
) {
240 typedef std::map
<std::string
, EditlineHistoryWP
> WeakHistoryMap
;
241 static std::recursive_mutex g_mutex
;
242 static WeakHistoryMap g_weak_map
;
243 std::lock_guard
<std::recursive_mutex
> guard(g_mutex
);
244 WeakHistoryMap::const_iterator pos
= g_weak_map
.find(prefix
);
245 EditlineHistorySP history_sp
;
246 if (pos
!= g_weak_map
.end()) {
247 history_sp
= pos
->second
.lock();
250 g_weak_map
.erase(pos
);
252 history_sp
.reset(new EditlineHistory(prefix
, 800, true));
253 g_weak_map
[prefix
] = history_sp
;
257 bool IsValid() const { return m_history
!= nullptr; }
259 HistoryW
*GetHistoryPtr() { return m_history
; }
261 void Enter(const EditLineCharType
*line_cstr
) {
263 history_w(m_history
, &m_event
, H_ENTER
, line_cstr
);
268 const char *path
= GetHistoryFilePath();
270 history_w(m_history
, &m_event
, H_LOAD
, path
);
279 const char *path
= GetHistoryFilePath();
281 history_w(m_history
, &m_event
, H_SAVE
, path
);
289 /// The history object.
290 HistoryW
*m_history
= nullptr;
291 /// The history event needed to contain all history events.
293 /// The prefix name (usually the editline program name) to use when
294 /// loading/saving history.
295 std::string m_prefix
;
296 /// Path to the history file.
302 // Editline private methods
304 void Editline::SetBaseLineNumber(int line_number
) {
305 m_base_line_number
= line_number
;
306 m_line_number_digits
=
307 std::max
<int>(3, std::to_string(line_number
).length() + 1);
310 std::string
Editline::PromptForIndex(int line_index
) {
311 bool use_line_numbers
= m_multiline_enabled
&& m_base_line_number
> 0;
312 std::string prompt
= m_set_prompt
;
313 if (use_line_numbers
&& prompt
.length() == 0)
315 std::string continuation_prompt
= prompt
;
316 if (m_set_continuation_prompt
.length() > 0) {
317 continuation_prompt
= m_set_continuation_prompt
;
318 // Ensure that both prompts are the same length through space padding
319 const size_t prompt_width
= ColumnWidth(prompt
);
320 const size_t cont_prompt_width
= ColumnWidth(continuation_prompt
);
321 const size_t padded_prompt_width
=
322 std::max(prompt_width
, cont_prompt_width
);
323 if (prompt_width
< padded_prompt_width
)
324 prompt
+= std::string(padded_prompt_width
- prompt_width
, ' ');
325 else if (cont_prompt_width
< padded_prompt_width
)
326 continuation_prompt
+=
327 std::string(padded_prompt_width
- cont_prompt_width
, ' ');
330 if (use_line_numbers
) {
331 StreamString prompt_stream
;
332 prompt_stream
.Printf(
333 "%*d%s", m_line_number_digits
, m_base_line_number
+ line_index
,
334 (line_index
== 0) ? prompt
.c_str() : continuation_prompt
.c_str());
335 return std::string(std::move(prompt_stream
.GetString()));
337 return (line_index
== 0) ? prompt
: continuation_prompt
;
340 void Editline::SetCurrentLine(int line_index
) {
341 m_current_line_index
= line_index
;
342 m_current_prompt
= PromptForIndex(line_index
);
345 size_t Editline::GetPromptWidth() { return ColumnWidth(PromptForIndex(0)); }
347 bool Editline::IsEmacs() {
349 el_get(m_editline
, EL_EDITOR
, &editor
);
350 return editor
[0] == 'e';
353 bool Editline::IsOnlySpaces() {
354 const LineInfoW
*info
= el_wline(m_editline
);
355 for (const EditLineCharType
*character
= info
->buffer
;
356 character
< info
->lastchar
; character
++) {
357 if (*character
!= ' ')
363 int Editline::GetLineIndexForLocation(CursorLocation location
, int cursor_row
) {
365 if (location
== CursorLocation::EditingPrompt
||
366 location
== CursorLocation::BlockEnd
||
367 location
== CursorLocation::EditingCursor
) {
368 for (unsigned index
= 0; index
< m_current_line_index
; index
++) {
369 line
+= CountRowsForLine(m_input_lines
[index
]);
371 if (location
== CursorLocation::EditingCursor
) {
373 } else if (location
== CursorLocation::BlockEnd
) {
374 for (unsigned index
= m_current_line_index
; index
< m_input_lines
.size();
376 line
+= CountRowsForLine(m_input_lines
[index
]);
384 void Editline::MoveCursor(CursorLocation from
, CursorLocation to
) {
385 const LineInfoW
*info
= el_wline(m_editline
);
386 int editline_cursor_position
=
387 (int)((info
->cursor
- info
->buffer
) + GetPromptWidth());
388 int editline_cursor_row
= editline_cursor_position
/ m_terminal_width
;
390 // Determine relative starting and ending lines
391 int fromLine
= GetLineIndexForLocation(from
, editline_cursor_row
);
392 int toLine
= GetLineIndexForLocation(to
, editline_cursor_row
);
393 if (toLine
!= fromLine
) {
394 fprintf(m_output_file
,
395 (toLine
> fromLine
) ? ANSI_DOWN_N_ROWS
: ANSI_UP_N_ROWS
,
396 std::abs(toLine
- fromLine
));
399 // Determine target column
401 if (to
== CursorLocation::EditingCursor
) {
403 editline_cursor_position
- (editline_cursor_row
* m_terminal_width
) + 1;
404 } else if (to
== CursorLocation::BlockEnd
&& !m_input_lines
.empty()) {
406 ((m_input_lines
[m_input_lines
.size() - 1].length() + GetPromptWidth()) %
410 fprintf(m_output_file
, ANSI_SET_COLUMN_N
, toColumn
);
413 void Editline::DisplayInput(int firstIndex
) {
414 fprintf(m_output_file
, ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW
, 1);
415 int line_count
= (int)m_input_lines
.size();
416 for (int index
= firstIndex
; index
< line_count
; index
++) {
417 fprintf(m_output_file
,
420 "%s" EditLineStringFormatSpec
" ",
421 m_prompt_ansi_prefix
.c_str(), PromptForIndex(index
).c_str(),
422 m_prompt_ansi_suffix
.c_str(), m_input_lines
[index
].c_str());
423 if (index
< line_count
- 1)
424 fprintf(m_output_file
, "\n");
428 int Editline::CountRowsForLine(const EditLineStringType
&content
) {
430 PromptForIndex(0); // Prompt width is constant during an edit session
431 int line_length
= (int)(content
.length() + ColumnWidth(prompt
));
432 return (line_length
/ m_terminal_width
) + 1;
435 void Editline::SaveEditedLine() {
436 const LineInfoW
*info
= el_wline(m_editline
);
437 m_input_lines
[m_current_line_index
] =
438 EditLineStringType(info
->buffer
, info
->lastchar
- info
->buffer
);
441 StringList
Editline::GetInputAsStringList(int line_count
) {
443 for (EditLineStringType line
: m_input_lines
) {
446 #if LLDB_EDITLINE_USE_WCHAR
448 llvm::convertWideToUTF8(line
, buffer
);
449 lines
.AppendString(buffer
);
451 lines
.AppendString(line
);
458 unsigned char Editline::RecallHistory(HistoryOperation op
) {
459 assert(op
== HistoryOperation::Older
|| op
== HistoryOperation::Newer
);
460 if (!m_history_sp
|| !m_history_sp
->IsValid())
463 HistoryW
*pHistory
= m_history_sp
->GetHistoryPtr();
464 HistEventW history_event
;
465 std::vector
<EditLineStringType
> new_input_lines
;
467 // Treat moving from the "live" entry differently
470 case HistoryOperation::Newer
:
471 return CC_ERROR
; // Can't go newer than the "live" entry
472 case HistoryOperation::Older
: {
473 if (history_w(pHistory
, &history_event
,
474 GetOperation(HistoryOperation::Newest
)) == -1)
476 // Save any edits to the "live" entry in case we return by moving forward
477 // in history (it would be more bash-like to save over any current entry,
478 // but libedit doesn't offer the ability to add entries anywhere except
481 m_live_history_lines
= m_input_lines
;
485 llvm_unreachable("unsupported history direction");
488 if (history_w(pHistory
, &history_event
, GetOperation(op
)) == -1) {
490 case HistoryOperation::Older
:
491 // Can't move earlier than the earliest entry.
493 case HistoryOperation::Newer
:
494 // Moving to newer-than-the-newest entry yields the "live" entry.
495 new_input_lines
= m_live_history_lines
;
496 m_in_history
= false;
499 llvm_unreachable("unsupported history direction");
504 // If we're pulling the lines from history, split them apart
506 new_input_lines
= SplitLines(history_event
.str
);
508 // Erase the current edit session and replace it with a new one
509 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockStart
);
510 m_input_lines
= new_input_lines
;
513 // Prepare to edit the last line when moving to previous entry, or the first
514 // line when moving to next entry
516 case HistoryOperation::Older
:
517 m_current_line_index
= (int)m_input_lines
.size() - 1;
519 case HistoryOperation::Newer
:
520 m_current_line_index
= 0;
523 llvm_unreachable("unsupported history direction");
525 SetCurrentLine(m_current_line_index
);
526 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingPrompt
);
530 int Editline::GetCharacter(EditLineGetCharType
*c
) {
531 const LineInfoW
*info
= el_wline(m_editline
);
533 // Paint a ANSI formatted version of the desired prompt over the version
534 // libedit draws. (will only be requested if colors are supported)
535 if (m_needs_prompt_repaint
) {
536 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
537 fprintf(m_output_file
,
541 m_prompt_ansi_prefix
.c_str(), Prompt(),
542 m_prompt_ansi_suffix
.c_str());
543 MoveCursor(CursorLocation::EditingPrompt
, CursorLocation::EditingCursor
);
544 m_needs_prompt_repaint
= false;
547 if (m_multiline_enabled
) {
548 // Detect when the number of rows used for this input line changes due to
550 int lineLength
= (int)((info
->lastchar
- info
->buffer
) + GetPromptWidth());
551 int new_line_rows
= (lineLength
/ m_terminal_width
) + 1;
552 if (m_current_line_rows
!= -1 && new_line_rows
!= m_current_line_rows
) {
553 // Respond by repainting the current state from this line on
554 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
556 DisplayInput(m_current_line_index
);
557 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingCursor
);
559 m_current_line_rows
= new_line_rows
;
562 // Read an actual character
564 lldb::ConnectionStatus status
= lldb::eConnectionStatusSuccess
;
567 if (m_terminal_size_has_changed
)
568 ApplyTerminalSizeChange();
570 // This mutex is locked by our caller (GetLine). Unlock it while we read a
571 // character (blocking operation), so we do not hold the mutex
572 // indefinitely. This gives a chance for someone to interrupt us. After
573 // Read returns, immediately lock the mutex again and check if we were
575 m_output_mutex
.unlock();
577 m_input_connection
.Read(&ch
, 1, std::nullopt
, status
, nullptr);
578 m_output_mutex
.lock();
579 if (m_editor_status
== EditorStatus::Interrupted
) {
580 while (read_count
> 0 && status
== lldb::eConnectionStatusSuccess
)
582 m_input_connection
.Read(&ch
, 1, std::nullopt
, status
, nullptr);
583 lldbassert(status
== lldb::eConnectionStatusInterrupted
);
588 if (CompleteCharacter(ch
, *c
))
592 case lldb::eConnectionStatusSuccess
: // Success
595 case lldb::eConnectionStatusInterrupted
:
596 llvm_unreachable("Interrupts should have been handled above.");
598 case lldb::eConnectionStatusError
: // Check GetError() for details
599 case lldb::eConnectionStatusTimedOut
: // Request timed out
600 case lldb::eConnectionStatusEndOfFile
: // End-of-file encountered
601 case lldb::eConnectionStatusNoConnection
: // No connection
602 case lldb::eConnectionStatusLostConnection
: // Lost connection while
603 // connected to a valid
605 m_editor_status
= EditorStatus::EndOfInput
;
612 const char *Editline::Prompt() {
613 if (!m_prompt_ansi_prefix
.empty() || !m_prompt_ansi_suffix
.empty())
614 m_needs_prompt_repaint
= true;
615 return m_current_prompt
.c_str();
618 unsigned char Editline::BreakLineCommand(int ch
) {
619 // Preserve any content beyond the cursor, truncate and save the current line
620 const LineInfoW
*info
= el_wline(m_editline
);
622 EditLineStringType(info
->buffer
, info
->cursor
- info
->buffer
);
623 auto new_line_fragment
=
624 EditLineStringType(info
->cursor
, info
->lastchar
- info
->cursor
);
625 m_input_lines
[m_current_line_index
] = current_line
;
627 // Ignore whitespace-only extra fragments when breaking a line
628 if (::IsOnlySpaces(new_line_fragment
))
629 new_line_fragment
= EditLineConstString("");
631 // Establish the new cursor position at the start of a line when inserting a
633 m_revert_cursor_index
= 0;
635 // Don't perform automatic formatting when pasting
636 if (!IsInputPending(m_input_file
)) {
637 // Apply smart indentation
638 if (m_fix_indentation_callback
) {
639 StringList lines
= GetInputAsStringList(m_current_line_index
+ 1);
640 #if LLDB_EDITLINE_USE_WCHAR
642 llvm::convertWideToUTF8(new_line_fragment
, buffer
);
643 lines
.AppendString(buffer
);
645 lines
.AppendString(new_line_fragment
);
648 int indent_correction
= m_fix_indentation_callback(this, lines
, 0);
649 new_line_fragment
= FixIndentation(new_line_fragment
, indent_correction
);
650 m_revert_cursor_index
= GetIndentation(new_line_fragment
);
654 // Insert the new line and repaint everything from the split line on down
655 m_input_lines
.insert(m_input_lines
.begin() + m_current_line_index
+ 1,
657 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
658 DisplayInput(m_current_line_index
);
660 // Reposition the cursor to the right line and prepare to edit the new line
661 SetCurrentLine(m_current_line_index
+ 1);
662 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingPrompt
);
666 unsigned char Editline::EndOrAddLineCommand(int ch
) {
667 // Don't perform end of input detection when pasting, always treat this as a
669 if (IsInputPending(m_input_file
)) {
670 return BreakLineCommand(ch
);
673 // Save any edits to this line
676 // If this is the end of the last line, consider whether to add a line
678 const LineInfoW
*info
= el_wline(m_editline
);
679 if (m_current_line_index
== m_input_lines
.size() - 1 &&
680 info
->cursor
== info
->lastchar
) {
681 if (m_is_input_complete_callback
) {
682 auto lines
= GetInputAsStringList();
683 if (!m_is_input_complete_callback(this, lines
)) {
684 return BreakLineCommand(ch
);
687 // The completion test is allowed to change the input lines when complete
688 m_input_lines
.clear();
689 for (unsigned index
= 0; index
< lines
.GetSize(); index
++) {
690 #if LLDB_EDITLINE_USE_WCHAR
691 std::wstring wbuffer
;
692 llvm::ConvertUTF8toWide(lines
[index
], wbuffer
);
693 m_input_lines
.insert(m_input_lines
.end(), wbuffer
);
695 m_input_lines
.insert(m_input_lines
.end(), lines
[index
]);
700 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockEnd
);
701 fprintf(m_output_file
, "\n");
702 m_editor_status
= EditorStatus::Complete
;
706 unsigned char Editline::DeleteNextCharCommand(int ch
) {
707 LineInfoW
*info
= const_cast<LineInfoW
*>(el_wline(m_editline
));
709 // Just delete the next character normally if possible
710 if (info
->cursor
< info
->lastchar
) {
712 el_deletestr(m_editline
, 1);
716 // Fail when at the end of the last line, except when ^D is pressed on the
717 // line is empty, in which case it is treated as EOF
718 if (m_current_line_index
== m_input_lines
.size() - 1) {
719 if (ch
== 4 && info
->buffer
== info
->lastchar
) {
720 fprintf(m_output_file
, "^D\n");
721 m_editor_status
= EditorStatus::EndOfInput
;
727 // Prepare to combine this line with the one below
728 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
730 // Insert the next line of text at the cursor and restore the cursor position
731 const EditLineCharType
*cursor
= info
->cursor
;
732 el_winsertstr(m_editline
, m_input_lines
[m_current_line_index
+ 1].c_str());
733 info
->cursor
= cursor
;
736 // Delete the extra line
737 m_input_lines
.erase(m_input_lines
.begin() + m_current_line_index
+ 1);
739 // Clear and repaint from this line on down
740 DisplayInput(m_current_line_index
);
741 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingCursor
);
745 unsigned char Editline::DeletePreviousCharCommand(int ch
) {
746 LineInfoW
*info
= const_cast<LineInfoW
*>(el_wline(m_editline
));
748 // Just delete the previous character normally when not at the start of a
750 if (info
->cursor
> info
->buffer
) {
751 el_deletestr(m_editline
, 1);
755 // No prior line and no prior character? Let the user know
756 if (m_current_line_index
== 0)
759 // No prior character, but prior line? Combine with the line above
761 SetCurrentLine(m_current_line_index
- 1);
762 auto priorLine
= m_input_lines
[m_current_line_index
];
763 m_input_lines
.erase(m_input_lines
.begin() + m_current_line_index
);
764 m_input_lines
[m_current_line_index
] =
765 priorLine
+ m_input_lines
[m_current_line_index
];
767 // Repaint from the new line down
768 fprintf(m_output_file
, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N
,
769 CountRowsForLine(priorLine
), 1);
770 DisplayInput(m_current_line_index
);
772 // Put the cursor back where libedit expects it to be before returning to
773 // editing by telling libedit about the newly inserted text
774 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingPrompt
);
775 el_winsertstr(m_editline
, priorLine
.c_str());
779 unsigned char Editline::PreviousLineCommand(int ch
) {
782 if (m_current_line_index
== 0) {
783 return RecallHistory(HistoryOperation::Older
);
786 // Start from a known location
787 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
789 // Treat moving up from a blank last line as a deletion of that line
790 if (m_current_line_index
== m_input_lines
.size() - 1 && IsOnlySpaces()) {
791 m_input_lines
.erase(m_input_lines
.begin() + m_current_line_index
);
792 fprintf(m_output_file
, ANSI_CLEAR_BELOW
);
795 SetCurrentLine(m_current_line_index
- 1);
796 fprintf(m_output_file
, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N
,
797 CountRowsForLine(m_input_lines
[m_current_line_index
]), 1);
801 unsigned char Editline::NextLineCommand(int ch
) {
804 // Handle attempts to move down from the last line
805 if (m_current_line_index
== m_input_lines
.size() - 1) {
806 // Don't add an extra line if the existing last line is blank, move through
808 if (IsOnlySpaces()) {
809 return RecallHistory(HistoryOperation::Newer
);
812 // Determine indentation for the new line
814 if (m_fix_indentation_callback
) {
815 StringList lines
= GetInputAsStringList();
816 lines
.AppendString("");
817 indentation
= m_fix_indentation_callback(this, lines
, 0);
819 m_input_lines
.insert(
821 EditLineStringType(indentation
, EditLineCharType(' ')));
824 // Move down past the current line using newlines to force scrolling if
826 SetCurrentLine(m_current_line_index
+ 1);
827 const LineInfoW
*info
= el_wline(m_editline
);
828 int cursor_position
= (int)((info
->cursor
- info
->buffer
) + GetPromptWidth());
829 int cursor_row
= cursor_position
/ m_terminal_width
;
830 for (int line_count
= 0; line_count
< m_current_line_rows
- cursor_row
;
832 fprintf(m_output_file
, "\n");
837 unsigned char Editline::PreviousHistoryCommand(int ch
) {
840 return RecallHistory(HistoryOperation::Older
);
843 unsigned char Editline::NextHistoryCommand(int ch
) {
846 return RecallHistory(HistoryOperation::Newer
);
849 unsigned char Editline::FixIndentationCommand(int ch
) {
850 if (!m_fix_indentation_callback
)
853 // Insert the character typed before proceeding
854 EditLineCharType inserted
[] = {(EditLineCharType
)ch
, 0};
855 el_winsertstr(m_editline
, inserted
);
856 LineInfoW
*info
= const_cast<LineInfoW
*>(el_wline(m_editline
));
857 int cursor_position
= info
->cursor
- info
->buffer
;
859 // Save the edits and determine the correct indentation level
861 StringList lines
= GetInputAsStringList(m_current_line_index
+ 1);
862 int indent_correction
=
863 m_fix_indentation_callback(this, lines
, cursor_position
);
865 // If it is already correct no special work is needed
866 if (indent_correction
== 0)
869 // Change the indentation level of the line
870 std::string currentLine
= lines
.GetStringAtIndex(m_current_line_index
);
871 if (indent_correction
> 0) {
872 currentLine
= currentLine
.insert(0, indent_correction
, ' ');
874 currentLine
= currentLine
.erase(0, -indent_correction
);
876 #if LLDB_EDITLINE_USE_WCHAR
877 std::wstring wbuffer
;
878 llvm::ConvertUTF8toWide(currentLine
, wbuffer
);
879 m_input_lines
[m_current_line_index
] = wbuffer
;
881 m_input_lines
[m_current_line_index
] = currentLine
;
884 // Update the display to reflect the change
885 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
886 DisplayInput(m_current_line_index
);
888 // Reposition the cursor back on the original line and prepare to restart
889 // editing with a new cursor position
890 SetCurrentLine(m_current_line_index
);
891 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingPrompt
);
892 m_revert_cursor_index
= cursor_position
+ indent_correction
;
896 unsigned char Editline::RevertLineCommand(int ch
) {
897 el_winsertstr(m_editline
, m_input_lines
[m_current_line_index
].c_str());
898 if (m_revert_cursor_index
>= 0) {
899 LineInfoW
*info
= const_cast<LineInfoW
*>(el_wline(m_editline
));
900 info
->cursor
= info
->buffer
+ m_revert_cursor_index
;
901 if (info
->cursor
> info
->lastchar
) {
902 info
->cursor
= info
->lastchar
;
904 m_revert_cursor_index
= -1;
909 unsigned char Editline::BufferStartCommand(int ch
) {
911 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockStart
);
913 m_revert_cursor_index
= 0;
917 unsigned char Editline::BufferEndCommand(int ch
) {
919 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockEnd
);
920 SetCurrentLine((int)m_input_lines
.size() - 1);
921 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingPrompt
);
925 /// Prints completions and their descriptions to the given file. Only the
926 /// completions in the interval [start, end) are printed.
928 PrintCompletion(FILE *output_file
,
929 llvm::ArrayRef
<CompletionResult::Completion
> results
,
930 size_t max_completion_length
, size_t max_length
,
931 std::optional
<size_t> max_height
= std::nullopt
) {
932 constexpr size_t ellipsis_length
= 3;
933 constexpr size_t padding_length
= 8;
934 constexpr size_t separator_length
= 4;
936 const size_t description_col
=
937 std::min(max_completion_length
+ padding_length
, max_length
);
939 size_t lines_printed
= 0;
940 size_t results_printed
= 0;
941 for (const CompletionResult::Completion
&c
: results
) {
942 if (max_height
&& lines_printed
>= *max_height
)
947 if (c
.GetCompletion().empty())
950 // Print the leading padding.
951 fprintf(output_file
, " ");
953 // Print the completion with trailing padding to the description column if
954 // that fits on the screen. Otherwise print whatever fits on the screen
955 // followed by ellipsis.
956 const size_t completion_length
= c
.GetCompletion().size();
957 if (padding_length
+ completion_length
< max_length
) {
958 fprintf(output_file
, "%-*s",
959 static_cast<int>(description_col
- padding_length
),
960 c
.GetCompletion().c_str());
962 // If the completion doesn't fit on the screen, print ellipsis and don't
963 // bother with the description.
964 fprintf(output_file
, "%.*s...\n",
965 static_cast<int>(max_length
- padding_length
- ellipsis_length
),
966 c
.GetCompletion().c_str());
971 // If we don't have a description, or we don't have enough space left to
972 // print the separator followed by the ellipsis, we're done.
973 if (c
.GetDescription().empty() ||
974 description_col
+ separator_length
+ ellipsis_length
>= max_length
) {
975 fprintf(output_file
, "\n");
980 // Print the separator.
981 fprintf(output_file
, " -- ");
983 // Descriptions can contain newlines. We want to print them below each
984 // other, aligned after the separator. For example, foo has a
985 // two-line description:
987 // foo -- Something that fits on the line.
988 // More information below.
990 // However, as soon as a line exceed the available screen width and
991 // print ellipsis, we don't print the next line. For example, foo has a
992 // three-line description:
994 // foo -- Something that fits on the line.
995 // Something much longer that doesn't fit...
997 // Because we had to print ellipsis on line two, we don't print the
1000 for (llvm::StringRef line
: llvm::split(c
.GetDescription(), '\n')) {
1003 if (max_height
&& lines_printed
>= *max_height
)
1006 fprintf(output_file
, "%*s",
1007 static_cast<int>(description_col
+ separator_length
), "");
1010 const size_t position
= description_col
+ separator_length
;
1011 const size_t description_length
= line
.size();
1012 if (position
+ description_length
< max_length
) {
1013 fprintf(output_file
, "%.*s\n", static_cast<int>(description_length
),
1017 fprintf(output_file
, "%.*s...\n",
1018 static_cast<int>(max_length
- position
- ellipsis_length
),
1025 return results_printed
;
1028 void Editline::DisplayCompletions(
1029 Editline
&editline
, llvm::ArrayRef
<CompletionResult::Completion
> results
) {
1030 assert(!results
.empty());
1032 fprintf(editline
.m_output_file
,
1033 "\n" ANSI_CLEAR_BELOW
"Available completions:\n");
1035 /// Account for the current line, the line showing "Available completions"
1036 /// before and the line saying "More" after.
1037 const size_t page_size
= editline
.GetTerminalHeight() - 3;
1042 std::max_element(results
.begin(), results
.end(), [](auto &c1
, auto &c2
) {
1043 return c1
.GetCompletion().size() < c2
.GetCompletion().size();
1046 const size_t max_len
= longest
->GetCompletion().size();
1049 while (cur_pos
< results
.size()) {
1051 PrintCompletion(editline
.m_output_file
, results
.slice(cur_pos
), max_len
,
1052 editline
.GetTerminalWidth(),
1053 all
? std::nullopt
: std::optional
<size_t>(page_size
));
1055 if (cur_pos
>= results
.size())
1058 fprintf(editline
.m_output_file
, "More (Y/n/a): ");
1059 // The type for the output and the type for the parameter are different,
1060 // to allow interoperability with older versions of libedit. The container
1061 // for the reply must be as wide as what our implementation is using,
1062 // but libedit may use a narrower type depending on the build
1064 EditLineGetCharType reply
= L
'n';
1065 int got_char
= el_wgetc(editline
.m_editline
,
1066 reinterpret_cast<EditLineCharType
*>(&reply
));
1067 // Check for a ^C or other interruption.
1068 if (editline
.m_editor_status
== EditorStatus::Interrupted
) {
1069 editline
.m_editor_status
= EditorStatus::Editing
;
1070 fprintf(editline
.m_output_file
, "^C\n");
1074 fprintf(editline
.m_output_file
, "\n");
1075 if (got_char
== -1 || reply
== 'n')
1082 unsigned char Editline::TabCommand(int ch
) {
1083 if (!m_completion_callback
)
1086 const LineInfo
*line_info
= el_line(m_editline
);
1088 llvm::StringRef
line(line_info
->buffer
,
1089 line_info
->lastchar
- line_info
->buffer
);
1090 unsigned cursor_index
= line_info
->cursor
- line_info
->buffer
;
1091 CompletionResult result
;
1092 CompletionRequest
request(line
, cursor_index
, result
);
1094 m_completion_callback(request
);
1096 llvm::ArrayRef
<CompletionResult::Completion
> results
= result
.GetResults();
1098 StringList completions
;
1099 result
.GetMatches(completions
);
1101 if (results
.size() == 0)
1104 if (results
.size() == 1) {
1105 CompletionResult::Completion completion
= results
.front();
1106 switch (completion
.GetMode()) {
1107 case CompletionMode::Normal
: {
1108 std::string to_add
= completion
.GetCompletion();
1109 // Terminate the current argument with a quote if it started with a quote.
1110 Args
&parsedLine
= request
.GetParsedLine();
1111 if (!parsedLine
.empty() && request
.GetCursorIndex() < parsedLine
.size() &&
1112 request
.GetParsedArg().IsQuoted()) {
1113 to_add
.push_back(request
.GetParsedArg().GetQuoteChar());
1115 to_add
.push_back(' ');
1116 el_deletestr(m_editline
, request
.GetCursorArgumentPrefix().size());
1117 el_insertstr(m_editline
, to_add
.c_str());
1118 // Clear all the autosuggestion parts if the only single space can be completed.
1120 return CC_REDISPLAY
;
1123 case CompletionMode::Partial
: {
1124 std::string to_add
= completion
.GetCompletion();
1125 to_add
= to_add
.substr(request
.GetCursorArgumentPrefix().size());
1126 el_insertstr(m_editline
, to_add
.c_str());
1129 case CompletionMode::RewriteLine
: {
1130 el_deletestr(m_editline
, line_info
->cursor
- line_info
->buffer
);
1131 el_insertstr(m_editline
, completion
.GetCompletion().c_str());
1135 return CC_REDISPLAY
;
1138 // If we get a longer match display that first.
1139 std::string longest_prefix
= completions
.LongestCommonPrefix();
1140 if (!longest_prefix
.empty())
1142 longest_prefix
.substr(request
.GetCursorArgumentPrefix().size());
1143 if (!longest_prefix
.empty()) {
1144 el_insertstr(m_editline
, longest_prefix
.c_str());
1145 return CC_REDISPLAY
;
1148 DisplayCompletions(*this, results
);
1151 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingCursor
);
1152 return CC_REDISPLAY
;
1155 unsigned char Editline::ApplyAutosuggestCommand(int ch
) {
1156 if (!m_suggestion_callback
) {
1157 return CC_REDISPLAY
;
1160 const LineInfo
*line_info
= el_line(m_editline
);
1161 llvm::StringRef
line(line_info
->buffer
,
1162 line_info
->lastchar
- line_info
->buffer
);
1164 if (std::optional
<std::string
> to_add
= m_suggestion_callback(line
))
1165 el_insertstr(m_editline
, to_add
->c_str());
1167 return CC_REDISPLAY
;
1170 unsigned char Editline::TypedCharacter(int ch
) {
1171 std::string typed
= std::string(1, ch
);
1172 el_insertstr(m_editline
, typed
.c_str());
1174 if (!m_suggestion_callback
) {
1175 return CC_REDISPLAY
;
1178 const LineInfo
*line_info
= el_line(m_editline
);
1179 llvm::StringRef
line(line_info
->buffer
,
1180 line_info
->lastchar
- line_info
->buffer
);
1182 if (std::optional
<std::string
> to_add
= m_suggestion_callback(line
)) {
1183 std::string to_add_color
=
1184 m_suggestion_ansi_prefix
+ to_add
.value() + m_suggestion_ansi_suffix
;
1185 fputs(typed
.c_str(), m_output_file
);
1186 fputs(to_add_color
.c_str(), m_output_file
);
1187 size_t new_autosuggestion_size
= line
.size() + to_add
->length();
1188 // Print spaces to hide any remains of a previous longer autosuggestion.
1189 if (new_autosuggestion_size
< m_previous_autosuggestion_size
) {
1190 size_t spaces_to_print
=
1191 m_previous_autosuggestion_size
- new_autosuggestion_size
;
1192 std::string spaces
= std::string(spaces_to_print
, ' ');
1193 fputs(spaces
.c_str(), m_output_file
);
1195 m_previous_autosuggestion_size
= new_autosuggestion_size
;
1197 int editline_cursor_position
=
1198 (int)((line_info
->cursor
- line_info
->buffer
) + GetPromptWidth());
1199 int editline_cursor_row
= editline_cursor_position
/ m_terminal_width
;
1201 editline_cursor_position
- (editline_cursor_row
* m_terminal_width
);
1202 fprintf(m_output_file
, ANSI_SET_COLUMN_N
, toColumn
);
1206 return CC_REDISPLAY
;
1209 void Editline::AddFunctionToEditLine(const EditLineCharType
*command
,
1210 const EditLineCharType
*helptext
,
1211 EditlineCommandCallbackType callbackFn
) {
1212 el_wset(m_editline
, EL_ADDFN
, command
, helptext
, callbackFn
);
1215 void Editline::SetEditLinePromptCallback(
1216 EditlinePromptCallbackType callbackFn
) {
1217 el_set(m_editline
, EL_PROMPT
, callbackFn
);
1220 void Editline::SetGetCharacterFunction(EditlineGetCharCallbackType callbackFn
) {
1221 el_wset(m_editline
, EL_GETCFN
, callbackFn
);
1224 void Editline::ConfigureEditor(bool multiline
) {
1225 if (m_editline
&& m_multiline_enabled
== multiline
)
1227 m_multiline_enabled
= multiline
;
1230 // Disable edit mode to stop the terminal from flushing all input during
1231 // the call to el_end() since we expect to have multiple editline instances
1233 el_set(m_editline
, EL_EDITMODE
, 0);
1238 el_init(m_editor_name
.c_str(), m_input_file
, m_output_file
, m_error_file
);
1239 ApplyTerminalSizeChange();
1241 if (m_history_sp
&& m_history_sp
->IsValid()) {
1242 if (!m_history_sp
->Load()) {
1243 fputs("Could not load history file\n.", m_output_file
);
1245 el_wset(m_editline
, EL_HIST
, history
, m_history_sp
->GetHistoryPtr());
1247 el_set(m_editline
, EL_CLIENTDATA
, this);
1248 el_set(m_editline
, EL_SIGNAL
, 0);
1249 el_set(m_editline
, EL_EDITOR
, "emacs");
1251 SetGetCharacterFunction([](EditLine
*editline
, EditLineGetCharType
*c
) {
1252 return Editline::InstanceFor(editline
)->GetCharacter(c
);
1255 SetEditLinePromptCallback([](EditLine
*editline
) {
1256 return Editline::InstanceFor(editline
)->Prompt();
1259 // Commands used for multiline support, registered whether or not they're
1261 AddFunctionToEditLine(
1262 EditLineConstString("lldb-break-line"),
1263 EditLineConstString("Insert a line break"),
1264 [](EditLine
*editline
, int ch
) {
1265 return Editline::InstanceFor(editline
)->BreakLineCommand(ch
);
1268 AddFunctionToEditLine(
1269 EditLineConstString("lldb-end-or-add-line"),
1270 EditLineConstString("End editing or continue when incomplete"),
1271 [](EditLine
*editline
, int ch
) {
1272 return Editline::InstanceFor(editline
)->EndOrAddLineCommand(ch
);
1274 AddFunctionToEditLine(
1275 EditLineConstString("lldb-delete-next-char"),
1276 EditLineConstString("Delete next character"),
1277 [](EditLine
*editline
, int ch
) {
1278 return Editline::InstanceFor(editline
)->DeleteNextCharCommand(ch
);
1280 AddFunctionToEditLine(
1281 EditLineConstString("lldb-delete-previous-char"),
1282 EditLineConstString("Delete previous character"),
1283 [](EditLine
*editline
, int ch
) {
1284 return Editline::InstanceFor(editline
)->DeletePreviousCharCommand(ch
);
1286 AddFunctionToEditLine(
1287 EditLineConstString("lldb-previous-line"),
1288 EditLineConstString("Move to previous line"),
1289 [](EditLine
*editline
, int ch
) {
1290 return Editline::InstanceFor(editline
)->PreviousLineCommand(ch
);
1292 AddFunctionToEditLine(
1293 EditLineConstString("lldb-next-line"),
1294 EditLineConstString("Move to next line"), [](EditLine
*editline
, int ch
) {
1295 return Editline::InstanceFor(editline
)->NextLineCommand(ch
);
1297 AddFunctionToEditLine(
1298 EditLineConstString("lldb-previous-history"),
1299 EditLineConstString("Move to previous history"),
1300 [](EditLine
*editline
, int ch
) {
1301 return Editline::InstanceFor(editline
)->PreviousHistoryCommand(ch
);
1303 AddFunctionToEditLine(
1304 EditLineConstString("lldb-next-history"),
1305 EditLineConstString("Move to next history"),
1306 [](EditLine
*editline
, int ch
) {
1307 return Editline::InstanceFor(editline
)->NextHistoryCommand(ch
);
1309 AddFunctionToEditLine(
1310 EditLineConstString("lldb-buffer-start"),
1311 EditLineConstString("Move to start of buffer"),
1312 [](EditLine
*editline
, int ch
) {
1313 return Editline::InstanceFor(editline
)->BufferStartCommand(ch
);
1315 AddFunctionToEditLine(
1316 EditLineConstString("lldb-buffer-end"),
1317 EditLineConstString("Move to end of buffer"),
1318 [](EditLine
*editline
, int ch
) {
1319 return Editline::InstanceFor(editline
)->BufferEndCommand(ch
);
1321 AddFunctionToEditLine(
1322 EditLineConstString("lldb-fix-indentation"),
1323 EditLineConstString("Fix line indentation"),
1324 [](EditLine
*editline
, int ch
) {
1325 return Editline::InstanceFor(editline
)->FixIndentationCommand(ch
);
1328 // Register the complete callback under two names for compatibility with
1329 // older clients using custom .editrc files (largely because libedit has a
1330 // bad bug where if you have a bind command that tries to bind to a function
1331 // name that doesn't exist, it can corrupt the heap and crash your process
1333 EditlineCommandCallbackType complete_callback
= [](EditLine
*editline
,
1335 return Editline::InstanceFor(editline
)->TabCommand(ch
);
1337 AddFunctionToEditLine(EditLineConstString("lldb-complete"),
1338 EditLineConstString("Invoke completion"),
1340 AddFunctionToEditLine(EditLineConstString("lldb_complete"),
1341 EditLineConstString("Invoke completion"),
1344 // General bindings we don't mind being overridden
1346 el_set(m_editline
, EL_BIND
, "^r", "em-inc-search-prev",
1347 NULL
); // Cycle through backwards search, entering string
1349 if (m_suggestion_callback
) {
1350 AddFunctionToEditLine(
1351 EditLineConstString("lldb-apply-complete"),
1352 EditLineConstString("Adopt autocompletion"),
1353 [](EditLine
*editline
, int ch
) {
1354 return Editline::InstanceFor(editline
)->ApplyAutosuggestCommand(ch
);
1357 el_set(m_editline
, EL_BIND
, "^f", "lldb-apply-complete",
1358 NULL
); // Apply a part that is suggested automatically
1360 AddFunctionToEditLine(
1361 EditLineConstString("lldb-typed-character"),
1362 EditLineConstString("Typed character"),
1363 [](EditLine
*editline
, int ch
) {
1364 return Editline::InstanceFor(editline
)->TypedCharacter(ch
);
1367 char bind_key
[2] = {0, 0};
1368 llvm::StringRef ascii_chars
=
1369 "abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXZY1234567890!\"#$%"
1370 "&'()*+,./:;<=>?@[]_`{|}~ ";
1371 for (char c
: ascii_chars
) {
1373 el_set(m_editline
, EL_BIND
, bind_key
, "lldb-typed-character", NULL
);
1375 el_set(m_editline
, EL_BIND
, "\\-", "lldb-typed-character", NULL
);
1376 el_set(m_editline
, EL_BIND
, "\\^", "lldb-typed-character", NULL
);
1377 el_set(m_editline
, EL_BIND
, "\\\\", "lldb-typed-character", NULL
);
1381 el_set(m_editline
, EL_BIND
, "^w", "ed-delete-prev-word",
1382 NULL
); // Delete previous word, behave like bash in emacs mode
1383 el_set(m_editline
, EL_BIND
, "\t", "lldb-complete",
1384 NULL
); // Bind TAB to auto complete
1386 // Allow ctrl-left-arrow and ctrl-right-arrow for navigation, behave like
1387 // bash in emacs mode.
1388 el_set(m_editline
, EL_BIND
, ESCAPE
"[1;5C", "em-next-word", NULL
);
1389 el_set(m_editline
, EL_BIND
, ESCAPE
"[1;5D", "ed-prev-word", NULL
);
1390 el_set(m_editline
, EL_BIND
, ESCAPE
"[5C", "em-next-word", NULL
);
1391 el_set(m_editline
, EL_BIND
, ESCAPE
"[5D", "ed-prev-word", NULL
);
1392 el_set(m_editline
, EL_BIND
, ESCAPE ESCAPE
"[C", "em-next-word", NULL
);
1393 el_set(m_editline
, EL_BIND
, ESCAPE ESCAPE
"[D", "ed-prev-word", NULL
);
1395 // Allow user-specific customization prior to registering bindings we
1396 // absolutely require
1397 el_source(m_editline
, nullptr);
1399 // Register an internal binding that external developers shouldn't use
1400 AddFunctionToEditLine(
1401 EditLineConstString("lldb-revert-line"),
1402 EditLineConstString("Revert line to saved state"),
1403 [](EditLine
*editline
, int ch
) {
1404 return Editline::InstanceFor(editline
)->RevertLineCommand(ch
);
1407 // Register keys that perform auto-indent correction
1408 if (m_fix_indentation_callback
&& m_fix_indentation_callback_chars
) {
1409 char bind_key
[2] = {0, 0};
1410 const char *indent_chars
= m_fix_indentation_callback_chars
;
1411 while (*indent_chars
) {
1412 bind_key
[0] = *indent_chars
;
1413 el_set(m_editline
, EL_BIND
, bind_key
, "lldb-fix-indentation", NULL
);
1418 // Multi-line editor bindings
1420 el_set(m_editline
, EL_BIND
, "\n", "lldb-end-or-add-line", NULL
);
1421 el_set(m_editline
, EL_BIND
, "\r", "lldb-end-or-add-line", NULL
);
1422 el_set(m_editline
, EL_BIND
, ESCAPE
"\n", "lldb-break-line", NULL
);
1423 el_set(m_editline
, EL_BIND
, ESCAPE
"\r", "lldb-break-line", NULL
);
1424 el_set(m_editline
, EL_BIND
, "^p", "lldb-previous-line", NULL
);
1425 el_set(m_editline
, EL_BIND
, "^n", "lldb-next-line", NULL
);
1426 el_set(m_editline
, EL_BIND
, "^?", "lldb-delete-previous-char", NULL
);
1427 el_set(m_editline
, EL_BIND
, "^d", "lldb-delete-next-char", NULL
);
1428 el_set(m_editline
, EL_BIND
, ESCAPE
"[3~", "lldb-delete-next-char", NULL
);
1429 el_set(m_editline
, EL_BIND
, ESCAPE
"[\\^", "lldb-revert-line", NULL
);
1431 // Editor-specific bindings
1433 el_set(m_editline
, EL_BIND
, ESCAPE
"<", "lldb-buffer-start", NULL
);
1434 el_set(m_editline
, EL_BIND
, ESCAPE
">", "lldb-buffer-end", NULL
);
1435 el_set(m_editline
, EL_BIND
, ESCAPE
"[A", "lldb-previous-line", NULL
);
1436 el_set(m_editline
, EL_BIND
, ESCAPE
"[B", "lldb-next-line", NULL
);
1437 el_set(m_editline
, EL_BIND
, ESCAPE ESCAPE
"[A", "lldb-previous-history",
1439 el_set(m_editline
, EL_BIND
, ESCAPE ESCAPE
"[B", "lldb-next-history",
1441 el_set(m_editline
, EL_BIND
, ESCAPE
"[1;3A", "lldb-previous-history",
1443 el_set(m_editline
, EL_BIND
, ESCAPE
"[1;3B", "lldb-next-history", NULL
);
1445 el_set(m_editline
, EL_BIND
, "^H", "lldb-delete-previous-char", NULL
);
1447 el_set(m_editline
, EL_BIND
, "-a", ESCAPE
"[A", "lldb-previous-line",
1449 el_set(m_editline
, EL_BIND
, "-a", ESCAPE
"[B", "lldb-next-line", NULL
);
1450 el_set(m_editline
, EL_BIND
, "-a", "x", "lldb-delete-next-char", NULL
);
1451 el_set(m_editline
, EL_BIND
, "-a", "^H", "lldb-delete-previous-char",
1453 el_set(m_editline
, EL_BIND
, "-a", "^?", "lldb-delete-previous-char",
1456 // Escape is absorbed exiting edit mode, so re-register important
1457 // sequences without the prefix
1458 el_set(m_editline
, EL_BIND
, "-a", "[A", "lldb-previous-line", NULL
);
1459 el_set(m_editline
, EL_BIND
, "-a", "[B", "lldb-next-line", NULL
);
1460 el_set(m_editline
, EL_BIND
, "-a", "[\\^", "lldb-revert-line", NULL
);
1465 // Editline public methods
1467 Editline
*Editline::InstanceFor(EditLine
*editline
) {
1469 el_get(editline
, EL_CLIENTDATA
, &editor
);
1473 Editline::Editline(const char *editline_name
, FILE *input_file
,
1474 FILE *output_file
, FILE *error_file
,
1475 std::recursive_mutex
&output_mutex
)
1476 : m_editor_status(EditorStatus::Complete
), m_input_file(input_file
),
1477 m_output_file(output_file
), m_error_file(error_file
),
1478 m_input_connection(fileno(input_file
), false),
1479 m_output_mutex(output_mutex
) {
1480 // Get a shared history instance
1481 m_editor_name
= (editline_name
== nullptr) ? "lldb-tmp" : editline_name
;
1482 m_history_sp
= EditlineHistory::GetHistory(m_editor_name
);
1485 Editline::~Editline() {
1487 // Disable edit mode to stop the terminal from flushing all input during
1488 // the call to el_end() since we expect to have multiple editline instances
1490 el_set(m_editline
, EL_EDITMODE
, 0);
1492 m_editline
= nullptr;
1495 // EditlineHistory objects are sometimes shared between multiple Editline
1496 // instances with the same program name. So just release our shared pointer
1497 // and if we are the last owner, it will save the history to the history save
1498 // file automatically.
1499 m_history_sp
.reset();
1502 void Editline::SetPrompt(const char *prompt
) {
1503 m_set_prompt
= prompt
== nullptr ? "" : prompt
;
1506 void Editline::SetContinuationPrompt(const char *continuation_prompt
) {
1507 m_set_continuation_prompt
=
1508 continuation_prompt
== nullptr ? "" : continuation_prompt
;
1511 void Editline::TerminalSizeChanged() { m_terminal_size_has_changed
= 1; }
1513 void Editline::ApplyTerminalSizeChange() {
1517 m_terminal_size_has_changed
= 0;
1518 el_resize(m_editline
);
1520 // This function is documenting as taking (const char *, void *) for the
1521 // vararg part, but in reality in was consuming arguments until the first
1522 // null pointer. This was fixed in libedit in April 2019
1523 // <http://mail-index.netbsd.org/source-changes/2019/04/26/msg105454.html>,
1524 // but we're keeping the workaround until a version with that fix is more
1525 // widely available.
1526 if (el_get(m_editline
, EL_GETTC
, "co", &columns
, nullptr) == 0) {
1527 m_terminal_width
= columns
;
1528 if (m_current_line_rows
!= -1) {
1529 const LineInfoW
*info
= el_wline(m_editline
);
1531 (int)((info
->lastchar
- info
->buffer
) + GetPromptWidth());
1532 m_current_line_rows
= (lineLength
/ columns
) + 1;
1535 m_terminal_width
= INT_MAX
;
1536 m_current_line_rows
= 1;
1540 if (el_get(m_editline
, EL_GETTC
, "li", &rows
, nullptr) == 0) {
1541 m_terminal_height
= rows
;
1543 m_terminal_height
= INT_MAX
;
1547 const char *Editline::GetPrompt() { return m_set_prompt
.c_str(); }
1549 uint32_t Editline::GetCurrentLine() { return m_current_line_index
; }
1551 bool Editline::Interrupt() {
1553 std::lock_guard
<std::recursive_mutex
> guard(m_output_mutex
);
1554 if (m_editor_status
== EditorStatus::Editing
) {
1555 fprintf(m_output_file
, "^C\n");
1556 result
= m_input_connection
.InterruptRead();
1558 m_editor_status
= EditorStatus::Interrupted
;
1562 bool Editline::Cancel() {
1564 std::lock_guard
<std::recursive_mutex
> guard(m_output_mutex
);
1565 if (m_editor_status
== EditorStatus::Editing
) {
1566 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockStart
);
1567 fprintf(m_output_file
, ANSI_CLEAR_BELOW
);
1568 result
= m_input_connection
.InterruptRead();
1570 m_editor_status
= EditorStatus::Interrupted
;
1574 bool Editline::GetLine(std::string
&line
, bool &interrupted
) {
1575 ConfigureEditor(false);
1576 m_input_lines
= std::vector
<EditLineStringType
>();
1577 m_input_lines
.insert(m_input_lines
.begin(), EditLineConstString(""));
1579 std::lock_guard
<std::recursive_mutex
> guard(m_output_mutex
);
1581 lldbassert(m_editor_status
!= EditorStatus::Editing
);
1582 if (m_editor_status
== EditorStatus::Interrupted
) {
1583 m_editor_status
= EditorStatus::Complete
;
1589 m_in_history
= false;
1590 m_editor_status
= EditorStatus::Editing
;
1591 m_revert_cursor_index
= -1;
1594 auto input
= el_wgets(m_editline
, &count
);
1596 interrupted
= m_editor_status
== EditorStatus::Interrupted
;
1598 if (input
== nullptr) {
1599 fprintf(m_output_file
, "\n");
1600 m_editor_status
= EditorStatus::EndOfInput
;
1602 m_history_sp
->Enter(input
);
1603 #if LLDB_EDITLINE_USE_WCHAR
1604 llvm::convertWideToUTF8(SplitLines(input
)[0], line
);
1606 line
= SplitLines(input
)[0];
1608 m_editor_status
= EditorStatus::Complete
;
1611 return m_editor_status
!= EditorStatus::EndOfInput
;
1614 bool Editline::GetLines(int first_line_number
, StringList
&lines
,
1615 bool &interrupted
) {
1616 ConfigureEditor(true);
1618 // Print the initial input lines, then move the cursor back up to the start
1620 SetBaseLineNumber(first_line_number
);
1621 m_input_lines
= std::vector
<EditLineStringType
>();
1622 m_input_lines
.insert(m_input_lines
.begin(), EditLineConstString(""));
1624 std::lock_guard
<std::recursive_mutex
> guard(m_output_mutex
);
1625 // Begin the line editing loop
1628 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::BlockStart
);
1629 m_editor_status
= EditorStatus::Editing
;
1630 m_in_history
= false;
1632 m_revert_cursor_index
= -1;
1633 while (m_editor_status
== EditorStatus::Editing
) {
1635 m_current_line_rows
= -1;
1636 el_wpush(m_editline
, EditLineConstString(
1637 "\x1b[^")); // Revert to the existing line content
1638 el_wgets(m_editline
, &count
);
1641 interrupted
= m_editor_status
== EditorStatus::Interrupted
;
1643 // Save the completed entry in history before returning. Don't save empty
1644 // input as that just clutters the command history.
1645 if (!m_input_lines
.empty())
1646 m_history_sp
->Enter(CombineLines(m_input_lines
).c_str());
1648 lines
= GetInputAsStringList();
1650 return m_editor_status
!= EditorStatus::EndOfInput
;
1653 void Editline::PrintAsync(Stream
*stream
, const char *s
, size_t len
) {
1654 std::lock_guard
<std::recursive_mutex
> guard(m_output_mutex
);
1655 if (m_editor_status
== EditorStatus::Editing
) {
1657 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockStart
);
1658 fprintf(m_output_file
, ANSI_CLEAR_BELOW
);
1660 stream
->Write(s
, len
);
1662 if (m_editor_status
== EditorStatus::Editing
) {
1664 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingCursor
);
1668 bool Editline::CompleteCharacter(char ch
, EditLineGetCharType
&out
) {
1669 #if !LLDB_EDITLINE_USE_WCHAR
1670 if (ch
== (char)EOF
)
1673 out
= (unsigned char)ch
;
1676 llvm::SmallString
<4> input
;
1678 input
.push_back(ch
);
1679 auto *cur_ptr
= reinterpret_cast<const llvm::UTF8
*>(input
.begin());
1680 auto *end_ptr
= reinterpret_cast<const llvm::UTF8
*>(input
.end());
1681 llvm::UTF32 code_point
= 0;
1682 llvm::ConversionResult cr
= llvm::convertUTF8Sequence(
1683 &cur_ptr
, end_ptr
, &code_point
, llvm::lenientConversion
);
1685 case llvm::conversionOK
:
1687 return out
!= (EditLineGetCharType
)WEOF
;
1688 case llvm::targetExhausted
:
1689 case llvm::sourceIllegal
:
1691 case llvm::sourceExhausted
:
1692 lldb::ConnectionStatus status
;
1693 size_t read_count
= m_input_connection
.Read(
1694 &ch
, 1, std::chrono::seconds(0), status
, nullptr);
1695 if (read_count
== 0)