• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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