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