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