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