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 = 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 // Delete characters for the unindentation AND including the character we just added. 890 el_wdeletestr (m_editline, -indent_correction + 1); 891 892 // Rewrite the character that caused the unindentation. 893 el_winsertstr (m_editline, inserted); 894 } 895 info->cursor = info->buffer + cursor_position + indent_correction; 896 return CC_REFRESH; 897 } 898 899 unsigned char 900 Editline::RevertLineCommand (int ch) 901 { 902 el_winsertstr (m_editline, m_input_lines[m_current_line_index].c_str()); 903 if (m_revert_cursor_index >= 0) 904 { 905 LineInfoW * info = const_cast<LineInfoW *>(el_wline (m_editline)); 906 info->cursor = info->buffer + m_revert_cursor_index; 907 if (info->cursor > info->lastchar) 908 { 909 info->cursor = info->lastchar; 910 } 911 m_revert_cursor_index = -1; 912 } 913 return CC_REFRESH; 914 } 915 916 unsigned char 917 Editline::BufferStartCommand (int ch) 918 { 919 SaveEditedLine(); 920 MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockStart); 921 SetCurrentLine (0); 922 m_revert_cursor_index = 0; 923 return CC_NEWLINE; 924 } 925 926 unsigned char 927 Editline::BufferEndCommand (int ch) 928 { 929 SaveEditedLine(); 930 MoveCursor (CursorLocation::EditingCursor, CursorLocation::BlockEnd); 931 SetCurrentLine ((int)m_input_lines.size() - 1); 932 MoveCursor (CursorLocation::BlockEnd, CursorLocation::EditingPrompt); 933 return CC_NEWLINE; 934 } 935 936 unsigned char 937 Editline::TabCommand (int ch) 938 { 939 if (m_completion_callback == nullptr) 940 return CC_ERROR; 941 942 const LineInfo *line_info = el_line (m_editline); 943 StringList completions; 944 int page_size = 40; 945 946 const int num_completions = m_completion_callback (line_info->buffer, 947 line_info->cursor, 948 line_info->lastchar, 949 0, // Don't skip any matches (start at match zero) 950 -1, // Get all the matches 951 completions, 952 m_completion_callback_baton); 953 954 if (num_completions == 0) 955 return CC_ERROR; 956 // if (num_completions == -1) 957 // { 958 // el_insertstr (m_editline, m_completion_key); 959 // return CC_REDISPLAY; 960 // } 961 // else 962 if (num_completions == -2) 963 { 964 // Replace the entire line with the first string... 965 el_deletestr (m_editline, line_info->cursor - line_info->buffer); 966 el_insertstr (m_editline, completions.GetStringAtIndex (0)); 967 return CC_REDISPLAY; 968 } 969 970 // If we get a longer match display that first. 971 const char *completion_str = completions.GetStringAtIndex (0); 972 if (completion_str != nullptr && *completion_str != '\0') 973 { 974 el_insertstr (m_editline, completion_str); 975 return CC_REDISPLAY; 976 } 977 978 if (num_completions > 1) 979 { 980 int num_elements = num_completions + 1; 981 fprintf (m_output_file, "\n" ANSI_CLEAR_BELOW "Available completions:"); 982 if (num_completions < page_size) 983 { 984 for (int i = 1; i < num_elements; i++) 985 { 986 completion_str = completions.GetStringAtIndex (i); 987 fprintf (m_output_file, "\n\t%s", completion_str); 988 } 989 fprintf (m_output_file, "\n"); 990 } 991 else 992 { 993 int cur_pos = 1; 994 char reply; 995 int got_char; 996 while (cur_pos < num_elements) 997 { 998 int endpoint = cur_pos + page_size; 999 if (endpoint > num_elements) 1000 endpoint = num_elements; 1001 for (; cur_pos < endpoint; cur_pos++) 1002 { 1003 completion_str = completions.GetStringAtIndex (cur_pos); 1004 fprintf (m_output_file, "\n\t%s", completion_str); 1005 } 1006 1007 if (cur_pos >= num_elements) 1008 { 1009 fprintf (m_output_file, "\n"); 1010 break; 1011 } 1012 1013 fprintf (m_output_file, "\nMore (Y/n/a): "); 1014 reply = 'n'; 1015 got_char = el_getc(m_editline, &reply); 1016 if (got_char == -1 || reply == 'n') 1017 break; 1018 if (reply == 'a') 1019 page_size = num_elements - cur_pos; 1020 } 1021 } 1022 DisplayInput(); 1023 MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor); 1024 } 1025 return CC_REDISPLAY; 1026 } 1027 1028 void 1029 Editline::ConfigureEditor (bool multiline) 1030 { 1031 if (m_editline && m_multiline_enabled == multiline) 1032 return; 1033 m_multiline_enabled = multiline; 1034 1035 if (m_editline) 1036 { 1037 // Disable edit mode to stop the terminal from flushing all input 1038 // during the call to el_end() since we expect to have multiple editline 1039 // instances in this program. 1040 el_set (m_editline, EL_EDITMODE, 0); 1041 el_end (m_editline); 1042 } 1043 1044 m_editline = el_init (m_editor_name.c_str(), m_input_file, m_output_file, m_error_file); 1045 TerminalSizeChanged(); 1046 1047 if (m_history_sp && m_history_sp->IsValid()) 1048 { 1049 m_history_sp->Load(); 1050 el_wset (m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr()); 1051 } 1052 el_set (m_editline, EL_CLIENTDATA, this); 1053 el_set (m_editline, EL_SIGNAL, 0); 1054 el_set (m_editline, EL_EDITOR, "emacs"); 1055 el_set (m_editline, EL_PROMPT, (EditlinePromptCallbackType)([] (EditLine *editline) { 1056 return Editline::InstanceFor (editline)->Prompt(); 1057 })); 1058 1059 el_wset (m_editline, EL_GETCFN, 1060 (EditlineGetCharCallbackType)([] (EditLine * editline, EditLineCharType * c) { 1061 return Editline::InstanceFor (editline)->GetCharacter (c); 1062 })); 1063 1064 // Commands used for multiline support, registered whether or not they're used 1065 el_set (m_editline, EL_ADDFN, "lldb-break-line", "Insert a line break", 1066 (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { 1067 return Editline::InstanceFor (editline)->BreakLineCommand (ch); 1068 })); 1069 el_set (m_editline, EL_ADDFN, "lldb-delete-next-char", "Delete next character", 1070 (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { 1071 return Editline::InstanceFor (editline)->DeleteNextCharCommand (ch); 1072 })); 1073 el_set (m_editline, EL_ADDFN, "lldb-delete-previous-char", "Delete previous character", 1074 (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { 1075 return Editline::InstanceFor (editline)->DeletePreviousCharCommand (ch); 1076 })); 1077 el_set (m_editline, EL_ADDFN, "lldb-previous-line", "Move to previous line", 1078 (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { 1079 return Editline::InstanceFor (editline)->PreviousLineCommand (ch); 1080 })); 1081 el_set (m_editline, EL_ADDFN, "lldb-next-line", "Move to next line", 1082 (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { 1083 return Editline::InstanceFor (editline)->NextLineCommand (ch); 1084 })); 1085 el_set (m_editline, EL_ADDFN, "lldb-buffer-start", "Move to start of buffer", 1086 (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { 1087 return Editline::InstanceFor (editline)->BufferStartCommand (ch); 1088 })); 1089 el_set (m_editline, EL_ADDFN, "lldb-buffer-end", "Move to end of buffer", 1090 (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { 1091 return Editline::InstanceFor (editline)->BufferEndCommand (ch); 1092 })); 1093 el_set (m_editline, EL_ADDFN, "lldb-fix-indentation", "Fix line indentation", 1094 (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { 1095 return Editline::InstanceFor (editline)->FixIndentationCommand (ch); 1096 })); 1097 1098 // Register the complete callback under two names for compatibility with older clients using 1099 // custom .editrc files (largely becuase libedit has a bad bug where if you have a bind command 1100 // that tries to bind to a function name that doesn't exist, it can corrupt the heap and 1101 // crash your process later.) 1102 EditlineCommandCallbackType complete_callback = [] (EditLine * editline, int ch) { 1103 return Editline::InstanceFor (editline)->TabCommand (ch); 1104 }; 1105 el_set (m_editline, EL_ADDFN, "lldb-complete", "Invoke completion", complete_callback); 1106 el_set (m_editline, EL_ADDFN, "lldb_complete", "Invoke completion", complete_callback); 1107 1108 // General bindings we don't mind being overridden 1109 if (!multiline) { 1110 el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string 1111 } 1112 el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash in emacs mode 1113 el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to auto complete 1114 1115 // Allow user-specific customization prior to registering bindings we absolutely require 1116 el_source (m_editline, NULL); 1117 1118 // Register an internal binding that external developers shouldn't use 1119 el_set (m_editline, EL_ADDFN, "lldb-revert-line", "Revert line to saved state", 1120 (EditlineCommandCallbackType)([] (EditLine * editline, int ch) { 1121 return Editline::InstanceFor (editline)->RevertLineCommand (ch); 1122 })); 1123 1124 // Register keys that perform auto-indent correction 1125 if (m_fix_indentation_callback && m_fix_indentation_callback_chars) 1126 { 1127 char bind_key[2] = { 0, 0 }; 1128 const char * indent_chars = m_fix_indentation_callback_chars; 1129 while (*indent_chars) 1130 { 1131 bind_key[0] = *indent_chars; 1132 el_set (m_editline, EL_BIND, bind_key, "lldb-fix-indentation", NULL); 1133 ++indent_chars; 1134 } 1135 } 1136 1137 // Multi-line editor bindings 1138 if (multiline) 1139 { 1140 el_set (m_editline, EL_BIND, "\n", "lldb-break-line", NULL); 1141 el_set (m_editline, EL_BIND, "\r", "lldb-break-line", NULL); 1142 el_set (m_editline, EL_BIND, "^p", "lldb-previous-line", NULL); 1143 el_set (m_editline, EL_BIND, "^n", "lldb-next-line", NULL); 1144 el_set (m_editline, EL_BIND, "^?", "lldb-delete-previous-char", NULL); 1145 el_set (m_editline, EL_BIND, "^d", "lldb-delete-next-char", NULL); 1146 el_set (m_editline, EL_BIND, ESCAPE "[3~", "lldb-delete-next-char", NULL); 1147 el_set (m_editline, EL_BIND, ESCAPE "[\\^", "lldb-revert-line", NULL); 1148 1149 // Editor-specific bindings 1150 if (IsEmacs()) 1151 { 1152 el_set (m_editline, EL_BIND, ESCAPE "<", "lldb-buffer-start", NULL); 1153 el_set (m_editline, EL_BIND, ESCAPE ">", "lldb-buffer-end", NULL); 1154 el_set (m_editline, EL_BIND, ESCAPE "[A", "lldb-previous-line", NULL); 1155 el_set (m_editline, EL_BIND, ESCAPE "[B", "lldb-next-line", NULL); 1156 } 1157 else 1158 { 1159 el_set (m_editline, EL_BIND, "^H", "lldb-delete-previous-char", NULL); 1160 1161 el_set (m_editline, EL_BIND, "-a", ESCAPE "[A", "lldb-previous-line", NULL); 1162 el_set (m_editline, EL_BIND, "-a", ESCAPE "[B", "lldb-next-line", NULL); 1163 el_set (m_editline, EL_BIND, "-a", "x", "lldb-delete-next-char", NULL); 1164 el_set (m_editline, EL_BIND, "-a", "^H", "lldb-delete-previous-char", NULL); 1165 el_set (m_editline, EL_BIND, "-a", "^?", "lldb-delete-previous-char", NULL); 1166 1167 // Escape is absorbed exiting edit mode, so re-register important sequences 1168 // without the prefix 1169 el_set (m_editline, EL_BIND, "-a", "[A", "lldb-previous-line", NULL); 1170 el_set (m_editline, EL_BIND, "-a", "[B", "lldb-next-line", NULL); 1171 el_set (m_editline, EL_BIND, "-a", "[\\^", "lldb-revert-line", NULL); 1172 } 1173 } 1174 } 1175 1176 //------------------------------------------------------------------ 1177 // Editline public methods 1178 //------------------------------------------------------------------ 1179 1180 Editline * 1181 Editline::InstanceFor (EditLine * editline) 1182 { 1183 Editline * editor; 1184 el_get (editline, EL_CLIENTDATA, &editor); 1185 return editor; 1186 } 1187 1188 Editline::Editline (const char * editline_name, FILE * input_file, FILE * output_file, FILE * error_file, bool color_prompts) : 1189 m_editor_status (EditorStatus::Complete), 1190 m_color_prompts(color_prompts), 1191 m_input_file (input_file), 1192 m_output_file (output_file), 1193 m_error_file (error_file), 1194 m_input_connection (fileno(input_file), false) 1195 { 1196 // Get a shared history instance 1197 m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name; 1198 m_history_sp = EditlineHistory::GetHistory (m_editor_name); 1199 } 1200 1201 Editline::~Editline() 1202 { 1203 if (m_editline) 1204 { 1205 // Disable edit mode to stop the terminal from flushing all input 1206 // during the call to el_end() since we expect to have multiple editline 1207 // instances in this program. 1208 el_set (m_editline, EL_EDITMODE, 0); 1209 el_end (m_editline); 1210 m_editline = nullptr; 1211 } 1212 1213 // EditlineHistory objects are sometimes shared between multiple 1214 // Editline instances with the same program name. So just release 1215 // our shared pointer and if we are the last owner, it will save the 1216 // history to the history save file automatically. 1217 m_history_sp.reset(); 1218 } 1219 1220 void 1221 Editline::SetPrompt (const char * prompt) 1222 { 1223 m_set_prompt = prompt == nullptr ? "" : prompt; 1224 } 1225 1226 void 1227 Editline::SetContinuationPrompt (const char * continuation_prompt) 1228 { 1229 m_set_continuation_prompt = continuation_prompt == nullptr ? "" : continuation_prompt; 1230 } 1231 1232 void 1233 Editline::TerminalSizeChanged() 1234 { 1235 if (m_editline != nullptr) 1236 { 1237 el_resize (m_editline); 1238 int columns; 1239 // Despite the man page claiming non-zero indicates success, it's actually zero 1240 if (el_get (m_editline, EL_GETTC, "co", &columns) == 0) 1241 { 1242 m_terminal_width = columns; 1243 if (m_current_line_rows != -1) 1244 { 1245 const LineInfoW * info = el_wline (m_editline); 1246 int lineLength = (int)((info->lastchar - info->buffer) + GetPromptWidth()); 1247 m_current_line_rows = (lineLength / columns) + 1; 1248 } 1249 } 1250 else 1251 { 1252 m_terminal_width = INT_MAX; 1253 m_current_line_rows = 1; 1254 } 1255 } 1256 } 1257 1258 const char * 1259 Editline::GetPrompt() 1260 { 1261 return m_set_prompt.c_str(); 1262 } 1263 1264 uint32_t 1265 Editline::GetCurrentLine() 1266 { 1267 return m_current_line_index; 1268 } 1269 1270 bool 1271 Editline::Interrupt() 1272 { 1273 bool result = true; 1274 Mutex::Locker locker(m_output_mutex); 1275 if (m_editor_status == EditorStatus::Editing) { 1276 fprintf(m_output_file, "^C\n"); 1277 result = m_input_connection.InterruptRead(); 1278 } 1279 m_editor_status = EditorStatus::Interrupted; 1280 return result; 1281 } 1282 1283 bool 1284 Editline::Cancel() 1285 { 1286 bool result = true; 1287 Mutex::Locker locker(m_output_mutex); 1288 if (m_editor_status == EditorStatus::Editing) { 1289 MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); 1290 fprintf(m_output_file, ANSI_CLEAR_BELOW); 1291 result = m_input_connection.InterruptRead(); 1292 } 1293 m_editor_status = EditorStatus::Interrupted; 1294 return result; 1295 } 1296 1297 void 1298 Editline::SetAutoCompleteCallback (CompleteCallbackType callback, void * baton) 1299 { 1300 m_completion_callback = callback; 1301 m_completion_callback_baton = baton; 1302 } 1303 1304 void 1305 Editline::SetIsInputCompleteCallback (IsInputCompleteCallbackType callback, void * baton) 1306 { 1307 m_is_input_complete_callback = callback; 1308 m_is_input_complete_callback_baton = baton; 1309 } 1310 1311 bool 1312 Editline::SetFixIndentationCallback (FixIndentationCallbackType callback, 1313 void * baton, 1314 const char * indent_chars) 1315 { 1316 m_fix_indentation_callback = callback; 1317 m_fix_indentation_callback_baton = baton; 1318 m_fix_indentation_callback_chars = indent_chars; 1319 return false; 1320 } 1321 1322 bool 1323 Editline::GetLine (std::string &line, bool &interrupted) 1324 { 1325 ConfigureEditor (false); 1326 m_input_lines = std::vector<EditLineStringType>(); 1327 m_input_lines.insert (m_input_lines.begin(), EditLineConstString("")); 1328 1329 Mutex::Locker locker(m_output_mutex); 1330 1331 lldbassert(m_editor_status != EditorStatus::Editing); 1332 if (m_editor_status == EditorStatus::Interrupted) 1333 { 1334 m_editor_status = EditorStatus::Complete; 1335 interrupted = true; 1336 return true; 1337 } 1338 1339 SetCurrentLine (0); 1340 m_in_history = false; 1341 m_editor_status = EditorStatus::Editing; 1342 m_revert_cursor_index = -1; 1343 1344 #ifdef USE_SETUPTERM_WORKAROUND 1345 setupterm((char *)0, fileno(m_output_file), (int *)0); 1346 #endif 1347 1348 int count; 1349 auto input = el_wgets (m_editline, &count); 1350 1351 interrupted = m_editor_status == EditorStatus::Interrupted; 1352 if (!interrupted) 1353 { 1354 if (input == nullptr) 1355 { 1356 fprintf (m_output_file, "\n"); 1357 m_editor_status = EditorStatus::EndOfInput; 1358 } 1359 else 1360 { 1361 m_history_sp->Enter (input); 1362 #if LLDB_EDITLINE_USE_WCHAR 1363 line = m_utf8conv.to_bytes (SplitLines (input)[0]); 1364 #else 1365 line = SplitLines (input)[0]; 1366 #endif 1367 m_editor_status = EditorStatus::Complete; 1368 } 1369 } 1370 return m_editor_status != EditorStatus::EndOfInput; 1371 } 1372 1373 bool 1374 Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted) 1375 { 1376 ConfigureEditor (true); 1377 1378 // Print the initial input lines, then move the cursor back up to the start of input 1379 SetBaseLineNumber (first_line_number); 1380 m_input_lines = std::vector<EditLineStringType>(); 1381 m_input_lines.insert (m_input_lines.begin(), EditLineConstString("")); 1382 1383 Mutex::Locker locker(m_output_mutex); 1384 // Begin the line editing loop 1385 DisplayInput(); 1386 SetCurrentLine (0); 1387 MoveCursor (CursorLocation::BlockEnd, CursorLocation::BlockStart); 1388 m_editor_status = EditorStatus::Editing; 1389 m_in_history = false; 1390 1391 m_revert_cursor_index = -1; 1392 while (m_editor_status == EditorStatus::Editing) 1393 { 1394 #ifdef USE_SETUPTERM_WORKAROUND 1395 setupterm((char *)0, fileno(m_output_file), (int *)0); 1396 #endif 1397 int count; 1398 m_current_line_rows = -1; 1399 el_wpush (m_editline, EditLineConstString("\x1b[^")); // Revert to the existing line content 1400 el_wgets (m_editline, &count); 1401 } 1402 1403 interrupted = m_editor_status == EditorStatus::Interrupted; 1404 if (!interrupted) 1405 { 1406 // Save the completed entry in history before returning 1407 m_history_sp->Enter (CombineLines (m_input_lines).c_str()); 1408 1409 lines = GetInputAsStringList(); 1410 } 1411 return m_editor_status != EditorStatus::EndOfInput; 1412 } 1413 1414 void 1415 Editline::PrintAsync (Stream *stream, const char *s, size_t len) 1416 { 1417 Mutex::Locker locker(m_output_mutex); 1418 if (m_editor_status == EditorStatus::Editing) 1419 { 1420 MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); 1421 fprintf(m_output_file, ANSI_CLEAR_BELOW); 1422 } 1423 stream->Write (s, len); 1424 stream->Flush(); 1425 if (m_editor_status == EditorStatus::Editing) 1426 { 1427 DisplayInput(); 1428 MoveCursor(CursorLocation::BlockEnd, CursorLocation::EditingCursor); 1429 } 1430 } 1431