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