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