1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <cstdio> // NOLINT
29 #include <string.h> // NOLINT
30 #include <readline/readline.h> // NOLINT
31 #include <readline/history.h> // NOLINT
32
33 // The readline includes leaves RETURN defined which breaks V8 compilation.
34 #undef RETURN
35
36 #include "d8.h"
37
38 // There are incompatibilities between different versions and different
39 // implementations of readline. This smooths out one known incompatibility.
40 #if RL_READLINE_VERSION >= 0x0500
41 #define completion_matches rl_completion_matches
42 #endif
43
44
45 namespace v8 {
46
47
48 class ReadLineEditor: public LineEditor {
49 public:
ReadLineEditor()50 ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { }
51 virtual Handle<String> Prompt(const char* prompt);
52 virtual bool Open(Isolate* isolate);
53 virtual bool Close();
54 virtual void AddHistory(const char* str);
55
56 static const char* kHistoryFileName;
57 static const int kMaxHistoryEntries;
58
59 private:
60 #ifndef V8_SHARED
61 static char** AttemptedCompletion(const char* text, int start, int end);
62 static char* CompletionGenerator(const char* text, int state);
63 #endif // V8_SHARED
64 static char kWordBreakCharacters[];
65
66 Isolate* isolate_;
67 };
68
69
70 static ReadLineEditor read_line_editor;
71 char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"',
72 '\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(',
73 '\0'};
74
75
76 const char* ReadLineEditor::kHistoryFileName = ".d8_history";
77 const int ReadLineEditor::kMaxHistoryEntries = 1000;
78
79
Open(Isolate * isolate)80 bool ReadLineEditor::Open(Isolate* isolate) {
81 isolate_ = isolate;
82
83 rl_initialize();
84
85 #ifdef V8_SHARED
86 // Don't do completion on shared library mode
87 // http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC24
88 rl_bind_key('\t', rl_insert);
89 #else
90 rl_attempted_completion_function = AttemptedCompletion;
91 #endif // V8_SHARED
92
93 rl_completer_word_break_characters = kWordBreakCharacters;
94 rl_bind_key('\t', rl_complete);
95 using_history();
96 stifle_history(kMaxHistoryEntries);
97 return read_history(kHistoryFileName) == 0;
98 }
99
100
Close()101 bool ReadLineEditor::Close() {
102 return write_history(kHistoryFileName) == 0;
103 }
104
105
Prompt(const char * prompt)106 Handle<String> ReadLineEditor::Prompt(const char* prompt) {
107 char* result = NULL;
108 { // Release lock for blocking input.
109 Unlocker unlock(Isolate::GetCurrent());
110 result = readline(prompt);
111 }
112 if (result == NULL) return Handle<String>();
113 AddHistory(result);
114 return String::NewFromUtf8(isolate_, result);
115 }
116
117
AddHistory(const char * str)118 void ReadLineEditor::AddHistory(const char* str) {
119 // Do not record empty input.
120 if (strlen(str) == 0) return;
121 // Remove duplicate history entry.
122 history_set_pos(history_length-1);
123 if (current_history()) {
124 do {
125 if (strcmp(current_history()->line, str) == 0) {
126 remove_history(where_history());
127 break;
128 }
129 } while (previous_history());
130 }
131 add_history(str);
132 }
133
134
135 #ifndef V8_SHARED
AttemptedCompletion(const char * text,int start,int end)136 char** ReadLineEditor::AttemptedCompletion(const char* text,
137 int start,
138 int end) {
139 char** result = completion_matches(text, CompletionGenerator);
140 rl_attempted_completion_over = true;
141 return result;
142 }
143
144
CompletionGenerator(const char * text,int state)145 char* ReadLineEditor::CompletionGenerator(const char* text, int state) {
146 static unsigned current_index;
147 static Persistent<Array> current_completions;
148 Isolate* isolate = read_line_editor.isolate_;
149 Locker lock(isolate);
150 HandleScope scope(isolate);
151 Handle<Array> completions;
152 if (state == 0) {
153 Local<String> full_text = String::NewFromUtf8(isolate,
154 rl_line_buffer,
155 String::kNormalString,
156 rl_point);
157 completions = Shell::GetCompletions(isolate,
158 String::NewFromUtf8(isolate, text),
159 full_text);
160 current_completions.Reset(isolate, completions);
161 current_index = 0;
162 } else {
163 completions = Local<Array>::New(isolate, current_completions);
164 }
165 if (current_index < completions->Length()) {
166 Handle<Integer> index = Integer::New(current_index);
167 Handle<Value> str_obj = completions->Get(index);
168 current_index++;
169 String::Utf8Value str(str_obj);
170 return strdup(*str);
171 } else {
172 current_completions.Reset();
173 return NULL;
174 }
175 }
176 #endif // V8_SHARED
177
178
179 } // namespace v8
180