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