1c7d437c1SPeter Collingbourne //===-- LineEditor.cpp - line editor --------------------------------------===//
2c7d437c1SPeter Collingbourne //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c7d437c1SPeter Collingbourne //
7c7d437c1SPeter Collingbourne //===----------------------------------------------------------------------===//
8c7d437c1SPeter Collingbourne 
9c7d437c1SPeter Collingbourne #include "llvm/LineEditor/LineEditor.h"
10c7d437c1SPeter Collingbourne #include "llvm/ADT/SmallString.h"
11c7d437c1SPeter Collingbourne #include "llvm/Config/config.h"
12c7d437c1SPeter Collingbourne #include "llvm/Support/Path.h"
13c7d437c1SPeter Collingbourne #include "llvm/Support/raw_ostream.h"
1435623fb7SEugene Zelenko #include <algorithm>
1535623fb7SEugene Zelenko #include <cassert>
1635623fb7SEugene Zelenko #include <cstdio>
17c7d437c1SPeter Collingbourne #ifdef HAVE_LIBEDIT
18c7d437c1SPeter Collingbourne #include <histedit.h>
19c7d437c1SPeter Collingbourne #endif
20c7d437c1SPeter Collingbourne 
21c7d437c1SPeter Collingbourne using namespace llvm;
22c7d437c1SPeter Collingbourne 
getDefaultHistoryPath(StringRef ProgName)23c7d437c1SPeter Collingbourne std::string LineEditor::getDefaultHistoryPath(StringRef ProgName) {
24c7d437c1SPeter Collingbourne   SmallString<32> Path;
25c7d437c1SPeter Collingbourne   if (sys::path::home_directory(Path)) {
26c7d437c1SPeter Collingbourne     sys::path::append(Path, "." + ProgName + "-history");
27adcd0268SBenjamin Kramer     return std::string(Path.str());
28c7d437c1SPeter Collingbourne   }
29c7d437c1SPeter Collingbourne   return std::string();
30c7d437c1SPeter Collingbourne }
31c7d437c1SPeter Collingbourne 
32*3a3cb929SKazu Hirata LineEditor::CompleterConcept::~CompleterConcept() = default;
33*3a3cb929SKazu Hirata LineEditor::ListCompleterConcept::~ListCompleterConcept() = default;
34c7d437c1SPeter Collingbourne 
getCommonPrefix(const std::vector<Completion> & Comps)35c7d437c1SPeter Collingbourne std::string LineEditor::ListCompleterConcept::getCommonPrefix(
36c7d437c1SPeter Collingbourne     const std::vector<Completion> &Comps) {
37c7d437c1SPeter Collingbourne   assert(!Comps.empty());
38c7d437c1SPeter Collingbourne 
39c7d437c1SPeter Collingbourne   std::string CommonPrefix = Comps[0].TypedText;
40c7d437c1SPeter Collingbourne   for (std::vector<Completion>::const_iterator I = Comps.begin() + 1,
41c7d437c1SPeter Collingbourne                                                E = Comps.end();
42c7d437c1SPeter Collingbourne        I != E; ++I) {
43c7d437c1SPeter Collingbourne     size_t Len = std::min(CommonPrefix.size(), I->TypedText.size());
44c7d437c1SPeter Collingbourne     size_t CommonLen = 0;
45c7d437c1SPeter Collingbourne     for (; CommonLen != Len; ++CommonLen) {
46c7d437c1SPeter Collingbourne       if (CommonPrefix[CommonLen] != I->TypedText[CommonLen])
47c7d437c1SPeter Collingbourne         break;
48c7d437c1SPeter Collingbourne     }
49c7d437c1SPeter Collingbourne     CommonPrefix.resize(CommonLen);
50c7d437c1SPeter Collingbourne   }
51c7d437c1SPeter Collingbourne   return CommonPrefix;
52c7d437c1SPeter Collingbourne }
53c7d437c1SPeter Collingbourne 
54c7d437c1SPeter Collingbourne LineEditor::CompletionAction
complete(StringRef Buffer,size_t Pos) const55c7d437c1SPeter Collingbourne LineEditor::ListCompleterConcept::complete(StringRef Buffer, size_t Pos) const {
56c7d437c1SPeter Collingbourne   CompletionAction Action;
57c7d437c1SPeter Collingbourne   std::vector<Completion> Comps = getCompletions(Buffer, Pos);
58c7d437c1SPeter Collingbourne   if (Comps.empty()) {
59c7d437c1SPeter Collingbourne     Action.Kind = CompletionAction::AK_ShowCompletions;
60c7d437c1SPeter Collingbourne     return Action;
61c7d437c1SPeter Collingbourne   }
62c7d437c1SPeter Collingbourne 
63c7d437c1SPeter Collingbourne   std::string CommonPrefix = getCommonPrefix(Comps);
64c7d437c1SPeter Collingbourne 
65c7d437c1SPeter Collingbourne   // If the common prefix is non-empty we can simply insert it. If there is a
66c7d437c1SPeter Collingbourne   // single completion, this will insert the full completion. If there is more
67c7d437c1SPeter Collingbourne   // than one, this might be enough information to jog the user's memory but if
68c7d437c1SPeter Collingbourne   // not the user can also hit tab again to see the completions because the
69c7d437c1SPeter Collingbourne   // common prefix will then be empty.
70c7d437c1SPeter Collingbourne   if (CommonPrefix.empty()) {
71c7d437c1SPeter Collingbourne     Action.Kind = CompletionAction::AK_ShowCompletions;
72ccdd5bb2SKazu Hirata     for (const Completion &Comp : Comps)
73ccdd5bb2SKazu Hirata       Action.Completions.push_back(Comp.DisplayText);
74c7d437c1SPeter Collingbourne   } else {
75c7d437c1SPeter Collingbourne     Action.Kind = CompletionAction::AK_Insert;
76c7d437c1SPeter Collingbourne     Action.Text = CommonPrefix;
77c7d437c1SPeter Collingbourne   }
78c7d437c1SPeter Collingbourne 
79c7d437c1SPeter Collingbourne   return Action;
80c7d437c1SPeter Collingbourne }
81c7d437c1SPeter Collingbourne 
getCompletionAction(StringRef Buffer,size_t Pos) const82c7d437c1SPeter Collingbourne LineEditor::CompletionAction LineEditor::getCompletionAction(StringRef Buffer,
83c7d437c1SPeter Collingbourne                                                              size_t Pos) const {
84c7d437c1SPeter Collingbourne   if (!Completer) {
85c7d437c1SPeter Collingbourne     CompletionAction Action;
86c7d437c1SPeter Collingbourne     Action.Kind = CompletionAction::AK_ShowCompletions;
87c7d437c1SPeter Collingbourne     return Action;
88c7d437c1SPeter Collingbourne   }
89c7d437c1SPeter Collingbourne 
90c7d437c1SPeter Collingbourne   return Completer->complete(Buffer, Pos);
91c7d437c1SPeter Collingbourne }
92c7d437c1SPeter Collingbourne 
93c7d437c1SPeter Collingbourne #ifdef HAVE_LIBEDIT
94c7d437c1SPeter Collingbourne 
95c7d437c1SPeter Collingbourne // libedit-based implementation.
96c7d437c1SPeter Collingbourne 
97c7d437c1SPeter Collingbourne struct LineEditor::InternalData {
98c7d437c1SPeter Collingbourne   LineEditor *LE;
99c7d437c1SPeter Collingbourne 
100c7d437c1SPeter Collingbourne   History *Hist;
101c7d437c1SPeter Collingbourne   EditLine *EL;
102c7d437c1SPeter Collingbourne 
103c7d437c1SPeter Collingbourne   unsigned PrevCount;
104c7d437c1SPeter Collingbourne   std::string ContinuationOutput;
10545b4c499SPeter Collingbourne 
10645b4c499SPeter Collingbourne   FILE *Out;
107c7d437c1SPeter Collingbourne };
108c7d437c1SPeter Collingbourne 
10935623fb7SEugene Zelenko namespace {
11035623fb7SEugene Zelenko 
ElGetPromptFn(EditLine * EL)11135623fb7SEugene Zelenko const char *ElGetPromptFn(EditLine *EL) {
112c7d437c1SPeter Collingbourne   LineEditor::InternalData *Data;
113c7d437c1SPeter Collingbourne   if (el_get(EL, EL_CLIENTDATA, &Data) == 0)
114c7d437c1SPeter Collingbourne     return Data->LE->getPrompt().c_str();
115c7d437c1SPeter Collingbourne   return "> ";
116c7d437c1SPeter Collingbourne }
117c7d437c1SPeter Collingbourne 
118c7d437c1SPeter Collingbourne // Handles tab completion.
119c7d437c1SPeter Collingbourne //
120c7d437c1SPeter Collingbourne // This function is really horrible. But since the alternative is to get into
121c7d437c1SPeter Collingbourne // the line editor business, here we are.
ElCompletionFn(EditLine * EL,int ch)12235623fb7SEugene Zelenko unsigned char ElCompletionFn(EditLine *EL, int ch) {
123c7d437c1SPeter Collingbourne   LineEditor::InternalData *Data;
124c7d437c1SPeter Collingbourne   if (el_get(EL, EL_CLIENTDATA, &Data) == 0) {
125c7d437c1SPeter Collingbourne     if (!Data->ContinuationOutput.empty()) {
126c7d437c1SPeter Collingbourne       // This is the continuation of the AK_ShowCompletions branch below.
12745b4c499SPeter Collingbourne       FILE *Out = Data->Out;
128c7d437c1SPeter Collingbourne 
129c7d437c1SPeter Collingbourne       // Print the required output (see below).
130c7d437c1SPeter Collingbourne       ::fwrite(Data->ContinuationOutput.c_str(),
131c7d437c1SPeter Collingbourne                Data->ContinuationOutput.size(), 1, Out);
132c7d437c1SPeter Collingbourne 
133c7d437c1SPeter Collingbourne       // Push a sequence of Ctrl-B characters to move the cursor back to its
134c7d437c1SPeter Collingbourne       // original position.
135c7d437c1SPeter Collingbourne       std::string Prevs(Data->PrevCount, '\02');
136029750fbSBenjamin Kramer       ::el_push(EL, const_cast<char *>(Prevs.c_str()));
137c7d437c1SPeter Collingbourne 
138c7d437c1SPeter Collingbourne       Data->ContinuationOutput.clear();
139c7d437c1SPeter Collingbourne 
140c7d437c1SPeter Collingbourne       return CC_REFRESH;
141c7d437c1SPeter Collingbourne     }
142c7d437c1SPeter Collingbourne 
143c7d437c1SPeter Collingbourne     const LineInfo *LI = ::el_line(EL);
144c7d437c1SPeter Collingbourne     LineEditor::CompletionAction Action = Data->LE->getCompletionAction(
145c7d437c1SPeter Collingbourne         StringRef(LI->buffer, LI->lastchar - LI->buffer),
146c7d437c1SPeter Collingbourne         LI->cursor - LI->buffer);
147c7d437c1SPeter Collingbourne     switch (Action.Kind) {
148c7d437c1SPeter Collingbourne     case LineEditor::CompletionAction::AK_Insert:
149c7d437c1SPeter Collingbourne       ::el_insertstr(EL, Action.Text.c_str());
150c7d437c1SPeter Collingbourne       return CC_REFRESH;
151c7d437c1SPeter Collingbourne 
152c7d437c1SPeter Collingbourne     case LineEditor::CompletionAction::AK_ShowCompletions:
153c7d437c1SPeter Collingbourne       if (Action.Completions.empty()) {
154c7d437c1SPeter Collingbourne         return CC_REFRESH_BEEP;
155c7d437c1SPeter Collingbourne       } else {
156c7d437c1SPeter Collingbourne         // Push a Ctrl-E and a tab. The Ctrl-E causes libedit to move the cursor
157c7d437c1SPeter Collingbourne         // to the end of the line, so that when we emit a newline we will be on
158c7d437c1SPeter Collingbourne         // a new blank line. The tab causes libedit to call this function again
159c7d437c1SPeter Collingbourne         // after moving the cursor. There doesn't seem to be anything we can do
160c7d437c1SPeter Collingbourne         // from here to cause libedit to move the cursor immediately. This will
161c7d437c1SPeter Collingbourne         // break horribly if the user has rebound their keys, so for now we do
162c7d437c1SPeter Collingbourne         // not permit user rebinding.
163029750fbSBenjamin Kramer         ::el_push(EL, const_cast<char *>("\05\t"));
164c7d437c1SPeter Collingbourne 
165c7d437c1SPeter Collingbourne         // This assembles the output for the continuation block above.
166c7d437c1SPeter Collingbourne         raw_string_ostream OS(Data->ContinuationOutput);
167c7d437c1SPeter Collingbourne 
168c7d437c1SPeter Collingbourne         // Move cursor to a blank line.
169c7d437c1SPeter Collingbourne         OS << "\n";
170c7d437c1SPeter Collingbourne 
171c7d437c1SPeter Collingbourne         // Emit the completions.
172c7d437c1SPeter Collingbourne         for (std::vector<std::string>::iterator I = Action.Completions.begin(),
173c7d437c1SPeter Collingbourne                                                 E = Action.Completions.end();
174c7d437c1SPeter Collingbourne              I != E; ++I) {
175c7d437c1SPeter Collingbourne           OS << *I << "\n";
176c7d437c1SPeter Collingbourne         }
177c7d437c1SPeter Collingbourne 
178c7d437c1SPeter Collingbourne         // Fool libedit into thinking nothing has changed. Reprint its prompt
179c7d437c1SPeter Collingbourne         // and the user input. Note that the cursor will remain at the end of
180c7d437c1SPeter Collingbourne         // the line after this.
181c7d437c1SPeter Collingbourne         OS << Data->LE->getPrompt()
182c7d437c1SPeter Collingbourne            << StringRef(LI->buffer, LI->lastchar - LI->buffer);
183c7d437c1SPeter Collingbourne 
184c7d437c1SPeter Collingbourne         // This is the number of characters we need to tell libedit to go back:
185c7d437c1SPeter Collingbourne         // the distance between end of line and the original cursor position.
186c7d437c1SPeter Collingbourne         Data->PrevCount = LI->lastchar - LI->cursor;
187c7d437c1SPeter Collingbourne 
188c7d437c1SPeter Collingbourne         return CC_REFRESH;
189c7d437c1SPeter Collingbourne       }
190c7d437c1SPeter Collingbourne     }
191c7d437c1SPeter Collingbourne   }
192029750fbSBenjamin Kramer   return CC_ERROR;
193c7d437c1SPeter Collingbourne }
194c7d437c1SPeter Collingbourne 
19535623fb7SEugene Zelenko } // end anonymous namespace
19635623fb7SEugene Zelenko 
LineEditor(StringRef ProgName,StringRef HistoryPath,FILE * In,FILE * Out,FILE * Err)197c7d437c1SPeter Collingbourne LineEditor::LineEditor(StringRef ProgName, StringRef HistoryPath, FILE *In,
198c7d437c1SPeter Collingbourne                        FILE *Out, FILE *Err)
199adcd0268SBenjamin Kramer     : Prompt((ProgName + "> ").str()), HistoryPath(std::string(HistoryPath)),
200c7d437c1SPeter Collingbourne       Data(new InternalData) {
201c7d437c1SPeter Collingbourne   if (HistoryPath.empty())
202c7d437c1SPeter Collingbourne     this->HistoryPath = getDefaultHistoryPath(ProgName);
203c7d437c1SPeter Collingbourne 
204c7d437c1SPeter Collingbourne   Data->LE = this;
20545b4c499SPeter Collingbourne   Data->Out = Out;
206c7d437c1SPeter Collingbourne 
207c7d437c1SPeter Collingbourne   Data->Hist = ::history_init();
208c7d437c1SPeter Collingbourne   assert(Data->Hist);
209c7d437c1SPeter Collingbourne 
210c7d437c1SPeter Collingbourne   Data->EL = ::el_init(ProgName.str().c_str(), In, Out, Err);
211c7d437c1SPeter Collingbourne   assert(Data->EL);
212c7d437c1SPeter Collingbourne 
213c7d437c1SPeter Collingbourne   ::el_set(Data->EL, EL_PROMPT, ElGetPromptFn);
214c7d437c1SPeter Collingbourne   ::el_set(Data->EL, EL_EDITOR, "emacs");
215c7d437c1SPeter Collingbourne   ::el_set(Data->EL, EL_HIST, history, Data->Hist);
216c7d437c1SPeter Collingbourne   ::el_set(Data->EL, EL_ADDFN, "tab_complete", "Tab completion function",
217c7d437c1SPeter Collingbourne            ElCompletionFn);
218c7d437c1SPeter Collingbourne   ::el_set(Data->EL, EL_BIND, "\t", "tab_complete", NULL);
219c7d437c1SPeter Collingbourne   ::el_set(Data->EL, EL_BIND, "^r", "em-inc-search-prev",
220c7d437c1SPeter Collingbourne            NULL); // Cycle through backwards search, entering string
221c7d437c1SPeter Collingbourne   ::el_set(Data->EL, EL_BIND, "^w", "ed-delete-prev-word",
222c7d437c1SPeter Collingbourne            NULL); // Delete previous word, behave like bash does.
223c7d437c1SPeter Collingbourne   ::el_set(Data->EL, EL_BIND, "\033[3~", "ed-delete-next-char",
224c7d437c1SPeter Collingbourne            NULL); // Fix the delete key.
225c7d437c1SPeter Collingbourne   ::el_set(Data->EL, EL_CLIENTDATA, Data.get());
226c7d437c1SPeter Collingbourne 
227c7d437c1SPeter Collingbourne   HistEvent HE;
228c7d437c1SPeter Collingbourne   ::history(Data->Hist, &HE, H_SETSIZE, 800);
229c7d437c1SPeter Collingbourne   ::history(Data->Hist, &HE, H_SETUNIQUE, 1);
230c7d437c1SPeter Collingbourne   loadHistory();
231c7d437c1SPeter Collingbourne }
232c7d437c1SPeter Collingbourne 
~LineEditor()233c7d437c1SPeter Collingbourne LineEditor::~LineEditor() {
234c7d437c1SPeter Collingbourne   saveHistory();
235c7d437c1SPeter Collingbourne 
236c7d437c1SPeter Collingbourne   ::history_end(Data->Hist);
237c7d437c1SPeter Collingbourne   ::el_end(Data->EL);
23845b4c499SPeter Collingbourne   ::fwrite("\n", 1, 1, Data->Out);
239c7d437c1SPeter Collingbourne }
240c7d437c1SPeter Collingbourne 
saveHistory()241c7d437c1SPeter Collingbourne void LineEditor::saveHistory() {
242c7d437c1SPeter Collingbourne   if (!HistoryPath.empty()) {
243c7d437c1SPeter Collingbourne     HistEvent HE;
244c7d437c1SPeter Collingbourne     ::history(Data->Hist, &HE, H_SAVE, HistoryPath.c_str());
245c7d437c1SPeter Collingbourne   }
246c7d437c1SPeter Collingbourne }
247c7d437c1SPeter Collingbourne 
loadHistory()248c7d437c1SPeter Collingbourne void LineEditor::loadHistory() {
249c7d437c1SPeter Collingbourne   if (!HistoryPath.empty()) {
250c7d437c1SPeter Collingbourne     HistEvent HE;
251c7d437c1SPeter Collingbourne     ::history(Data->Hist, &HE, H_LOAD, HistoryPath.c_str());
252c7d437c1SPeter Collingbourne   }
253c7d437c1SPeter Collingbourne }
254c7d437c1SPeter Collingbourne 
readLine() const255c7d437c1SPeter Collingbourne Optional<std::string> LineEditor::readLine() const {
256c7d437c1SPeter Collingbourne   // Call el_gets to prompt the user and read the user's input.
257c7d437c1SPeter Collingbourne   int LineLen = 0;
258c7d437c1SPeter Collingbourne   const char *Line = ::el_gets(Data->EL, &LineLen);
259c7d437c1SPeter Collingbourne 
260c7d437c1SPeter Collingbourne   // Either of these may mean end-of-file.
261c7d437c1SPeter Collingbourne   if (!Line || LineLen == 0)
262c7d437c1SPeter Collingbourne     return Optional<std::string>();
263c7d437c1SPeter Collingbourne 
264c7d437c1SPeter Collingbourne   // Strip any newlines off the end of the string.
265c7d437c1SPeter Collingbourne   while (LineLen > 0 &&
266c7d437c1SPeter Collingbourne          (Line[LineLen - 1] == '\n' || Line[LineLen - 1] == '\r'))
267c7d437c1SPeter Collingbourne     --LineLen;
268c7d437c1SPeter Collingbourne 
269c7d437c1SPeter Collingbourne   HistEvent HE;
270c7d437c1SPeter Collingbourne   if (LineLen > 0)
271c7d437c1SPeter Collingbourne     ::history(Data->Hist, &HE, H_ENTER, Line);
272c7d437c1SPeter Collingbourne 
273c7d437c1SPeter Collingbourne   return std::string(Line, LineLen);
274c7d437c1SPeter Collingbourne }
275c7d437c1SPeter Collingbourne 
27635623fb7SEugene Zelenko #else // HAVE_LIBEDIT
277c7d437c1SPeter Collingbourne 
278c7d437c1SPeter Collingbourne // Simple fgets-based implementation.
279c7d437c1SPeter Collingbourne 
280c7d437c1SPeter Collingbourne struct LineEditor::InternalData {
281c7d437c1SPeter Collingbourne   FILE *In;
282c7d437c1SPeter Collingbourne   FILE *Out;
283c7d437c1SPeter Collingbourne };
284c7d437c1SPeter Collingbourne 
LineEditor(StringRef ProgName,StringRef HistoryPath,FILE * In,FILE * Out,FILE * Err)285c7d437c1SPeter Collingbourne LineEditor::LineEditor(StringRef ProgName, StringRef HistoryPath, FILE *In,
286c7d437c1SPeter Collingbourne                        FILE *Out, FILE *Err)
287c7d437c1SPeter Collingbourne     : Prompt((ProgName + "> ").str()), Data(new InternalData) {
288c7d437c1SPeter Collingbourne   Data->In = In;
289c7d437c1SPeter Collingbourne   Data->Out = Out;
290c7d437c1SPeter Collingbourne }
291c7d437c1SPeter Collingbourne 
~LineEditor()292c7d437c1SPeter Collingbourne LineEditor::~LineEditor() {
293c7d437c1SPeter Collingbourne   ::fwrite("\n", 1, 1, Data->Out);
294c7d437c1SPeter Collingbourne }
295c7d437c1SPeter Collingbourne 
saveHistory()296c7d437c1SPeter Collingbourne void LineEditor::saveHistory() {}
loadHistory()297c7d437c1SPeter Collingbourne void LineEditor::loadHistory() {}
298c7d437c1SPeter Collingbourne 
readLine() const299c7d437c1SPeter Collingbourne Optional<std::string> LineEditor::readLine() const {
300c7d437c1SPeter Collingbourne   ::fprintf(Data->Out, "%s", Prompt.c_str());
301c7d437c1SPeter Collingbourne 
302c7d437c1SPeter Collingbourne   std::string Line;
303c7d437c1SPeter Collingbourne   do {
304c7d437c1SPeter Collingbourne     char Buf[64];
305c7d437c1SPeter Collingbourne     char *Res = ::fgets(Buf, sizeof(Buf), Data->In);
306c7d437c1SPeter Collingbourne     if (!Res) {
307c7d437c1SPeter Collingbourne       if (Line.empty())
308c7d437c1SPeter Collingbourne         return Optional<std::string>();
309c7d437c1SPeter Collingbourne       else
310c7d437c1SPeter Collingbourne         return Line;
311c7d437c1SPeter Collingbourne     }
312c7d437c1SPeter Collingbourne     Line.append(Buf);
313c7d437c1SPeter Collingbourne   } while (Line.empty() ||
314c7d437c1SPeter Collingbourne            (Line[Line.size() - 1] != '\n' && Line[Line.size() - 1] != '\r'));
315c7d437c1SPeter Collingbourne 
316c7d437c1SPeter Collingbourne   while (!Line.empty() &&
317c7d437c1SPeter Collingbourne          (Line[Line.size() - 1] == '\n' || Line[Line.size() - 1] == '\r'))
318c7d437c1SPeter Collingbourne     Line.resize(Line.size() - 1);
319c7d437c1SPeter Collingbourne 
320c7d437c1SPeter Collingbourne   return Line;
321c7d437c1SPeter Collingbourne }
322c7d437c1SPeter Collingbourne 
32335623fb7SEugene Zelenko #endif // HAVE_LIBEDIT
324