1262182Semaste//===-- Editline.cpp --------------------------------------------*- C++ -*-===// 2262182Semaste// 3262182Semaste// The LLVM Compiler Infrastructure 4262182Semaste// 5262182Semaste// This file is distributed under the University of Illinois Open Source 6262182Semaste// License. See LICENSE.TXT for details. 7262182Semaste// 8262182Semaste//===----------------------------------------------------------------------===// 9262182Semaste 10262182Semaste 11262182Semaste#include "lldb/Host/Editline.h" 12262182Semaste 13262182Semaste#include "lldb/Core/Error.h" 14262182Semaste#include "lldb/Core/StreamString.h" 15262182Semaste#include "lldb/Core/StringList.h" 16262182Semaste#include "lldb/Host/Host.h" 17262182Semaste 18262182Semaste#include <limits.h> 19262182Semaste 20262182Semasteusing namespace lldb; 21262182Semasteusing namespace lldb_private; 22262182Semaste 23262182Semastestatic const char k_prompt_escape_char = '\1'; 24262182Semaste 25262182SemasteEditline::Editline (const char *prog, // prog can't be NULL 26262182Semaste const char *prompt, // can be NULL for no prompt 27262182Semaste FILE *fin, 28262182Semaste FILE *fout, 29262182Semaste FILE *ferr) : 30262182Semaste m_editline (NULL), 31262182Semaste m_history (NULL), 32262182Semaste m_history_event (), 33262182Semaste m_program (), 34262182Semaste m_prompt (), 35262182Semaste m_lines_prompt (), 36262182Semaste m_getc_buffer (), 37262182Semaste m_getc_mutex (Mutex::eMutexTypeNormal), 38262182Semaste m_getc_cond (), 39262182Semaste// m_gets_mutex (Mutex::eMutexTypeNormal), 40262182Semaste m_completion_callback (NULL), 41262182Semaste m_completion_callback_baton (NULL), 42262182Semaste m_line_complete_callback (NULL), 43262182Semaste m_line_complete_callback_baton (NULL), 44262182Semaste m_lines_command (Command::None), 45262182Semaste m_lines_curr_line (0), 46262182Semaste m_lines_max_line (0), 47262182Semaste m_prompt_with_line_numbers (false), 48262182Semaste m_getting_line (false), 49262182Semaste m_got_eof (false), 50262182Semaste m_interrupted (false) 51262182Semaste{ 52262182Semaste if (prog && prog[0]) 53262182Semaste { 54262182Semaste m_program = prog; 55262182Semaste m_editline = ::el_init(prog, fin, fout, ferr); 56262182Semaste m_history = ::history_init(); 57262182Semaste } 58262182Semaste else 59262182Semaste { 60262182Semaste m_editline = ::el_init("lldb-tmp", fin, fout, ferr); 61262182Semaste } 62262182Semaste if (prompt && prompt[0]) 63262182Semaste SetPrompt (prompt); 64262182Semaste 65262182Semaste //::el_set (m_editline, EL_BIND, "^[[A", NULL); // Print binding for up arrow key 66262182Semaste //::el_set (m_editline, EL_BIND, "^[[B", NULL); // Print binding for up down key 67262182Semaste 68262182Semaste assert (m_editline); 69262182Semaste ::el_set (m_editline, EL_CLIENTDATA, this); 70262182Semaste 71262182Semaste // only defined for newer versions of editline 72262182Semaste#ifdef EL_PROMPT_ESC 73262182Semaste ::el_set (m_editline, EL_PROMPT_ESC, GetPromptCallback, k_prompt_escape_char); 74262182Semaste#else 75262182Semaste // fall back on old prompt setting code 76262182Semaste ::el_set (m_editline, EL_PROMPT, GetPromptCallback); 77262182Semaste#endif 78262182Semaste ::el_set (m_editline, EL_EDITOR, "emacs"); 79262182Semaste if (m_history) 80262182Semaste { 81262182Semaste ::el_set (m_editline, EL_HIST, history, m_history); 82262182Semaste } 83262182Semaste ::el_set (m_editline, EL_ADDFN, "lldb-complete", "Editline completion function", Editline::CallbackComplete); 84262182Semaste ::el_set (m_editline, EL_ADDFN, "lldb-edit-prev-line", "Editline edit prev line", Editline::CallbackEditPrevLine); 85262182Semaste ::el_set (m_editline, EL_ADDFN, "lldb-edit-next-line", "Editline edit next line", Editline::CallbackEditNextLine); 86262182Semaste 87262182Semaste ::el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string 88262182Semaste ::el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does. 89262182Semaste ::el_set (m_editline, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key. 90262182Semaste ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be autocompelte 91262182Semaste 92262182Semaste // Source $PWD/.editrc then $HOME/.editrc 93262182Semaste ::el_source (m_editline, NULL); 94262182Semaste 95262182Semaste if (m_history) 96262182Semaste { 97262182Semaste ::history (m_history, &m_history_event, H_SETSIZE, 800); 98262182Semaste ::history (m_history, &m_history_event, H_SETUNIQUE, 1); 99262182Semaste } 100262182Semaste 101262182Semaste // Always read through our callback function so we don't read 102262182Semaste // stuff we aren't supposed to. This also stops the extra echoing 103262182Semaste // that can happen when you have more input than editline can handle 104262182Semaste // at once. 105262182Semaste SetGetCharCallback(GetCharFromInputFileCallback); 106262182Semaste 107262182Semaste LoadHistory(); 108262182Semaste} 109262182Semaste 110262182SemasteEditline::~Editline() 111262182Semaste{ 112262182Semaste SaveHistory(); 113262182Semaste 114262182Semaste if (m_history) 115262182Semaste { 116262182Semaste ::history_end (m_history); 117262182Semaste m_history = NULL; 118262182Semaste } 119262182Semaste 120262182Semaste // Disable edit mode to stop the terminal from flushing all input 121262182Semaste // during the call to el_end() since we expect to have multiple editline 122262182Semaste // instances in this program. 123262182Semaste ::el_set (m_editline, EL_EDITMODE, 0); 124262182Semaste 125262182Semaste ::el_end(m_editline); 126262182Semaste m_editline = NULL; 127262182Semaste} 128262182Semaste 129262182Semastevoid 130262182SemasteEditline::SetGetCharCallback (GetCharCallbackType callback) 131262182Semaste{ 132262182Semaste ::el_set (m_editline, EL_GETCFN, callback); 133262182Semaste} 134262182Semaste 135262182SemasteFileSpec 136262182SemasteEditline::GetHistoryFile() 137262182Semaste{ 138262182Semaste char history_path[PATH_MAX]; 139262182Semaste ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_program.c_str()); 140262182Semaste return FileSpec(history_path, true); 141262182Semaste} 142262182Semaste 143262182Semastebool 144262182SemasteEditline::LoadHistory () 145262182Semaste{ 146262182Semaste if (m_history) 147262182Semaste { 148262182Semaste FileSpec history_file(GetHistoryFile()); 149262182Semaste if (history_file.Exists()) 150262182Semaste ::history (m_history, &m_history_event, H_LOAD, history_file.GetPath().c_str()); 151262182Semaste return true; 152262182Semaste } 153262182Semaste return false; 154262182Semaste} 155262182Semaste 156262182Semastebool 157262182SemasteEditline::SaveHistory () 158262182Semaste{ 159262182Semaste if (m_history) 160262182Semaste { 161262182Semaste std::string history_path = GetHistoryFile().GetPath(); 162262182Semaste ::history (m_history, &m_history_event, H_SAVE, history_path.c_str()); 163262182Semaste return true; 164262182Semaste } 165262182Semaste return false; 166262182Semaste} 167262182Semaste 168262182Semaste 169262182SemasteError 170262182SemasteEditline::PrivateGetLine(std::string &line) 171262182Semaste{ 172262182Semaste Error error; 173262182Semaste if (m_interrupted) 174262182Semaste { 175262182Semaste error.SetErrorString("interrupted"); 176262182Semaste return error; 177262182Semaste } 178262182Semaste 179262182Semaste line.clear(); 180262182Semaste if (m_editline != NULL) 181262182Semaste { 182262182Semaste int line_len = 0; 183262182Semaste const char *line_cstr = NULL; 184262182Semaste // Call el_gets to prompt the user and read the user's input. 185262182Semaste// { 186262182Semaste// // Make sure we know when we are in el_gets() by using a mutex 187262182Semaste// Mutex::Locker locker (m_gets_mutex); 188262182Semaste line_cstr = ::el_gets (m_editline, &line_len); 189262182Semaste// } 190262182Semaste 191262182Semaste static int save_errno = (line_len < 0) ? errno : 0; 192262182Semaste 193262182Semaste if (save_errno != 0) 194262182Semaste { 195262182Semaste error.SetError(save_errno, eErrorTypePOSIX); 196262182Semaste } 197262182Semaste else if (line_cstr) 198262182Semaste { 199262182Semaste // Decrement the length so we don't have newline characters in "line" for when 200262182Semaste // we assign the cstr into the std::string 201262182Semaste while (line_len > 0 && 202262182Semaste (line_cstr[line_len - 1] == '\n' || 203262182Semaste line_cstr[line_len - 1] == '\r')) 204262182Semaste --line_len; 205262182Semaste 206262182Semaste if (line_len > 0) 207262182Semaste { 208262182Semaste // We didn't strip the newlines, we just adjusted the length, and 209262182Semaste // we want to add the history item with the newlines 210262182Semaste if (m_history) 211262182Semaste ::history (m_history, &m_history_event, H_ENTER, line_cstr); 212262182Semaste 213262182Semaste // Copy the part of the c string that we want (removing the newline chars) 214262182Semaste line.assign(line_cstr, line_len); 215262182Semaste } 216262182Semaste } 217262182Semaste } 218262182Semaste else 219262182Semaste { 220262182Semaste error.SetErrorString("the EditLine instance has been deleted"); 221262182Semaste } 222262182Semaste return error; 223262182Semaste} 224262182Semaste 225262182Semaste 226262182SemasteError 227262182SemasteEditline::GetLine(std::string &line) 228262182Semaste{ 229262182Semaste Error error; 230262182Semaste line.clear(); 231262182Semaste 232262182Semaste // Set arrow key bindings for up and down arrows for single line 233262182Semaste // mode where up and down arrows do prev/next history 234262182Semaste ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow 235262182Semaste ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow 236262182Semaste m_interrupted = false; 237262182Semaste 238262182Semaste if (!m_got_eof) 239262182Semaste { 240262182Semaste if (m_getting_line) 241262182Semaste { 242262182Semaste error.SetErrorString("already getting a line"); 243262182Semaste return error; 244262182Semaste } 245262182Semaste if (m_lines_curr_line > 0) 246262182Semaste { 247262182Semaste error.SetErrorString("already getting lines"); 248262182Semaste return error; 249262182Semaste } 250262182Semaste m_getting_line = true; 251262182Semaste error = PrivateGetLine(line); 252262182Semaste m_getting_line = false; 253262182Semaste } 254262182Semaste 255262182Semaste if (m_got_eof && line.empty()) 256262182Semaste { 257262182Semaste // Only set the error if we didn't get an error back from PrivateGetLine() 258262182Semaste if (error.Success()) 259262182Semaste error.SetErrorString("end of file"); 260262182Semaste } 261262182Semaste 262262182Semaste return error; 263262182Semaste} 264262182Semaste 265262182Semastesize_t 266262182SemasteEditline::Push (const char *bytes, size_t len) 267262182Semaste{ 268262182Semaste if (m_editline) 269262182Semaste { 270262182Semaste // Must NULL terminate the string for el_push() so we stick it 271262182Semaste // into a std::string first 272262182Semaste ::el_push(m_editline, 273262182Semaste const_cast<char*>(std::string (bytes, len).c_str())); 274262182Semaste return len; 275262182Semaste } 276262182Semaste return 0; 277262182Semaste} 278262182Semaste 279262182Semaste 280262182SemasteError 281262182SemasteEditline::GetLines(const std::string &end_line, StringList &lines) 282262182Semaste{ 283262182Semaste Error error; 284262182Semaste if (m_getting_line) 285262182Semaste { 286262182Semaste error.SetErrorString("already getting a line"); 287262182Semaste return error; 288262182Semaste } 289262182Semaste if (m_lines_curr_line > 0) 290262182Semaste { 291262182Semaste error.SetErrorString("already getting lines"); 292262182Semaste return error; 293262182Semaste } 294262182Semaste 295262182Semaste // Set arrow key bindings for up and down arrows for multiple line 296262182Semaste // mode where up and down arrows do edit prev/next line 297262182Semaste ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow 298262182Semaste ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow 299262182Semaste ::el_set (m_editline, EL_BIND, "^b", "ed-prev-history", NULL); 300262182Semaste ::el_set (m_editline, EL_BIND, "^n", "ed-next-history", NULL); 301262182Semaste m_interrupted = false; 302262182Semaste 303262182Semaste LineStatus line_status = LineStatus::Success; 304262182Semaste 305262182Semaste lines.Clear(); 306262182Semaste 307262182Semaste FILE *out_file = GetOutputFile(); 308262182Semaste FILE *err_file = GetErrorFile(); 309262182Semaste m_lines_curr_line = 1; 310262182Semaste while (line_status != LineStatus::Done) 311262182Semaste { 312262182Semaste const uint32_t line_idx = m_lines_curr_line-1; 313262182Semaste if (line_idx >= lines.GetSize()) 314262182Semaste lines.SetSize(m_lines_curr_line); 315262182Semaste m_lines_max_line = lines.GetSize(); 316262182Semaste m_lines_command = Command::None; 317262182Semaste assert(line_idx < m_lines_max_line); 318262182Semaste std::string &line = lines[line_idx]; 319262182Semaste error = PrivateGetLine(line); 320262182Semaste if (error.Fail()) 321262182Semaste { 322262182Semaste line_status = LineStatus::Error; 323262182Semaste } 324262182Semaste else 325262182Semaste { 326262182Semaste switch (m_lines_command) 327262182Semaste { 328262182Semaste case Command::None: 329262182Semaste if (m_line_complete_callback) 330262182Semaste { 331262182Semaste line_status = m_line_complete_callback (this, 332262182Semaste lines, 333262182Semaste line_idx, 334262182Semaste error, 335262182Semaste m_line_complete_callback_baton); 336262182Semaste } 337262182Semaste else if (line == end_line) 338262182Semaste { 339262182Semaste line_status = LineStatus::Done; 340262182Semaste } 341262182Semaste 342262182Semaste if (line_status == LineStatus::Success) 343262182Semaste { 344262182Semaste ++m_lines_curr_line; 345262182Semaste // If we already have content for the next line because 346262182Semaste // we were editing previous lines, then populate the line 347262182Semaste // with the appropriate contents 348262182Semaste if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty()) 349262182Semaste ::el_push (m_editline, 350262182Semaste const_cast<char*>(lines[line_idx+1].c_str())); 351262182Semaste } 352262182Semaste else if (line_status == LineStatus::Error) 353262182Semaste { 354262182Semaste // Clear to end of line ("ESC[K"), then print the error, 355262182Semaste // then go to the next line ("\n") and then move cursor up 356262182Semaste // two lines ("ESC[2A"). 357262182Semaste fprintf (err_file, "\033[Kerror: %s\n\033[2A", error.AsCString()); 358262182Semaste } 359262182Semaste break; 360262182Semaste case Command::EditPrevLine: 361262182Semaste if (m_lines_curr_line > 1) 362262182Semaste { 363262182Semaste //::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 364262182Semaste ::fprintf (out_file, "\033[1A\033[1000D\033[2K"); 365262182Semaste if (!lines[line_idx-1].empty()) 366262182Semaste ::el_push (m_editline, 367262182Semaste const_cast<char*>(lines[line_idx-1].c_str())); 368262182Semaste --m_lines_curr_line; 369262182Semaste } 370262182Semaste break; 371262182Semaste case Command::EditNextLine: 372262182Semaste // Allow the down arrow to create a new line 373262182Semaste ++m_lines_curr_line; 374262182Semaste //::fprintf (out_file, "\033[1B\033[%uD\033[2K", (uint32_t)(m_lines_prompt.size() + lines[line_idx].size())); 375262182Semaste ::fprintf (out_file, "\033[1B\033[1000D\033[2K"); 376262182Semaste if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty()) 377262182Semaste ::el_push (m_editline, 378262182Semaste const_cast<char*>(lines[line_idx+1].c_str())); 379262182Semaste break; 380262182Semaste } 381262182Semaste } 382262182Semaste } 383262182Semaste m_lines_curr_line = 0; 384262182Semaste m_lines_command = Command::None; 385262182Semaste 386262182Semaste // If we have a callback, call it one more time to let the 387262182Semaste // user know the lines are complete 388262182Semaste if (m_line_complete_callback) 389262182Semaste m_line_complete_callback (this, 390262182Semaste lines, 391262182Semaste UINT32_MAX, 392262182Semaste error, 393262182Semaste m_line_complete_callback_baton); 394262182Semaste 395262182Semaste return error; 396262182Semaste} 397262182Semaste 398262182Semasteunsigned char 399262182SemasteEditline::HandleCompletion (int ch) 400262182Semaste{ 401262182Semaste if (m_completion_callback == NULL) 402262182Semaste return CC_ERROR; 403262182Semaste 404262182Semaste const LineInfo *line_info = ::el_line(m_editline); 405262182Semaste StringList completions; 406262182Semaste int page_size = 40; 407262182Semaste 408262182Semaste const int num_completions = m_completion_callback (line_info->buffer, 409262182Semaste line_info->cursor, 410262182Semaste line_info->lastchar, 411262182Semaste 0, // Don't skip any matches (start at match zero) 412262182Semaste -1, // Get all the matches 413262182Semaste completions, 414262182Semaste m_completion_callback_baton); 415262182Semaste 416262182Semaste FILE *out_file = GetOutputFile(); 417262182Semaste 418262182Semaste// if (num_completions == -1) 419262182Semaste// { 420262182Semaste// ::el_insertstr (m_editline, m_completion_key); 421262182Semaste// return CC_REDISPLAY; 422262182Semaste// } 423262182Semaste// else 424262182Semaste if (num_completions == -2) 425262182Semaste { 426262182Semaste // Replace the entire line with the first string... 427262182Semaste ::el_deletestr (m_editline, line_info->cursor - line_info->buffer); 428262182Semaste ::el_insertstr (m_editline, completions.GetStringAtIndex(0)); 429262182Semaste return CC_REDISPLAY; 430262182Semaste } 431262182Semaste 432262182Semaste // If we get a longer match display that first. 433262182Semaste const char *completion_str = completions.GetStringAtIndex(0); 434262182Semaste if (completion_str != NULL && *completion_str != '\0') 435262182Semaste { 436262182Semaste el_insertstr (m_editline, completion_str); 437262182Semaste return CC_REDISPLAY; 438262182Semaste } 439262182Semaste 440262182Semaste if (num_completions > 1) 441262182Semaste { 442262182Semaste int num_elements = num_completions + 1; 443262182Semaste ::fprintf (out_file, "\nAvailable completions:"); 444262182Semaste if (num_completions < page_size) 445262182Semaste { 446262182Semaste for (int i = 1; i < num_elements; i++) 447262182Semaste { 448262182Semaste completion_str = completions.GetStringAtIndex(i); 449262182Semaste ::fprintf (out_file, "\n\t%s", completion_str); 450262182Semaste } 451262182Semaste ::fprintf (out_file, "\n"); 452262182Semaste } 453262182Semaste else 454262182Semaste { 455262182Semaste int cur_pos = 1; 456262182Semaste char reply; 457262182Semaste int got_char; 458262182Semaste while (cur_pos < num_elements) 459262182Semaste { 460262182Semaste int endpoint = cur_pos + page_size; 461262182Semaste if (endpoint > num_elements) 462262182Semaste endpoint = num_elements; 463262182Semaste for (; cur_pos < endpoint; cur_pos++) 464262182Semaste { 465262182Semaste completion_str = completions.GetStringAtIndex(cur_pos); 466262182Semaste ::fprintf (out_file, "\n\t%s", completion_str); 467262182Semaste } 468262182Semaste 469262182Semaste if (cur_pos >= num_elements) 470262182Semaste { 471262182Semaste ::fprintf (out_file, "\n"); 472262182Semaste break; 473262182Semaste } 474262182Semaste 475262182Semaste ::fprintf (out_file, "\nMore (Y/n/a): "); 476262182Semaste reply = 'n'; 477262182Semaste got_char = el_getc(m_editline, &reply); 478262182Semaste if (got_char == -1 || reply == 'n') 479262182Semaste break; 480262182Semaste if (reply == 'a') 481262182Semaste page_size = num_elements - cur_pos; 482262182Semaste } 483262182Semaste } 484262182Semaste 485262182Semaste } 486262182Semaste 487262182Semaste if (num_completions == 0) 488262182Semaste return CC_REFRESH_BEEP; 489262182Semaste else 490262182Semaste return CC_REDISPLAY; 491262182Semaste} 492262182Semaste 493262182SemasteEditline * 494262182SemasteEditline::GetClientData (::EditLine *e) 495262182Semaste{ 496262182Semaste Editline *editline = NULL; 497262182Semaste if (e && ::el_get(e, EL_CLIENTDATA, &editline) == 0) 498262182Semaste return editline; 499262182Semaste return NULL; 500262182Semaste} 501262182Semaste 502262182SemasteFILE * 503262182SemasteEditline::GetInputFile () 504262182Semaste{ 505262182Semaste return GetFilePointer (m_editline, 0); 506262182Semaste} 507262182Semaste 508262182SemasteFILE * 509262182SemasteEditline::GetOutputFile () 510262182Semaste{ 511262182Semaste return GetFilePointer (m_editline, 1); 512262182Semaste} 513262182Semaste 514262182SemasteFILE * 515262182SemasteEditline::GetErrorFile () 516262182Semaste{ 517262182Semaste return GetFilePointer (m_editline, 2); 518262182Semaste} 519262182Semaste 520262182Semasteconst char * 521262182SemasteEditline::GetPrompt() 522262182Semaste{ 523262182Semaste if (m_prompt_with_line_numbers && m_lines_curr_line > 0) 524262182Semaste { 525262182Semaste StreamString strm; 526262182Semaste strm.Printf("%3u: ", m_lines_curr_line); 527262182Semaste m_lines_prompt = std::move(strm.GetString()); 528262182Semaste return m_lines_prompt.c_str(); 529262182Semaste } 530262182Semaste else 531262182Semaste { 532262182Semaste return m_prompt.c_str(); 533262182Semaste } 534262182Semaste} 535262182Semaste 536262182Semastevoid 537262182SemasteEditline::SetPrompt (const char *p) 538262182Semaste{ 539262182Semaste if (p && p[0]) 540262182Semaste m_prompt = p; 541262182Semaste else 542262182Semaste m_prompt.clear(); 543262182Semaste size_t start_pos = 0; 544262182Semaste size_t escape_pos; 545262182Semaste while ((escape_pos = m_prompt.find('\033', start_pos)) != std::string::npos) 546262182Semaste { 547262182Semaste m_prompt.insert(escape_pos, 1, k_prompt_escape_char); 548262182Semaste start_pos += 2; 549262182Semaste } 550262182Semaste} 551262182Semaste 552262182SemasteFILE * 553262182SemasteEditline::GetFilePointer (::EditLine *e, int fd) 554262182Semaste{ 555262182Semaste FILE *file_ptr = NULL; 556262182Semaste if (e && ::el_get(e, EL_GETFP, fd, &file_ptr) == 0) 557262182Semaste return file_ptr; 558262182Semaste return NULL; 559262182Semaste} 560262182Semaste 561262182Semasteunsigned char 562262182SemasteEditline::CallbackEditPrevLine (::EditLine *e, int ch) 563262182Semaste{ 564262182Semaste Editline *editline = GetClientData (e); 565262182Semaste if (editline->m_lines_curr_line > 1) 566262182Semaste { 567262182Semaste editline->m_lines_command = Command::EditPrevLine; 568262182Semaste return CC_NEWLINE; 569262182Semaste } 570262182Semaste return CC_ERROR; 571262182Semaste} 572262182Semasteunsigned char 573262182SemasteEditline::CallbackEditNextLine (::EditLine *e, int ch) 574262182Semaste{ 575262182Semaste Editline *editline = GetClientData (e); 576262182Semaste if (editline->m_lines_curr_line < editline->m_lines_max_line) 577262182Semaste { 578262182Semaste editline->m_lines_command = Command::EditNextLine; 579262182Semaste return CC_NEWLINE; 580262182Semaste } 581262182Semaste return CC_ERROR; 582262182Semaste} 583262182Semaste 584262182Semasteunsigned char 585262182SemasteEditline::CallbackComplete (::EditLine *e, int ch) 586262182Semaste{ 587262182Semaste Editline *editline = GetClientData (e); 588262182Semaste if (editline) 589262182Semaste return editline->HandleCompletion (ch); 590262182Semaste return CC_ERROR; 591262182Semaste} 592262182Semaste 593262182Semasteconst char * 594262182SemasteEditline::GetPromptCallback (::EditLine *e) 595262182Semaste{ 596262182Semaste Editline *editline = GetClientData (e); 597262182Semaste if (editline) 598262182Semaste return editline->GetPrompt(); 599262182Semaste return ""; 600262182Semaste} 601262182Semaste 602262182Semastesize_t 603262182SemasteEditline::SetInputBuffer (const char *c, size_t len) 604262182Semaste{ 605262182Semaste if (c && len > 0) 606262182Semaste { 607262182Semaste Mutex::Locker locker(m_getc_mutex); 608262182Semaste SetGetCharCallback(GetCharInputBufferCallback); 609262182Semaste m_getc_buffer.append(c, len); 610262182Semaste m_getc_cond.Broadcast(); 611262182Semaste } 612262182Semaste return len; 613262182Semaste} 614262182Semaste 615262182Semasteint 616262182SemasteEditline::GetChar (char *c) 617262182Semaste{ 618262182Semaste Mutex::Locker locker(m_getc_mutex); 619262182Semaste if (m_getc_buffer.empty()) 620262182Semaste m_getc_cond.Wait(m_getc_mutex); 621262182Semaste if (m_getc_buffer.empty()) 622262182Semaste return 0; 623262182Semaste *c = m_getc_buffer[0]; 624262182Semaste m_getc_buffer.erase(0,1); 625262182Semaste return 1; 626262182Semaste} 627262182Semaste 628262182Semasteint 629262182SemasteEditline::GetCharInputBufferCallback (EditLine *e, char *c) 630262182Semaste{ 631262182Semaste Editline *editline = GetClientData (e); 632262182Semaste if (editline) 633262182Semaste return editline->GetChar(c); 634262182Semaste return 0; 635262182Semaste} 636262182Semaste 637262182Semasteint 638262182SemasteEditline::GetCharFromInputFileCallback (EditLine *e, char *c) 639262182Semaste{ 640262182Semaste Editline *editline = GetClientData (e); 641262182Semaste if (editline && editline->m_got_eof == false) 642262182Semaste { 643262182Semaste char ch = ::fgetc(editline->GetInputFile()); 644262182Semaste if (ch == '\x04') 645262182Semaste { 646262182Semaste // Only turn a CTRL+D into a EOF if we receive the 647262182Semaste // CTRL+D an empty line, otherwise it will forward 648262182Semaste // delete the character at the cursor 649262182Semaste const LineInfo *line_info = ::el_line(e); 650262182Semaste if (line_info != NULL && 651262182Semaste line_info->buffer == line_info->cursor && 652262182Semaste line_info->cursor == line_info->lastchar) 653262182Semaste { 654262182Semaste ch = EOF; 655262182Semaste } 656262182Semaste } 657262182Semaste 658262182Semaste if (ch == EOF) 659262182Semaste { 660262182Semaste editline->m_got_eof = true; 661262182Semaste } 662262182Semaste else 663262182Semaste { 664262182Semaste *c = ch; 665262182Semaste return 1; 666262182Semaste } 667262182Semaste } 668262182Semaste return 0; 669262182Semaste} 670262182Semaste 671262182Semastevoid 672262182SemasteEditline::Hide () 673262182Semaste{ 674262182Semaste FILE *out_file = GetOutputFile(); 675262182Semaste if (out_file) 676262182Semaste { 677262182Semaste const LineInfo *line_info = ::el_line(m_editline); 678262182Semaste if (line_info) 679262182Semaste ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer)); 680262182Semaste } 681262182Semaste} 682262182Semaste 683262182Semaste 684262182Semastevoid 685262182SemasteEditline::Refresh() 686262182Semaste{ 687262182Semaste ::el_set (m_editline, EL_REFRESH); 688262182Semaste} 689262182Semaste 690262182Semastevoid 691262182SemasteEditline::Interrupt () 692262182Semaste{ 693262182Semaste m_interrupted = true; 694262182Semaste if (m_getting_line || m_lines_curr_line > 0) 695262182Semaste el_insertstr(m_editline, "\n"); // True to force the line to complete itself so we get exit from el_gets() 696262182Semaste} 697