LLVM: lib/LineEditor/LineEditor.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

12#include "llvm/Config/config.h"

15#include

16#include

17#include

18#ifdef HAVE_LIBEDIT

19#include <histedit.h>

20constexpr int DefaultHistorySize = 800;

21#endif

22

23using namespace llvm;

24

29 return std::string(Path);

30 }

31 return std::string();

32}

33

34LineEditor::CompleterConcept::~CompleterConcept() = default;

35LineEditor::ListCompleterConcept::~ListCompleterConcept() = default;

36

37std::string LineEditor::ListCompleterConcept::getCommonPrefix(

38 const std::vector &Comps) {

39 assert(!Comps.empty());

40

41 std::string CommonPrefix = Comps[0].TypedText;

43 size_t Len = std::min(CommonPrefix.size(), C.TypedText.size());

44 size_t CommonLen = 0;

45 for (; CommonLen != Len; ++CommonLen) {

46 if (CommonPrefix[CommonLen] != C.TypedText[CommonLen])

47 break;

48 }

49 CommonPrefix.resize(CommonLen);

50 }

51 return CommonPrefix;

52}

53

54LineEditor::CompletionAction

55LineEditor::ListCompleterConcept::complete(StringRef Buffer, size_t Pos) const {

57 std::vector Comps = getCompletions(Buffer, Pos);

58 if (Comps.empty()) {

60 return Action;

61 }

62

63 std::string CommonPrefix = getCommonPrefix(Comps);

64

65

66

67

68

69

70 if (CommonPrefix.empty()) {

73 Action.Completions.push_back(Comp.DisplayText);

74 } else {

76 Action.Text = CommonPrefix;

77 }

78

79 return Action;

80}

81

83 size_t Pos) const {

84 if (!Completer) {

87 return Action;

88 }

89

90 return Completer->complete(Buffer, Pos);

91}

92

93#ifdef HAVE_LIBEDIT

94

95

96

99

100 History *Hist;

101 EditLine *EL;

102

103 unsigned PrevCount;

104 std::string ContinuationOutput;

105

106 FILE *Out;

107};

108

109namespace {

110

111const char *ElGetPromptFn(EditLine *EL) {

113 if (el_get(EL, EL_CLIENTDATA, &Data) == 0)

114 return Data->LE->getPrompt().c_str();

115 return "> ";

116}

117

118

119

120

121

122unsigned char ElCompletionFn(EditLine *EL, int ch) {

123 LineEditor::InternalData *Data;

124 if (el_get(EL, EL_CLIENTDATA, &Data) == 0) {

125 if (!Data->ContinuationOutput.empty()) {

126

127 FILE *Out = Data->Out;

128

129

130 ::fwrite(Data->ContinuationOutput.c_str(),

131 Data->ContinuationOutput.size(), 1, Out);

132

133

134

135 std::string Prevs(Data->PrevCount, '\02');

136 ::el_push(EL, const_cast<char *>(Prevs.c_str()));

137

138 Data->ContinuationOutput.clear();

139

140 return CC_REFRESH;

141 }

142

143 const LineInfo *LI = ::el_line(EL);

144 LineEditor::CompletionAction Action = Data->LE->getCompletionAction(

145 StringRef(LI->buffer, LI->lastchar - LI->buffer),

146 LI->cursor - LI->buffer);

147 switch (Action.Kind) {

149 ::el_insertstr(EL, Action.Text.c_str());

150 return CC_REFRESH;

151

154 return CC_REFRESH_BEEP;

155 } else {

156

157

158

159

160

161

162

163 ::el_push(EL, const_cast<char *>("\05\t"));

164

165

166 raw_string_ostream OS(Data->ContinuationOutput);

167

168

169 OS << "\n";

170

171

174

175

176

177

178 OS << Data->LE->getPrompt()

179 << StringRef(LI->buffer, LI->lastchar - LI->buffer);

180

181

182

183 Data->PrevCount = LI->lastchar - LI->cursor;

184

185 return CC_REFRESH;

186 }

187 }

188 }

189 return CC_ERROR;

190}

191

192}

193

195 FILE *Out, FILE *Err)

196 : Prompt((ProgName + "> ").str()), HistoryPath(std::string(HistoryPath)),

198 if (HistoryPath.empty())

200

201 Data->LE = this;

202 Data->Out = Out;

203

204 Data->Hist = ::history_init();

206

207 Data->EL = ::el_init(ProgName.str().c_str(), In, Out, Err);

209

210 ::el_set(Data->EL, EL_PROMPT, ElGetPromptFn);

