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