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 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 32c7d437c1SPeter Collingbourne LineEditor::CompleterConcept::~CompleterConcept() {} 33c7d437c1SPeter Collingbourne LineEditor::ListCompleterConcept::~ListCompleterConcept() {} 34c7d437c1SPeter Collingbourne 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 55c7d437c1SPeter 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; 72*ccdd5bb2SKazu Hirata for (const Completion &Comp : Comps) 73*ccdd5bb2SKazu 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 82c7d437c1SPeter 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 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. 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 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 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 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 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 255c7d437c1SPeter 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 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 292c7d437c1SPeter Collingbourne LineEditor::~LineEditor() { 293c7d437c1SPeter Collingbourne ::fwrite("\n", 1, 1, Data->Out); 294c7d437c1SPeter Collingbourne } 295c7d437c1SPeter Collingbourne 296c7d437c1SPeter Collingbourne void LineEditor::saveHistory() {} 297c7d437c1SPeter Collingbourne void LineEditor::loadHistory() {} 298c7d437c1SPeter Collingbourne 299c7d437c1SPeter 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