• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Editline.cpp ------------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <iomanip>
10 #include <limits.h>
11 
12 #include "lldb/Host/ConnectionFileDescriptor.h"
13 #include "lldb/Host/Editline.h"
14 #include "lldb/Host/FileSystem.h"
15 #include "lldb/Host/Host.h"
16 #include "lldb/Utility/CompletionRequest.h"
17 #include "lldb/Utility/FileSpec.h"
18 #include "lldb/Utility/LLDBAssert.h"
19 #include "lldb/Utility/SelectHelper.h"
20 #include "lldb/Utility/Status.h"
21 #include "lldb/Utility/StreamString.h"
22 #include "lldb/Utility/StringList.h"
23 #include "lldb/Utility/Timeout.h"
24 
25 #include "llvm/Support/FileSystem.h"
26 #include "llvm/Support/Threading.h"
27 
28 using namespace lldb_private;
29 using namespace lldb_private::line_editor;
30 
31 // Workaround for what looks like an OS X-specific issue, but other platforms
32 // may benefit from something similar if issues arise.  The libedit library
33 // doesn't explicitly initialize the curses termcap library, which it gets away
34 // with until TERM is set to VT100 where it stumbles over an implementation
35 // assumption that may not exist on other platforms.  The setupterm() function
36 // would normally require headers that don't work gracefully in this context,
37 // so the function declaration has been hoisted here.
38 #if defined(__APPLE__)
39 extern "C" {
40 int setupterm(char *term, int fildes, int *errret);
41 }
42 #define USE_SETUPTERM_WORKAROUND
43 #endif
44 
45 // Editline uses careful cursor management to achieve the illusion of editing a
46 // multi-line block of text with a single line editor.  Preserving this
47 // illusion requires fairly careful management of cursor state.  Read and
48 // understand the relationship between DisplayInput(), MoveCursor(),
49 // SetCurrentLine(), and SaveEditedLine() before making changes.
50 
51 /// https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
52 #define ESCAPE "\x1b"
53 /// Faint, decreased intensity or second colour.
54 #define ANSI_FAINT ESCAPE "[2m"
55 /// Normal colour or normal intensity (neither bold nor faint).
56 #define ANSI_UNFAINT ESCAPE "[0m"
57 #define ANSI_CLEAR_BELOW ESCAPE "[J"
58 #define ANSI_CLEAR_RIGHT ESCAPE "[K"
59 #define ANSI_SET_COLUMN_N ESCAPE "[%dG"
60 #define ANSI_UP_N_ROWS ESCAPE "[%dA"
61 #define ANSI_DOWN_N_ROWS ESCAPE "[%dB"
62 
63 #if LLDB_EDITLINE_USE_WCHAR
64 
65 #define EditLineConstString(str) L##str
66 #define EditLineStringFormatSpec "%ls"
67 
68 #else
69 
70 #define EditLineConstString(str) str
71 #define EditLineStringFormatSpec "%s"
72 
73 // use #defines so wide version functions and structs will resolve to old
74 // versions for case of libedit not built with wide char support
75 #define history_w history
76 #define history_winit history_init
77 #define history_wend history_end
78 #define HistoryW History
79 #define HistEventW HistEvent
80 #define LineInfoW LineInfo
81 
82 #define el_wgets el_gets
83 #define el_wgetc el_getc
84 #define el_wpush el_push
85 #define el_wparse el_parse
86 #define el_wset el_set
87 #define el_wget el_get
88 #define el_wline el_line
89 #define el_winsertstr el_insertstr
90 #define el_wdeletestr el_deletestr
91 
92 #endif // #if LLDB_EDITLINE_USE_WCHAR
93 
IsOnlySpaces(const EditLineStringType & content)94 bool IsOnlySpaces(const EditLineStringType &content) {
95   for (wchar_t ch : content) {
96     if (ch != EditLineCharType(' '))
97       return false;
98   }
99   return true;
100 }
101 
GetOperation(HistoryOperation op)102 static int GetOperation(HistoryOperation op) {
103   // The naming used by editline for the history operations is counter
104   // intuitive to how it's used in LLDB's editline implementation.
105   //
106   //  - The H_LAST returns the oldest entry in the history.
107   //
108   //  - The H_PREV operation returns the previous element in the history, which
109   //    is newer than the current one.
110   //
111   //  - The H_CURR returns the current entry in the history.
112   //
113   //  - The H_NEXT operation returns the next element in the history, which is
114   //    older than the current one.
115   //
116   //  - The H_FIRST returns the most recent entry in the history.
117   //
118   // The naming of the enum entries match the semantic meaning.
119   switch(op) {
120     case HistoryOperation::Oldest:
121       return H_LAST;
122     case HistoryOperation::Older:
123       return H_NEXT;
124     case HistoryOperation::Current:
125       return H_CURR;
126     case HistoryOperation::Newer:
127       return H_PREV;
128     case HistoryOperation::Newest:
129       return H_FIRST;
130   }
131   llvm_unreachable("Fully covered switch!");
132 }
133 
134 
CombineLines(const std::vector<EditLineStringType> & lines)135 EditLineStringType CombineLines(const std::vector<EditLineStringType> &lines) {
136   EditLineStringStreamType combined_stream;
137   for (EditLineStringType line : lines) {
138     combined_stream << line.c_str() << "\n";
139   }
140   return combined_stream.str();
141 }
142 
SplitLines(const EditLineStringType & input)143 std::vector<EditLineStringType> SplitLines(const EditLineStringType &input) {
144   std::vector<EditLineStringType> result;
145   size_t start = 0;
146   while (start < input.length()) {
147     size_t end = input.find('\n', start);
148     if (end == std::string::npos) {
149       result.push_back(input.substr(start));
150       break;
151     }
152     result.push_back(input.substr(start, end - start));
153     start = end + 1;
154   }
155   return result;
156 }
157 
FixIndentation(const EditLineStringType & line,int indent_correction)158 EditLineStringType FixIndentation(const EditLineStringType &line,
159                                   int indent_correction) {
160   if (indent_correction == 0)
161     return line;
162   if (indent_correction < 0)
163     return line.substr(-indent_correction);
164   return EditLineStringType(indent_correction, EditLineCharType(' ')) + line;
165 }
166 
GetIndentation(const EditLineStringType & line)167 int GetIndentation(const EditLineStringType &line) {
168   int space_count = 0;
169   for (EditLineCharType ch : line) {
170     if (ch != EditLineCharType(' '))
171       break;
172     ++space_count;
173   }
174   return space_count;
175 }
176 
IsInputPending(FILE * file)177 bool IsInputPending(FILE *file) {
178   // FIXME: This will be broken on Windows if we ever re-enable Editline.  You
179   // can't use select
180   // on something that isn't a socket.  This will have to be re-written to not
181   // use a FILE*, but instead use some kind of yet-to-be-created abstraction
182   // that select-like functionality on non-socket objects.
183   const int fd = fileno(file);
184   SelectHelper select_helper;
185   select_helper.SetTimeout(std::chrono::microseconds(0));
186   select_helper.FDSetRead(fd);
187   return select_helper.Select().Success();
188 }
189 
190 namespace lldb_private {
191 namespace line_editor {
192 typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP;
193 
194 // EditlineHistory objects are sometimes shared between multiple Editline
195 // instances with the same program name.
196 
197 class EditlineHistory {
198 private:
199   // Use static GetHistory() function to get a EditlineHistorySP to one of
200   // these objects
EditlineHistory(const std::string & prefix,uint32_t size,bool unique_entries)201   EditlineHistory(const std::string &prefix, uint32_t size, bool unique_entries)
202       : m_history(nullptr), m_event(), m_prefix(prefix), m_path() {
203     m_history = history_winit();
204     history_w(m_history, &m_event, H_SETSIZE, size);
205     if (unique_entries)
206       history_w(m_history, &m_event, H_SETUNIQUE, 1);
207   }
208 
GetHistoryFilePath()209   const char *GetHistoryFilePath() {
210     // Compute the history path lazily.
211     if (m_path.empty() && m_history && !m_prefix.empty()) {
212       llvm::SmallString<128> lldb_history_file;
213       FileSystem::Instance().GetHomeDirectory(lldb_history_file);
214       llvm::sys::path::append(lldb_history_file, ".lldb");
215 
216       // LLDB stores its history in ~/.lldb/. If for some reason this directory
217       // isn't writable or cannot be created, history won't be available.
218       if (!llvm::sys::fs::create_directory(lldb_history_file)) {
219 #if LLDB_EDITLINE_USE_WCHAR
220         std::string filename = m_prefix + "-widehistory";
221 #else
222         std::string filename = m_prefix + "-history";
223 #endif
224         llvm::sys::path::append(lldb_history_file, filename);
225         m_path = std::string(lldb_history_file.str());
226       }
227     }
228 
229     if (m_path.empty())
230       return nullptr;
231 
232     return m_path.c_str();
233   }
234 
235 public:
~EditlineHistory()236   ~EditlineHistory() {
237     Save();
238 
239     if (m_history) {
240       history_wend(m_history);
241       m_history = nullptr;
242     }
243   }
244 
GetHistory(const std::string & prefix)245   static EditlineHistorySP GetHistory(const std::string &prefix) {
246     typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap;
247     static std::recursive_mutex g_mutex;
248     static WeakHistoryMap g_weak_map;
249     std::lock_guard<std::recursive_mutex> guard(g_mutex);
250     WeakHistoryMap::const_iterator pos = g_weak_map.find(prefix);
251     EditlineHistorySP history_sp;
252     if (pos != g_weak_map.end()) {
253       history_sp = pos->second.lock();
254       if (history_sp)
255         return history_sp;
256       g_weak_map.erase(pos);
257     }
258     history_sp.reset(new EditlineHistory(prefix, 800, true));
259     g_weak_map[prefix] = history_sp;
260     return history_sp;
261   }
262 
IsValid() const263   bool IsValid() const { return m_history != nullptr; }
264 
GetHistoryPtr()265   HistoryW *GetHistoryPtr() { return m_history; }
266 
Enter(const EditLineCharType * line_cstr)267   void Enter(const EditLineCharType *line_cstr) {
268     if (m_history)
269       history_w(m_history, &m_event, H_ENTER, line_cstr);
270   }
271 
Load()272   bool Load() {
273     if (m_history) {
274       const char *path = GetHistoryFilePath();
275       if (path) {
276         history_w(m_history, &m_event, H_LOAD, path);
277         return true;
278       }
279     }
280     return false;
281   }
282 
Save()283   bool Save() {
284     if (m_history) {
285       const char *path = GetHistoryFilePath();
286       if (path) {
287         history_w(m_history, &m_event, H_SAVE, path);
288         return true;
289       }
290     }
291     return false;
292   }
293 
294 protected:
295   HistoryW *m_history; // The history object
296   HistEventW m_event;  // The history event needed to contain all history events
297   std::string m_prefix; // The prefix name (usually the editline program name)
298                         // to use when loading/saving history
299   std::string m_path;   // Path to the history file
300 };
301 }
302 }
303 
304 // Editline private methods
305 
SetBaseLineNumber(int line_number)306 void Editline::SetBaseLineNumber(int line_number) {
307   m_base_line_number = line_number;
308   m_line_number_digits =
309       std::max<int>(3, std::to_string(line_number).length() + 1);
310 }
311 
PromptForIndex(int line_index)312 std::string Editline::PromptForIndex(int line_index) {
313   bool use_line_numbers = m_multiline_enabled && m_base_line_number > 0;
314   std::string prompt = m_set_prompt;
315   if (use_line_numbers && prompt.length() == 0)
316     prompt = ": ";
317   std::string continuation_prompt = prompt;
318   if (m_set_continuation_prompt.length() > 0) {
319     continuation_prompt = m_set_continuation_prompt;
320 
321     // Ensure that both prompts are the same length through space padding
322     while (continuation_prompt.length() < prompt.length()) {
323       continuation_prompt += ' ';
324     }
325     while (prompt.length() < continuation_prompt.length()) {
326       prompt += ' ';
327     }
328   }
329 
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()));
336   }
337   return (line_index == 0) ? prompt : continuation_prompt;
338 }
339 
SetCurrentLine(int line_index)340 void Editline::SetCurrentLine(int line_index) {
341   m_current_line_index = line_index;
342   m_current_prompt = PromptForIndex(line_index);
343 }
344 
GetPromptWidth()345 int Editline::GetPromptWidth() { return (int)PromptForIndex(0).length(); }
346 
IsEmacs()347 bool Editline::IsEmacs() {
348   const char *editor;
349   el_get(m_editline, EL_EDITOR, &editor);
350   return editor[0] == 'e';
351 }
352 
IsOnlySpaces()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 != ' ')
358       return false;
359   }
360   return true;
361 }
362 
GetLineIndexForLocation(CursorLocation location,int cursor_row)363 int Editline::GetLineIndexForLocation(CursorLocation location, int cursor_row) {
364   int line = 0;
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]);
370     }
371     if (location == CursorLocation::EditingCursor) {
372       line += cursor_row;
373     } else if (location == CursorLocation::BlockEnd) {
374       for (unsigned index = m_current_line_index; index < m_input_lines.size();
375            index++) {
376         line += CountRowsForLine(m_input_lines[index]);
377       }
378       --line;
379     }
380   }
381   return line;
382 }
383 
MoveCursor(CursorLocation from,CursorLocation to)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;
389 
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));
397   }
398 
399   // Determine target column
400   int toColumn = 1;
401   if (to == CursorLocation::EditingCursor) {
402     toColumn =
403         editline_cursor_position - (editline_cursor_row * m_terminal_width) + 1;
404   } else if (to == CursorLocation::BlockEnd && !m_input_lines.empty()) {
405     toColumn =
406         ((m_input_lines[m_input_lines.size() - 1].length() + GetPromptWidth()) %
407          80) +
408         1;
409   }
410   fprintf(m_output_file, ANSI_SET_COLUMN_N, toColumn);
411 }
412 
DisplayInput(int firstIndex)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   const char *faint = m_color_prompts ? ANSI_FAINT : "";
417   const char *unfaint = m_color_prompts ? ANSI_UNFAINT : "";
418 
419   for (int index = firstIndex; index < line_count; index++) {
420     fprintf(m_output_file, "%s"
421                            "%s"
422                            "%s" EditLineStringFormatSpec " ",
423             faint, PromptForIndex(index).c_str(), unfaint,
424             m_input_lines[index].c_str());
425     if (index < line_count - 1)
426       fprintf(m_output_file, "\n");
427   }
428 }
429 
CountRowsForLine(const EditLineStringType & content)430 int Editline::CountRowsForLine(const EditLineStringType &content) {
431   std::string prompt =
432       PromptForIndex(0); // Prompt width is constant during an edit session
433   int line_length = (int)(content.length() + prompt.length());
434   return (line_length / m_terminal_width) + 1;
435 }
436 
SaveEditedLine()437 void Editline::SaveEditedLine() {
438   const LineInfoW *info = el_wline(m_editline);
439   m_input_lines[m_current_line_index] =
440       EditLineStringType(info->buffer, info->lastchar - info->buffer);
441 }
442 
GetInputAsStringList(int line_count)443 StringList Editline::GetInputAsStringList(int line_count) {
444   StringList lines;
445   for (EditLineStringType line : m_input_lines) {
446     if (line_count == 0)
447       break;
448 #if LLDB_EDITLINE_USE_WCHAR
449     lines.AppendString(m_utf8conv.to_bytes(line));
450 #else
451     lines.AppendString(line);
452 #endif
453     --line_count;
454   }
455   return lines;
456 }
457 
RecallHistory(HistoryOperation op)458 unsigned char Editline::RecallHistory(HistoryOperation op) {
459   assert(op == HistoryOperation::Older || op == HistoryOperation::Newer);
460   if (!m_history_sp || !m_history_sp->IsValid())
461     return CC_ERROR;
462 
463   HistoryW *pHistory = m_history_sp->GetHistoryPtr();
464   HistEventW history_event;
465   std::vector<EditLineStringType> new_input_lines;
466 
467   // Treat moving from the "live" entry differently
468   if (!m_in_history) {
469     switch (op) {
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)
475         return CC_ERROR;
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
479       // the end.)
480       SaveEditedLine();
481       m_live_history_lines = m_input_lines;
482       m_in_history = true;
483     } break;
484     default:
485       llvm_unreachable("unsupported history direction");
486     }
487   } else {
488     if (history_w(pHistory, &history_event, GetOperation(op)) == -1) {
489       switch (op) {
490       case HistoryOperation::Older:
491         // Can't move earlier than the earliest entry.
492         return CC_ERROR;
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;
497         break;
498       default:
499         llvm_unreachable("unsupported history direction");
500       }
501     }
502   }
503 
504   // If we're pulling the lines from history, split them apart
505   if (m_in_history)
506     new_input_lines = SplitLines(history_event.str);
507 
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;
511   DisplayInput();
512 
513   // Prepare to edit the last line when moving to previous entry, or the first
514   // line when moving to next entry
515   switch (op) {
516   case HistoryOperation::Older:
517     m_current_line_index = (int)m_input_lines.size() - 1;
518     break;
519   case HistoryOperation::Newer:
520     m_current_line_index = 0;
521     break;
522   default:
523     llvm_unreachable("unsupported history direction");
524   }
525   SetCurrentLine(m_current_line_index);
526   MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
527   return CC_NEWLINE;
528 }
529 
GetCharacter(EditLineGetCharType * c)530 int Editline::GetCharacter(EditLineGetCharType *c) {
531   const LineInfoW *info = el_wline(m_editline);
532 
533   // Paint a faint version of the desired prompt over the version libedit draws
534   // (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, "%s"
538                            "%s"
539                            "%s",
540             ANSI_FAINT, Prompt(), ANSI_UNFAINT);
541     MoveCursor(CursorLocation::EditingPrompt, CursorLocation::EditingCursor);
542     m_needs_prompt_repaint = false;
543   }
544 
545   if (m_multiline_enabled) {
546     // Detect when the number of rows used for this input line changes due to
547     // an edit
548     int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth());
549     int new_line_rows = (lineLength / m_terminal_width) + 1;
550     if (m_current_line_rows != -1 && new_line_rows != m_current_line_rows) {
551       // Respond by repainting the current state from this line on
552       MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
553       SaveEditedLine();
554       DisplayInput(m_current_line_index);
555       MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
556     }
557     m_current_line_rows = new_line_rows;
558   }
559 
560   // Read an actual character
561   while (true) {
562     lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
563     char ch = 0;
564 
565     if (m_terminal_size_has_changed)
566       ApplyTerminalSizeChange();
567 
568     // This mutex is locked by our caller (GetLine). Unlock it while we read a
569     // character (blocking operation), so we do not hold the mutex
570     // indefinitely. This gives a chance for someone to interrupt us. After
571     // Read returns, immediately lock the mutex again and check if we were
572     // interrupted.
573     m_output_mutex.unlock();
574     int read_count =
575         m_input_connection.Read(&ch, 1, llvm::None, status, nullptr);
576     m_output_mutex.lock();
577     if (m_editor_status == EditorStatus::Interrupted) {
578       while (read_count > 0 && status == lldb::eConnectionStatusSuccess)
579         read_count =
580             m_input_connection.Read(&ch, 1, llvm::None, status, nullptr);
581       lldbassert(status == lldb::eConnectionStatusInterrupted);
582       return 0;
583     }
584 
585     if (read_count) {
586       if (CompleteCharacter(ch, *c))
587         return 1;
588     } else {
589       switch (status) {
590       case lldb::eConnectionStatusSuccess: // Success
591         break;
592 
593       case lldb::eConnectionStatusInterrupted:
594         llvm_unreachable("Interrupts should have been handled above.");
595 
596       case lldb::eConnectionStatusError:        // Check GetError() for details
597       case lldb::eConnectionStatusTimedOut:     // Request timed out
598       case lldb::eConnectionStatusEndOfFile:    // End-of-file encountered
599       case lldb::eConnectionStatusNoConnection: // No connection
600       case lldb::eConnectionStatusLostConnection: // Lost connection while
601                                                   // connected to a valid
602                                                   // connection
603         m_editor_status = EditorStatus::EndOfInput;
604         return 0;
605       }
606     }
607   }
608 }
609 
Prompt()610 const char *Editline::Prompt() {
611   if (m_color_prompts)
612     m_needs_prompt_repaint = true;
613   return m_current_prompt.c_str();
614 }
615 
BreakLineCommand(int ch)616 unsigned char Editline::BreakLineCommand(int ch) {
617   // Preserve any content beyond the cursor, truncate and save the current line
618   const LineInfoW *info = el_wline(m_editline);
619   auto current_line =
620       EditLineStringType(info->buffer, info->cursor - info->buffer);
621   auto new_line_fragment =
622       EditLineStringType(info->cursor, info->lastchar - info->cursor);
623   m_input_lines[m_current_line_index] = current_line;
624 
625   // Ignore whitespace-only extra fragments when breaking a line
626   if (::IsOnlySpaces(new_line_fragment))
627     new_line_fragment = EditLineConstString("");
628 
629   // Establish the new cursor position at the start of a line when inserting a
630   // line break
631   m_revert_cursor_index = 0;
632 
633   // Don't perform automatic formatting when pasting
634   if (!IsInputPending(m_input_file)) {
635     // Apply smart indentation
636     if (m_fix_indentation_callback) {
637       StringList lines = GetInputAsStringList(m_current_line_index + 1);
638 #if LLDB_EDITLINE_USE_WCHAR
639       lines.AppendString(m_utf8conv.to_bytes(new_line_fragment));
640 #else
641       lines.AppendString(new_line_fragment);
642 #endif
643 
644       int indent_correction = m_fix_indentation_callback(
645           this, lines, 0, m_fix_indentation_callback_baton);
646       new_line_fragment = FixIndentation(new_line_fragment, indent_correction);
647       m_revert_cursor_index = GetIndentation(new_line_fragment);
648     }
649   }
650 
651   // Insert the new line and repaint everything from the split line on down
652   m_input_lines.insert(m_input_lines.begin() + m_current_line_index + 1,
653                        new_line_fragment);
654   MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
655   DisplayInput(m_current_line_index);
656 
657   // Reposition the cursor to the right line and prepare to edit the new line
658   SetCurrentLine(m_current_line_index + 1);
659   MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
660   return CC_NEWLINE;
661 }
662 
EndOrAddLineCommand(int ch)663 unsigned char Editline::EndOrAddLineCommand(int ch) {
664   // Don't perform end of input detection when pasting, always treat this as a
665   // line break
666   if (IsInputPending(m_input_file)) {
667     return BreakLineCommand(ch);
668   }
669 
670   // Save any edits to this line
671   SaveEditedLine();
672 
673   // If this is the end of the last line, consider whether to add a line
674   // instead
675   const LineInfoW *info = el_wline(m_editline);
676   if (m_current_line_index == m_input_lines.size() - 1 &&
677       info->cursor == info->lastchar) {
678     if (m_is_input_complete_callback) {
679       auto lines = GetInputAsStringList();
680       if (!m_is_input_complete_callback(this, lines,
681                                         m_is_input_complete_callback_baton)) {
682         return BreakLineCommand(ch);
683       }
684 
685       // The completion test is allowed to change the input lines when complete
686       m_input_lines.clear();
687       for (unsigned index = 0; index < lines.GetSize(); index++) {
688 #if LLDB_EDITLINE_USE_WCHAR
689         m_input_lines.insert(m_input_lines.end(),
690                              m_utf8conv.from_bytes(lines[index]));
691 #else
692         m_input_lines.insert(m_input_lines.end(), lines[index]);
693 #endif
694       }
695     }
696   }
697   MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd);
698   fprintf(m_output_file, "\n");
699   m_editor_status = EditorStatus::Complete;
700   return CC_NEWLINE;
701 }
702 
DeleteNextCharCommand(int ch)703 unsigned char Editline::DeleteNextCharCommand(int ch) {
704   LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline));
705 
706   // Just delete the next character normally if possible
707   if (info->cursor < info->lastchar) {
708     info->cursor++;
709     el_deletestr(m_editline, 1);
710     return CC_REFRESH;
711   }
712 
713   // Fail when at the end of the last line, except when ^D is pressed on the
714   // line is empty, in which case it is treated as EOF
715   if (m_current_line_index == m_input_lines.size() - 1) {
716     if (ch == 4 && info->buffer == info->lastchar) {
717       fprintf(m_output_file, "^D\n");
718       m_editor_status = EditorStatus::EndOfInput;
719       return CC_EOF;
720     }
721     return CC_ERROR;
722   }
723 
724   // Prepare to combine this line with the one below
725   MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
726 
727   // Insert the next line of text at the cursor and restore the cursor position
728   const EditLineCharType *cursor = info->cursor;
729   el_winsertstr(m_editline, m_input_lines[m_current_line_index + 1].c_str());
730   info->cursor = cursor;
731   SaveEditedLine();
732 
733   // Delete the extra line
734   m_input_lines.erase(m_input_lines.begin() + m_current_line_index + 1);
735 
736   // Clear and repaint from this line on down
737   DisplayInput(m_current_line_index);
738   MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
739   return CC_REFRESH;
740 }
741 
DeletePreviousCharCommand(int ch)742 unsigned char Editline::DeletePreviousCharCommand(int ch) {
743   LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline));
744 
745   // Just delete the previous character normally when not at the start of a
746   // line
747   if (info->cursor > info->buffer) {
748     el_deletestr(m_editline, 1);
749     return CC_REFRESH;
750   }
751 
752   // No prior line and no prior character?  Let the user know
753   if (m_current_line_index == 0)
754     return CC_ERROR;
755 
756   // No prior character, but prior line?  Combine with the line above
757   SaveEditedLine();
758   SetCurrentLine(m_current_line_index - 1);
759   auto priorLine = m_input_lines[m_current_line_index];
760   m_input_lines.erase(m_input_lines.begin() + m_current_line_index);
761   m_input_lines[m_current_line_index] =
762       priorLine + m_input_lines[m_current_line_index];
763 
764   // Repaint from the new line down
765   fprintf(m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N,
766           CountRowsForLine(priorLine), 1);
767   DisplayInput(m_current_line_index);
768 
769   // Put the cursor back where libedit expects it to be before returning to
770   // editing by telling libedit about the newly inserted text
771   MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
772   el_winsertstr(m_editline, priorLine.c_str());
773   return CC_REDISPLAY;
774 }
775 
PreviousLineCommand(int ch)776 unsigned char Editline::PreviousLineCommand(int ch) {
777   SaveEditedLine();
778 
779   if (m_current_line_index == 0) {
780     return RecallHistory(HistoryOperation::Older);
781   }
782 
783   // Start from a known location
784   MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
785 
786   // Treat moving up from a blank last line as a deletion of that line
787   if (m_current_line_index == m_input_lines.size() - 1 && IsOnlySpaces()) {
788     m_input_lines.erase(m_input_lines.begin() + m_current_line_index);
789     fprintf(m_output_file, ANSI_CLEAR_BELOW);
790   }
791 
792   SetCurrentLine(m_current_line_index - 1);
793   fprintf(m_output_file, ANSI_UP_N_ROWS ANSI_SET_COLUMN_N,
794           CountRowsForLine(m_input_lines[m_current_line_index]), 1);
795   return CC_NEWLINE;
796 }
797 
NextLineCommand(int ch)798 unsigned char Editline::NextLineCommand(int ch) {
799   SaveEditedLine();
800 
801   // Handle attempts to move down from the last line
802   if (m_current_line_index == m_input_lines.size() - 1) {
803     // Don't add an extra line if the existing last line is blank, move through
804     // history instead
805     if (IsOnlySpaces()) {
806       return RecallHistory(HistoryOperation::Newer);
807     }
808 
809     // Determine indentation for the new line
810     int indentation = 0;
811     if (m_fix_indentation_callback) {
812       StringList lines = GetInputAsStringList();
813       lines.AppendString("");
814       indentation = m_fix_indentation_callback(
815           this, lines, 0, m_fix_indentation_callback_baton);
816     }
817     m_input_lines.insert(
818         m_input_lines.end(),
819         EditLineStringType(indentation, EditLineCharType(' ')));
820   }
821 
822   // Move down past the current line using newlines to force scrolling if
823   // needed
824   SetCurrentLine(m_current_line_index + 1);
825   const LineInfoW *info = el_wline(m_editline);
826   int cursor_position = (int)((info->cursor - info->buffer) + GetPromptWidth());
827   int cursor_row = cursor_position / m_terminal_width;
828   for (int line_count = 0; line_count < m_current_line_rows - cursor_row;
829        line_count++) {
830     fprintf(m_output_file, "\n");
831   }
832   return CC_NEWLINE;
833 }
834 
PreviousHistoryCommand(int ch)835 unsigned char Editline::PreviousHistoryCommand(int ch) {
836   SaveEditedLine();
837 
838   return RecallHistory(HistoryOperation::Older);
839 }
840 
NextHistoryCommand(int ch)841 unsigned char Editline::NextHistoryCommand(int ch) {
842   SaveEditedLine();
843 
844   return RecallHistory(HistoryOperation::Newer);
845 }
846 
FixIndentationCommand(int ch)847 unsigned char Editline::FixIndentationCommand(int ch) {
848   if (!m_fix_indentation_callback)
849     return CC_NORM;
850 
851   // Insert the character typed before proceeding
852   EditLineCharType inserted[] = {(EditLineCharType)ch, 0};
853   el_winsertstr(m_editline, inserted);
854   LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline));
855   int cursor_position = info->cursor - info->buffer;
856 
857   // Save the edits and determine the correct indentation level
858   SaveEditedLine();
859   StringList lines = GetInputAsStringList(m_current_line_index + 1);
860   int indent_correction = m_fix_indentation_callback(
861       this, lines, cursor_position, m_fix_indentation_callback_baton);
862 
863   // If it is already correct no special work is needed
864   if (indent_correction == 0)
865     return CC_REFRESH;
866 
867   // Change the indentation level of the line
868   std::string currentLine = lines.GetStringAtIndex(m_current_line_index);
869   if (indent_correction > 0) {
870     currentLine = currentLine.insert(0, indent_correction, ' ');
871   } else {
872     currentLine = currentLine.erase(0, -indent_correction);
873   }
874 #if LLDB_EDITLINE_USE_WCHAR
875   m_input_lines[m_current_line_index] = m_utf8conv.from_bytes(currentLine);
876 #else
877   m_input_lines[m_current_line_index] = currentLine;
878 #endif
879 
880   // Update the display to reflect the change
881   MoveCursor(CursorLocation::EditingCursor, CursorLocation::EditingPrompt);
882   DisplayInput(m_current_line_index);
883 
884   // Reposition the cursor back on the original line and prepare to restart
885   // editing with a new cursor position
886   SetCurrentLine(m_current_line_index);
887   MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
888   m_revert_cursor_index = cursor_position + indent_correction;
889   return CC_NEWLINE;
890 }
891 
RevertLineCommand(int ch)892 unsigned char Editline::RevertLineCommand(int ch) {
893   el_winsertstr(m_editline, m_input_lines[m_current_line_index].c_str());
894   if (m_revert_cursor_index >= 0) {
895     LineInfoW *info = const_cast<LineInfoW *>(el_wline(m_editline));
896     info->cursor = info->buffer + m_revert_cursor_index;
897     if (info->cursor > info->lastchar) {
898       info->cursor = info->lastchar;
899     }
900     m_revert_cursor_index = -1;
901   }
902   return CC_REFRESH;
903 }
904 
BufferStartCommand(int ch)905 unsigned char Editline::BufferStartCommand(int ch) {
906   SaveEditedLine();
907   MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
908   SetCurrentLine(0);
909   m_revert_cursor_index = 0;
910   return CC_NEWLINE;
911 }
912 
BufferEndCommand(int ch)913 unsigned char Editline::BufferEndCommand(int ch) {
914   SaveEditedLine();
915   MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockEnd);
916   SetCurrentLine((int)m_input_lines.size() - 1);
917   MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingPrompt);
918   return CC_NEWLINE;
919 }
920 
921 /// Prints completions and their descriptions to the given file. Only the
922 /// completions in the interval [start, end) are printed.
923 static void
PrintCompletion(FILE * output_file,llvm::ArrayRef<CompletionResult::Completion> results,size_t max_len)924 PrintCompletion(FILE *output_file,
925                 llvm::ArrayRef<CompletionResult::Completion> results,
926                 size_t max_len) {
927   for (const CompletionResult::Completion &c : results) {
928     fprintf(output_file, "\t%-*s", (int)max_len, c.GetCompletion().c_str());
929     if (!c.GetDescription().empty())
930       fprintf(output_file, " -- %s", c.GetDescription().c_str());
931     fprintf(output_file, "\n");
932   }
933 }
934 
935 static void
DisplayCompletions(::EditLine * editline,FILE * output_file,llvm::ArrayRef<CompletionResult::Completion> results)936 DisplayCompletions(::EditLine *editline, FILE *output_file,
937                    llvm::ArrayRef<CompletionResult::Completion> results) {
938   assert(!results.empty());
939 
940   fprintf(output_file, "\n" ANSI_CLEAR_BELOW "Available completions:\n");
941   const size_t page_size = 40;
942   bool all = false;
943 
944   auto longest =
945       std::max_element(results.begin(), results.end(), [](auto &c1, auto &c2) {
946         return c1.GetCompletion().size() < c2.GetCompletion().size();
947       });
948 
949   const size_t max_len = longest->GetCompletion().size();
950 
951   if (results.size() < page_size) {
952     PrintCompletion(output_file, results, max_len);
953     return;
954   }
955 
956   size_t cur_pos = 0;
957   while (cur_pos < results.size()) {
958     size_t remaining = results.size() - cur_pos;
959     size_t next_size = all ? remaining : std::min(page_size, remaining);
960 
961     PrintCompletion(output_file, results.slice(cur_pos, next_size), max_len);
962 
963     cur_pos += next_size;
964 
965     if (cur_pos >= results.size())
966       break;
967 
968     fprintf(output_file, "More (Y/n/a): ");
969     char reply = 'n';
970     int got_char = el_getc(editline, &reply);
971     fprintf(output_file, "\n");
972     if (got_char == -1 || reply == 'n')
973       break;
974     if (reply == 'a')
975       all = true;
976   }
977 }
978 
TabCommand(int ch)979 unsigned char Editline::TabCommand(int ch) {
980   if (m_completion_callback == nullptr)
981     return CC_ERROR;
982 
983   const LineInfo *line_info = el_line(m_editline);
984 
985   llvm::StringRef line(line_info->buffer,
986                        line_info->lastchar - line_info->buffer);
987   unsigned cursor_index = line_info->cursor - line_info->buffer;
988   CompletionResult result;
989   CompletionRequest request(line, cursor_index, result);
990 
991   m_completion_callback(request, m_completion_callback_baton);
992 
993   llvm::ArrayRef<CompletionResult::Completion> results = result.GetResults();
994 
995   StringList completions;
996   result.GetMatches(completions);
997 
998   if (results.size() == 0)
999     return CC_ERROR;
1000 
1001   if (results.size() == 1) {
1002     CompletionResult::Completion completion = results.front();
1003     switch (completion.GetMode()) {
1004     case CompletionMode::Normal: {
1005       std::string to_add = completion.GetCompletion();
1006       to_add = to_add.substr(request.GetCursorArgumentPrefix().size());
1007       // Terminate the current argument with a quote if it started with a quote.
1008       if (!request.GetParsedLine().empty() && request.GetParsedArg().IsQuoted())
1009         to_add.push_back(request.GetParsedArg().GetQuoteChar());
1010       to_add.push_back(' ');
1011       el_insertstr(m_editline, to_add.c_str());
1012       // Clear all the autosuggestion parts if the only single space can be completed.
1013       if (to_add == " ")
1014         return CC_REDISPLAY;
1015       return CC_REFRESH;
1016     }
1017     case CompletionMode::Partial: {
1018       std::string to_add = completion.GetCompletion();
1019       to_add = to_add.substr(request.GetCursorArgumentPrefix().size());
1020       el_insertstr(m_editline, to_add.c_str());
1021       break;
1022     }
1023     case CompletionMode::RewriteLine: {
1024       el_deletestr(m_editline, line_info->cursor - line_info->buffer);
1025       el_insertstr(m_editline, completion.GetCompletion().c_str());
1026       break;
1027     }
1028     }
1029     return CC_REDISPLAY;
1030   }
1031 
1032   // If we get a longer match display that first.
1033   std::string longest_prefix = completions.LongestCommonPrefix();
1034   if (!longest_prefix.empty())
1035     longest_prefix =
1036         longest_prefix.substr(request.GetCursorArgumentPrefix().size());
1037   if (!longest_prefix.empty()) {
1038     el_insertstr(m_editline, longest_prefix.c_str());
1039     return CC_REDISPLAY;
1040   }
1041 
1042   DisplayCompletions(m_editline, m_output_file, results);
1043 
1044   DisplayInput();
1045   MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
1046   return CC_REDISPLAY;
1047 }
1048 
ApplyAutosuggestCommand(int ch)1049 unsigned char Editline::ApplyAutosuggestCommand(int ch) {
1050   const LineInfo *line_info = el_line(m_editline);
1051   llvm::StringRef line(line_info->buffer,
1052                        line_info->lastchar - line_info->buffer);
1053 
1054   if (llvm::Optional<std::string> to_add =
1055           m_suggestion_callback(line, m_suggestion_callback_baton))
1056     el_insertstr(m_editline, to_add->c_str());
1057 
1058   return CC_REDISPLAY;
1059 }
1060 
TypedCharacter(int ch)1061 unsigned char Editline::TypedCharacter(int ch) {
1062   std::string typed = std::string(1, ch);
1063   el_insertstr(m_editline, typed.c_str());
1064   const LineInfo *line_info = el_line(m_editline);
1065   llvm::StringRef line(line_info->buffer,
1066                        line_info->lastchar - line_info->buffer);
1067 
1068   if (llvm::Optional<std::string> to_add =
1069           m_suggestion_callback(line, m_suggestion_callback_baton)) {
1070     std::string to_add_color = ANSI_FAINT + to_add.getValue() + ANSI_UNFAINT;
1071     fputs(typed.c_str(), m_output_file);
1072     fputs(to_add_color.c_str(), m_output_file);
1073     size_t new_autosuggestion_size = line.size() + to_add->length();
1074     // Print spaces to hide any remains of a previous longer autosuggestion.
1075     if (new_autosuggestion_size < m_previous_autosuggestion_size) {
1076       size_t spaces_to_print =
1077           m_previous_autosuggestion_size - new_autosuggestion_size;
1078       std::string spaces = std::string(spaces_to_print, ' ');
1079       fputs(spaces.c_str(), m_output_file);
1080     }
1081     m_previous_autosuggestion_size = new_autosuggestion_size;
1082 
1083     int editline_cursor_position =
1084         (int)((line_info->cursor - line_info->buffer) + GetPromptWidth());
1085     int editline_cursor_row = editline_cursor_position / m_terminal_width;
1086     int toColumn =
1087         editline_cursor_position - (editline_cursor_row * m_terminal_width);
1088     fprintf(m_output_file, ANSI_SET_COLUMN_N, toColumn);
1089     return CC_REFRESH;
1090   }
1091 
1092   return CC_REDISPLAY;
1093 }
1094 
ConfigureEditor(bool multiline)1095 void Editline::ConfigureEditor(bool multiline) {
1096   if (m_editline && m_multiline_enabled == multiline)
1097     return;
1098   m_multiline_enabled = multiline;
1099 
1100   if (m_editline) {
1101     // Disable edit mode to stop the terminal from flushing all input during
1102     // the call to el_end() since we expect to have multiple editline instances
1103     // in this program.
1104     el_set(m_editline, EL_EDITMODE, 0);
1105     el_end(m_editline);
1106   }
1107 
1108   m_editline =
1109       el_init(m_editor_name.c_str(), m_input_file, m_output_file, m_error_file);
1110   ApplyTerminalSizeChange();
1111 
1112   if (m_history_sp && m_history_sp->IsValid()) {
1113     if (!m_history_sp->Load()) {
1114         fputs("Could not load history file\n.", m_output_file);
1115     }
1116     el_wset(m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr());
1117   }
1118   el_set(m_editline, EL_CLIENTDATA, this);
1119   el_set(m_editline, EL_SIGNAL, 0);
1120   el_set(m_editline, EL_EDITOR, "emacs");
1121   el_set(m_editline, EL_PROMPT,
1122          (EditlinePromptCallbackType)([](EditLine *editline) {
1123            return Editline::InstanceFor(editline)->Prompt();
1124          }));
1125 
1126   el_wset(m_editline, EL_GETCFN, (EditlineGetCharCallbackType)([](
1127                                      EditLine *editline, EditLineGetCharType *c) {
1128             return Editline::InstanceFor(editline)->GetCharacter(c);
1129           }));
1130 
1131   // Commands used for multiline support, registered whether or not they're
1132   // used
1133   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-break-line"),
1134           EditLineConstString("Insert a line break"),
1135           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1136             return Editline::InstanceFor(editline)->BreakLineCommand(ch);
1137           }));
1138   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-end-or-add-line"),
1139           EditLineConstString("End editing or continue when incomplete"),
1140           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1141             return Editline::InstanceFor(editline)->EndOrAddLineCommand(ch);
1142           }));
1143   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-next-char"),
1144           EditLineConstString("Delete next character"),
1145           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1146             return Editline::InstanceFor(editline)->DeleteNextCharCommand(ch);
1147           }));
1148   el_wset(
1149       m_editline, EL_ADDFN, EditLineConstString("lldb-delete-previous-char"),
1150       EditLineConstString("Delete previous character"),
1151       (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1152         return Editline::InstanceFor(editline)->DeletePreviousCharCommand(ch);
1153       }));
1154   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-line"),
1155           EditLineConstString("Move to previous line"),
1156           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1157             return Editline::InstanceFor(editline)->PreviousLineCommand(ch);
1158           }));
1159   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-line"),
1160           EditLineConstString("Move to next line"),
1161           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1162             return Editline::InstanceFor(editline)->NextLineCommand(ch);
1163           }));
1164   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-history"),
1165           EditLineConstString("Move to previous history"),
1166           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1167             return Editline::InstanceFor(editline)->PreviousHistoryCommand(ch);
1168           }));
1169   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-history"),
1170           EditLineConstString("Move to next history"),
1171           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1172             return Editline::InstanceFor(editline)->NextHistoryCommand(ch);
1173           }));
1174   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-start"),
1175           EditLineConstString("Move to start of buffer"),
1176           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1177             return Editline::InstanceFor(editline)->BufferStartCommand(ch);
1178           }));
1179   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-end"),
1180           EditLineConstString("Move to end of buffer"),
1181           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1182             return Editline::InstanceFor(editline)->BufferEndCommand(ch);
1183           }));
1184   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-fix-indentation"),
1185           EditLineConstString("Fix line indentation"),
1186           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1187             return Editline::InstanceFor(editline)->FixIndentationCommand(ch);
1188           }));
1189 
1190   // Register the complete callback under two names for compatibility with
1191   // older clients using custom .editrc files (largely because libedit has a
1192   // bad bug where if you have a bind command that tries to bind to a function
1193   // name that doesn't exist, it can corrupt the heap and crash your process
1194   // later.)
1195   EditlineCommandCallbackType complete_callback = [](EditLine *editline,
1196                                                      int ch) {
1197     return Editline::InstanceFor(editline)->TabCommand(ch);
1198   };
1199   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-complete"),
1200           EditLineConstString("Invoke completion"), complete_callback);
1201   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb_complete"),
1202           EditLineConstString("Invoke completion"), complete_callback);
1203 
1204   // General bindings we don't mind being overridden
1205   if (!multiline) {
1206     el_set(m_editline, EL_BIND, "^r", "em-inc-search-prev",
1207            NULL); // Cycle through backwards search, entering string
1208 
1209     if (m_suggestion_callback) {
1210       el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-apply-complete"),
1211               EditLineConstString("Adopt autocompletion"),
1212               (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1213                 return Editline::InstanceFor(editline)->ApplyAutosuggestCommand(
1214                     ch);
1215               }));
1216 
1217       el_set(m_editline, EL_BIND, "^f", "lldb-apply-complete",
1218              NULL); // Apply a part that is suggested automatically
1219 
1220       el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-typed-character"),
1221               EditLineConstString("Typed character"),
1222               (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1223                 return Editline::InstanceFor(editline)->TypedCharacter(ch);
1224               }));
1225 
1226       char bind_key[2] = {0, 0};
1227       llvm::StringRef ascii_chars =
1228           "abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXZY1234567890!\"#$%"
1229           "&'()*+,./:;<=>?@[]_`{|}~ ";
1230       for (char c : ascii_chars) {
1231         bind_key[0] = c;
1232         el_set(m_editline, EL_BIND, bind_key, "lldb-typed-character", NULL);
1233       }
1234       el_set(m_editline, EL_BIND, "\\-", "lldb-typed-character", NULL);
1235       el_set(m_editline, EL_BIND, "\\^", "lldb-typed-character", NULL);
1236       el_set(m_editline, EL_BIND, "\\\\", "lldb-typed-character", NULL);
1237     }
1238   }
1239 
1240   el_set(m_editline, EL_BIND, "^w", "ed-delete-prev-word",
1241          NULL); // Delete previous word, behave like bash in emacs mode
1242   el_set(m_editline, EL_BIND, "\t", "lldb-complete",
1243          NULL); // Bind TAB to auto complete
1244 
1245   // Allow ctrl-left-arrow and ctrl-right-arrow for navigation, behave like
1246   // bash in emacs mode.
1247   el_set(m_editline, EL_BIND, ESCAPE "[1;5C", "em-next-word", NULL);
1248   el_set(m_editline, EL_BIND, ESCAPE "[1;5D", "ed-prev-word", NULL);
1249   el_set(m_editline, EL_BIND, ESCAPE "[5C", "em-next-word", NULL);
1250   el_set(m_editline, EL_BIND, ESCAPE "[5D", "ed-prev-word", NULL);
1251   el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[C", "em-next-word", NULL);
1252   el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[D", "ed-prev-word", NULL);
1253 
1254   // Allow user-specific customization prior to registering bindings we
1255   // absolutely require
1256   el_source(m_editline, nullptr);
1257 
1258   // Register an internal binding that external developers shouldn't use
1259   el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-revert-line"),
1260           EditLineConstString("Revert line to saved state"),
1261           (EditlineCommandCallbackType)([](EditLine *editline, int ch) {
1262             return Editline::InstanceFor(editline)->RevertLineCommand(ch);
1263           }));
1264 
1265   // Register keys that perform auto-indent correction
1266   if (m_fix_indentation_callback && m_fix_indentation_callback_chars) {
1267     char bind_key[2] = {0, 0};
1268     const char *indent_chars = m_fix_indentation_callback_chars;
1269     while (*indent_chars) {
1270       bind_key[0] = *indent_chars;
1271       el_set(m_editline, EL_BIND, bind_key, "lldb-fix-indentation", NULL);
1272       ++indent_chars;
1273     }
1274   }
1275 
1276   // Multi-line editor bindings
1277   if (multiline) {
1278     el_set(m_editline, EL_BIND, "\n", "lldb-end-or-add-line", NULL);
1279     el_set(m_editline, EL_BIND, "\r", "lldb-end-or-add-line", NULL);
1280     el_set(m_editline, EL_BIND, ESCAPE "\n", "lldb-break-line", NULL);
1281     el_set(m_editline, EL_BIND, ESCAPE "\r", "lldb-break-line", NULL);
1282     el_set(m_editline, EL_BIND, "^p", "lldb-previous-line", NULL);
1283     el_set(m_editline, EL_BIND, "^n", "lldb-next-line", NULL);
1284     el_set(m_editline, EL_BIND, "^?", "lldb-delete-previous-char", NULL);
1285     el_set(m_editline, EL_BIND, "^d", "lldb-delete-next-char", NULL);
1286     el_set(m_editline, EL_BIND, ESCAPE "[3~", "lldb-delete-next-char", NULL);
1287     el_set(m_editline, EL_BIND, ESCAPE "[\\^", "lldb-revert-line", NULL);
1288 
1289     // Editor-specific bindings
1290     if (IsEmacs()) {
1291       el_set(m_editline, EL_BIND, ESCAPE "<", "lldb-buffer-start", NULL);
1292       el_set(m_editline, EL_BIND, ESCAPE ">", "lldb-buffer-end", NULL);
1293       el_set(m_editline, EL_BIND, ESCAPE "[A", "lldb-previous-line", NULL);
1294       el_set(m_editline, EL_BIND, ESCAPE "[B", "lldb-next-line", NULL);
1295       el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[A", "lldb-previous-history",
1296              NULL);
1297       el_set(m_editline, EL_BIND, ESCAPE ESCAPE "[B", "lldb-next-history",
1298              NULL);
1299       el_set(m_editline, EL_BIND, ESCAPE "[1;3A", "lldb-previous-history",
1300              NULL);
1301       el_set(m_editline, EL_BIND, ESCAPE "[1;3B", "lldb-next-history", NULL);
1302     } else {
1303       el_set(m_editline, EL_BIND, "^H", "lldb-delete-previous-char", NULL);
1304 
1305       el_set(m_editline, EL_BIND, "-a", ESCAPE "[A", "lldb-previous-line",
1306              NULL);
1307       el_set(m_editline, EL_BIND, "-a", ESCAPE "[B", "lldb-next-line", NULL);
1308       el_set(m_editline, EL_BIND, "-a", "x", "lldb-delete-next-char", NULL);
1309       el_set(m_editline, EL_BIND, "-a", "^H", "lldb-delete-previous-char",
1310              NULL);
1311       el_set(m_editline, EL_BIND, "-a", "^?", "lldb-delete-previous-char",
1312              NULL);
1313 
1314       // Escape is absorbed exiting edit mode, so re-register important
1315       // sequences without the prefix
1316       el_set(m_editline, EL_BIND, "-a", "[A", "lldb-previous-line", NULL);
1317       el_set(m_editline, EL_BIND, "-a", "[B", "lldb-next-line", NULL);
1318       el_set(m_editline, EL_BIND, "-a", "[\\^", "lldb-revert-line", NULL);
1319     }
1320   }
1321 }
1322 
1323 // Editline public methods
1324 
InstanceFor(EditLine * editline)1325 Editline *Editline::InstanceFor(EditLine *editline) {
1326   Editline *editor;
1327   el_get(editline, EL_CLIENTDATA, &editor);
1328   return editor;
1329 }
1330 
Editline(const char * editline_name,FILE * input_file,FILE * output_file,FILE * error_file,bool color_prompts)1331 Editline::Editline(const char *editline_name, FILE *input_file,
1332                    FILE *output_file, FILE *error_file, bool color_prompts)
1333     : m_editor_status(EditorStatus::Complete), m_color_prompts(color_prompts),
1334       m_input_file(input_file), m_output_file(output_file),
1335       m_error_file(error_file), m_input_connection(fileno(input_file), false) {
1336   // Get a shared history instance
1337   m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name;
1338   m_history_sp = EditlineHistory::GetHistory(m_editor_name);
1339 
1340 #ifdef USE_SETUPTERM_WORKAROUND
1341   if (m_output_file) {
1342     const int term_fd = fileno(m_output_file);
1343     if (term_fd != -1) {
1344       static std::mutex *g_init_terminal_fds_mutex_ptr = nullptr;
1345       static std::set<int> *g_init_terminal_fds_ptr = nullptr;
1346       static llvm::once_flag g_once_flag;
1347       llvm::call_once(g_once_flag, [&]() {
1348         g_init_terminal_fds_mutex_ptr =
1349             new std::mutex(); // NOTE: Leak to avoid C++ destructor chain issues
1350         g_init_terminal_fds_ptr = new std::set<int>(); // NOTE: Leak to avoid
1351                                                        // C++ destructor chain
1352                                                        // issues
1353       });
1354 
1355       // We must make sure to initialize the terminal a given file descriptor
1356       // only once. If we do this multiple times, we start leaking memory.
1357       std::lock_guard<std::mutex> guard(*g_init_terminal_fds_mutex_ptr);
1358       if (g_init_terminal_fds_ptr->find(term_fd) ==
1359           g_init_terminal_fds_ptr->end()) {
1360         g_init_terminal_fds_ptr->insert(term_fd);
1361         setupterm((char *)0, term_fd, (int *)0);
1362       }
1363     }
1364   }
1365 #endif
1366 }
1367 
~Editline()1368 Editline::~Editline() {
1369   if (m_editline) {
1370     // Disable edit mode to stop the terminal from flushing all input during
1371     // the call to el_end() since we expect to have multiple editline instances
1372     // in this program.
1373     el_set(m_editline, EL_EDITMODE, 0);
1374     el_end(m_editline);
1375     m_editline = nullptr;
1376   }
1377 
1378   // EditlineHistory objects are sometimes shared between multiple Editline
1379   // instances with the same program name. So just release our shared pointer
1380   // and if we are the last owner, it will save the history to the history save
1381   // file automatically.
1382   m_history_sp.reset();
1383 }
1384 
SetPrompt(const char * prompt)1385 void Editline::SetPrompt(const char *prompt) {
1386   m_set_prompt = prompt == nullptr ? "" : prompt;
1387 }
1388 
SetContinuationPrompt(const char * continuation_prompt)1389 void Editline::SetContinuationPrompt(const char *continuation_prompt) {
1390   m_set_continuation_prompt =
1391       continuation_prompt == nullptr ? "" : continuation_prompt;
1392 }
1393 
TerminalSizeChanged()1394 void Editline::TerminalSizeChanged() { m_terminal_size_has_changed = 1; }
1395 
ApplyTerminalSizeChange()1396 void Editline::ApplyTerminalSizeChange() {
1397   if (!m_editline)
1398     return;
1399 
1400   m_terminal_size_has_changed = 0;
1401   el_resize(m_editline);
1402   int columns;
1403   // This function is documenting as taking (const char *, void *) for the
1404   // vararg part, but in reality in was consuming arguments until the first
1405   // null pointer. This was fixed in libedit in April 2019
1406   // <http://mail-index.netbsd.org/source-changes/2019/04/26/msg105454.html>,
1407   // but we're keeping the workaround until a version with that fix is more
1408   // widely available.
1409   if (el_get(m_editline, EL_GETTC, "co", &columns, nullptr) == 0) {
1410     m_terminal_width = columns;
1411     if (m_current_line_rows != -1) {
1412       const LineInfoW *info = el_wline(m_editline);
1413       int lineLength =
1414           (int)((info->lastchar - info->buffer) + GetPromptWidth());
1415       m_current_line_rows = (lineLength / columns) + 1;
1416     }
1417   } else {
1418     m_terminal_width = INT_MAX;
1419     m_current_line_rows = 1;
1420   }
1421 }
1422 
GetPrompt()1423 const char *Editline::GetPrompt() { return m_set_prompt.c_str(); }
1424 
GetCurrentLine()1425 uint32_t Editline::GetCurrentLine() { return m_current_line_index; }
1426 
Interrupt()1427 bool Editline::Interrupt() {
1428   bool result = true;
1429   std::lock_guard<std::mutex> guard(m_output_mutex);
1430   if (m_editor_status == EditorStatus::Editing) {
1431     fprintf(m_output_file, "^C\n");
1432     result = m_input_connection.InterruptRead();
1433   }
1434   m_editor_status = EditorStatus::Interrupted;
1435   return result;
1436 }
1437 
Cancel()1438 bool Editline::Cancel() {
1439   bool result = true;
1440   std::lock_guard<std::mutex> guard(m_output_mutex);
1441   if (m_editor_status == EditorStatus::Editing) {
1442     MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
1443     fprintf(m_output_file, ANSI_CLEAR_BELOW);
1444     result = m_input_connection.InterruptRead();
1445   }
1446   m_editor_status = EditorStatus::Interrupted;
1447   return result;
1448 }
1449 
SetSuggestionCallback(SuggestionCallbackType callback,void * baton)1450 void Editline::SetSuggestionCallback(SuggestionCallbackType callback,
1451                                      void *baton) {
1452   m_suggestion_callback = callback;
1453   m_suggestion_callback_baton = baton;
1454 }
1455 
SetAutoCompleteCallback(CompleteCallbackType callback,void * baton)1456 void Editline::SetAutoCompleteCallback(CompleteCallbackType callback,
1457                                        void *baton) {
1458   m_completion_callback = callback;
1459   m_completion_callback_baton = baton;
1460 }
1461 
SetIsInputCompleteCallback(IsInputCompleteCallbackType callback,void * baton)1462 void Editline::SetIsInputCompleteCallback(IsInputCompleteCallbackType callback,
1463                                           void *baton) {
1464   m_is_input_complete_callback = callback;
1465   m_is_input_complete_callback_baton = baton;
1466 }
1467 
SetFixIndentationCallback(FixIndentationCallbackType callback,void * baton,const char * indent_chars)1468 bool Editline::SetFixIndentationCallback(FixIndentationCallbackType callback,
1469                                          void *baton,
1470                                          const char *indent_chars) {
1471   m_fix_indentation_callback = callback;
1472   m_fix_indentation_callback_baton = baton;
1473   m_fix_indentation_callback_chars = indent_chars;
1474   return false;
1475 }
1476 
GetLine(std::string & line,bool & interrupted)1477 bool Editline::GetLine(std::string &line, bool &interrupted) {
1478   ConfigureEditor(false);
1479   m_input_lines = std::vector<EditLineStringType>();
1480   m_input_lines.insert(m_input_lines.begin(), EditLineConstString(""));
1481 
1482   std::lock_guard<std::mutex> guard(m_output_mutex);
1483 
1484   lldbassert(m_editor_status != EditorStatus::Editing);
1485   if (m_editor_status == EditorStatus::Interrupted) {
1486     m_editor_status = EditorStatus::Complete;
1487     interrupted = true;
1488     return true;
1489   }
1490 
1491   SetCurrentLine(0);
1492   m_in_history = false;
1493   m_editor_status = EditorStatus::Editing;
1494   m_revert_cursor_index = -1;
1495 
1496   int count;
1497   auto input = el_wgets(m_editline, &count);
1498 
1499   interrupted = m_editor_status == EditorStatus::Interrupted;
1500   if (!interrupted) {
1501     if (input == nullptr) {
1502       fprintf(m_output_file, "\n");
1503       m_editor_status = EditorStatus::EndOfInput;
1504     } else {
1505       m_history_sp->Enter(input);
1506 #if LLDB_EDITLINE_USE_WCHAR
1507       line = m_utf8conv.to_bytes(SplitLines(input)[0]);
1508 #else
1509       line = SplitLines(input)[0];
1510 #endif
1511       m_editor_status = EditorStatus::Complete;
1512     }
1513   }
1514   return m_editor_status != EditorStatus::EndOfInput;
1515 }
1516 
GetLines(int first_line_number,StringList & lines,bool & interrupted)1517 bool Editline::GetLines(int first_line_number, StringList &lines,
1518                         bool &interrupted) {
1519   ConfigureEditor(true);
1520 
1521   // Print the initial input lines, then move the cursor back up to the start
1522   // of input
1523   SetBaseLineNumber(first_line_number);
1524   m_input_lines = std::vector<EditLineStringType>();
1525   m_input_lines.insert(m_input_lines.begin(), EditLineConstString(""));
1526 
1527   std::lock_guard<std::mutex> guard(m_output_mutex);
1528   // Begin the line editing loop
1529   DisplayInput();
1530   SetCurrentLine(0);
1531   MoveCursor(CursorLocation::BlockEnd, CursorLocation::BlockStart);
1532   m_editor_status = EditorStatus::Editing;
1533   m_in_history = false;
1534 
1535   m_revert_cursor_index = -1;
1536   while (m_editor_status == EditorStatus::Editing) {
1537     int count;
1538     m_current_line_rows = -1;
1539     el_wpush(m_editline, EditLineConstString(
1540                              "\x1b[^")); // Revert to the existing line content
1541     el_wgets(m_editline, &count);
1542   }
1543 
1544   interrupted = m_editor_status == EditorStatus::Interrupted;
1545   if (!interrupted) {
1546     // Save the completed entry in history before returning
1547     m_history_sp->Enter(CombineLines(m_input_lines).c_str());
1548 
1549     lines = GetInputAsStringList();
1550   }
1551   return m_editor_status != EditorStatus::EndOfInput;
1552 }
1553 
PrintAsync(Stream * stream,const char * s,size_t len)1554 void Editline::PrintAsync(Stream *stream, const char *s, size_t len) {
1555   std::lock_guard<std::mutex> guard(m_output_mutex);
1556   if (m_editor_status == EditorStatus::Editing) {
1557     MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart);
1558     fprintf(m_output_file, ANSI_CLEAR_BELOW);
1559   }
1560   stream->Write(s, len);
1561   stream->Flush();
1562   if (m_editor_status == EditorStatus::Editing) {
1563     DisplayInput();
1564     MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor);
1565   }
1566 }
1567 
CompleteCharacter(char ch,EditLineGetCharType & out)1568 bool Editline::CompleteCharacter(char ch, EditLineGetCharType &out) {
1569 #if !LLDB_EDITLINE_USE_WCHAR
1570   if (ch == (char)EOF)
1571     return false;
1572 
1573   out = (unsigned char)ch;
1574   return true;
1575 #else
1576   std::codecvt_utf8<wchar_t> cvt;
1577   llvm::SmallString<4> input;
1578   for (;;) {
1579     const char *from_next;
1580     wchar_t *to_next;
1581     std::mbstate_t state = std::mbstate_t();
1582     input.push_back(ch);
1583     switch (cvt.in(state, input.begin(), input.end(), from_next, &out, &out + 1,
1584                    to_next)) {
1585     case std::codecvt_base::ok:
1586       return out != (int)WEOF;
1587 
1588     case std::codecvt_base::error:
1589     case std::codecvt_base::noconv:
1590       return false;
1591 
1592     case std::codecvt_base::partial:
1593       lldb::ConnectionStatus status;
1594       size_t read_count = m_input_connection.Read(
1595           &ch, 1, std::chrono::seconds(0), status, nullptr);
1596       if (read_count == 0)
1597         return false;
1598       break;
1599     }
1600   }
1601 #endif
1602 }
1603