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