blob: 298518d72ab4ab31ebab2ee90ba208d23ea8b231 [file] [log] [blame]
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001// Copyright 2012 the V8 project authors. All rights reserved.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002// 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
ager@chromium.org8bb60582008-12-11 12:02:20 +000028#include <cstdio> // NOLINT
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000029#include <string.h> // NOLINT
ager@chromium.org5c838252010-02-19 08:53:10 +000030#include <readline/readline.h> // NOLINT
31#include <readline/history.h> // NOLINT
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000032
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000033// The readline includes leaves RETURN defined which breaks V8 compilation.
34#undef RETURN
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000035
36#include "d8.h"
37
ager@chromium.org8bb60582008-12-11 12:02:20 +000038// There are incompatibilities between different versions and different
ager@chromium.org32912102009-01-16 10:38:43 +000039// implementations of readline. This smooths out one known incompatibility.
ager@chromium.org8bb60582008-12-11 12:02:20 +000040#if RL_READLINE_VERSION >= 0x0500
41#define completion_matches rl_completion_matches
42#endif
43
44
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000045namespace v8 {
46
47
48class ReadLineEditor: public LineEditor {
49 public:
50 ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { }
ulan@chromium.org2efb9002012-01-19 15:36:35 +000051 virtual Handle<String> Prompt(const char* prompt);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000052 virtual bool Open(Isolate* isolate);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000053 virtual bool Close();
54 virtual void AddHistory(const char* str);
ulan@chromium.org2efb9002012-01-19 15:36:35 +000055
56 static const char* kHistoryFileName;
57 static const int kMaxHistoryEntries;
58
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000059 private:
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000060#ifndef V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000061 static char** AttemptedCompletion(const char* text, int start, int end);
62 static char* CompletionGenerator(const char* text, int state);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000063#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000064 static char kWordBreakCharacters[];
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000065
66 Isolate* isolate_;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000067};
68
69
70static ReadLineEditor read_line_editor;
71char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"',
72 '\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(',
73 '\0'};
74
75
ulan@chromium.org2efb9002012-01-19 15:36:35 +000076const char* ReadLineEditor::kHistoryFileName = ".d8_history";
77const int ReadLineEditor::kMaxHistoryEntries = 1000;
78
79
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000080bool ReadLineEditor::Open(Isolate* isolate) {
81 isolate_ = isolate;
82
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000083 rl_initialize();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000084
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
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000090 rl_attempted_completion_function = AttemptedCompletion;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000091#endif // V8_SHARED
92
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000093 rl_completer_word_break_characters = kWordBreakCharacters;
94 rl_bind_key('\t', rl_complete);
95 using_history();
ulan@chromium.org2efb9002012-01-19 15:36:35 +000096 stifle_history(kMaxHistoryEntries);
97 return read_history(kHistoryFileName) == 0;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000098}
99
100
101bool ReadLineEditor::Close() {
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000102 return write_history(kHistoryFileName) == 0;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000103}
104
105
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000106Handle<String> ReadLineEditor::Prompt(const char* prompt) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000107 char* result = NULL;
108 { // Release lock for blocking input.
109 Unlocker unlock(Isolate::GetCurrent());
110 result = readline(prompt);
111 }
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000112 if (result != NULL) {
113 AddHistory(result);
114 } else {
115 return Handle<String>();
116 }
117 return String::New(result);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000118}
119
120
121void ReadLineEditor::AddHistory(const char* str) {
lrn@chromium.org34e60782011-09-15 07:25:40 +0000122 // Do not record empty input.
123 if (strlen(str) == 0) return;
124 // Remove duplicate history entry.
125 history_set_pos(history_length-1);
126 if (current_history()) {
127 do {
128 if (strcmp(current_history()->line, str) == 0) {
129 remove_history(where_history());
130 break;
131 }
132 } while (previous_history());
133 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000134 add_history(str);
135}
136
137
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000138#ifndef V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000139char** ReadLineEditor::AttemptedCompletion(const char* text,
140 int start,
141 int end) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000142 char** result = completion_matches(text, CompletionGenerator);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000143 rl_attempted_completion_over = true;
144 return result;
145}
146
147
148char* ReadLineEditor::CompletionGenerator(const char* text, int state) {
149 static unsigned current_index;
150 static Persistent<Array> current_completions;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000151 Isolate* isolate = read_line_editor.isolate_;
152 Locker lock(isolate);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000153 HandleScope scope;
154 Handle<Array> completions;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000155 if (state == 0) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000156 Local<String> full_text = String::New(rl_line_buffer, rl_point);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000157 completions = Shell::GetCompletions(isolate, String::New(text), full_text);
158 current_completions.Reset(isolate, completions);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000159 current_index = 0;
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000160 } else {
161 completions = Local<Array>::New(isolate, current_completions);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000162 }
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000163 if (current_index < completions->Length()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000164 Handle<Integer> index = Integer::New(current_index);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000165 Handle<Value> str_obj = completions->Get(index);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000166 current_index++;
167 String::Utf8Value str(str_obj);
168 return strdup(*str);
169 } else {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +0000170 current_completions.Dispose(isolate);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000171 current_completions.Clear();
172 return NULL;
173 }
174}
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000175#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000176
177
178} // namespace v8