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