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/Editline.h"
15 #include "lldb/Host/ConnectionFileDescriptor.h"
16 #include "lldb/Host/FileSystem.h"
17 #include "lldb/Host/Host.h"
18 #include "lldb/Utility/CompletionRequest.h"
19 #include "lldb/Utility/FileSpec.h"
20 #include "lldb/Utility/LLDBAssert.h"
21 #include "lldb/Utility/SelectHelper.h"
22 #include "lldb/Utility/Status.h"
23 #include "lldb/Utility/StreamString.h"
24 #include "lldb/Utility/StringList.h"
25 #include "lldb/Utility/Timeout.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 // Workaround for what looks like an OS X-specific issue, but other platforms
35 // may benefit from something similar if issues arise. The libedit library
36 // doesn't explicitly initialize the curses termcap library, which it gets away
37 // with until TERM is set to VT100 where it stumbles over an implementation
38 // assumption that may not exist on other platforms. The setupterm() function
39 // would normally require headers that don't work gracefully in this context,
40 // so the function declaration has been hoisted here.
41 #if defined(__APPLE__)
43 int setupterm(char *term
, int fildes
, int *errret
);
45 #define USE_SETUPTERM_WORKAROUND
48 // Editline uses careful cursor management to achieve the illusion of editing a
49 // multi-line block of text with a single line editor. Preserving this
50 // illusion requires fairly careful management of cursor state. Read and
51 // understand the relationship between DisplayInput(), MoveCursor(),
52 // SetCurrentLine(), and SaveEditedLine() before making changes.
54 /// https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
56 #define ANSI_CLEAR_BELOW ESCAPE "[J"
57 #define ANSI_CLEAR_RIGHT ESCAPE "[K"
58 #define ANSI_SET_COLUMN_N ESCAPE "[%dG"
59 #define ANSI_UP_N_ROWS ESCAPE "[%dA"
60 #define ANSI_DOWN_N_ROWS ESCAPE "[%dB"
62 #if LLDB_EDITLINE_USE_WCHAR
64 #define EditLineConstString(str) L##str
65 #define EditLineStringFormatSpec "%ls"
69 #define EditLineConstString(str) str
70 #define EditLineStringFormatSpec "%s"
72 // use #defines so wide version functions and structs will resolve to old
73 // versions for case of libedit not built with wide char support
74 #define history_w history
75 #define history_winit history_init
76 #define history_wend history_end
77 #define HistoryW History
78 #define HistEventW HistEvent
79 #define LineInfoW LineInfo
81 #define el_wgets el_gets
82 #define el_wgetc el_getc
83 #define el_wpush el_push
84 #define el_wparse el_parse
85 #define el_wset el_set
86 #define el_wget el_get
87 #define el_wline el_line
88 #define el_winsertstr el_insertstr
89 #define el_wdeletestr el_deletestr
91 #endif // #if LLDB_EDITLINE_USE_WCHAR
93 bool IsOnlySpaces(const EditLineStringType
&content
) {
94 for (wchar_t ch
: content
) {
95 if (ch
!= EditLineCharType(' '))
101 static size_t ColumnWidth(llvm::StringRef str
) {
102 return llvm::sys::locale::columnWidth(str
);
105 static int GetOperation(HistoryOperation op
) {
106 // The naming used by editline for the history operations is counter
107 // intuitive to how it's used in LLDB's editline implementation.
109 // - The H_LAST returns the oldest entry in the history.
111 // - The H_PREV operation returns the previous element in the history, which
112 // is newer than the current one.
114 // - The H_CURR returns the current entry in the history.
116 // - The H_NEXT operation returns the next element in the history, which is
117 // older than the current one.
119 // - The H_FIRST returns the most recent entry in the history.
121 // The naming of the enum entries match the semantic meaning.
123 case HistoryOperation::Oldest
:
125 case HistoryOperation::Older
:
127 case HistoryOperation::Current
:
129 case HistoryOperation::Newer
:
131 case HistoryOperation::Newest
:
134 llvm_unreachable("Fully covered switch!");
138 EditLineStringType
CombineLines(const std::vector
<EditLineStringType
> &lines
) {
139 EditLineStringStreamType combined_stream
;
140 for (EditLineStringType line
: lines
) {
141 combined_stream
<< line
.c_str() << "\n";
143 return combined_stream
.str();
146 std::vector
<EditLineStringType
> SplitLines(const EditLineStringType
&input
) {
147 std::vector
<EditLineStringType
> result
;
149 while (start
< input
.length()) {
150 size_t end
= input
.find('\n', start
);
151 if (end
== std::string::npos
) {
152 result
.push_back(input
.substr(start
));
155 result
.push_back(input
.substr(start
, end
- start
));
158 // Treat an empty history session as a single command of zero-length instead
159 // of returning an empty vector.
160 if (result
.empty()) {
161 result
.emplace_back();
166 EditLineStringType
FixIndentation(const EditLineStringType
&line
,
167 int indent_correction
) {
168 if (indent_correction
== 0)
170 if (indent_correction
< 0)
171 return line
.substr(-indent_correction
);
172 return EditLineStringType(indent_correction
, EditLineCharType(' ')) + line
;
175 int GetIndentation(const EditLineStringType
&line
) {
177 for (EditLineCharType ch
: line
) {
178 if (ch
!= EditLineCharType(' '))
185 bool IsInputPending(FILE *file
) {
186 // FIXME: This will be broken on Windows if we ever re-enable Editline. You
188 // on something that isn't a socket. This will have to be re-written to not
189 // use a FILE*, but instead use some kind of yet-to-be-created abstraction
190 // that select-like functionality on non-socket objects.
191 const int fd
= fileno(file
);
192 SelectHelper select_helper
;
193 select_helper
.SetTimeout(std::chrono::microseconds(0));
194 select_helper
.FDSetRead(fd
);
195 return select_helper
.Select().Success();
198 namespace lldb_private
{
199 namespace line_editor
{
200 typedef std::weak_ptr
<EditlineHistory
> EditlineHistoryWP
;
202 // EditlineHistory objects are sometimes shared between multiple Editline
203 // instances with the same program name.
205 class EditlineHistory
{
207 // Use static GetHistory() function to get a EditlineHistorySP to one of
209 EditlineHistory(const std::string
&prefix
, uint32_t size
, bool unique_entries
)
211 m_history
= history_winit();
212 history_w(m_history
, &m_event
, H_SETSIZE
, size
);
214 history_w(m_history
, &m_event
, H_SETUNIQUE
, 1);
217 const char *GetHistoryFilePath() {
218 // Compute the history path lazily.
219 if (m_path
.empty() && m_history
&& !m_prefix
.empty()) {
220 llvm::SmallString
<128> lldb_history_file
;
221 FileSystem::Instance().GetHomeDirectory(lldb_history_file
);
222 llvm::sys::path::append(lldb_history_file
, ".lldb");
224 // LLDB stores its history in ~/.lldb/. If for some reason this directory
225 // isn't writable or cannot be created, history won't be available.
226 if (!llvm::sys::fs::create_directory(lldb_history_file
)) {
227 #if LLDB_EDITLINE_USE_WCHAR
228 std::string filename
= m_prefix
+ "-widehistory";
230 std::string filename
= m_prefix
+ "-history";
232 llvm::sys::path::append(lldb_history_file
, filename
);
233 m_path
= std::string(lldb_history_file
.str());
240 return m_path
.c_str();
248 history_wend(m_history
);
253 static EditlineHistorySP
GetHistory(const std::string
&prefix
) {
254 typedef std::map
<std::string
, EditlineHistoryWP
> WeakHistoryMap
;
255 static std::recursive_mutex g_mutex
;
256 static WeakHistoryMap g_weak_map
;
257 std::lock_guard
<std::recursive_mutex
> guard(g_mutex
);
258 WeakHistoryMap::const_iterator pos
= g_weak_map
.find(prefix
);
259 EditlineHistorySP history_sp
;
260 if (pos
!= g_weak_map
.end()) {
261 history_sp
= pos
->second
.lock();
264 g_weak_map
.erase(pos
);
266 history_sp
.reset(new EditlineHistory(prefix
, 800, true));
267 g_weak_map
[prefix
] = history_sp
;
271 bool IsValid() const { return m_history
!= nullptr; }
273 HistoryW
*GetHistoryPtr() { return m_history
; }
275 void Enter(const EditLineCharType
*line_cstr
) {
277 history_w(m_history
, &m_event
, H_ENTER
, line_cstr
);
282 const char *path
= GetHistoryFilePath();
284 history_w(m_history
, &m_event
, H_LOAD
, path
);
293 const char *path
= GetHistoryFilePath();
295 history_w(m_history
, &m_event
, H_SAVE
, path
);
303 /// The history object.
304 HistoryW
*m_history
= nullptr;
305 /// The history event needed to contain all history events.
307 /// The prefix name (usually the editline program name) to use when
308 /// loading/saving history.
309 std::string m_prefix
;
310 /// Path to the history file.
316 // Editline private methods
318 void Editline::SetBaseLineNumber(int line_number
) {
319 m_base_line_number
= line_number
;
320 m_line_number_digits
=
321 std::max
<int>(3, std::to_string(line_number
).length() + 1);
324 std::string
Editline::PromptForIndex(int line_index
) {
325 bool use_line_numbers
= m_multiline_enabled
&& m_base_line_number
> 0;
326 std::string prompt
= m_set_prompt
;
327 if (use_line_numbers
&& prompt
.length() == 0)
329 std::string continuation_prompt
= prompt
;
330 if (m_set_continuation_prompt
.length() > 0) {
331 continuation_prompt
= m_set_continuation_prompt
;
332 // Ensure that both prompts are the same length through space padding
333 const size_t prompt_width
= ColumnWidth(prompt
);
334 const size_t cont_prompt_width
= ColumnWidth(continuation_prompt
);
335 const size_t padded_prompt_width
=
336 std::max(prompt_width
, cont_prompt_width
);
337 if (prompt_width
< padded_prompt_width
)
338 prompt
+= std::string(padded_prompt_width
- prompt_width
, ' ');
339 else if (cont_prompt_width
< padded_prompt_width
)
340 continuation_prompt
+=
341 std::string(padded_prompt_width
- cont_prompt_width
, ' ');
344 if (use_line_numbers
) {
345 StreamString prompt_stream
;
346 prompt_stream
.Printf(
347 "%*d%s", m_line_number_digits
, m_base_line_number
+ line_index
,
348 (line_index
== 0) ? prompt
.c_str() : continuation_prompt
.c_str());
349 return std::string(std::move(prompt_stream
.GetString()));
351 return (line_index
== 0) ? prompt
: continuation_prompt
;
354 void Editline::SetCurrentLine(int line_index
) {
355 m_current_line_index
= line_index
;
356 m_current_prompt
= PromptForIndex(line_index
);
359 size_t Editline::GetPromptWidth() { return ColumnWidth(PromptForIndex(0)); }
361 bool Editline::IsEmacs() {
363 el_get(m_editline
, EL_EDITOR
, &editor
);
364 return editor
[0] == 'e';
367 bool Editline::IsOnlySpaces() {
368 const LineInfoW
*info
= el_wline(m_editline
);
369 for (const EditLineCharType
*character
= info
->buffer
;
370 character
< info
->lastchar
; character
++) {
371 if (*character
!= ' ')
377 int Editline::GetLineIndexForLocation(CursorLocation location
, int cursor_row
) {
379 if (location
== CursorLocation::EditingPrompt
||
380 location
== CursorLocation::BlockEnd
||
381 location
== CursorLocation::EditingCursor
) {
382 for (unsigned index
= 0; index
< m_current_line_index
; index
++) {
383 line
+= CountRowsForLine(m_input_lines
[index
]);
385 if (location
== CursorLocation::EditingCursor
) {
387 } else if (location
== CursorLocation::BlockEnd
) {
388 for (unsigned index
= m_current_line_index
; index
< m_input_lines
.size();
390 line
+= CountRowsForLine(m_input_lines
[index
]);
398 void Editline::MoveCursor(CursorLocation from
, CursorLocation to
) {
399 const LineInfoW
*info
= el_wline(m_editline
);
400 int editline_cursor_position
=
401 (int)((info
->cursor
- info
->buffer
) + GetPromptWidth());
402 int editline_cursor_row
= editline_cursor_position
/ m_terminal_width
;
404 // Determine relative starting and ending lines
405 int fromLine
= GetLineIndexForLocation(from
, editline_cursor_row
);
406 int toLine
= GetLineIndexForLocation(to
, editline_cursor_row
);
407 if (toLine
!= fromLine
) {
408 fprintf(m_output_file
,
409 (toLine
> fromLine
) ? ANSI_DOWN_N_ROWS
: ANSI_UP_N_ROWS
,
410 std::abs(toLine
- fromLine
));
413 // Determine target column
415 if (to
== CursorLocation::EditingCursor
) {
417 editline_cursor_position
- (editline_cursor_row
* m_terminal_width
) + 1;
418 } else if (to
== CursorLocation::BlockEnd
&& !m_input_lines
.empty()) {
420 ((m_input_lines
[m_input_lines
.size() - 1].length() + GetPromptWidth()) %
424 fprintf(m_output_file
, ANSI_SET_COLUMN_N
, toColumn
);
427 void Editline::DisplayInput(int firstIndex
) {
428 fprintf(m_output_file
, ANSI_SET_COLUMN_N ANSI_CLEAR_BELOW
, 1);
429 int line_count
= (int)m_input_lines
.size();
430 for (int index
= firstIndex
; index
< line_count
; index
++) {
431 fprintf(m_output_file
,
434 "%s" EditLineStringFormatSpec
" ",
435 m_prompt_ansi_prefix
.c_str(), PromptForIndex(index
).c_str(),
436 m_prompt_ansi_suffix
.c_str(), m_input_lines
[index
].c_str());
437 if (index
< line_count
- 1)
438 fprintf(m_output_file
, "\n");
442 int Editline::CountRowsForLine(const EditLineStringType
&content
) {
444 PromptForIndex(0); // Prompt width is constant during an edit session
445 int line_length
= (int)(content
.length() + ColumnWidth(prompt
));
446 return (line_length
/ m_terminal_width
) + 1;
449 void Editline::SaveEditedLine() {
450 const LineInfoW
*info
= el_wline(m_editline
);
451 m_input_lines
[m_current_line_index
] =
452 EditLineStringType(info
->buffer
, info
->lastchar
- info
->buffer
);
455 StringList
Editline::GetInputAsStringList(int line_count
) {
457 for (EditLineStringType line
: m_input_lines
) {
460 #if LLDB_EDITLINE_USE_WCHAR
461 lines
.AppendString(m_utf8conv
.to_bytes(line
));
463 lines
.AppendString(line
);
470 unsigned char Editline::RecallHistory(HistoryOperation op
) {
471 assert(op
== HistoryOperation::Older
|| op
== HistoryOperation::Newer
);
472 if (!m_history_sp
|| !m_history_sp
->IsValid())
475 HistoryW
*pHistory
= m_history_sp
->GetHistoryPtr();
476 HistEventW history_event
;
477 std::vector
<EditLineStringType
> new_input_lines
;
479 // Treat moving from the "live" entry differently
482 case HistoryOperation::Newer
:
483 return CC_ERROR
; // Can't go newer than the "live" entry
484 case HistoryOperation::Older
: {
485 if (history_w(pHistory
, &history_event
,
486 GetOperation(HistoryOperation::Newest
)) == -1)
488 // Save any edits to the "live" entry in case we return by moving forward
489 // in history (it would be more bash-like to save over any current entry,
490 // but libedit doesn't offer the ability to add entries anywhere except
493 m_live_history_lines
= m_input_lines
;
497 llvm_unreachable("unsupported history direction");
500 if (history_w(pHistory
, &history_event
, GetOperation(op
)) == -1) {
502 case HistoryOperation::Older
:
503 // Can't move earlier than the earliest entry.
505 case HistoryOperation::Newer
:
506 // Moving to newer-than-the-newest entry yields the "live" entry.
507 new_input_lines
= m_live_history_lines
;
508 m_in_history
= false;
511 llvm_unreachable("unsupported history direction");
516 // If we're pulling the lines from history, split them apart
518 new_input_lines
= SplitLines(history_event
.str
);
520 // Erase the current edit session and replace it with a new one
521 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockStart
);
522 m_input_lines
= new_input_lines
;
525 // Prepare to edit the last line when moving to previous entry, or the first
526 // line when moving to next entry
528 case HistoryOperation::Older
:
529 m_current_line_index
= (int)m_input_lines
.size() - 1;
531 case HistoryOperation::Newer
:
532 m_current_line_index
= 0;
535 llvm_unreachable("unsupported history direction");
537 SetCurrentLine(m_current_line_index
);
538 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingPrompt
);
542 int Editline::GetCharacter(EditLineGetCharType
*c
) {
543 const LineInfoW
*info
= el_wline(m_editline
);
545 // Paint a ANSI formatted version of the desired prompt over the version
546 // libedit draws. (will only be requested if colors are supported)
547 if (m_needs_prompt_repaint
) {
548 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
549 fprintf(m_output_file
,
553 m_prompt_ansi_prefix
.c_str(), Prompt(),
554 m_prompt_ansi_suffix
.c_str());
555 MoveCursor(CursorLocation::EditingPrompt
, CursorLocation::EditingCursor
);
556 m_needs_prompt_repaint
= false;
559 if (m_multiline_enabled
) {
560 // Detect when the number of rows used for this input line changes due to
562 int lineLength
= (int)((info
->lastchar
- info
->buffer
) + GetPromptWidth());
563 int new_line_rows
= (lineLength
/ m_terminal_width
) + 1;
564 if (m_current_line_rows
!= -1 && new_line_rows
!= m_current_line_rows
) {
565 // Respond by repainting the current state from this line on
566 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
568 DisplayInput(m_current_line_index
);
569 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingCursor
);
571 m_current_line_rows
= new_line_rows
;
574 // Read an actual character
576 lldb::ConnectionStatus status
= lldb::eConnectionStatusSuccess
;
579 if (m_terminal_size_has_changed
)
580 ApplyTerminalSizeChange();
582 // This mutex is locked by our caller (GetLine). Unlock it while we read a
583 // character (blocking operation), so we do not hold the mutex
584 // indefinitely. This gives a chance for someone to interrupt us. After
585 // Read returns, immediately lock the mutex again and check if we were
587 m_output_mutex
.unlock();
589 m_input_connection
.Read(&ch
, 1, std::nullopt
, status
, nullptr);
590 m_output_mutex
.lock();
591 if (m_editor_status
== EditorStatus::Interrupted
) {
592 while (read_count
> 0 && status
== lldb::eConnectionStatusSuccess
)
594 m_input_connection
.Read(&ch
, 1, std::nullopt
, status
, nullptr);
595 lldbassert(status
== lldb::eConnectionStatusInterrupted
);
600 if (CompleteCharacter(ch
, *c
))
604 case lldb::eConnectionStatusSuccess
: // Success
607 case lldb::eConnectionStatusInterrupted
:
608 llvm_unreachable("Interrupts should have been handled above.");
610 case lldb::eConnectionStatusError
: // Check GetError() for details
611 case lldb::eConnectionStatusTimedOut
: // Request timed out
612 case lldb::eConnectionStatusEndOfFile
: // End-of-file encountered
613 case lldb::eConnectionStatusNoConnection
: // No connection
614 case lldb::eConnectionStatusLostConnection
: // Lost connection while
615 // connected to a valid
617 m_editor_status
= EditorStatus::EndOfInput
;
624 const char *Editline::Prompt() {
625 if (!m_prompt_ansi_prefix
.empty() || !m_prompt_ansi_suffix
.empty())
626 m_needs_prompt_repaint
= true;
627 return m_current_prompt
.c_str();
630 unsigned char Editline::BreakLineCommand(int ch
) {
631 // Preserve any content beyond the cursor, truncate and save the current line
632 const LineInfoW
*info
= el_wline(m_editline
);
634 EditLineStringType(info
->buffer
, info
->cursor
- info
->buffer
);
635 auto new_line_fragment
=
636 EditLineStringType(info
->cursor
, info
->lastchar
- info
->cursor
);
637 m_input_lines
[m_current_line_index
] = current_line
;
639 // Ignore whitespace-only extra fragments when breaking a line
640 if (::IsOnlySpaces(new_line_fragment
))
641 new_line_fragment
= EditLineConstString("");
643 // Establish the new cursor position at the start of a line when inserting a
645 m_revert_cursor_index
= 0;
647 // Don't perform automatic formatting when pasting
648 if (!IsInputPending(m_input_file
)) {
649 // Apply smart indentation
650 if (m_fix_indentation_callback
) {
651 StringList lines
= GetInputAsStringList(m_current_line_index
+ 1);
652 #if LLDB_EDITLINE_USE_WCHAR
653 lines
.AppendString(m_utf8conv
.to_bytes(new_line_fragment
));
655 lines
.AppendString(new_line_fragment
);
658 int indent_correction
= m_fix_indentation_callback(this, lines
, 0);
659 new_line_fragment
= FixIndentation(new_line_fragment
, indent_correction
);
660 m_revert_cursor_index
= GetIndentation(new_line_fragment
);
664 // Insert the new line and repaint everything from the split line on down
665 m_input_lines
.insert(m_input_lines
.begin() + m_current_line_index
+ 1,
667 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
668 DisplayInput(m_current_line_index
);
670 // Reposition the cursor to the right line and prepare to edit the new line
671 SetCurrentLine(m_current_line_index
+ 1);
672 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingPrompt
);
676 unsigned char Editline::EndOrAddLineCommand(int ch
) {
677 // Don't perform end of input detection when pasting, always treat this as a
679 if (IsInputPending(m_input_file
)) {
680 return BreakLineCommand(ch
);
683 // Save any edits to this line
686 // If this is the end of the last line, consider whether to add a line
688 const LineInfoW
*info
= el_wline(m_editline
);
689 if (m_current_line_index
== m_input_lines
.size() - 1 &&
690 info
->cursor
== info
->lastchar
) {
691 if (m_is_input_complete_callback
) {
692 auto lines
= GetInputAsStringList();
693 if (!m_is_input_complete_callback(this, lines
)) {
694 return BreakLineCommand(ch
);
697 // The completion test is allowed to change the input lines when complete
698 m_input_lines
.clear();
699 for (unsigned index
= 0; index
< lines
.GetSize(); index
++) {
700 #if LLDB_EDITLINE_USE_WCHAR
701 m_input_lines
.insert(m_input_lines
.end(),
702 m_utf8conv
.from_bytes(lines
[index
]));
704 m_input_lines
.insert(m_input_lines
.end(), lines
[index
]);
709 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockEnd
);
710 fprintf(m_output_file
, "\n");
711 m_editor_status
= EditorStatus::Complete
;
715 unsigned char Editline::DeleteNextCharCommand(int ch
) {
716 LineInfoW
*info
= const_cast<LineInfoW
*>(el_wline(m_editline
));
718 // Just delete the next character normally if possible
719 if (info
->cursor
< info
->lastchar
) {
721 el_deletestr(m_editline
, 1);
725 // Fail when at the end of the last line, except when ^D is pressed on the
726 // line is empty, in which case it is treated as EOF
727 if (m_current_line_index
== m_input_lines
.size() - 1) {
728 if (ch
== 4 && info
->buffer
== info
->lastchar
) {
729 fprintf(m_output_file
, "^D\n");
730 m_editor_status
= EditorStatus::EndOfInput
;
736 // Prepare to combine this line with the one below
737 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
739 // Insert the next line of text at the cursor and restore the cursor position
740 const EditLineCharType
*cursor
= info
->cursor
;
741 el_winsertstr(m_editline
, m_input_lines
[m_current_line_index
+ 1].c_str());
742 info
->cursor
= cursor
;
745 // Delete the extra line
746 m_input_lines
.erase(m_input_lines
.begin() + m_current_line_index
+ 1);
748 // Clear and repaint from this line on down
749 DisplayInput(m_current_line_index
);
750 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingCursor
);
754 unsigned char Editline::DeletePreviousCharCommand(int ch
) {
755 LineInfoW
*info
= const_cast<LineInfoW
*>(el_wline(m_editline
));
757 // Just delete the previous character normally when not at the start of a
759 if (info
->cursor
> info
->buffer
) {
760 el_deletestr(m_editline
, 1);
764 // No prior line and no prior character? Let the user know
765 if (m_current_line_index
== 0)
768 // No prior character, but prior line? Combine with the line above
770 SetCurrentLine(m_current_line_index
- 1);
771 auto priorLine
= m_input_lines
[m_current_line_index
];
772 m_input_lines
.erase(m_input_lines
.begin() + m_current_line_index
);
773 m_input_lines
[m_current_line_index
] =
774 priorLine
+ m_input_lines
[m_current_line_index
];
776 // Repaint from the new line down
777 fprintf(m_output_file
, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N
,
778 CountRowsForLine(priorLine
), 1);
779 DisplayInput(m_current_line_index
);
781 // Put the cursor back where libedit expects it to be before returning to
782 // editing by telling libedit about the newly inserted text
783 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingPrompt
);
784 el_winsertstr(m_editline
, priorLine
.c_str());
788 unsigned char Editline::PreviousLineCommand(int ch
) {
791 if (m_current_line_index
== 0) {
792 return RecallHistory(HistoryOperation::Older
);
795 // Start from a known location
796 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
798 // Treat moving up from a blank last line as a deletion of that line
799 if (m_current_line_index
== m_input_lines
.size() - 1 && IsOnlySpaces()) {
800 m_input_lines
.erase(m_input_lines
.begin() + m_current_line_index
);
801 fprintf(m_output_file
, ANSI_CLEAR_BELOW
);
804 SetCurrentLine(m_current_line_index
- 1);
805 fprintf(m_output_file
, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N
,
806 CountRowsForLine(m_input_lines
[m_current_line_index
]), 1);
810 unsigned char Editline::NextLineCommand(int ch
) {
813 // Handle attempts to move down from the last line
814 if (m_current_line_index
== m_input_lines
.size() - 1) {
815 // Don't add an extra line if the existing last line is blank, move through
817 if (IsOnlySpaces()) {
818 return RecallHistory(HistoryOperation::Newer
);
821 // Determine indentation for the new line
823 if (m_fix_indentation_callback
) {
824 StringList lines
= GetInputAsStringList();
825 lines
.AppendString("");
826 indentation
= m_fix_indentation_callback(this, lines
, 0);
828 m_input_lines
.insert(
830 EditLineStringType(indentation
, EditLineCharType(' ')));
833 // Move down past the current line using newlines to force scrolling if
835 SetCurrentLine(m_current_line_index
+ 1);
836 const LineInfoW
*info
= el_wline(m_editline
);
837 int cursor_position
= (int)((info
->cursor
- info
->buffer
) + GetPromptWidth());
838 int cursor_row
= cursor_position
/ m_terminal_width
;
839 for (int line_count
= 0; line_count
< m_current_line_rows
- cursor_row
;
841 fprintf(m_output_file
, "\n");
846 unsigned char Editline::PreviousHistoryCommand(int ch
) {
849 return RecallHistory(HistoryOperation::Older
);
852 unsigned char Editline::NextHistoryCommand(int ch
) {
855 return RecallHistory(HistoryOperation::Newer
);
858 unsigned char Editline::FixIndentationCommand(int ch
) {
859 if (!m_fix_indentation_callback
)
862 // Insert the character typed before proceeding
863 EditLineCharType inserted
[] = {(EditLineCharType
)ch
, 0};
864 el_winsertstr(m_editline
, inserted
);
865 LineInfoW
*info
= const_cast<LineInfoW
*>(el_wline(m_editline
));
866 int cursor_position
= info
->cursor
- info
->buffer
;
868 // Save the edits and determine the correct indentation level
870 StringList lines
= GetInputAsStringList(m_current_line_index
+ 1);
871 int indent_correction
=
872 m_fix_indentation_callback(this, lines
, cursor_position
);
874 // If it is already correct no special work is needed
875 if (indent_correction
== 0)
878 // Change the indentation level of the line
879 std::string currentLine
= lines
.GetStringAtIndex(m_current_line_index
);
880 if (indent_correction
> 0) {
881 currentLine
= currentLine
.insert(0, indent_correction
, ' ');
883 currentLine
= currentLine
.erase(0, -indent_correction
);
885 #if LLDB_EDITLINE_USE_WCHAR
886 m_input_lines
[m_current_line_index
] = m_utf8conv
.from_bytes(currentLine
);
888 m_input_lines
[m_current_line_index
] = currentLine
;
891 // Update the display to reflect the change
892 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::EditingPrompt
);
893 DisplayInput(m_current_line_index
);
895 // Reposition the cursor back on the original line and prepare to restart
896 // editing with a new cursor position
897 SetCurrentLine(m_current_line_index
);
898 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingPrompt
);
899 m_revert_cursor_index
= cursor_position
+ indent_correction
;
903 unsigned char Editline::RevertLineCommand(int ch
) {
904 el_winsertstr(m_editline
, m_input_lines
[m_current_line_index
].c_str());
905 if (m_revert_cursor_index
>= 0) {
906 LineInfoW
*info
= const_cast<LineInfoW
*>(el_wline(m_editline
));
907 info
->cursor
= info
->buffer
+ m_revert_cursor_index
;
908 if (info
->cursor
> info
->lastchar
) {
909 info
->cursor
= info
->lastchar
;
911 m_revert_cursor_index
= -1;
916 unsigned char Editline::BufferStartCommand(int ch
) {
918 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockStart
);
920 m_revert_cursor_index
= 0;
924 unsigned char Editline::BufferEndCommand(int ch
) {
926 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockEnd
);
927 SetCurrentLine((int)m_input_lines
.size() - 1);
928 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingPrompt
);
932 /// Prints completions and their descriptions to the given file. Only the
933 /// completions in the interval [start, end) are printed.
935 PrintCompletion(FILE *output_file
,
936 llvm::ArrayRef
<CompletionResult::Completion
> results
,
938 for (const CompletionResult::Completion
&c
: results
) {
939 fprintf(output_file
, "\t%-*s", (int)max_len
, c
.GetCompletion().c_str());
940 if (!c
.GetDescription().empty())
941 fprintf(output_file
, " -- %s", c
.GetDescription().c_str());
942 fprintf(output_file
, "\n");
946 void Editline::DisplayCompletions(
947 Editline
&editline
, llvm::ArrayRef
<CompletionResult::Completion
> results
) {
948 assert(!results
.empty());
950 fprintf(editline
.m_output_file
,
951 "\n" ANSI_CLEAR_BELOW
"Available completions:\n");
952 const size_t page_size
= 40;
956 std::max_element(results
.begin(), results
.end(), [](auto &c1
, auto &c2
) {
957 return c1
.GetCompletion().size() < c2
.GetCompletion().size();
960 const size_t max_len
= longest
->GetCompletion().size();
962 if (results
.size() < page_size
) {
963 PrintCompletion(editline
.m_output_file
, results
, max_len
);
968 while (cur_pos
< results
.size()) {
969 size_t remaining
= results
.size() - cur_pos
;
970 size_t next_size
= all
? remaining
: std::min(page_size
, remaining
);
972 PrintCompletion(editline
.m_output_file
, results
.slice(cur_pos
, next_size
),
975 cur_pos
+= next_size
;
977 if (cur_pos
>= results
.size())
980 fprintf(editline
.m_output_file
, "More (Y/n/a): ");
982 int got_char
= el_getc(editline
.m_editline
, &reply
);
983 // Check for a ^C or other interruption.
984 if (editline
.m_editor_status
== EditorStatus::Interrupted
) {
985 editline
.m_editor_status
= EditorStatus::Editing
;
986 fprintf(editline
.m_output_file
, "^C\n");
990 fprintf(editline
.m_output_file
, "\n");
991 if (got_char
== -1 || reply
== 'n')
998 unsigned char Editline::TabCommand(int ch
) {
999 if (!m_completion_callback
)
1002 const LineInfo
*line_info
= el_line(m_editline
);
1004 llvm::StringRef
line(line_info
->buffer
,
1005 line_info
->lastchar
- line_info
->buffer
);
1006 unsigned cursor_index
= line_info
->cursor
- line_info
->buffer
;
1007 CompletionResult result
;
1008 CompletionRequest
request(line
, cursor_index
, result
);
1010 m_completion_callback(request
);
1012 llvm::ArrayRef
<CompletionResult::Completion
> results
= result
.GetResults();
1014 StringList completions
;
1015 result
.GetMatches(completions
);
1017 if (results
.size() == 0)
1020 if (results
.size() == 1) {
1021 CompletionResult::Completion completion
= results
.front();
1022 switch (completion
.GetMode()) {
1023 case CompletionMode::Normal
: {
1024 std::string to_add
= completion
.GetCompletion();
1025 // Terminate the current argument with a quote if it started with a quote.
1026 if (!request
.GetParsedLine().empty() && request
.GetParsedArg().IsQuoted())
1027 to_add
.push_back(request
.GetParsedArg().GetQuoteChar());
1028 to_add
.push_back(' ');
1029 el_deletestr(m_editline
, request
.GetCursorArgumentPrefix().size());
1030 el_insertstr(m_editline
, to_add
.c_str());
1031 // Clear all the autosuggestion parts if the only single space can be completed.
1033 return CC_REDISPLAY
;
1036 case CompletionMode::Partial
: {
1037 std::string to_add
= completion
.GetCompletion();
1038 to_add
= to_add
.substr(request
.GetCursorArgumentPrefix().size());
1039 el_insertstr(m_editline
, to_add
.c_str());
1042 case CompletionMode::RewriteLine
: {
1043 el_deletestr(m_editline
, line_info
->cursor
- line_info
->buffer
);
1044 el_insertstr(m_editline
, completion
.GetCompletion().c_str());
1048 return CC_REDISPLAY
;
1051 // If we get a longer match display that first.
1052 std::string longest_prefix
= completions
.LongestCommonPrefix();
1053 if (!longest_prefix
.empty())
1055 longest_prefix
.substr(request
.GetCursorArgumentPrefix().size());
1056 if (!longest_prefix
.empty()) {
1057 el_insertstr(m_editline
, longest_prefix
.c_str());
1058 return CC_REDISPLAY
;
1061 DisplayCompletions(*this, results
);
1064 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingCursor
);
1065 return CC_REDISPLAY
;
1068 unsigned char Editline::ApplyAutosuggestCommand(int ch
) {
1069 if (!m_suggestion_callback
) {
1070 return CC_REDISPLAY
;
1073 const LineInfo
*line_info
= el_line(m_editline
);
1074 llvm::StringRef
line(line_info
->buffer
,
1075 line_info
->lastchar
- line_info
->buffer
);
1077 if (std::optional
<std::string
> to_add
= m_suggestion_callback(line
))
1078 el_insertstr(m_editline
, to_add
->c_str());
1080 return CC_REDISPLAY
;
1083 unsigned char Editline::TypedCharacter(int ch
) {
1084 std::string typed
= std::string(1, ch
);
1085 el_insertstr(m_editline
, typed
.c_str());
1087 if (!m_suggestion_callback
) {
1088 return CC_REDISPLAY
;
1091 const LineInfo
*line_info
= el_line(m_editline
);
1092 llvm::StringRef
line(line_info
->buffer
,
1093 line_info
->lastchar
- line_info
->buffer
);
1095 if (std::optional
<std::string
> to_add
= m_suggestion_callback(line
)) {
1096 std::string to_add_color
=
1097 m_suggestion_ansi_prefix
+ to_add
.value() + m_suggestion_ansi_suffix
;
1098 fputs(typed
.c_str(), m_output_file
);
1099 fputs(to_add_color
.c_str(), m_output_file
);
1100 size_t new_autosuggestion_size
= line
.size() + to_add
->length();
1101 // Print spaces to hide any remains of a previous longer autosuggestion.
1102 if (new_autosuggestion_size
< m_previous_autosuggestion_size
) {
1103 size_t spaces_to_print
=
1104 m_previous_autosuggestion_size
- new_autosuggestion_size
;
1105 std::string spaces
= std::string(spaces_to_print
, ' ');
1106 fputs(spaces
.c_str(), m_output_file
);
1108 m_previous_autosuggestion_size
= new_autosuggestion_size
;
1110 int editline_cursor_position
=
1111 (int)((line_info
->cursor
- line_info
->buffer
) + GetPromptWidth());
1112 int editline_cursor_row
= editline_cursor_position
/ m_terminal_width
;
1114 editline_cursor_position
- (editline_cursor_row
* m_terminal_width
);
1115 fprintf(m_output_file
, ANSI_SET_COLUMN_N
, toColumn
);
1119 return CC_REDISPLAY
;
1122 void Editline::AddFunctionToEditLine(const EditLineCharType
*command
,
1123 const EditLineCharType
*helptext
,
1124 EditlineCommandCallbackType callbackFn
) {
1125 el_wset(m_editline
, EL_ADDFN
, command
, helptext
, callbackFn
);
1128 void Editline::SetEditLinePromptCallback(
1129 EditlinePromptCallbackType callbackFn
) {
1130 el_set(m_editline
, EL_PROMPT
, callbackFn
);
1133 void Editline::SetGetCharacterFunction(EditlineGetCharCallbackType callbackFn
) {
1134 el_wset(m_editline
, EL_GETCFN
, callbackFn
);
1137 void Editline::ConfigureEditor(bool multiline
) {
1138 if (m_editline
&& m_multiline_enabled
== multiline
)
1140 m_multiline_enabled
= multiline
;
1143 // Disable edit mode to stop the terminal from flushing all input during
1144 // the call to el_end() since we expect to have multiple editline instances
1146 el_set(m_editline
, EL_EDITMODE
, 0);
1151 el_init(m_editor_name
.c_str(), m_input_file
, m_output_file
, m_error_file
);
1152 ApplyTerminalSizeChange();
1154 if (m_history_sp
&& m_history_sp
->IsValid()) {
1155 if (!m_history_sp
->Load()) {
1156 fputs("Could not load history file\n.", m_output_file
);
1158 el_wset(m_editline
, EL_HIST
, history
, m_history_sp
->GetHistoryPtr());
1160 el_set(m_editline
, EL_CLIENTDATA
, this);
1161 el_set(m_editline
, EL_SIGNAL
, 0);
1162 el_set(m_editline
, EL_EDITOR
, "emacs");
1164 SetGetCharacterFunction([](EditLine
*editline
, EditLineGetCharType
*c
) {
1165 return Editline::InstanceFor(editline
)->GetCharacter(c
);
1168 SetEditLinePromptCallback([](EditLine
*editline
) {
1169 return Editline::InstanceFor(editline
)->Prompt();
1172 // Commands used for multiline support, registered whether or not they're
1174 AddFunctionToEditLine(
1175 EditLineConstString("lldb-break-line"),
1176 EditLineConstString("Insert a line break"),
1177 [](EditLine
*editline
, int ch
) {
1178 return Editline::InstanceFor(editline
)->BreakLineCommand(ch
);
1181 AddFunctionToEditLine(
1182 EditLineConstString("lldb-end-or-add-line"),
1183 EditLineConstString("End editing or continue when incomplete"),
1184 [](EditLine
*editline
, int ch
) {
1185 return Editline::InstanceFor(editline
)->EndOrAddLineCommand(ch
);
1187 AddFunctionToEditLine(
1188 EditLineConstString("lldb-delete-next-char"),
1189 EditLineConstString("Delete next character"),
1190 [](EditLine
*editline
, int ch
) {
1191 return Editline::InstanceFor(editline
)->DeleteNextCharCommand(ch
);
1193 AddFunctionToEditLine(
1194 EditLineConstString("lldb-delete-previous-char"),
1195 EditLineConstString("Delete previous character"),
1196 [](EditLine
*editline
, int ch
) {
1197 return Editline::InstanceFor(editline
)->DeletePreviousCharCommand(ch
);
1199 AddFunctionToEditLine(
1200 EditLineConstString("lldb-previous-line"),
1201 EditLineConstString("Move to previous line"),
1202 [](EditLine
*editline
, int ch
) {
1203 return Editline::InstanceFor(editline
)->PreviousLineCommand(ch
);
1205 AddFunctionToEditLine(
1206 EditLineConstString("lldb-next-line"),
1207 EditLineConstString("Move to next line"), [](EditLine
*editline
, int ch
) {
1208 return Editline::InstanceFor(editline
)->NextLineCommand(ch
);
1210 AddFunctionToEditLine(
1211 EditLineConstString("lldb-previous-history"),
1212 EditLineConstString("Move to previous history"),
1213 [](EditLine
*editline
, int ch
) {
1214 return Editline::InstanceFor(editline
)->PreviousHistoryCommand(ch
);
1216 AddFunctionToEditLine(
1217 EditLineConstString("lldb-next-history"),
1218 EditLineConstString("Move to next history"),
1219 [](EditLine
*editline
, int ch
) {
1220 return Editline::InstanceFor(editline
)->NextHistoryCommand(ch
);
1222 AddFunctionToEditLine(
1223 EditLineConstString("lldb-buffer-start"),
1224 EditLineConstString("Move to start of buffer"),
1225 [](EditLine
*editline
, int ch
) {
1226 return Editline::InstanceFor(editline
)->BufferStartCommand(ch
);
1228 AddFunctionToEditLine(
1229 EditLineConstString("lldb-buffer-end"),
1230 EditLineConstString("Move to end of buffer"),
1231 [](EditLine
*editline
, int ch
) {
1232 return Editline::InstanceFor(editline
)->BufferEndCommand(ch
);
1234 AddFunctionToEditLine(
1235 EditLineConstString("lldb-fix-indentation"),
1236 EditLineConstString("Fix line indentation"),
1237 [](EditLine
*editline
, int ch
) {
1238 return Editline::InstanceFor(editline
)->FixIndentationCommand(ch
);
1241 // Register the complete callback under two names for compatibility with
1242 // older clients using custom .editrc files (largely because libedit has a
1243 // bad bug where if you have a bind command that tries to bind to a function
1244 // name that doesn't exist, it can corrupt the heap and crash your process
1246 EditlineCommandCallbackType complete_callback
= [](EditLine
*editline
,
1248 return Editline::InstanceFor(editline
)->TabCommand(ch
);
1250 AddFunctionToEditLine(EditLineConstString("lldb-complete"),
1251 EditLineConstString("Invoke completion"),
1253 AddFunctionToEditLine(EditLineConstString("lldb_complete"),
1254 EditLineConstString("Invoke completion"),
1257 // General bindings we don't mind being overridden
1259 el_set(m_editline
, EL_BIND
, "^r", "em-inc-search-prev",
1260 NULL
); // Cycle through backwards search, entering string
1262 if (m_suggestion_callback
) {
1263 AddFunctionToEditLine(
1264 EditLineConstString("lldb-apply-complete"),
1265 EditLineConstString("Adopt autocompletion"),
1266 [](EditLine
*editline
, int ch
) {
1267 return Editline::InstanceFor(editline
)->ApplyAutosuggestCommand(ch
);
1270 el_set(m_editline
, EL_BIND
, "^f", "lldb-apply-complete",
1271 NULL
); // Apply a part that is suggested automatically
1273 AddFunctionToEditLine(
1274 EditLineConstString("lldb-typed-character"),
1275 EditLineConstString("Typed character"),
1276 [](EditLine
*editline
, int ch
) {
1277 return Editline::InstanceFor(editline
)->TypedCharacter(ch
);
1280 char bind_key
[2] = {0, 0};
1281 llvm::StringRef ascii_chars
=
1282 "abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXZY1234567890!\"#$%"
1283 "&'()*+,./:;<=>?@[]_`{|}~ ";
1284 for (char c
: ascii_chars
) {
1286 el_set(m_editline
, EL_BIND
, bind_key
, "lldb-typed-character", NULL
);
1288 el_set(m_editline
, EL_BIND
, "\\-", "lldb-typed-character", NULL
);
1289 el_set(m_editline
, EL_BIND
, "\\^", "lldb-typed-character", NULL
);
1290 el_set(m_editline
, EL_BIND
, "\\\\", "lldb-typed-character", NULL
);
1294 el_set(m_editline
, EL_BIND
, "^w", "ed-delete-prev-word",
1295 NULL
); // Delete previous word, behave like bash in emacs mode
1296 el_set(m_editline
, EL_BIND
, "\t", "lldb-complete",
1297 NULL
); // Bind TAB to auto complete
1299 // Allow ctrl-left-arrow and ctrl-right-arrow for navigation, behave like
1300 // bash in emacs mode.
1301 el_set(m_editline
, EL_BIND
, ESCAPE
"[1;5C", "em-next-word", NULL
);
1302 el_set(m_editline
, EL_BIND
, ESCAPE
"[1;5D", "ed-prev-word", NULL
);
1303 el_set(m_editline
, EL_BIND
, ESCAPE
"[5C", "em-next-word", NULL
);
1304 el_set(m_editline
, EL_BIND
, ESCAPE
"[5D", "ed-prev-word", NULL
);
1305 el_set(m_editline
, EL_BIND
, ESCAPE ESCAPE
"[C", "em-next-word", NULL
);
1306 el_set(m_editline
, EL_BIND
, ESCAPE ESCAPE
"[D", "ed-prev-word", NULL
);
1308 // Allow user-specific customization prior to registering bindings we
1309 // absolutely require
1310 el_source(m_editline
, nullptr);
1312 // Register an internal binding that external developers shouldn't use
1313 AddFunctionToEditLine(
1314 EditLineConstString("lldb-revert-line"),
1315 EditLineConstString("Revert line to saved state"),
1316 [](EditLine
*editline
, int ch
) {
1317 return Editline::InstanceFor(editline
)->RevertLineCommand(ch
);
1320 // Register keys that perform auto-indent correction
1321 if (m_fix_indentation_callback
&& m_fix_indentation_callback_chars
) {
1322 char bind_key
[2] = {0, 0};
1323 const char *indent_chars
= m_fix_indentation_callback_chars
;
1324 while (*indent_chars
) {
1325 bind_key
[0] = *indent_chars
;
1326 el_set(m_editline
, EL_BIND
, bind_key
, "lldb-fix-indentation", NULL
);
1331 // Multi-line editor bindings
1333 el_set(m_editline
, EL_BIND
, "\n", "lldb-end-or-add-line", NULL
);
1334 el_set(m_editline
, EL_BIND
, "\r", "lldb-end-or-add-line", NULL
);
1335 el_set(m_editline
, EL_BIND
, ESCAPE
"\n", "lldb-break-line", NULL
);
1336 el_set(m_editline
, EL_BIND
, ESCAPE
"\r", "lldb-break-line", NULL
);
1337 el_set(m_editline
, EL_BIND
, "^p", "lldb-previous-line", NULL
);
1338 el_set(m_editline
, EL_BIND
, "^n", "lldb-next-line", NULL
);
1339 el_set(m_editline
, EL_BIND
, "^?", "lldb-delete-previous-char", NULL
);
1340 el_set(m_editline
, EL_BIND
, "^d", "lldb-delete-next-char", NULL
);
1341 el_set(m_editline
, EL_BIND
, ESCAPE
"[3~", "lldb-delete-next-char", NULL
);
1342 el_set(m_editline
, EL_BIND
, ESCAPE
"[\\^", "lldb-revert-line", NULL
);
1344 // Editor-specific bindings
1346 el_set(m_editline
, EL_BIND
, ESCAPE
"<", "lldb-buffer-start", NULL
);
1347 el_set(m_editline
, EL_BIND
, ESCAPE
">", "lldb-buffer-end", NULL
);
1348 el_set(m_editline
, EL_BIND
, ESCAPE
"[A", "lldb-previous-line", NULL
);
1349 el_set(m_editline
, EL_BIND
, ESCAPE
"[B", "lldb-next-line", NULL
);
1350 el_set(m_editline
, EL_BIND
, ESCAPE ESCAPE
"[A", "lldb-previous-history",
1352 el_set(m_editline
, EL_BIND
, ESCAPE ESCAPE
"[B", "lldb-next-history",
1354 el_set(m_editline
, EL_BIND
, ESCAPE
"[1;3A", "lldb-previous-history",
1356 el_set(m_editline
, EL_BIND
, ESCAPE
"[1;3B", "lldb-next-history", NULL
);
1358 el_set(m_editline
, EL_BIND
, "^H", "lldb-delete-previous-char", NULL
);
1360 el_set(m_editline
, EL_BIND
, "-a", ESCAPE
"[A", "lldb-previous-line",
1362 el_set(m_editline
, EL_BIND
, "-a", ESCAPE
"[B", "lldb-next-line", NULL
);
1363 el_set(m_editline
, EL_BIND
, "-a", "x", "lldb-delete-next-char", NULL
);
1364 el_set(m_editline
, EL_BIND
, "-a", "^H", "lldb-delete-previous-char",
1366 el_set(m_editline
, EL_BIND
, "-a", "^?", "lldb-delete-previous-char",
1369 // Escape is absorbed exiting edit mode, so re-register important
1370 // sequences without the prefix
1371 el_set(m_editline
, EL_BIND
, "-a", "[A", "lldb-previous-line", NULL
);
1372 el_set(m_editline
, EL_BIND
, "-a", "[B", "lldb-next-line", NULL
);
1373 el_set(m_editline
, EL_BIND
, "-a", "[\\^", "lldb-revert-line", NULL
);
1378 // Editline public methods
1380 Editline
*Editline::InstanceFor(EditLine
*editline
) {
1382 el_get(editline
, EL_CLIENTDATA
, &editor
);
1386 Editline::Editline(const char *editline_name
, FILE *input_file
,
1387 FILE *output_file
, FILE *error_file
,
1388 std::recursive_mutex
&output_mutex
)
1389 : m_editor_status(EditorStatus::Complete
), m_input_file(input_file
),
1390 m_output_file(output_file
), m_error_file(error_file
),
1391 m_input_connection(fileno(input_file
), false),
1392 m_output_mutex(output_mutex
) {
1393 // Get a shared history instance
1394 m_editor_name
= (editline_name
== nullptr) ? "lldb-tmp" : editline_name
;
1395 m_history_sp
= EditlineHistory::GetHistory(m_editor_name
);
1397 #ifdef USE_SETUPTERM_WORKAROUND
1398 if (m_output_file
) {
1399 const int term_fd
= fileno(m_output_file
);
1400 if (term_fd
!= -1) {
1401 static std::recursive_mutex
*g_init_terminal_fds_mutex_ptr
= nullptr;
1402 static std::set
<int> *g_init_terminal_fds_ptr
= nullptr;
1403 static llvm::once_flag g_once_flag
;
1404 llvm::call_once(g_once_flag
, [&]() {
1405 g_init_terminal_fds_mutex_ptr
=
1406 new std::recursive_mutex(); // NOTE: Leak to avoid C++ destructor
1408 g_init_terminal_fds_ptr
= new std::set
<int>(); // NOTE: Leak to avoid
1409 // C++ destructor chain
1413 // We must make sure to initialize the terminal a given file descriptor
1414 // only once. If we do this multiple times, we start leaking memory.
1415 std::lock_guard
<std::recursive_mutex
> guard(
1416 *g_init_terminal_fds_mutex_ptr
);
1417 if (g_init_terminal_fds_ptr
->find(term_fd
) ==
1418 g_init_terminal_fds_ptr
->end()) {
1419 g_init_terminal_fds_ptr
->insert(term_fd
);
1420 setupterm((char *)0, term_fd
, (int *)0);
1427 Editline::~Editline() {
1429 // Disable edit mode to stop the terminal from flushing all input during
1430 // the call to el_end() since we expect to have multiple editline instances
1432 el_set(m_editline
, EL_EDITMODE
, 0);
1434 m_editline
= nullptr;
1437 // EditlineHistory objects are sometimes shared between multiple Editline
1438 // instances with the same program name. So just release our shared pointer
1439 // and if we are the last owner, it will save the history to the history save
1440 // file automatically.
1441 m_history_sp
.reset();
1444 void Editline::SetPrompt(const char *prompt
) {
1445 m_set_prompt
= prompt
== nullptr ? "" : prompt
;
1448 void Editline::SetContinuationPrompt(const char *continuation_prompt
) {
1449 m_set_continuation_prompt
=
1450 continuation_prompt
== nullptr ? "" : continuation_prompt
;
1453 void Editline::TerminalSizeChanged() { m_terminal_size_has_changed
= 1; }
1455 void Editline::ApplyTerminalSizeChange() {
1459 m_terminal_size_has_changed
= 0;
1460 el_resize(m_editline
);
1462 // This function is documenting as taking (const char *, void *) for the
1463 // vararg part, but in reality in was consuming arguments until the first
1464 // null pointer. This was fixed in libedit in April 2019
1465 // <http://mail-index.netbsd.org/source-changes/2019/04/26/msg105454.html>,
1466 // but we're keeping the workaround until a version with that fix is more
1467 // widely available.
1468 if (el_get(m_editline
, EL_GETTC
, "co", &columns
, nullptr) == 0) {
1469 m_terminal_width
= columns
;
1470 if (m_current_line_rows
!= -1) {
1471 const LineInfoW
*info
= el_wline(m_editline
);
1473 (int)((info
->lastchar
- info
->buffer
) + GetPromptWidth());
1474 m_current_line_rows
= (lineLength
/ columns
) + 1;
1477 m_terminal_width
= INT_MAX
;
1478 m_current_line_rows
= 1;
1482 const char *Editline::GetPrompt() { return m_set_prompt
.c_str(); }
1484 uint32_t Editline::GetCurrentLine() { return m_current_line_index
; }
1486 bool Editline::Interrupt() {
1488 std::lock_guard
<std::recursive_mutex
> guard(m_output_mutex
);
1489 if (m_editor_status
== EditorStatus::Editing
) {
1490 fprintf(m_output_file
, "^C\n");
1491 result
= m_input_connection
.InterruptRead();
1493 m_editor_status
= EditorStatus::Interrupted
;
1497 bool Editline::Cancel() {
1499 std::lock_guard
<std::recursive_mutex
> guard(m_output_mutex
);
1500 if (m_editor_status
== EditorStatus::Editing
) {
1501 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockStart
);
1502 fprintf(m_output_file
, ANSI_CLEAR_BELOW
);
1503 result
= m_input_connection
.InterruptRead();
1505 m_editor_status
= EditorStatus::Interrupted
;
1509 bool Editline::GetLine(std::string
&line
, bool &interrupted
) {
1510 ConfigureEditor(false);
1511 m_input_lines
= std::vector
<EditLineStringType
>();
1512 m_input_lines
.insert(m_input_lines
.begin(), EditLineConstString(""));
1514 std::lock_guard
<std::recursive_mutex
> guard(m_output_mutex
);
1516 lldbassert(m_editor_status
!= EditorStatus::Editing
);
1517 if (m_editor_status
== EditorStatus::Interrupted
) {
1518 m_editor_status
= EditorStatus::Complete
;
1524 m_in_history
= false;
1525 m_editor_status
= EditorStatus::Editing
;
1526 m_revert_cursor_index
= -1;
1529 auto input
= el_wgets(m_editline
, &count
);
1531 interrupted
= m_editor_status
== EditorStatus::Interrupted
;
1533 if (input
== nullptr) {
1534 fprintf(m_output_file
, "\n");
1535 m_editor_status
= EditorStatus::EndOfInput
;
1537 m_history_sp
->Enter(input
);
1538 #if LLDB_EDITLINE_USE_WCHAR
1539 line
= m_utf8conv
.to_bytes(SplitLines(input
)[0]);
1541 line
= SplitLines(input
)[0];
1543 m_editor_status
= EditorStatus::Complete
;
1546 return m_editor_status
!= EditorStatus::EndOfInput
;
1549 bool Editline::GetLines(int first_line_number
, StringList
&lines
,
1550 bool &interrupted
) {
1551 ConfigureEditor(true);
1553 // Print the initial input lines, then move the cursor back up to the start
1555 SetBaseLineNumber(first_line_number
);
1556 m_input_lines
= std::vector
<EditLineStringType
>();
1557 m_input_lines
.insert(m_input_lines
.begin(), EditLineConstString(""));
1559 std::lock_guard
<std::recursive_mutex
> guard(m_output_mutex
);
1560 // Begin the line editing loop
1563 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::BlockStart
);
1564 m_editor_status
= EditorStatus::Editing
;
1565 m_in_history
= false;
1567 m_revert_cursor_index
= -1;
1568 while (m_editor_status
== EditorStatus::Editing
) {
1570 m_current_line_rows
= -1;
1571 el_wpush(m_editline
, EditLineConstString(
1572 "\x1b[^")); // Revert to the existing line content
1573 el_wgets(m_editline
, &count
);
1576 interrupted
= m_editor_status
== EditorStatus::Interrupted
;
1578 // Save the completed entry in history before returning. Don't save empty
1579 // input as that just clutters the command history.
1580 if (!m_input_lines
.empty())
1581 m_history_sp
->Enter(CombineLines(m_input_lines
).c_str());
1583 lines
= GetInputAsStringList();
1585 return m_editor_status
!= EditorStatus::EndOfInput
;
1588 void Editline::PrintAsync(Stream
*stream
, const char *s
, size_t len
) {
1589 std::lock_guard
<std::recursive_mutex
> guard(m_output_mutex
);
1590 if (m_editor_status
== EditorStatus::Editing
) {
1591 MoveCursor(CursorLocation::EditingCursor
, CursorLocation::BlockStart
);
1592 fprintf(m_output_file
, ANSI_CLEAR_BELOW
);
1594 stream
->Write(s
, len
);
1596 if (m_editor_status
== EditorStatus::Editing
) {
1598 MoveCursor(CursorLocation::BlockEnd
, CursorLocation::EditingCursor
);
1602 bool Editline::CompleteCharacter(char ch
, EditLineGetCharType
&out
) {
1603 #if !LLDB_EDITLINE_USE_WCHAR
1604 if (ch
== (char)EOF
)
1607 out
= (unsigned char)ch
;
1610 std::codecvt_utf8
<wchar_t> cvt
;
1611 llvm::SmallString
<4> input
;
1613 const char *from_next
;
1615 std::mbstate_t state
= std::mbstate_t();
1616 input
.push_back(ch
);
1617 switch (cvt
.in(state
, input
.begin(), input
.end(), from_next
, &out
, &out
+ 1,
1619 case std::codecvt_base::ok
:
1620 return out
!= (EditLineGetCharType
)WEOF
;
1622 case std::codecvt_base::error
:
1623 case std::codecvt_base::noconv
:
1626 case std::codecvt_base::partial
:
1627 lldb::ConnectionStatus status
;
1628 size_t read_count
= m_input_connection
.Read(
1629 &ch
, 1, std::chrono::seconds(0), status
, nullptr);
1630 if (read_count
== 0)