Editline.cpp revision 269024
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 20using namespace lldb; 21using namespace lldb_private; 22 23static const char k_prompt_escape_char = '\1'; 24 25Editline::Editline (const char *prog, // prog can't be NULL 26 const char *prompt, // can be NULL for no prompt 27 FILE *fin, 28 FILE *fout, 29 FILE *ferr) : 30 m_editline (NULL), 31 m_history (NULL), 32 m_history_event (), 33 m_program (), 34 m_prompt (), 35 m_lines_prompt (), 36 m_getc_buffer (), 37 m_getc_mutex (Mutex::eMutexTypeNormal), 38 m_getc_cond (), 39// m_gets_mutex (Mutex::eMutexTypeNormal), 40 m_completion_callback (NULL), 41 m_completion_callback_baton (NULL), 42 m_line_complete_callback (NULL), 43 m_line_complete_callback_baton (NULL), 44 m_lines_command (Command::None), 45 m_lines_curr_line (0), 46 m_lines_max_line (0), 47 m_prompt_with_line_numbers (false), 48 m_getting_line (false), 49 m_got_eof (false), 50 m_interrupted (false) 51{ 52 if (prog && prog[0]) 53 { 54 m_program = prog; 55 m_editline = ::el_init(prog, fin, fout, ferr); 56 m_history = ::history_init(); 57 } 58 else 59 { 60 m_editline = ::el_init("lldb-tmp", fin, fout, ferr); 61 } 62 if (prompt && prompt[0]) 63 SetPrompt (prompt); 64 65 //::el_set (m_editline, EL_BIND, "^[[A", NULL); // Print binding for up arrow key 66 //::el_set (m_editline, EL_BIND, "^[[B", NULL); // Print binding for up down key 67 68 assert (m_editline); 69 ::el_set (m_editline, EL_CLIENTDATA, this); 70 71 // only defined for newer versions of editline 72#ifdef EL_PROMPT_ESC 73 ::el_set (m_editline, EL_PROMPT_ESC, GetPromptCallback, k_prompt_escape_char); 74#else 75 // fall back on old prompt setting code 76 ::el_set (m_editline, EL_PROMPT, GetPromptCallback); 77#endif 78 ::el_set (m_editline, EL_EDITOR, "emacs"); 79 if (m_history) 80 { 81 ::el_set (m_editline, EL_HIST, history, m_history); 82 } 83 ::el_set (m_editline, EL_ADDFN, "lldb-complete", "Editline completion function", Editline::CallbackComplete); 84 ::el_set (m_editline, EL_ADDFN, "lldb-edit-prev-line", "Editline edit prev line", Editline::CallbackEditPrevLine); 85 ::el_set (m_editline, EL_ADDFN, "lldb-edit-next-line", "Editline edit next line", Editline::CallbackEditNextLine); 86 87 ::el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string 88 ::el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does. 89 ::el_set (m_editline, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key. 90 ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be autocompelte 91 92 // Source $PWD/.editrc then $HOME/.editrc 93 ::el_source (m_editline, NULL); 94 95 if (m_history) 96 { 97 ::history (m_history, &m_history_event, H_SETSIZE, 800); 98 ::history (m_history, &m_history_event, H_SETUNIQUE, 1); 99 } 100 101 // Always read through our callback function so we don't read 102 // stuff we aren't supposed to. This also stops the extra echoing 103 // that can happen when you have more input than editline can handle 104 // at once. 105 SetGetCharCallback(GetCharFromInputFileCallback); 106 107 LoadHistory(); 108} 109 110Editline::~Editline() 111{ 112 SaveHistory(); 113 114 if (m_history) 115 { 116 ::history_end (m_history); 117 m_history = NULL; 118 } 119 120 // Disable edit mode to stop the terminal from flushing all input 121 // during the call to el_end() since we expect to have multiple editline 122 // instances in this program. 123 ::el_set (m_editline, EL_EDITMODE, 0); 124 125 ::el_end(m_editline); 126 m_editline = NULL; 127} 128 129void 130Editline::SetGetCharCallback (GetCharCallbackType callback) 131{ 132 ::el_set (m_editline, EL_GETCFN, callback); 133} 134 135FileSpec 136Editline::GetHistoryFile() 137{ 138 char history_path[PATH_MAX]; 139 ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_program.c_str()); 140 return FileSpec(history_path, true); 141} 142 143bool 144Editline::LoadHistory () 145{ 146 if (m_history) 147 { 148 FileSpec history_file(GetHistoryFile()); 149 if (history_file.Exists()) 150 ::history (m_history, &m_history_event, H_LOAD, history_file.GetPath().c_str()); 151 return true; 152 } 153 return false; 154} 155 156bool 157Editline::SaveHistory () 158{ 159 if (m_history) 160 { 161 std::string history_path = GetHistoryFile().GetPath(); 162 ::history (m_history, &m_history_event, H_SAVE, history_path.c_str()); 163 return true; 164 } 165 return false; 166} 167 168 169Error 170Editline::PrivateGetLine(std::string &line) 171{ 172 Error error; 173 if (m_interrupted) 174 { 175 error.SetErrorString("interrupted"); 176 return error; 177 } 178 179 line.clear(); 180 if (m_editline != NULL) 181 { 182 int line_len = 0; 183 const char *line_cstr = NULL; 184 // Call el_gets to prompt the user and read the user's input. 185// { 186// // Make sure we know when we are in el_gets() by using a mutex 187// Mutex::Locker locker (m_gets_mutex); 188 line_cstr = ::el_gets (m_editline, &line_len); 189// } 190 191 static int save_errno = (line_len < 0) ? errno : 0; 192 193 if (save_errno != 0) 194 { 195 error.SetError(save_errno, eErrorTypePOSIX); 196 } 197 else if (line_cstr) 198 { 199 // Decrement the length so we don't have newline characters in "line" for when 200 // we assign the cstr into the std::string 201 while (line_len > 0 && 202 (line_cstr[line_len - 1] == '\n' || 203 line_cstr[line_len - 1] == '\r')) 204 --line_len; 205 206 if (line_len > 0) 207 { 208 // We didn't strip the newlines, we just adjusted the length, and 209 // we want to add the history item with the newlines 210 if (m_history) 211 ::history (m_history, &m_history_event, H_ENTER, line_cstr); 212 213 // Copy the part of the c string that we want (removing the newline chars) 214 line.assign(line_cstr, line_len); 215 } 216 } 217 } 218 else 219 { 220 error.SetErrorString("the EditLine instance has been deleted"); 221 } 222 return error; 223} 224 225 226Error 227Editline::GetLine(std::string &line) 228{ 229 Error error; 230 line.clear(); 231 232 // Set arrow key bindings for up and down arrows for single line 233 // mode where up and down arrows do prev/next history 234 ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow 235 ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow 236 m_interrupted = false; 237 238 if (!m_got_eof) 239 { 240 if (m_getting_line) 241 { 242 error.SetErrorString("already getting a line"); 243 return error; 244 } 245 if (m_lines_curr_line > 0) 246 { 247 error.SetErrorString("already getting lines"); 248 return error; 249 } 250 m_getting_line = true; 251 error = PrivateGetLine(line); 252 m_getting_line = false; 253 } 254 255 if (m_got_eof && line.empty()) 256 { 257 // Only set the error if we didn't get an error back from PrivateGetLine() 258 if (error.Success()) 259 error.SetErrorString("end of file"); 260 } 261 262 return error; 263} 264 265size_t 266Editline::Push (const char *bytes, size_t len) 267{ 268 if (m_editline) 269 { 270 // Must NULL terminate the string for el_push() so we stick it 271 // into a std::string first 272 ::el_push(m_editline, 273 const_cast<char*>(std::string (bytes, len).c_str())); 274 return len; 275 } 276 return 0; 277} 278 279 280Error 281Editline::GetLines(const std::string &end_line, StringList &lines) 282{ 283 Error error; 284 if (m_getting_line) 285 { 286 error.SetErrorString("already getting a line"); 287 return error; 288 } 289 if (m_lines_curr_line > 0) 290 { 291 error.SetErrorString("already getting lines"); 292 return error; 293 } 294 295 // Set arrow key bindings for up and down arrows for multiple line 296 // mode where up and down arrows do edit prev/next line 297 ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow 298 ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow 299 ::el_set (m_editline, EL_BIND, "^b", "ed-prev-history", NULL); 300 ::el_set (m_editline, EL_BIND, "^n", "ed-next-history", NULL); 301 m_interrupted = false; 302 303 LineStatus line_status = LineStatus::Success; 304 305 lines.Clear(); 306 307 FILE *out_file = GetOutputFile(); 308 FILE *err_file = GetErrorFile(); 309 m_lines_curr_line = 1; 310 while (line_status != LineStatus::Done) 311 { 312 const uint32_t line_idx = m_lines_curr_line-1; 313 if (line_idx >= lines.GetSize()) 314 lines.SetSize(m_lines_curr_line); 315 m_lines_max_line = lines.GetSize(); 316 m_lines_command = Command::None; 317 assert(line_idx < m_lines_max_line); 318 std::string &line = lines[line_idx]; 319 error = PrivateGetLine(line); 320 if (error.Fail()) 321 { 322 line_status = LineStatus::Error; 323 } 324 else 325 { 326 switch (m_lines_command) 327 { 328 case Command::None: 329 if (m_line_complete_callback) 330 { 331 line_status = m_line_complete_callback (this, 332 lines, 333 line_idx, 334 error, 335 m_line_complete_callback_baton); 336 } 337 else if (line == end_line) 338 { 339 line_status = LineStatus::Done; 340 } 341 342 if (line_status == LineStatus::Success) 343 { 344 ++m_lines_curr_line; 345 // If we already have content for the next line because 346 // we were editing previous lines, then populate the line 347 // with the appropriate contents 348 if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty()) 349 ::el_push (m_editline, 350 const_cast<char*>(lines[line_idx+1].c_str())); 351 } 352 else if (line_status == LineStatus::Error) 353 { 354 // Clear to end of line ("ESC[K"), then print the error, 355 // then go to the next line ("\n") and then move cursor up 356 // two lines ("ESC[2A"). 357 fprintf (err_file, "\033[Kerror: %s\n\033[2A", error.AsCString()); 358 } 359 break; 360 case Command::EditPrevLine: 361 if (m_lines_curr_line > 1) 362 { 363 //::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 364 ::fprintf (out_file, "\033[1A\033[1000D\033[2K"); 365 if (!lines[line_idx-1].empty()) 366 ::el_push (m_editline, 367 const_cast<char*>(lines[line_idx-1].c_str())); 368 --m_lines_curr_line; 369 } 370 break; 371 case Command::EditNextLine: 372 // Allow the down arrow to create a new line 373 ++m_lines_curr_line; 374 //::fprintf (out_file, "\033[1B\033[%uD\033[2K", (uint32_t)(m_lines_prompt.size() + lines[line_idx].size())); 375 ::fprintf (out_file, "\033[1B\033[1000D\033[2K"); 376 if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty()) 377 ::el_push (m_editline, 378 const_cast<char*>(lines[line_idx+1].c_str())); 379 break; 380 } 381 } 382 } 383 m_lines_curr_line = 0; 384 m_lines_command = Command::None; 385 386 // If we have a callback, call it one more time to let the 387 // user know the lines are complete 388 if (m_line_complete_callback) 389 m_line_complete_callback (this, 390 lines, 391 UINT32_MAX, 392 error, 393 m_line_complete_callback_baton); 394 395 return error; 396} 397 398unsigned char 399Editline::HandleCompletion (int ch) 400{ 401 if (m_completion_callback == NULL) 402 return CC_ERROR; 403 404 const LineInfo *line_info = ::el_line(m_editline); 405 StringList completions; 406 int page_size = 40; 407 408 const int num_completions = m_completion_callback (line_info->buffer, 409 line_info->cursor, 410 line_info->lastchar, 411 0, // Don't skip any matches (start at match zero) 412 -1, // Get all the matches 413 completions, 414 m_completion_callback_baton); 415 416 FILE *out_file = GetOutputFile(); 417 418// if (num_completions == -1) 419// { 420// ::el_insertstr (m_editline, m_completion_key); 421// return CC_REDISPLAY; 422// } 423// else 424 if (num_completions == -2) 425 { 426 // Replace the entire line with the first string... 427 ::el_deletestr (m_editline, line_info->cursor - line_info->buffer); 428 ::el_insertstr (m_editline, completions.GetStringAtIndex(0)); 429 return CC_REDISPLAY; 430 } 431 432 // If we get a longer match display that first. 433 const char *completion_str = completions.GetStringAtIndex(0); 434 if (completion_str != NULL && *completion_str != '\0') 435 { 436 el_insertstr (m_editline, completion_str); 437 return CC_REDISPLAY; 438 } 439 440 if (num_completions > 1) 441 { 442 int num_elements = num_completions + 1; 443 ::fprintf (out_file, "\nAvailable completions:"); 444 if (num_completions < page_size) 445 { 446 for (int i = 1; i < num_elements; i++) 447 { 448 completion_str = completions.GetStringAtIndex(i); 449 ::fprintf (out_file, "\n\t%s", completion_str); 450 } 451 ::fprintf (out_file, "\n"); 452 } 453 else 454 { 455 int cur_pos = 1; 456 char reply; 457 int got_char; 458 while (cur_pos < num_elements) 459 { 460 int endpoint = cur_pos + page_size; 461 if (endpoint > num_elements) 462 endpoint = num_elements; 463 for (; cur_pos < endpoint; cur_pos++) 464 { 465 completion_str = completions.GetStringAtIndex(cur_pos); 466 ::fprintf (out_file, "\n\t%s", completion_str); 467 } 468 469 if (cur_pos >= num_elements) 470 { 471 ::fprintf (out_file, "\n"); 472 break; 473 } 474 475 ::fprintf (out_file, "\nMore (Y/n/a): "); 476 reply = 'n'; 477 got_char = el_getc(m_editline, &reply); 478 if (got_char == -1 || reply == 'n') 479 break; 480 if (reply == 'a') 481 page_size = num_elements - cur_pos; 482 } 483 } 484 485 } 486 487 if (num_completions == 0) 488 return CC_REFRESH_BEEP; 489 else 490 return CC_REDISPLAY; 491} 492 493Editline * 494Editline::GetClientData (::EditLine *e) 495{ 496 Editline *editline = NULL; 497 if (e && ::el_get(e, EL_CLIENTDATA, &editline) == 0) 498 return editline; 499 return NULL; 500} 501 502FILE * 503Editline::GetInputFile () 504{ 505 return GetFilePointer (m_editline, 0); 506} 507 508FILE * 509Editline::GetOutputFile () 510{ 511 return GetFilePointer (m_editline, 1); 512} 513 514FILE * 515Editline::GetErrorFile () 516{ 517 return GetFilePointer (m_editline, 2); 518} 519 520const char * 521Editline::GetPrompt() 522{ 523 if (m_prompt_with_line_numbers && m_lines_curr_line > 0) 524 { 525 StreamString strm; 526 strm.Printf("%3u: ", m_lines_curr_line); 527 m_lines_prompt = std::move(strm.GetString()); 528 return m_lines_prompt.c_str(); 529 } 530 else 531 { 532 return m_prompt.c_str(); 533 } 534} 535 536void 537Editline::SetPrompt (const char *p) 538{ 539 if (p && p[0]) 540 m_prompt = p; 541 else 542 m_prompt.clear(); 543 size_t start_pos = 0; 544 size_t escape_pos; 545 while ((escape_pos = m_prompt.find('\033', start_pos)) != std::string::npos) 546 { 547 m_prompt.insert(escape_pos, 1, k_prompt_escape_char); 548 start_pos += 2; 549 } 550} 551 552FILE * 553Editline::GetFilePointer (::EditLine *e, int fd) 554{ 555 FILE *file_ptr = NULL; 556 if (e && ::el_get(e, EL_GETFP, fd, &file_ptr) == 0) 557 return file_ptr; 558 return NULL; 559} 560 561unsigned char 562Editline::CallbackEditPrevLine (::EditLine *e, int ch) 563{ 564 Editline *editline = GetClientData (e); 565 if (editline->m_lines_curr_line > 1) 566 { 567 editline->m_lines_command = Command::EditPrevLine; 568 return CC_NEWLINE; 569 } 570 return CC_ERROR; 571} 572unsigned char 573Editline::CallbackEditNextLine (::EditLine *e, int ch) 574{ 575 Editline *editline = GetClientData (e); 576 if (editline->m_lines_curr_line < editline->m_lines_max_line) 577 { 578 editline->m_lines_command = Command::EditNextLine; 579 return CC_NEWLINE; 580 } 581 return CC_ERROR; 582} 583 584unsigned char 585Editline::CallbackComplete (::EditLine *e, int ch) 586{ 587 Editline *editline = GetClientData (e); 588 if (editline) 589 return editline->HandleCompletion (ch); 590 return CC_ERROR; 591} 592 593const char * 594Editline::GetPromptCallback (::EditLine *e) 595{ 596 Editline *editline = GetClientData (e); 597 if (editline) 598 return editline->GetPrompt(); 599 return ""; 600} 601 602size_t 603Editline::SetInputBuffer (const char *c, size_t len) 604{ 605 if (c && len > 0) 606 { 607 Mutex::Locker locker(m_getc_mutex); 608 SetGetCharCallback(GetCharInputBufferCallback); 609 m_getc_buffer.append(c, len); 610 m_getc_cond.Broadcast(); 611 } 612 return len; 613} 614 615int 616Editline::GetChar (char *c) 617{ 618 Mutex::Locker locker(m_getc_mutex); 619 if (m_getc_buffer.empty()) 620 m_getc_cond.Wait(m_getc_mutex); 621 if (m_getc_buffer.empty()) 622 return 0; 623 *c = m_getc_buffer[0]; 624 m_getc_buffer.erase(0,1); 625 return 1; 626} 627 628int 629Editline::GetCharInputBufferCallback (EditLine *e, char *c) 630{ 631 Editline *editline = GetClientData (e); 632 if (editline) 633 return editline->GetChar(c); 634 return 0; 635} 636 637int 638Editline::GetCharFromInputFileCallback (EditLine *e, char *c) 639{ 640 Editline *editline = GetClientData (e); 641 if (editline && editline->m_got_eof == false) 642 { 643 char ch = ::fgetc(editline->GetInputFile()); 644 if (ch == '\x04') 645 { 646 // Only turn a CTRL+D into a EOF if we receive the 647 // CTRL+D an empty line, otherwise it will forward 648 // delete the character at the cursor 649 const LineInfo *line_info = ::el_line(e); 650 if (line_info != NULL && 651 line_info->buffer == line_info->cursor && 652 line_info->cursor == line_info->lastchar) 653 { 654 ch = EOF; 655 } 656 } 657 658 if (ch == EOF) 659 { 660 editline->m_got_eof = true; 661 } 662 else 663 { 664 *c = ch; 665 return 1; 666 } 667 } 668 return 0; 669} 670 671void 672Editline::Hide () 673{ 674 FILE *out_file = GetOutputFile(); 675 if (out_file) 676 { 677 const LineInfo *line_info = ::el_line(m_editline); 678 if (line_info) 679 ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer)); 680 } 681} 682 683 684void 685Editline::Refresh() 686{ 687 ::el_set (m_editline, EL_REFRESH); 688} 689 690void 691Editline::Interrupt () 692{ 693 m_interrupted = true; 694 if (m_getting_line || m_lines_curr_line > 0) 695 el_insertstr(m_editline, "\n"); // True to force the line to complete itself so we get exit from el_gets() 696} 697