OLD | NEW |
| (Empty) |
1 // Copyright 2012 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <stdio.h> // NOLINT | |
6 #include <string.h> // NOLINT | |
7 #include <readline/readline.h> // NOLINT | |
8 #include <readline/history.h> // NOLINT | |
9 | |
10 // The readline includes leaves RETURN defined which breaks V8 compilation. | |
11 #undef RETURN | |
12 | |
13 #include "src/d8.h" | |
14 | |
15 // There are incompatibilities between different versions and different | |
16 // implementations of readline. This smooths out one known incompatibility. | |
17 #if RL_READLINE_VERSION >= 0x0500 | |
18 #define completion_matches rl_completion_matches | |
19 #endif | |
20 | |
21 | |
22 namespace v8 { | |
23 | |
24 | |
25 class ReadLineEditor: public LineEditor { | |
26 public: | |
27 ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { } | |
28 virtual Local<String> Prompt(const char* prompt); | |
29 virtual bool Open(Isolate* isolate); | |
30 virtual bool Close(); | |
31 virtual void AddHistory(const char* str); | |
32 | |
33 static const char* kHistoryFileName; | |
34 static const int kMaxHistoryEntries; | |
35 | |
36 private: | |
37 #ifndef V8_SHARED | |
38 static char** AttemptedCompletion(const char* text, int start, int end); | |
39 static char* CompletionGenerator(const char* text, int state); | |
40 #endif // V8_SHARED | |
41 static char kWordBreakCharacters[]; | |
42 | |
43 Isolate* isolate_; | |
44 }; | |
45 | |
46 | |
47 static ReadLineEditor read_line_editor; | |
48 char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"', | |
49 '\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(', | |
50 '\0'}; | |
51 | |
52 | |
53 const char* ReadLineEditor::kHistoryFileName = ".d8_history"; | |
54 const int ReadLineEditor::kMaxHistoryEntries = 1000; | |
55 | |
56 | |
57 bool ReadLineEditor::Open(Isolate* isolate) { | |
58 isolate_ = isolate; | |
59 | |
60 rl_initialize(); | |
61 | |
62 #ifdef V8_SHARED | |
63 // Don't do completion on shared library mode | |
64 // http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC24 | |
65 rl_bind_key('\t', rl_insert); | |
66 #else | |
67 rl_attempted_completion_function = AttemptedCompletion; | |
68 #endif // V8_SHARED | |
69 | |
70 rl_completer_word_break_characters = kWordBreakCharacters; | |
71 rl_bind_key('\t', rl_complete); | |
72 using_history(); | |
73 stifle_history(kMaxHistoryEntries); | |
74 return read_history(kHistoryFileName) == 0; | |
75 } | |
76 | |
77 | |
78 bool ReadLineEditor::Close() { | |
79 return write_history(kHistoryFileName) == 0; | |
80 } | |
81 | |
82 | |
83 Local<String> ReadLineEditor::Prompt(const char* prompt) { | |
84 char* result = NULL; | |
85 result = readline(prompt); | |
86 if (result == NULL) return Local<String>(); | |
87 AddHistory(result); | |
88 return String::NewFromUtf8(isolate_, result, NewStringType::kNormal) | |
89 .ToLocalChecked(); | |
90 } | |
91 | |
92 | |
93 void ReadLineEditor::AddHistory(const char* str) { | |
94 // Do not record empty input. | |
95 if (strlen(str) == 0) return; | |
96 // Remove duplicate history entry. | |
97 history_set_pos(history_length-1); | |
98 if (current_history()) { | |
99 do { | |
100 if (strcmp(current_history()->line, str) == 0) { | |
101 remove_history(where_history()); | |
102 break; | |
103 } | |
104 } while (previous_history()); | |
105 } | |
106 add_history(str); | |
107 } | |
108 | |
109 | |
110 #ifndef V8_SHARED | |
111 char** ReadLineEditor::AttemptedCompletion(const char* text, | |
112 int start, | |
113 int end) { | |
114 char** result = completion_matches(text, CompletionGenerator); | |
115 rl_attempted_completion_over = true; | |
116 return result; | |
117 } | |
118 | |
119 | |
120 char* ReadLineEditor::CompletionGenerator(const char* text, int state) { | |
121 static unsigned current_index; | |
122 static Global<Array> current_completions; | |
123 Isolate* isolate = read_line_editor.isolate_; | |
124 HandleScope scope(isolate); | |
125 Local<Array> completions; | |
126 if (state == 0) { | |
127 Local<String> full_text = | |
128 String::NewFromUtf8(isolate, rl_line_buffer, NewStringType::kNormal, | |
129 rl_point) | |
130 .ToLocalChecked(); | |
131 completions = Shell::GetCompletions( | |
132 isolate, String::NewFromUtf8(isolate, text, NewStringType::kNormal) | |
133 .ToLocalChecked(), | |
134 full_text); | |
135 current_completions.Reset(isolate, completions); | |
136 current_index = 0; | |
137 } else { | |
138 completions = Local<Array>::New(isolate, current_completions); | |
139 } | |
140 if (current_index < completions->Length()) { | |
141 Local<Context> context(isolate->GetCurrentContext()); | |
142 Local<Integer> index = Integer::New(isolate, current_index); | |
143 Local<Value> str_obj = completions->Get(context, index).ToLocalChecked(); | |
144 current_index++; | |
145 String::Utf8Value str(str_obj); | |
146 return strdup(*str); | |
147 } else { | |
148 current_completions.Reset(); | |
149 return NULL; | |
150 } | |
151 } | |
152 #endif // V8_SHARED | |
153 | |
154 | |
155 } // namespace v8 | |
OLD | NEW |