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 11 #include "lldb/Host/Editline.h" 12 13 #include "lldb/Core/Error.h" 14 #include "lldb/Core/StreamString.h" 15 #include "lldb/Core/StringList.h" 16 #include "lldb/Host/Host.h" 17 18 #include <limits.h> 19 20 using namespace lldb; 21 using namespace lldb_private; 22 23 namespace lldb_private { 24 typedef std::weak_ptr<EditlineHistory> EditlineHistoryWP; 25 26 27 // EditlineHistory objects are sometimes shared between multiple 28 // Editline instances with the same program name. This class allows 29 // multiple editline instances to 30 // 31 32 class EditlineHistory 33 { 34 private: 35 // Use static GetHistory() function to get a EditlineHistorySP to one of these objects 36 EditlineHistory(const std::string &prefix, uint32_t size, bool unique_entries) : 37 m_history (NULL), 38 m_event (), 39 m_prefix (prefix), 40 m_path () 41 { 42 m_history = ::history_init(); 43 ::history (m_history, &m_event, H_SETSIZE, size); 44 if (unique_entries) 45 ::history (m_history, &m_event, H_SETUNIQUE, 1); 46 } 47 48 const char * 49 GetHistoryFilePath() 50 { 51 if (m_path.empty() && m_history && !m_prefix.empty()) 52 { 53 char history_path[PATH_MAX]; 54 ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_prefix.c_str()); 55 m_path = std::move(FileSpec(history_path, true).GetPath()); 56 } 57 if (m_path.empty()) 58 return NULL; 59 return m_path.c_str(); 60 } 61 62 public: 63 64 ~EditlineHistory() 65 { 66 Save (); 67 68 if (m_history) 69 { 70 ::history_end (m_history); 71 m_history = NULL; 72 } 73 } 74 75 static EditlineHistorySP 76 GetHistory (const std::string &prefix) 77 { 78 typedef std::map<std::string, EditlineHistoryWP> WeakHistoryMap; 79 static Mutex g_mutex(Mutex::eMutexTypeRecursive); 80 static WeakHistoryMap g_weak_map; 81 Mutex::Locker locker (g_mutex); 82 WeakHistoryMap::const_iterator pos = g_weak_map.find (prefix); 83 EditlineHistorySP history_sp; 84 if (pos != g_weak_map.end()) 85 { 86 history_sp = pos->second.lock(); 87 if (history_sp) 88 return history_sp; 89 g_weak_map.erase(pos); 90 } 91 history_sp.reset(new EditlineHistory(prefix, 800, true)); 92 g_weak_map[prefix] = history_sp; 93 return history_sp; 94 } 95 96 bool IsValid() const 97 { 98 return m_history != NULL; 99 } 100 101 ::History * 102 GetHistoryPtr () 103 { 104 return m_history; 105 } 106 107 void 108 Enter (const char *line_cstr) 109 { 110 if (m_history) 111 ::history (m_history, &m_event, H_ENTER, line_cstr); 112 } 113 114 bool 115 Load () 116 { 117 if (m_history) 118 { 119 const char *path = GetHistoryFilePath(); 120 if (path) 121 { 122 ::history (m_history, &m_event, H_LOAD, path); 123 return true; 124 } 125 } 126 return false; 127 } 128 129 bool 130 Save () 131 { 132 if (m_history) 133 { 134 const char *path = GetHistoryFilePath(); 135 if (path) 136 { 137 ::history (m_history, &m_event, H_SAVE, path); 138 return true; 139 } 140 } 141 return false; 142 } 143 144 protected: 145 ::History *m_history; // The history object 146 ::HistEvent m_event;// The history event needed to contain all history events 147 std::string m_prefix; // The prefix name (usually the editline program name) to use when loading/saving history 148 std::string m_path; // Path to the history file 149 }; 150 } 151 152 153 static const char k_prompt_escape_char = '\1'; 154 155 Editline::Editline (const char *prog, // prog can't be NULL 156 const char *prompt, // can be NULL for no prompt 157 bool configure_for_multiline, 158 FILE *fin, 159 FILE *fout, 160 FILE *ferr) : 161 m_editline (NULL), 162 m_history_sp (), 163 m_prompt (), 164 m_lines_prompt (), 165 m_getting_char (false), 166 m_completion_callback (NULL), 167 m_completion_callback_baton (NULL), 168 m_line_complete_callback (NULL), 169 m_line_complete_callback_baton (NULL), 170 m_lines_command (Command::None), 171 m_line_offset (0), 172 m_lines_curr_line (0), 173 m_lines_max_line (0), 174 m_file (fileno(fin), false), 175 m_prompt_with_line_numbers (false), 176 m_getting_line (false), 177 m_got_eof (false), 178 m_interrupted (false) 179 { 180 if (prog && prog[0]) 181 { 182 m_editline = ::el_init(prog, fin, fout, ferr); 183 184 // Get a shared history instance 185 m_history_sp = EditlineHistory::GetHistory(prog); 186 } 187 else 188 { 189 m_editline = ::el_init("lldb-tmp", fin, fout, ferr); 190 } 191 192 if (prompt && prompt[0]) 193 SetPrompt (prompt); 194 195 //::el_set (m_editline, EL_BIND, "^[[A", NULL); // Print binding for up arrow key 196 //::el_set (m_editline, EL_BIND, "^[[B", NULL); // Print binding for up down key 197 198 assert (m_editline); 199 ::el_set (m_editline, EL_CLIENTDATA, this); 200 201 // only defined for newer versions of editline 202 #ifdef EL_PROMPT_ESC 203 ::el_set (m_editline, EL_PROMPT_ESC, GetPromptCallback, k_prompt_escape_char); 204 #else 205 // fall back on old prompt setting code 206 ::el_set (m_editline, EL_PROMPT, GetPromptCallback); 207 #endif 208 ::el_set (m_editline, EL_EDITOR, "emacs"); 209 if (m_history_sp && m_history_sp->IsValid()) 210 { 211 ::el_set (m_editline, EL_HIST, history, m_history_sp->GetHistoryPtr()); 212 } 213 ::el_set (m_editline, EL_ADDFN, "lldb-complete", "Editline completion function", Editline::CallbackComplete); 214 // Keep old "lldb_complete" mapping for older clients that used this in their .editrc. editline also 215 // has a bad bug where if you have a bind command that tries to bind to a function name that doesn't 216 // exist, it will corrupt the heap and probably crash your process later. 217 ::el_set (m_editline, EL_ADDFN, "lldb_complete", "Editline completion function", Editline::CallbackComplete); 218 ::el_set (m_editline, EL_ADDFN, "lldb-edit-prev-line", "Editline edit prev line", Editline::CallbackEditPrevLine); 219 ::el_set (m_editline, EL_ADDFN, "lldb-edit-next-line", "Editline edit next line", Editline::CallbackEditNextLine); 220 221 ::el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string 222 ::el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does. 223 ::el_set (m_editline, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key. 224 ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be auto complete 225 226 if (configure_for_multiline) 227 { 228 // Use escape sequences for control characters due to bugs in editline 229 // where "-k up" and "-k down" don't always work. 230 ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow 231 ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow 232 // Bindings for next/prev history 233 ::el_set (m_editline, EL_BIND, "^P", "ed-prev-history", NULL); // Map up arrow 234 ::el_set (m_editline, EL_BIND, "^N", "ed-next-history", NULL); // Map down arrow 235 } 236 else 237 { 238 // Use escape sequences for control characters due to bugs in editline 239 // where "-k up" and "-k down" don't always work. 240 ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow 241 ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow 242 } 243 244 // Source $PWD/.editrc then $HOME/.editrc 245 ::el_source (m_editline, NULL); 246 247 // Always read through our callback function so we don't read 248 // stuff we aren't supposed to. This also stops the extra echoing 249 // that can happen when you have more input than editline can handle 250 // at once. 251 SetGetCharCallback(GetCharFromInputFileCallback); 252 253 LoadHistory(); 254 } 255 256 Editline::~Editline() 257 { 258 // EditlineHistory objects are sometimes shared between multiple 259 // Editline instances with the same program name. So just release 260 // our shared pointer and if we are the last owner, it will save the 261 // history to the history save file automatically. 262 m_history_sp.reset(); 263 264 // Disable edit mode to stop the terminal from flushing all input 265 // during the call to el_end() since we expect to have multiple editline 266 // instances in this program. 267 ::el_set (m_editline, EL_EDITMODE, 0); 268 269 ::el_end(m_editline); 270 m_editline = NULL; 271 } 272 273 void 274 Editline::SetGetCharCallback (GetCharCallbackType callback) 275 { 276 ::el_set (m_editline, EL_GETCFN, callback); 277 } 278 279 bool 280 Editline::LoadHistory () 281 { 282 if (m_history_sp) 283 return m_history_sp->Load(); 284 return false; 285 } 286 287 bool 288 Editline::SaveHistory () 289 { 290 if (m_history_sp) 291 return m_history_sp->Save(); 292 return false; 293 } 294 295 296 Error 297 Editline::PrivateGetLine(std::string &line) 298 { 299 Error error; 300 if (m_interrupted) 301 { 302 error.SetErrorString("interrupted"); 303 return error; 304 } 305 306 line.clear(); 307 if (m_editline != NULL) 308 { 309 int line_len = 0; 310 // Call el_gets to prompt the user and read the user's input. 311 const char *line_cstr = ::el_gets (m_editline, &line_len); 312 313 static int save_errno = (line_len < 0) ? errno : 0; 314 315 if (save_errno != 0) 316 { 317 error.SetError(save_errno, eErrorTypePOSIX); 318 } 319 else if (line_cstr) 320 { 321 // Decrement the length so we don't have newline characters in "line" for when 322 // we assign the cstr into the std::string 323 llvm::StringRef line_ref (line_cstr); 324 line_ref = line_ref.rtrim("\n\r"); 325 326 if (!line_ref.empty() && !m_interrupted) 327 { 328 // We didn't strip the newlines, we just adjusted the length, and 329 // we want to add the history item with the newlines 330 if (m_history_sp) 331 m_history_sp->Enter(line_cstr); 332 333 // Copy the part of the c string that we want (removing the newline chars) 334 line = std::move(line_ref.str()); 335 } 336 } 337 } 338 else 339 { 340 error.SetErrorString("the EditLine instance has been deleted"); 341 } 342 return error; 343 } 344 345 346 Error 347 Editline::GetLine(std::string &line, bool &interrupted) 348 { 349 Error error; 350 interrupted = false; 351 line.clear(); 352 353 // Set arrow key bindings for up and down arrows for single line 354 // mode where up and down arrows do prev/next history 355 m_interrupted = false; 356 357 if (!m_got_eof) 358 { 359 if (m_getting_line) 360 { 361 error.SetErrorString("already getting a line"); 362 return error; 363 } 364 if (m_lines_curr_line > 0) 365 { 366 error.SetErrorString("already getting lines"); 367 return error; 368 } 369 m_getting_line = true; 370 error = PrivateGetLine(line); 371 m_getting_line = false; 372 } 373 374 interrupted = m_interrupted; 375 376 if (m_got_eof && line.empty()) 377 { 378 // Only set the error if we didn't get an error back from PrivateGetLine() 379 if (error.Success()) 380 error.SetErrorString("end of file"); 381 } 382 383 return error; 384 } 385 386 size_t 387 Editline::Push (const char *bytes, size_t len) 388 { 389 if (m_editline) 390 { 391 // Must NULL terminate the string for el_push() so we stick it 392 // into a std::string first 393 ::el_push(m_editline, 394 const_cast<char*>(std::string (bytes, len).c_str())); 395 return len; 396 } 397 return 0; 398 } 399 400 401 Error 402 Editline::GetLines(const std::string &end_line, StringList &lines, bool &interrupted) 403 { 404 Error error; 405 interrupted = false; 406 if (m_getting_line) 407 { 408 error.SetErrorString("already getting a line"); 409 return error; 410 } 411 if (m_lines_curr_line > 0) 412 { 413 error.SetErrorString("already getting lines"); 414 return error; 415 } 416 417 // Set arrow key bindings for up and down arrows for multiple line 418 // mode where up and down arrows do edit prev/next line 419 m_interrupted = false; 420 421 LineStatus line_status = LineStatus::Success; 422 423 lines.Clear(); 424 425 FILE *out_file = GetOutputFile(); 426 FILE *err_file = GetErrorFile(); 427 m_lines_curr_line = 1; 428 while (line_status != LineStatus::Done) 429 { 430 const uint32_t line_idx = m_lines_curr_line-1; 431 if (line_idx >= lines.GetSize()) 432 lines.SetSize(m_lines_curr_line); 433 m_lines_max_line = lines.GetSize(); 434 m_lines_command = Command::None; 435 assert(line_idx < m_lines_max_line); 436 std::string &line = lines[line_idx]; 437 error = PrivateGetLine(line); 438 if (error.Fail()) 439 { 440 line_status = LineStatus::Error; 441 } 442 else if (m_interrupted) 443 { 444 interrupted = true; 445 line_status = LineStatus::Done; 446 } 447 else 448 { 449 switch (m_lines_command) 450 { 451 case Command::None: 452 if (m_line_complete_callback) 453 { 454 line_status = m_line_complete_callback (this, 455 lines, 456 line_idx, 457 error, 458 m_line_complete_callback_baton); 459 } 460 else if (line == end_line) 461 { 462 line_status = LineStatus::Done; 463 } 464 465 if (line_status == LineStatus::Success) 466 { 467 ++m_lines_curr_line; 468 // If we already have content for the next line because 469 // we were editing previous lines, then populate the line 470 // with the appropriate contents 471 if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty()) 472 ::el_push (m_editline, 473 const_cast<char*>(lines[line_idx+1].c_str())); 474 } 475 else if (line_status == LineStatus::Error) 476 { 477 // Clear to end of line ("ESC[K"), then print the error, 478 // then go to the next line ("\n") and then move cursor up 479 // two lines ("ESC[2A"). 480 fprintf (err_file, "\033[Kerror: %s\n\033[2A", error.AsCString()); 481 } 482 break; 483 case Command::EditPrevLine: 484 if (m_lines_curr_line > 1) 485 { 486 //::fprintf (out_file, "\033[1A\033[%uD\033[2K", (uint32_t)(m_lines_prompt.size() + lines[line_idx].size())); // Make cursor go up a line and clear that line 487 ::fprintf (out_file, "\033[1A\033[1000D\033[2K"); 488 if (!lines[line_idx-1].empty()) 489 ::el_push (m_editline, 490 const_cast<char*>(lines[line_idx-1].c_str())); 491 --m_lines_curr_line; 492 } 493 break; 494 case Command::EditNextLine: 495 // Allow the down arrow to create a new line 496 ++m_lines_curr_line; 497 //::fprintf (out_file, "\033[1B\033[%uD\033[2K", (uint32_t)(m_lines_prompt.size() + lines[line_idx].size())); 498 ::fprintf (out_file, "\033[1B\033[1000D\033[2K"); 499 if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty()) 500 ::el_push (m_editline, 501 const_cast<char*>(lines[line_idx+1].c_str())); 502 break; 503 } 504 } 505 } 506 m_lines_curr_line = 0; 507 m_lines_command = Command::None; 508 509 // If we have a callback, call it one more time to let the 510 // user know the lines are complete 511 if (m_line_complete_callback && !interrupted) 512 m_line_complete_callback (this, 513 lines, 514 UINT32_MAX, 515 error, 516 m_line_complete_callback_baton); 517 518 return error; 519 } 520 521 unsigned char 522 Editline::HandleCompletion (int ch) 523 { 524 if (m_completion_callback == NULL) 525 return CC_ERROR; 526 527 const LineInfo *line_info = ::el_line(m_editline); 528 StringList completions; 529 int page_size = 40; 530 531 const int num_completions = m_completion_callback (line_info->buffer, 532 line_info->cursor, 533 line_info->lastchar, 534 0, // Don't skip any matches (start at match zero) 535 -1, // Get all the matches 536 completions, 537 m_completion_callback_baton); 538 539 FILE *out_file = GetOutputFile(); 540 541 // if (num_completions == -1) 542 // { 543 // ::el_insertstr (m_editline, m_completion_key); 544 // return CC_REDISPLAY; 545 // } 546 // else 547 if (num_completions == -2) 548 { 549 // Replace the entire line with the first string... 550 ::el_deletestr (m_editline, line_info->cursor - line_info->buffer); 551 ::el_insertstr (m_editline, completions.GetStringAtIndex(0)); 552 return CC_REDISPLAY; 553 } 554 555 // If we get a longer match display that first. 556 const char *completion_str = completions.GetStringAtIndex(0); 557 if (completion_str != NULL && *completion_str != '\0') 558 { 559 el_insertstr (m_editline, completion_str); 560 return CC_REDISPLAY; 561 } 562 563 if (num_completions > 1) 564 { 565 int num_elements = num_completions + 1; 566 ::fprintf (out_file, "\nAvailable completions:"); 567 if (num_completions < page_size) 568 { 569 for (int i = 1; i < num_elements; i++) 570 { 571 completion_str = completions.GetStringAtIndex(i); 572 ::fprintf (out_file, "\n\t%s", completion_str); 573 } 574 ::fprintf (out_file, "\n"); 575 } 576 else 577 { 578 int cur_pos = 1; 579 char reply; 580 int got_char; 581 while (cur_pos < num_elements) 582 { 583 int endpoint = cur_pos + page_size; 584 if (endpoint > num_elements) 585 endpoint = num_elements; 586 for (; cur_pos < endpoint; cur_pos++) 587 { 588 completion_str = completions.GetStringAtIndex(cur_pos); 589 ::fprintf (out_file, "\n\t%s", completion_str); 590 } 591 592 if (cur_pos >= num_elements) 593 { 594 ::fprintf (out_file, "\n"); 595 break; 596 } 597 598 ::fprintf (out_file, "\nMore (Y/n/a): "); 599 reply = 'n'; 600 got_char = el_getc(m_editline, &reply); 601 if (got_char == -1 || reply == 'n') 602 break; 603 if (reply == 'a') 604 page_size = num_elements - cur_pos; 605 } 606 } 607 608 } 609 610 if (num_completions == 0) 611 return CC_REFRESH_BEEP; 612 else 613 return CC_REDISPLAY; 614 } 615 616 Editline * 617 Editline::GetClientData (::EditLine *e) 618 { 619 Editline *editline = NULL; 620 if (e && ::el_get(e, EL_CLIENTDATA, &editline) == 0) 621 return editline; 622 return NULL; 623 } 624 625 FILE * 626 Editline::GetInputFile () 627 { 628 return GetFilePointer (m_editline, 0); 629 } 630 631 FILE * 632 Editline::GetOutputFile () 633 { 634 return GetFilePointer (m_editline, 1); 635 } 636 637 FILE * 638 Editline::GetErrorFile () 639 { 640 return GetFilePointer (m_editline, 2); 641 } 642 643 const char * 644 Editline::GetPrompt() 645 { 646 if (m_prompt_with_line_numbers && m_lines_curr_line > 0) 647 { 648 StreamString strm; 649 strm.Printf("%3u: ", m_lines_curr_line); 650 m_lines_prompt = std::move(strm.GetString()); 651 return m_lines_prompt.c_str(); 652 } 653 else 654 { 655 return m_prompt.c_str(); 656 } 657 } 658 659 void 660 Editline::SetPrompt (const char *p) 661 { 662 if (p && p[0]) 663 m_prompt = p; 664 else 665 m_prompt.clear(); 666 size_t start_pos = 0; 667 size_t escape_pos; 668 while ((escape_pos = m_prompt.find('\033', start_pos)) != std::string::npos) 669 { 670 m_prompt.insert(escape_pos, 1, k_prompt_escape_char); 671 start_pos += 2; 672 } 673 } 674 675 FILE * 676 Editline::GetFilePointer (::EditLine *e, int fd) 677 { 678 FILE *file_ptr = NULL; 679 if (e && ::el_get(e, EL_GETFP, fd, &file_ptr) == 0) 680 return file_ptr; 681 return NULL; 682 } 683 684 unsigned char 685 Editline::CallbackEditPrevLine (::EditLine *e, int ch) 686 { 687 Editline *editline = GetClientData (e); 688 if (editline->m_lines_curr_line > 1) 689 { 690 editline->m_lines_command = Command::EditPrevLine; 691 return CC_NEWLINE; 692 } 693 return CC_ERROR; 694 } 695 unsigned char 696 Editline::CallbackEditNextLine (::EditLine *e, int ch) 697 { 698 Editline *editline = GetClientData (e); 699 if (editline->m_lines_curr_line < editline->m_lines_max_line) 700 { 701 editline->m_lines_command = Command::EditNextLine; 702 return CC_NEWLINE; 703 } 704 return CC_ERROR; 705 } 706 707 unsigned char 708 Editline::CallbackComplete (::EditLine *e, int ch) 709 { 710 Editline *editline = GetClientData (e); 711 if (editline) 712 return editline->HandleCompletion (ch); 713 return CC_ERROR; 714 } 715 716 const char * 717 Editline::GetPromptCallback (::EditLine *e) 718 { 719 Editline *editline = GetClientData (e); 720 if (editline) 721 return editline->GetPrompt(); 722 return ""; 723 } 724 725 int 726 Editline::GetCharFromInputFileCallback (EditLine *e, char *c) 727 { 728 Editline *editline = GetClientData (e); 729 if (editline && editline->m_got_eof == false) 730 { 731 FILE *f = editline->GetInputFile(); 732 if (f == NULL) 733 { 734 editline->m_got_eof = true; 735 return 0; 736 } 737 738 739 while (1) 740 { 741 lldb::ConnectionStatus status = eConnectionStatusSuccess; 742 char ch = 0; 743 // When we start to call el_gets() the editline library needs to 744 // output the prompt 745 editline->m_getting_char.SetValue(true, eBroadcastAlways); 746 const size_t n = editline->m_file.Read(&ch, 1, UINT32_MAX, status, NULL); 747 editline->m_getting_char.SetValue(false, eBroadcastAlways); 748 if (n) 749 { 750 if (ch == '\x04') 751 { 752 // Only turn a CTRL+D into a EOF if we receive the 753 // CTRL+D an empty line, otherwise it will forward 754 // delete the character at the cursor 755 const LineInfo *line_info = ::el_line(e); 756 if (line_info != NULL && 757 line_info->buffer == line_info->cursor && 758 line_info->cursor == line_info->lastchar) 759 { 760 editline->m_got_eof = true; 761 break; 762 } 763 } 764 765 if (status == eConnectionStatusEndOfFile) 766 { 767 editline->m_got_eof = true; 768 break; 769 } 770 else 771 { 772 *c = ch; 773 return 1; 774 } 775 } 776 else 777 { 778 switch (status) 779 { 780 case eConnectionStatusInterrupted: 781 editline->m_interrupted = true; 782 *c = '\n'; 783 return 1; 784 785 case eConnectionStatusSuccess: // Success 786 break; 787 788 case eConnectionStatusError: // Check GetError() for details 789 case eConnectionStatusTimedOut: // Request timed out 790 case eConnectionStatusEndOfFile: // End-of-file encountered 791 case eConnectionStatusNoConnection: // No connection 792 case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection 793 editline->m_got_eof = true; 794 break; 795 } 796 } 797 } 798 } 799 return 0; 800 } 801 802 void 803 Editline::Hide () 804 { 805 if (m_getting_line) 806 { 807 // If we are getting a line, we might have started to call el_gets() and 808 // it might be printing the prompt. Here we make sure we are actually getting 809 // a character. This way we know the entire prompt has been printed. 810 TimeValue timeout = TimeValue::Now(); 811 timeout.OffsetWithSeconds(1); 812 if (m_getting_char.WaitForValueEqualTo(true, &timeout)) 813 { 814 FILE *out_file = GetOutputFile(); 815 if (out_file) 816 { 817 const LineInfo *line_info = ::el_line(m_editline); 818 if (line_info) 819 ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer)); 820 } 821 } 822 } 823 } 824 825 826 void 827 Editline::Refresh() 828 { 829 if (m_getting_line) 830 { 831 // If we are getting a line, we might have started to call el_gets() and 832 // it might be printing the prompt. Here we make sure we are actually getting 833 // a character. This way we know the entire prompt has been printed. 834 TimeValue timeout = TimeValue::Now(); 835 timeout.OffsetWithSeconds(1); 836 if (m_getting_char.WaitForValueEqualTo(true, &timeout)) 837 { 838 ::el_set (m_editline, EL_REFRESH); 839 } 840 } 841 } 842 843 bool 844 Editline::Interrupt () 845 { 846 m_interrupted = true; 847 if (m_getting_line || m_lines_curr_line > 0) 848 return m_file.InterruptRead(); 849 return false; // Interrupt not handled as we weren't getting a line or lines 850 } 851