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