• 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 
29 #include <cstdio>  // 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 
39 // There are incompatibilities between different versions and different
40 // implementations of readline.  This smooths out one known incompatibility.
41 #if RL_READLINE_VERSION >= 0x0500
42 #define completion_matches rl_completion_matches
43 #endif
44 
45 
46 namespace v8 {
47 
48 
49 class ReadLineEditor: public LineEditor {
50  public:
ReadLineEditor()51   ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { }
52   virtual Handle<String> Prompt(const char* prompt);
53   virtual bool Open();
54   virtual bool Close();
55   virtual void AddHistory(const char* str);
56 
57   static const char* kHistoryFileName;
58   static const int kMaxHistoryEntries;
59 
60  private:
61   static char** AttemptedCompletion(const char* text, int start, int end);
62   static char* CompletionGenerator(const char* text, int state);
63   static char kWordBreakCharacters[];
64 };
65 
66 
67 static ReadLineEditor read_line_editor;
68 char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"',
69     '\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(',
70     '\0'};
71 
72 
73 const char* ReadLineEditor::kHistoryFileName = ".d8_history";
74 const int ReadLineEditor::kMaxHistoryEntries = 1000;
75 
76 
Open()77 bool ReadLineEditor::Open() {
78   rl_initialize();
79   rl_attempted_completion_function = AttemptedCompletion;
80   rl_completer_word_break_characters = kWordBreakCharacters;
81   rl_bind_key('\t', rl_complete);
82   using_history();
83   stifle_history(kMaxHistoryEntries);
84   return read_history(kHistoryFileName) == 0;
85 }
86 
87 
Close()88 bool ReadLineEditor::Close() {
89   return write_history(kHistoryFileName) == 0;
90 }
91 
92 
Prompt(const char * prompt)93 Handle<String> ReadLineEditor::Prompt(const char* prompt) {
94   char* result = NULL;
95   {  // Release lock for blocking input.
96     Unlocker unlock(Isolate::GetCurrent());
97     result = readline(prompt);
98   }
99   if (result != NULL) {
100     AddHistory(result);
101   } else {
102     return Handle<String>();
103   }
104   return String::New(result);
105 }
106 
107 
AddHistory(const char * str)108 void ReadLineEditor::AddHistory(const char* str) {
109   // Do not record empty input.
110   if (strlen(str) == 0) return;
111   // Remove duplicate history entry.
112   history_set_pos(history_length-1);
113   if (current_history()) {
114     do {
115       if (strcmp(current_history()->line, str) == 0) {
116         remove_history(where_history());
117         break;
118       }
119     } while (previous_history());
120   }
121   add_history(str);
122 }
123 
124 
AttemptedCompletion(const char * text,int start,int end)125 char** ReadLineEditor::AttemptedCompletion(const char* text,
126                                            int start,
127                                            int end) {
128   char** result = completion_matches(text, CompletionGenerator);
129   rl_attempted_completion_over = true;
130   return result;
131 }
132 
133 
CompletionGenerator(const char * text,int state)134 char* ReadLineEditor::CompletionGenerator(const char* text, int state) {
135   static unsigned current_index;
136   static Persistent<Array> current_completions;
137   if (state == 0) {
138     HandleScope scope;
139     Local<String> full_text = String::New(rl_line_buffer, rl_point);
140     Handle<Array> completions =
141       Shell::GetCompletions(String::New(text), full_text);
142     current_completions = Persistent<Array>::New(completions);
143     current_index = 0;
144   }
145   if (current_index < current_completions->Length()) {
146     HandleScope scope;
147     Handle<Integer> index = Integer::New(current_index);
148     Handle<Value> str_obj = current_completions->Get(index);
149     current_index++;
150     String::Utf8Value str(str_obj);
151     return strdup(*str);
152   } else {
153     current_completions.Dispose();
154     current_completions.Clear();
155     return NULL;
156   }
157 }
158 
159 
160 }  // namespace v8
161