211 ::el_set(Data->EL, EL_EDITOR, "emacs");

212 ::el_set(Data->EL, EL_HIST, history, Data->Hist);

213 ::el_set(Data->EL, EL_ADDFN, "tab_complete", "Tab completion function",

214 ElCompletionFn);

215 ::el_set(Data->EL, EL_BIND, "\t", "tab_complete", NULL);

216 ::el_set(Data->EL, EL_BIND, "^r", "em-inc-search-prev",

217 NULL);

218 ::el_set(Data->EL, EL_BIND, "^w", "ed-delete-prev-word",

219 NULL);

220 ::el_set(Data->EL, EL_BIND, "\033[3~", "ed-delete-next-char",

221 NULL);

222 ::el_set(Data->EL, EL_CLIENTDATA, Data.get());

223

225 HistEvent HE;

226 ::history(Data->Hist, &HE, H_SETUNIQUE, 1);

228}

229

232

233 ::history_end(Data->Hist);

234 ::el_end(Data->EL);

235 ::fwrite("\n", 1, 1, Data->Out);

236}

237

239 if (!HistoryPath.empty()) {

240 HistEvent HE;

241 ::history(Data->Hist, &HE, H_SAVE, HistoryPath.c_str());

242 }

243}

244

246 if (!HistoryPath.empty()) {

247 HistEvent HE;

248 ::history(Data->Hist, &HE, H_LOAD, HistoryPath.c_str());

249 }

250}

251

253 HistEvent HE;

254 ::history(Data->Hist, &HE, H_SETSIZE, size);

255}

256

258

259 int LineLen = 0;

260 const char *Line = ::el_gets(Data->EL, &LineLen);

261

262

263 if (!Line || LineLen == 0)

264 return std::nullopt;

265

266

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

279

280

281

286

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

301

303 ::fprintf(Data->Out, "%s", Prompt.c_str());

304

305 std::string Line;

306 do {

307 char Buf[64];

308 char *Res = ::fgets(Buf, sizeof(Buf), Data->In);

309 if (!Res) {

310 if (Line.empty())

311 return std::nullopt;

312 else

313 return Line;

314 }

315 Line.append(Buf);

316 } while (Line.empty() ||

317 (Line[Line.size() - 1] != '\n' && Line[Line.size() - 1] != '\r'));

318

319 while (!Line.empty() &&

320 (Line[Line.size() - 1] == '\n' || Line[Line.size() - 1] == '\r'))

321 Line.resize(Line.size() - 1);

322

323 return Line;

324}

325

326#endif

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

This file defines the SmallString class.

LLVM_ABI void setHistorySize(int size)

Definition LineEditor.cpp:300

LLVM_ABI CompletionAction getCompletionAction(StringRef Buffer, size_t Pos) const

Use the current completer to produce a CompletionAction for the given completion request.

Definition LineEditor.cpp:82

LLVM_ABI void loadHistory()

Definition LineEditor.cpp:299

static LLVM_ABI std::string getDefaultHistoryPath(StringRef ProgName)

Definition LineEditor.cpp:25

LLVM_ABI LineEditor(StringRef ProgName, StringRef HistoryPath="", FILE *In=stdin, FILE *Out=stdout, FILE *Err=stderr)

Create a LineEditor object.

Definition LineEditor.cpp:287

LLVM_ABI std::optional< std::string > readLine() const

Reads a line.

Definition LineEditor.cpp:302

LLVM_ABI void saveHistory()

Definition LineEditor.cpp:298

LLVM_ABI ~LineEditor()

Definition LineEditor.cpp:294

SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...

StringRef - Represent a constant reference to a string, i.e.

std::string str() const

str - Get the contents as an std::string.

@ C

The default llvm calling convention, compatible with C.

LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")

Append to path.

LLVM_ABI bool home_directory(SmallVectorImpl< char > &result)

Get the user's home directory.

This is an optimization pass for GlobalISel generic memory operations.

auto drop_begin(T &&RangeOrContainer, size_t N=1)

Return a range covering RangeOrContainer with the first N elements excluded.

auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)

Get the size of a range.

FunctionAddr VTableAddr uintptr_t uintptr_t Data

Definition LineEditor.cpp:282

FILE * In

Definition LineEditor.cpp:283

FILE * Out

Definition LineEditor.cpp:284

The action to perform upon a completion request.

std::string Text

The text to insert.

std::vector< std::string > Completions

The list of completions to show.

@ AK_ShowCompletions

Show Completions, or beep if the list is empty.

@ AK_Insert

Insert Text at the cursor position.

A possible completion at a given cursor position.