llvm.org GIT mirror llvm / cb6684b
Introduce line editor library. This library will be used by clang-query. I can imagine LLDB becoming another client of this library, so I think LLVM is a sensible place for it to live. It wraps libedit, and adds tab completion support. The code is loosely based on the line editor bits in LLDB, with a few improvements: - Polymorphism for retrieving the list of tab completions, based on the concept pattern from the new pass manager. - Tab completion doesn't corrupt terminal output if the input covers multiple lines. Unfortunately this can only be done in a truly horrible way, as far as I can tell. But since the alternative is to implement our own line editor (which I don't think LLVM should be in the business of doing, at least for now) I think it may be acceptable. - Includes a fallback for the case where the user doesn't have libedit installed. Note that this uses C stdio, mainly because libedit also uses C stdio. Differential Revision: http://llvm-reviews.chandlerc.com/D2200 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200595 91177308-0d34-0410-b5e6-96231b3b80d8 Peter Collingbourne 6 years ago
18 changed file(s) with 778 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
11891189 esac],
11901190 llvm_cv_enable_terminfo="yes")
11911191
1192 dnl --enable-libedit: check whether the user wants to turn off libedit.
1193 AC_ARG_ENABLE(libedit,AS_HELP_STRING(
1194 [--enable-libedit],
1195 [Use libedit if available (default is YES)]),
1196 [case "$enableval" in
1197 yes) llvm_cv_enable_libedit="yes" ;;
1198 no) llvm_cv_enable_libedit="no" ;;
1199 *) AC_MSG_ERROR([Invalid setting for --enable-libedit. Use "yes" or "no"]) ;;
1200 esac],
1201 llvm_cv_enable_libedit="yes")
1202
11921203 dnl --enable-libffi : check whether the user wants to turn off libffi:
11931204 AC_ARG_ENABLE(libffi,AS_HELP_STRING(
11941205 --enable-libffi,[Check for the presence of libffi (default is NO)]),
15031514 AC_SEARCH_LIBS(setupterm,tinfo terminfo curses ncurses ncursesw,
15041515 AC_DEFINE([HAVE_TERMINFO],[1],
15051516 [Define if the setupterm() function is supported this platform.]))
1517 fi
1518
1519 dnl The libedit library is optional; used by lib/LineEditor
1520 if test "$llvm_cv_enable_libedit" = "yes" ; then
1521 AC_SEARCH_LIBS(el_init,edit,
1522 AC_DEFINE([HAVE_LIBEDIT],[1],
1523 [Define if libedit is available on this platform.]))
15061524 fi
15071525
15081526 dnl libffi is optional; used to call external functions from the interpreter
9696 else()
9797 set(HAVE_LIBZ 0)
9898 endif()
99 check_library_exists(edit el_init "" HAVE_LIBEDIT)
99100 if(LLVM_ENABLE_TERMINFO)
100101 set(HAVE_TERMINFO 0)
101102 foreach(library tinfo terminfo curses ncurses ncursesw)
14501450 all,auto,none,{binding-name} (default=auto)
14511451 --enable-terminfo Query the terminfo database if available (default is
14521452 YES)
1453 --enable-libedit Use libedit if available (default is YES)
14531454 --enable-libffi Check for the presence of libffi (default is NO)
14541455 --enable-ltdl-install install libltdl
14551456
56805681 fi
56815682
56825683
5684 # Check whether --enable-libedit was given.
5685 if test "${enable_libedit+set}" = set; then
5686 enableval=$enable_libedit; case "$enableval" in
5687 yes) llvm_cv_enable_libedit="yes" ;;
5688 no) llvm_cv_enable_libedit="no" ;;
5689 *) { { echo "$as_me:$LINENO: error: Invalid setting for --enable-libedit. Use \"yes\" or \"no\"" >&5
5690 echo "$as_me: error: Invalid setting for --enable-libedit. Use \"yes\" or \"no\"" >&2;}
5691 { (exit 1); exit 1; }; } ;;
5692 esac
5693 else
5694 llvm_cv_enable_libedit="yes"
5695 fi
5696
5697
56835698 # Check whether --enable-libffi was given.
56845699 if test "${enable_libffi+set}" = set; then
56855700 enableval=$enable_libffi; case "$enableval" in
1066210677 lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
1066310678 lt_status=$lt_dlunknown
1066410679 cat > conftest.$ac_ext <
10665 #line 10666 "configure"
10680 #line 10681 "configure"
1066610681 #include "confdefs.h"
1066710682
1066810683 #if HAVE_DLFCN_H
1255112566
1255212567 cat >>confdefs.h <<\_ACEOF
1255312568 #define HAVE_TERMINFO 1
12569 _ACEOF
12570
12571 fi
12572
12573 fi
12574
12575 if test "$llvm_cv_enable_libedit" = "yes" ; then
12576 { echo "$as_me:$LINENO: checking for library containing el_init" >&5
12577 echo $ECHO_N "checking for library containing el_init... $ECHO_C" >&6; }
12578 if test "${ac_cv_search_el_init+set}" = set; then
12579 echo $ECHO_N "(cached) $ECHO_C" >&6
12580 else
12581 ac_func_search_save_LIBS=$LIBS
12582 cat >conftest.$ac_ext <<_ACEOF
12583 /* confdefs.h. */
12584 _ACEOF
12585 cat confdefs.h >>conftest.$ac_ext
12586 cat >>conftest.$ac_ext <<_ACEOF
12587 /* end confdefs.h. */
12588
12589 /* Override any GCC internal prototype to avoid an error.
12590 Use char because int might match the return type of a GCC
12591 builtin and then its argument prototype would still apply. */
12592 #ifdef __cplusplus
12593 extern "C"
12594 #endif
12595 char el_init ();
12596 int
12597 main ()
12598 {
12599 return el_init ();
12600 ;
12601 return 0;
12602 }
12603 _ACEOF
12604 for ac_lib in '' edit; do
12605 if test -z "$ac_lib"; then
12606 ac_res="none required"
12607 else
12608 ac_res=-l$ac_lib
12609 LIBS="-l$ac_lib $ac_func_search_save_LIBS"
12610 fi
12611 rm -f conftest.$ac_objext conftest$ac_exeext
12612 if { (ac_try="$ac_link"
12613 case "(($ac_try" in
12614 *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
12615 *) ac_try_echo=$ac_try;;
12616 esac
12617 eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
12618 (eval "$ac_link") 2>conftest.er1
12619 ac_status=$?
12620 grep -v '^ *+' conftest.er1 >conftest.err
12621 rm -f conftest.er1
12622 cat conftest.err >&5
12623 echo "$as_me:$LINENO: \$? = $ac_status" >&5
12624 (exit $ac_status); } &&
12625 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
12626 { (case "(($ac_try" in
12627 *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
12628 *) ac_try_echo=$ac_try;;
12629 esac
12630 eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
12631 (eval "$ac_try") 2>&5
12632 ac_status=$?
12633 echo "$as_me:$LINENO: \$? = $ac_status" >&5
12634 (exit $ac_status); }; } &&
12635 { ac_try='test -s conftest$ac_exeext'
12636 { (case "(($ac_try" in
12637 *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
12638 *) ac_try_echo=$ac_try;;
12639 esac
12640 eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
12641 (eval "$ac_try") 2>&5
12642 ac_status=$?
12643 echo "$as_me:$LINENO: \$? = $ac_status" >&5
12644 (exit $ac_status); }; }; then
12645 ac_cv_search_el_init=$ac_res
12646 else
12647 echo "$as_me: failed program was:" >&5
12648 sed 's/^/| /' conftest.$ac_ext >&5
12649
12650
12651 fi
12652
12653 rm -f core conftest.err conftest.$ac_objext \
12654 conftest$ac_exeext
12655 if test "${ac_cv_search_el_init+set}" = set; then
12656 break
12657 fi
12658 done
12659 if test "${ac_cv_search_el_init+set}" = set; then
12660 :
12661 else
12662 ac_cv_search_el_init=no
12663 fi
12664 rm conftest.$ac_ext
12665 LIBS=$ac_func_search_save_LIBS
12666 fi
12667 { echo "$as_me:$LINENO: result: $ac_cv_search_el_init" >&5
12668 echo "${ECHO_T}$ac_cv_search_el_init" >&6; }
12669 ac_res=$ac_cv_search_el_init
12670 if test "$ac_res" != no; then
12671 test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
12672
12673 cat >>confdefs.h <<\_ACEOF
12674 #define HAVE_LIBEDIT 1
1255412675 _ACEOF
1255512676
1255612677 fi
211211 /* Define to 1 if you have the 'z' library (-lz). */
212212 #cmakedefine HAVE_LIBZ ${HAVE_LIBZ}
213213
214 /* Define to 1 if you have the 'edit' library (-ledit). */
215 #cmakedefine HAVE_LIBEDIT ${HAVE_LIBEDIT}
216
214217 /* Define to 1 if you have the header file. */
215218 #cmakedefine HAVE_LIMITS_H ${HAVE_LIMITS_H}
216219
204204 /* Define if you have the libdl library or equivalent. */
205205 #undef HAVE_LIBDL
206206
207 /* Define if libedit is available on this platform. */
208 #undef HAVE_LIBEDIT
209
207210 /* Define to 1 if you have the `imagehlp' library (-limagehlp). */
208211 #undef HAVE_LIBIMAGEHLP
209212
0 //===-- llvm/LineEditor/LineEditor.h - line editor --------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_LINEEDITOR_LINEEDITOR_H
10 #define LLVM_LINEEDITOR_LINEEDITOR_H
11
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/ADT/OwningPtr.h"
15 #include
16 #include
17 #include
18
19 namespace llvm {
20
21 class LineEditor {
22 public:
23 /// Create a LineEditor object.
24 ///
25 /// \param ProgName The name of the current program. Used to form a default
26 /// prompt.
27 /// \param HistoryPath Path to the file in which to store history data, if
28 /// possible.
29 /// \param In The input stream used by the editor.
30 /// \param Out The output stream used by the editor.
31 /// \param Err The error stream used by the editor.
32 LineEditor(StringRef ProgName, StringRef HistoryPath = "", FILE *In = stdin,
33 FILE *Out = stdout, FILE *Err = stderr);
34 ~LineEditor();
35
36 /// Reads a line.
37 ///
38 /// \return The line, or llvm::Optional() on EOF.
39 llvm::Optional readLine() const;
40
41 void saveHistory();
42 void loadHistory();
43
44 static std::string getDefaultHistoryPath(StringRef ProgName);
45
46 /// The action to perform upon a completion request.
47 struct CompletionAction {
48 enum ActionKind {
49 /// Insert Text at the cursor position.
50 AK_Insert,
51 /// Show Completions, or beep if the list is empty.
52 AK_ShowCompletions
53 };
54
55 ActionKind Kind;
56
57 /// The text to insert.
58 std::string Text;
59
60 /// The list of completions to show.
61 std::vector Completions;
62 };
63
64 /// A possible completion at a given cursor position.
65 struct Completion {
66 Completion() {}
67 Completion(const std::string &TypedText, const std::string &DisplayText)
68 : TypedText(TypedText), DisplayText(DisplayText) {}
69
70 /// The text to insert. If the user has already input some of the
71 /// completion, this should only include the rest of the text.
72 std::string TypedText;
73
74 /// A description of this completion. This may be the completion itself, or
75 /// maybe a summary of its type or arguments.
76 std::string DisplayText;
77 };
78
79 /// Set the completer for this LineEditor. A completer is a function object
80 /// which takes arguments of type StringRef (the string to complete) and
81 /// size_t (the zero-based cursor position in the StringRef) and returns a
82 /// CompletionAction.
83 template void setCompleter(T Comp) {
84 Completer.reset(new CompleterModel(Comp));
85 }
86
87 /// Set the completer for this LineEditor to the given list completer.
88 /// A list completer is a function object which takes arguments of type
89 /// StringRef (the string to complete) and size_t (the zero-based cursor
90 /// position in the StringRef) and returns a std::vector.
91 template void setListCompleter(T Comp) {
92 Completer.reset(new ListCompleterModel(Comp));
93 }
94
95 /// Use the current completer to produce a CompletionAction for the given
96 /// completion request. If the current completer is a list completer, this
97 /// will return an AK_Insert CompletionAction if each completion has a common
98 /// prefix, or an AK_ShowCompletions CompletionAction otherwise.
99 ///
100 /// \param Buffer The string to complete
101 /// \param Pos The zero-based cursor position in the StringRef
102 CompletionAction getCompletionAction(StringRef Buffer, size_t Pos) const;
103
104 const std::string &getPrompt() const { return Prompt; }
105 void setPrompt(const std::string &P) { Prompt = P; }
106
107 // Public so callbacks in LineEditor.cpp can use it.
108 struct InternalData;
109
110 private:
111 std::string Prompt;
112 std::string HistoryPath;
113 OwningPtr Data;
114
115 struct CompleterConcept {
116 virtual ~CompleterConcept();
117 virtual CompletionAction complete(StringRef Buffer, size_t Pos) const = 0;
118 };
119
120 struct ListCompleterConcept : CompleterConcept {
121 ~ListCompleterConcept();
122 CompletionAction complete(StringRef Buffer, size_t Pos) const;
123 static std::string getCommonPrefix(const std::vector &Comps);
124 virtual std::vector getCompletions(StringRef Buffer,
125 size_t Pos) const = 0;
126 };
127
128 template
129 struct CompleterModel : CompleterConcept {
130 CompleterModel(T Value) : Value(Value) {}
131 CompletionAction complete(StringRef Buffer, size_t Pos) const {
132 return Value(Buffer, Pos);
133 }
134 T Value;
135 };
136
137 template
138 struct ListCompleterModel : ListCompleterConcept {
139 ListCompleterModel(T Value) : Value(Value) {}
140 std::vector getCompletions(StringRef Buffer, size_t Pos) const {
141 return Value(Buffer, Pos);
142 }
143 T Value;
144 };
145
146 llvm::OwningPtr Completer;
147 };
148
149 }
150
151 #endif
1414 add_subdirectory(ExecutionEngine)
1515 add_subdirectory(Target)
1616 add_subdirectory(AsmParser)
17 add_subdirectory(LineEditor)
1515 ;===------------------------------------------------------------------------===;
1616
1717 [common]
18 subdirectories = Analysis AsmParser Bitcode CodeGen DebugInfo ExecutionEngine Linker IR IRReader LTO MC Object Option Support TableGen Target Transforms
18 subdirectories = Analysis AsmParser Bitcode CodeGen DebugInfo ExecutionEngine LineEditor Linker IR IRReader LTO MC Object Option Support TableGen Target Transforms
1919
2020 [component_0]
2121 type = Group
0 add_llvm_library(LLVMLineEditor
1 LineEditor.cpp
2 )
3
4 if(HAVE_LIBEDIT)
5 target_link_libraries(LLVMLineEditor edit)
6 endif()
0 ;===- ./lib/LineEditor/LLVMBuild.txt ---------------------------*- Conf -*--===;
1 ;
2 ; The LLVM Compiler Infrastructure
3 ;
4 ; This file is distributed under the University of Illinois Open Source
5 ; License. See LICENSE.TXT for details.
6 ;
7 ;===------------------------------------------------------------------------===;
8 ;
9 ; This is an LLVMBuild description file for the components in this subdirectory.
10 ;
11 ; For more information on the LLVMBuild system, please see:
12 ;
13 ; http://llvm.org/docs/LLVMBuild.html
14 ;
15 ;===------------------------------------------------------------------------===;
16
17 [component_0]
18 type = Library
19 name = LineEditor
20 parent = Libraries
21 required_libraries = Support
0 //===-- LineEditor.cpp - line editor --------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/LineEditor/LineEditor.h"
10 #include "llvm/ADT/SmallString.h"
11 #include "llvm/Config/config.h"
12 #include "llvm/Support/Path.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include
15 #ifdef HAVE_LIBEDIT
16 #include
17 #endif
18
19 using namespace llvm;
20
21 std::string LineEditor::getDefaultHistoryPath(StringRef ProgName) {
22 SmallString<32> Path;
23 if (sys::path::home_directory(Path)) {
24 sys::path::append(Path, "." + ProgName + "-history");
25 return Path.str();
26 }
27 return std::string();
28 }
29
30 LineEditor::CompleterConcept::~CompleterConcept() {}
31 LineEditor::ListCompleterConcept::~ListCompleterConcept() {}
32
33 std::string LineEditor::ListCompleterConcept::getCommonPrefix(
34 const std::vector &Comps) {
35 assert(!Comps.empty());
36
37 std::string CommonPrefix = Comps[0].TypedText;
38 for (std::vector::const_iterator I = Comps.begin() + 1,
39 E = Comps.end();
40 I != E; ++I) {
41 size_t Len = std::min(CommonPrefix.size(), I->TypedText.size());
42 size_t CommonLen = 0;
43 for (; CommonLen != Len; ++CommonLen) {
44 if (CommonPrefix[CommonLen] != I->TypedText[CommonLen])
45 break;
46 }
47 CommonPrefix.resize(CommonLen);
48 }
49 return CommonPrefix;
50 }
51
52 LineEditor::CompletionAction
53 LineEditor::ListCompleterConcept::complete(StringRef Buffer, size_t Pos) const {
54 CompletionAction Action;
55 std::vector Comps = getCompletions(Buffer, Pos);
56 if (Comps.empty()) {
57 Action.Kind = CompletionAction::AK_ShowCompletions;
58 return Action;
59 }
60
61 std::string CommonPrefix = getCommonPrefix(Comps);
62
63 // If the common prefix is non-empty we can simply insert it. If there is a
64 // single completion, this will insert the full completion. If there is more
65 // than one, this might be enough information to jog the user's memory but if
66 // not the user can also hit tab again to see the completions because the
67 // common prefix will then be empty.
68 if (CommonPrefix.empty()) {
69 Action.Kind = CompletionAction::AK_ShowCompletions;
70 for (std::vector::iterator I = Comps.begin(), E = Comps.end();
71 I != E; ++I)
72 Action.Completions.push_back(I->DisplayText);
73 } else {
74 Action.Kind = CompletionAction::AK_Insert;
75 Action.Text = CommonPrefix;
76 }
77
78 return Action;
79 }
80
81 LineEditor::CompletionAction LineEditor::getCompletionAction(StringRef Buffer,
82 size_t Pos) const {
83 if (!Completer) {
84 CompletionAction Action;
85 Action.Kind = CompletionAction::AK_ShowCompletions;
86 return Action;
87 }
88
89 return Completer->complete(Buffer, Pos);
90 }
91
92 #ifdef HAVE_LIBEDIT
93
94 // libedit-based implementation.
95
96 struct LineEditor::InternalData {
97 LineEditor *LE;
98
99 History *Hist;
100 EditLine *EL;
101
102 unsigned PrevCount;
103 std::string ContinuationOutput;
104 };
105
106 static const char *ElGetPromptFn(EditLine *EL) {
107 LineEditor::InternalData *Data;
108 if (el_get(EL, EL_CLIENTDATA, &Data) == 0)
109 return Data->LE->getPrompt().c_str();
110 return "> ";
111 }
112
113 // Handles tab completion.
114 //
115 // This function is really horrible. But since the alternative is to get into
116 // the line editor business, here we are.
117 static unsigned char ElCompletionFn(EditLine *EL, int ch) {
118 LineEditor::InternalData *Data;
119 if (el_get(EL, EL_CLIENTDATA, &Data) == 0) {
120 if (!Data->ContinuationOutput.empty()) {
121 // This is the continuation of the AK_ShowCompletions branch below.
122 FILE *Out;
123 if (::el_get(EL, EL_GETFP, 1, &Out) != 0)
124 return CC_ERROR;
125
126 // Print the required output (see below).
127 ::fwrite(Data->ContinuationOutput.c_str(),
128 Data->ContinuationOutput.size(), 1, Out);
129
130 // Push a sequence of Ctrl-B characters to move the cursor back to its
131 // original position.
132 std::string Prevs(Data->PrevCount, '\02');
133 ::el_push(EL, (char *)Prevs.c_str());
134
135 Data->ContinuationOutput.clear();
136
137 return CC_REFRESH;
138 }
139
140 const LineInfo *LI = ::el_line(EL);
141 LineEditor::CompletionAction Action = Data->LE->getCompletionAction(
142 StringRef(LI->buffer, LI->lastchar - LI->buffer),
143 LI->cursor - LI->buffer);
144 switch (Action.Kind) {
145 case LineEditor::CompletionAction::AK_Insert:
146 ::el_insertstr(EL, Action.Text.c_str());
147 return CC_REFRESH;
148
149 case LineEditor::CompletionAction::AK_ShowCompletions:
150 if (Action.Completions.empty()) {
151 return CC_REFRESH_BEEP;
152 } else {
153 // Push a Ctrl-E and a tab. The Ctrl-E causes libedit to move the cursor
154 // to the end of the line, so that when we emit a newline we will be on
155 // a new blank line. The tab causes libedit to call this function again
156 // after moving the cursor. There doesn't seem to be anything we can do
157 // from here to cause libedit to move the cursor immediately. This will
158 // break horribly if the user has rebound their keys, so for now we do
159 // not permit user rebinding.
160 ::el_push(EL, (char *)"\05\t");
161
162 // This assembles the output for the continuation block above.
163 raw_string_ostream OS(Data->ContinuationOutput);
164
165 // Move cursor to a blank line.
166 OS << "\n";
167
168 // Emit the completions.
169 for (std::vector::iterator I = Action.Completions.begin(),
170 E = Action.Completions.end();
171 I != E; ++I) {
172 OS << *I << "\n";
173 }
174
175 // Fool libedit into thinking nothing has changed. Reprint its prompt
176 // and the user input. Note that the cursor will remain at the end of
177 // the line after this.
178 OS << Data->LE->getPrompt()
179 << StringRef(LI->buffer, LI->lastchar - LI->buffer);
180
181 // This is the number of characters we need to tell libedit to go back:
182 // the distance between end of line and the original cursor position.
183 Data->PrevCount = LI->lastchar - LI->cursor;
184
185 return CC_REFRESH;
186 }
187 }
188 } else {
189 return CC_ERROR;
190 }
191 }
192
193 LineEditor::LineEditor(StringRef ProgName, StringRef HistoryPath, FILE *In,
194 FILE *Out, FILE *Err)
195 : Prompt((ProgName + "> ").str()), HistoryPath(HistoryPath),
196 Data(new InternalData) {
197 if (HistoryPath.empty())
198 this->HistoryPath = getDefaultHistoryPath(ProgName);
199
200 Data->LE = this;
201
202 Data->Hist = ::history_init();
203 assert(Data->Hist);
204
205 Data->EL = ::el_init(ProgName.str().c_str(), In, Out, Err);
206 assert(Data->EL);
207
208 ::el_set(Data->EL, EL_PROMPT, ElGetPromptFn);
209 ::el_set(Data->EL, EL_EDITOR, "emacs");
210 ::el_set(Data->EL, EL_HIST, history, Data->Hist);
211 ::el_set(Data->EL, EL_ADDFN, "tab_complete", "Tab completion function",
212 ElCompletionFn);
213 ::el_set(Data->EL, EL_BIND, "\t", "tab_complete", NULL);
214 ::el_set(Data->EL, EL_BIND, "^r", "em-inc-search-prev",
215 NULL); // Cycle through backwards search, entering string
216 ::el_set(Data->EL, EL_BIND, "^w", "ed-delete-prev-word",
217 NULL); // Delete previous word, behave like bash does.
218 ::el_set(Data->EL, EL_BIND, "\033[3~", "ed-delete-next-char",
219 NULL); // Fix the delete key.
220 ::el_set(Data->EL, EL_CLIENTDATA, Data.get());
221
222 HistEvent HE;
223 ::history(Data->Hist, &HE, H_SETSIZE, 800);
224 ::history(Data->Hist, &HE, H_SETUNIQUE, 1);
225 loadHistory();
226 }
227
228 LineEditor::~LineEditor() {
229 saveHistory();
230
231 FILE *Out;
232 if (::el_get(Data->EL, EL_GETFP, 1, &Out) != 0)
233 Out = 0;
234
235 ::history_end(Data->Hist);
236 ::el_end(Data->EL);
237
238 if (Out)
239 ::fwrite("\n", 1, 1, Out);
240 }
241
242 void LineEditor::saveHistory() {
243 if (!HistoryPath.empty()) {
244 HistEvent HE;
245 ::history(Data->Hist, &HE, H_SAVE, HistoryPath.c_str());
246 }
247 }
248
249 void LineEditor::loadHistory() {
250 if (!HistoryPath.empty()) {
251 HistEvent HE;
252 ::history(Data->Hist, &HE, H_LOAD, HistoryPath.c_str());
253 }
254 }
255
256 Optional LineEditor::readLine() const {
257 // Call el_gets to prompt the user and read the user's input.
258 int LineLen = 0;
259 const char *Line = ::el_gets(Data->EL, &LineLen);
260
261 // Either of these may mean end-of-file.
262 if (!Line || LineLen == 0)
263 return Optional();
264
265 // Strip any newlines off the end of the string.
266 while (LineLen > 0 &&
267 (Line[LineLen - 1] == '\n' || Line[LineLen - 1] == '\r'))
268 --LineLen;
269
270 HistEvent HE;
271 if (LineLen > 0)
272 ::history(Data->Hist, &HE, H_ENTER, Line);
273
274 return std::string(Line, LineLen);
275 }
276
277 #else
278
279 // Simple fgets-based implementation.
280
281 struct LineEditor::InternalData {
282 FILE *In;
283 FILE *Out;
284 };
285
286 LineEditor::LineEditor(StringRef ProgName, StringRef HistoryPath, FILE *In,
287 FILE *Out, FILE *Err)
288 : Prompt((ProgName + "> ").str()), Data(new InternalData) {
289 Data->In = In;
290 Data->Out = Out;
291 }
292
293 LineEditor::~LineEditor() {
294 ::fwrite("\n", 1, 1, Data->Out);
295 }
296
297 void LineEditor::saveHistory() {}
298 void LineEditor::loadHistory() {}
299
300 Optional LineEditor::readLine() const {
301 ::fprintf(Data->Out, "%s", Prompt.c_str());
302
303 std::string Line;
304 do {
305 char Buf[64];
306 char *Res = ::fgets(Buf, sizeof(Buf), Data->In);
307 if (!Res) {
308 if (Line.empty())
309 return Optional();
310 else
311 return Line;
312 }
313 Line.append(Buf);
314 } while (Line.empty() ||
315 (Line[Line.size() - 1] != '\n' && Line[Line.size() - 1] != '\r'));
316
317 while (!Line.empty() &&
318 (Line[Line.size() - 1] == '\n' || Line[Line.size() - 1] == '\r'))
319 Line.resize(Line.size() - 1);
320
321 return Line;
322 }
323
324 #endif
0 ##===- lib/LineEditor/Makefile -----------------------------*- Makefile -*-===##
1 #
2 # The LLVM Compiler Infrastructure
3 #
4 # This file is distributed under the University of Illinois Open Source
5 # License. See LICENSE.TXT for details.
6 #
7 ##===----------------------------------------------------------------------===##
8
9 LEVEL = ../..
10 LIBRARYNAME = LLVMLineEditor
11 BUILD_ARCHIVE := 1
12
13 include $(LEVEL)/Makefile.common
14
1111
1212 PARALLEL_DIRS := IR AsmParser Bitcode Analysis Transforms CodeGen Target \
1313 ExecutionEngine Linker LTO MC Object Option DebugInfo \
14 IRReader
14 IRReader LineEditor
1515
1616 include $(LEVEL)/Makefile.common
1111 add_subdirectory(DebugInfo)
1212 add_subdirectory(ExecutionEngine)
1313 add_subdirectory(IR)
14 add_subdirectory(LineEditor)
1415 add_subdirectory(MC)
1516 add_subdirectory(Object)
1617 add_subdirectory(Option)
0 set(LLVM_LINK_COMPONENTS
1 LineEditor
2 )
3
4 add_llvm_unittest(LineEditorTests
5 LineEditor.cpp
6 )
0 //===-- LineEditor.cpp ----------------------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/LineEditor/LineEditor.h"
10 #include "llvm/Support/Path.h"
11 #include "gtest/gtest.h"
12
13 using namespace llvm;
14
15 class LineEditorTest : public testing::Test {
16 public:
17 SmallString<64> HistPath;
18 LineEditor *LE;
19
20 LineEditorTest() {
21 init();
22 }
23
24 void init() {
25 sys::fs::createTemporaryFile("temp", "history", HistPath);
26 ASSERT_FALSE(HistPath.empty());
27 LE = new LineEditor("test", HistPath);
28 }
29
30 ~LineEditorTest() {
31 delete LE;
32 sys::fs::remove(HistPath.str());
33 }
34 };
35
36 TEST_F(LineEditorTest, HistorySaveLoad) {
37 LE->saveHistory();
38 LE->loadHistory();
39 }
40
41 struct TestListCompleter {
42 std::vector Completions;
43
44 TestListCompleter(const std::vector &Completions)
45 : Completions(Completions) {}
46
47 std::vector operator()(StringRef Buffer,
48 size_t Pos) const {
49 EXPECT_TRUE(Buffer.empty());
50 EXPECT_EQ(0u, Pos);
51 return Completions;
52 }
53 };
54
55 TEST_F(LineEditorTest, ListCompleters) {
56 std::vector Comps;
57
58 Comps.push_back(LineEditor::Completion("foo", "int foo()"));
59 LE->setListCompleter(TestListCompleter(Comps));
60 LineEditor::CompletionAction CA = LE->getCompletionAction("", 0);
61 EXPECT_EQ(LineEditor::CompletionAction::AK_Insert, CA.Kind);
62 EXPECT_EQ("foo", CA.Text);
63
64 Comps.push_back(LineEditor::Completion("bar", "int bar()"));
65 LE->setListCompleter(TestListCompleter(Comps));
66 CA = LE->getCompletionAction("", 0);
67 EXPECT_EQ(LineEditor::CompletionAction::AK_ShowCompletions, CA.Kind);
68 ASSERT_EQ(2u, CA.Completions.size());
69 ASSERT_EQ("int foo()", CA.Completions[0]);
70 ASSERT_EQ("int bar()", CA.Completions[1]);
71
72 Comps.clear();
73 Comps.push_back(LineEditor::Completion("fee", "int fee()"));
74 Comps.push_back(LineEditor::Completion("fi", "int fi()"));
75 Comps.push_back(LineEditor::Completion("foe", "int foe()"));
76 Comps.push_back(LineEditor::Completion("fum", "int fum()"));
77 LE->setListCompleter(TestListCompleter(Comps));
78 CA = LE->getCompletionAction("", 0);
79 EXPECT_EQ(LineEditor::CompletionAction::AK_Insert, CA.Kind);
80 EXPECT_EQ("f", CA.Text);
81 }
0 ##===- unittests/LineEditor/Makefile -----------------------*- Makefile -*-===##
1 #
2 # The LLVM Compiler Infrastructure
3 #
4 # This file is distributed under the University of Illinois Open Source
5 # License. See LICENSE.TXT for details.
6 #
7 ##===----------------------------------------------------------------------===##
8
9 LEVEL = ../..
10 TESTNAME = LineEditor
11 LINK_COMPONENTS := lineeditor
12
13 include $(LEVEL)/Makefile.config
14 include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
88
99 LEVEL = ..
1010
11 PARALLEL_DIRS = ADT Analysis Bitcode CodeGen DebugInfo \
12 ExecutionEngine IR Linker MC Object Option Support Transforms
11 PARALLEL_DIRS = ADT Analysis Bitcode CodeGen DebugInfo ExecutionEngine IR \
12 LineEditor Linker MC Object Option Support Transforms
1313
1414 include $(LEVEL)/Makefile.config
1515 include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest