LLVM  4.0.0
LineEditor.cpp
Go to the documentation of this file.
1 //===-- LineEditor.cpp - line editor --------------------------------------===//
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 
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/Config/config.h"
13 #include "llvm/Support/Path.h"
15 #include <algorithm>
16 #include <cassert>
17 #include <cstdio>
18 #ifdef HAVE_LIBEDIT
19 #include <histedit.h>
20 #endif
21 
22 using namespace llvm;
23 
25  SmallString<32> Path;
26  if (sys::path::home_directory(Path)) {
27  sys::path::append(Path, "." + ProgName + "-history");
28  return Path.str();
29  }
30  return std::string();
31 }
32 
33 LineEditor::CompleterConcept::~CompleterConcept() {}
34 LineEditor::ListCompleterConcept::~ListCompleterConcept() {}
35 
36 std::string LineEditor::ListCompleterConcept::getCommonPrefix(
37  const std::vector<Completion> &Comps) {
38  assert(!Comps.empty());
39 
40  std::string CommonPrefix = Comps[0].TypedText;
41  for (std::vector<Completion>::const_iterator I = Comps.begin() + 1,
42  E = Comps.end();
43  I != E; ++I) {
44  size_t Len = std::min(CommonPrefix.size(), I->TypedText.size());
45  size_t CommonLen = 0;
46  for (; CommonLen != Len; ++CommonLen) {
47  if (CommonPrefix[CommonLen] != I->TypedText[CommonLen])
48  break;
49  }
50  CommonPrefix.resize(CommonLen);
51  }
52  return CommonPrefix;
53 }
54 
56 LineEditor::ListCompleterConcept::complete(StringRef Buffer, size_t Pos) const {
57  CompletionAction Action;
58  std::vector<Completion> Comps = getCompletions(Buffer, Pos);
59  if (Comps.empty()) {
60  Action.Kind = CompletionAction::AK_ShowCompletions;
61  return Action;
62  }
63 
64  std::string CommonPrefix = getCommonPrefix(Comps);
65 
66  // If the common prefix is non-empty we can simply insert it. If there is a
67  // single completion, this will insert the full completion. If there is more
68  // than one, this might be enough information to jog the user's memory but if
69  // not the user can also hit tab again to see the completions because the
70  // common prefix will then be empty.
71  if (CommonPrefix.empty()) {
72  Action.Kind = CompletionAction::AK_ShowCompletions;
73  for (std::vector<Completion>::iterator I = Comps.begin(), E = Comps.end();
74  I != E; ++I)
75  Action.Completions.push_back(I->DisplayText);
76  } else {
77  Action.Kind = CompletionAction::AK_Insert;
78  Action.Text = CommonPrefix;
79  }
80 
81  return Action;
82 }
83 
85  size_t Pos) const {
86  if (!Completer) {
87  CompletionAction Action;
89  return Action;
90  }
91 
92  return Completer->complete(Buffer, Pos);
93 }
94 
95 #ifdef HAVE_LIBEDIT
96 
97 // libedit-based implementation.
98 
101 
102  History *Hist;
103  EditLine *EL;
104 
105  unsigned PrevCount;
106  std::string ContinuationOutput;
107 
108  FILE *Out;
109 };
110 
111 namespace {
112 
113 const char *ElGetPromptFn(EditLine *EL) {
115  if (el_get(EL, EL_CLIENTDATA, &Data) == 0)
116  return Data->LE->getPrompt().c_str();
117  return "> ";
118 }
119 
120 // Handles tab completion.
121 //
122 // This function is really horrible. But since the alternative is to get into
123 // the line editor business, here we are.
124 unsigned char ElCompletionFn(EditLine *EL, int ch) {
126  if (el_get(EL, EL_CLIENTDATA, &Data) == 0) {
127  if (!Data->ContinuationOutput.empty()) {
128  // This is the continuation of the AK_ShowCompletions branch below.
129  FILE *Out = Data->Out;
130 
131  // Print the required output (see below).
132  ::fwrite(Data->ContinuationOutput.c_str(),
133  Data->ContinuationOutput.size(), 1, Out);
134 
135  // Push a sequence of Ctrl-B characters to move the cursor back to its
136  // original position.
137  std::string Prevs(Data->PrevCount, '\02');
138  ::el_push(EL, const_cast<char *>(Prevs.c_str()));
139 
140  Data->ContinuationOutput.clear();
141 
142  return CC_REFRESH;
143  }
144 
145  const LineInfo *LI = ::el_line(EL);
147  StringRef(LI->buffer, LI->lastchar - LI->buffer),
148  LI->cursor - LI->buffer);
149  switch (Action.Kind) {
151  ::el_insertstr(EL, Action.Text.c_str());
152  return CC_REFRESH;
153 
155  if (Action.Completions.empty()) {
156  return CC_REFRESH_BEEP;
157  } else {
158  // Push a Ctrl-E and a tab. The Ctrl-E causes libedit to move the cursor
159  // to the end of the line, so that when we emit a newline we will be on
160  // a new blank line. The tab causes libedit to call this function again
161  // after moving the cursor. There doesn't seem to be anything we can do
162  // from here to cause libedit to move the cursor immediately. This will
163  // break horribly if the user has rebound their keys, so for now we do
164  // not permit user rebinding.
165  ::el_push(EL, const_cast<char *>("\05\t"));
166 
167  // This assembles the output for the continuation block above.
169 
170  // Move cursor to a blank line.
171  OS << "\n";
172 
173  // Emit the completions.
174  for (std::vector<std::string>::iterator I = Action.Completions.begin(),
175  E = Action.Completions.end();
176  I != E; ++I) {
177  OS << *I << "\n";
178  }
179 
180  // Fool libedit into thinking nothing has changed. Reprint its prompt
181  // and the user input. Note that the cursor will remain at the end of
182  // the line after this.
183  OS << Data->LE->getPrompt()
184  << StringRef(LI->buffer, LI->lastchar - LI->buffer);
185 
186  // This is the number of characters we need to tell libedit to go back:
187  // the distance between end of line and the original cursor position.
188  Data->PrevCount = LI->lastchar - LI->cursor;
189 
190  return CC_REFRESH;
191  }
192  }
193  }
194  return CC_ERROR;
195 }
196 
197 } // end anonymous namespace
198 
199 LineEditor::LineEditor(StringRef ProgName, StringRef HistoryPath, FILE *In,
200  FILE *Out, FILE *Err)
201  : Prompt((ProgName + "> ").str()), HistoryPath(HistoryPath),
202  Data(new InternalData) {
203  if (HistoryPath.empty())
204  this->HistoryPath = getDefaultHistoryPath(ProgName);
205 
206  Data->LE = this;
207  Data->Out = Out;
208 
209  Data->Hist = ::history_init();
210  assert(Data->Hist);
211 
212  Data->EL = ::el_init(ProgName.str().c_str(), In, Out, Err);
213  assert(Data->EL);
214 
215  ::el_set(Data->EL, EL_PROMPT, ElGetPromptFn);
216  ::el_set(Data->EL, EL_EDITOR, "emacs");
217  ::el_set(Data->EL, EL_HIST, history, Data->Hist);
218  ::el_set(Data->EL, EL_ADDFN, "tab_complete", "Tab completion function",
219  ElCompletionFn);
220  ::el_set(Data->EL, EL_BIND, "\t", "tab_complete", NULL);
221  ::el_set(Data->EL, EL_BIND, "^r", "em-inc-search-prev",
222  NULL); // Cycle through backwards search, entering string
223  ::el_set(Data->EL, EL_BIND, "^w", "ed-delete-prev-word",
224  NULL); // Delete previous word, behave like bash does.
225  ::el_set(Data->EL, EL_BIND, "\033[3~", "ed-delete-next-char",
226  NULL); // Fix the delete key.
227  ::el_set(Data->EL, EL_CLIENTDATA, Data.get());
228 
229  HistEvent HE;
230  ::history(Data->Hist, &HE, H_SETSIZE, 800);
231  ::history(Data->Hist, &HE, H_SETUNIQUE, 1);
232  loadHistory();
233 }
234 
236  saveHistory();
237 
238  ::history_end(Data->Hist);
239  ::el_end(Data->EL);
240  ::fwrite("\n", 1, 1, Data->Out);
241 }
242 
244  if (!HistoryPath.empty()) {
245  HistEvent HE;
246  ::history(Data->Hist, &HE, H_SAVE, HistoryPath.c_str());
247  }
248 }
249 
251  if (!HistoryPath.empty()) {
252  HistEvent HE;
253  ::history(Data->Hist, &HE, H_LOAD, HistoryPath.c_str());
254  }
255 }
256 
258  // Call el_gets to prompt the user and read the user's input.
259  int LineLen = 0;
260  const char *Line = ::el_gets(Data->EL, &LineLen);
261 
262  // Either of these may mean end-of-file.
263  if (!Line || LineLen == 0)
264  return Optional<std::string>();
265 
266  // Strip any newlines off the end of the string.
267  while (LineLen > 0 &&
268  (Line[LineLen - 1] == '\n' || Line[LineLen - 1] == '\r'))
269  --LineLen;
270 
271  HistEvent HE;
272  if (LineLen > 0)
273  ::history(Data->Hist, &HE, H_ENTER, Line);
274 
275  return std::string(Line, LineLen);
276 }
277 
278 #else // HAVE_LIBEDIT
279 
280 // Simple fgets-based implementation.
281 
283  FILE *In;
284  FILE *Out;
285 };
286 
287 LineEditor::LineEditor(StringRef ProgName, StringRef HistoryPath, FILE *In,
288  FILE *Out, FILE *Err)
289  : Prompt((ProgName + "> ").str()), Data(new InternalData) {
290  Data->In = In;
291  Data->Out = Out;
292 }
293 
295  ::fwrite("\n", 1, 1, Data->Out);
296 }
297 
298 void LineEditor::saveHistory() {}
299 void LineEditor::loadHistory() {}
300 
302  ::fprintf(Data->Out, "%s", Prompt.c_str());
303 
304  std::string Line;
305  do {
306  char Buf[64];
307  char *Res = ::fgets(Buf, sizeof(Buf), Data->In);
308  if (!Res) {
309  if (Line.empty())
310  return Optional<std::string>();
311  else
312  return Line;
313  }
314  Line.append(Buf);
315  } while (Line.empty() ||
316  (Line[Line.size() - 1] != '\n' && Line[Line.size() - 1] != '\r'));
317 
318  while (!Line.empty() &&
319  (Line[Line.size() - 1] == '\n' || Line[Line.size() - 1] == '\r'))
320  Line.resize(Line.size() - 1);
321 
322  return Line;
323 }
324 
325 #endif // HAVE_LIBEDIT
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:448
llvm::Optional< std::string > readLine() const
Reads a line.
Definition: LineEditor.cpp:257
Maximum length of the test input libFuzzer tries to guess a good value based on the corpus and reports it always prefer smaller inputs during the corpus shuffle When libFuzzer itself reports a bug this exit code will be used If indicates the maximal total time in seconds to run the fuzzer minimizes the provided crash input Use with etc Experimental Use value profile to guide fuzzing Number of simultaneous worker processes to run the jobs If min(jobs, NumberOfCpuCores()/2)\" is used.") FUZZER_FLAG_INT(reload
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
Insert Text at the cursor position.
Definition: LineEditor.h:52
LineEditor(StringRef ProgName, StringRef HistoryPath="", FILE *In=stdin, FILE *Out=stdout, FILE *Err=stderr)
Create a LineEditor object.
Definition: LineEditor.cpp:199
static std::string getDefaultHistoryPath(StringRef ProgName)
Definition: LineEditor.cpp:24
The action to perform upon a completion request.
Definition: LineEditor.h:49
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:225
CompletionAction getCompletionAction(StringRef Buffer, size_t Pos) const
Use the current completer to produce a CompletionAction for the given completion request.
Definition: LineEditor.cpp:84
Show Completions, or beep if the list is empty.
Definition: LineEditor.h:54
std::vector< std::string > Completions
The list of completions to show.
Definition: LineEditor.h:63
StringRef str() const
Explicit conversion to StringRef.
Definition: SmallString.h:267
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:130
#define I(x, y, z)
Definition: MD5.cpp:54
std::string Text
The text to insert.
Definition: LineEditor.h:60
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:463
bool home_directory(SmallVectorImpl< char > &result)
Get the user's home directory.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:47
const std::string & getPrompt() const
Definition: LineEditor.h:106