blob: 89892631f76ca0a9811c83038dbfed39d6789f3a [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);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000052 virtual bool Open();
53 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[];
65};
66
67
68static ReadLineEditor read_line_editor;
69char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"',
70 '\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(',
71 '\0'};
72
73
ulan@chromium.org2efb9002012-01-19 15:36:35 +000074const char* ReadLineEditor::kHistoryFileName = ".d8_history";
75const int ReadLineEditor::kMaxHistoryEntries = 1000;
76
77
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000078bool ReadLineEditor::Open() {
79 rl_initialize();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000080
81#ifdef V8_SHARED
82 // Don't do completion on shared library mode
83 // http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC24
84 rl_bind_key('\t', rl_insert);
85#else
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000086 rl_attempted_completion_function = AttemptedCompletion;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000087#endif // V8_SHARED
88
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000089 rl_completer_word_break_characters = kWordBreakCharacters;
90 rl_bind_key('\t', rl_complete);
91 using_history();
ulan@chromium.org2efb9002012-01-19 15:36:35 +000092 stifle_history(kMaxHistoryEntries);
93 return read_history(kHistoryFileName) == 0;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000094}
95
96
97bool ReadLineEditor::Close() {
ulan@chromium.org2efb9002012-01-19 15:36:35 +000098 return write_history(kHistoryFileName) == 0;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000099}
100
101
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000102Handle<String> ReadLineEditor::Prompt(const char* prompt) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000103 char* result = NULL;
104 { // Release lock for blocking input.
105 Unlocker unlock(Isolate::GetCurrent());
106 result = readline(prompt);
107 }
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000108 if (result != NULL) {
109 AddHistory(result);
110 } else {
111 return Handle<String>();
112 }
113 return String::New(result);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000114}
115
116
117void ReadLineEditor::AddHistory(const char* str) {
lrn@chromium.org34e60782011-09-15 07:25:40 +0000118 // Do not record empty input.
119 if (strlen(str) == 0) return;
120 // Remove duplicate history entry.
121 history_set_pos(history_length-1);
122 if (current_history()) {
123 do {
124 if (strcmp(current_history()->line, str) == 0) {
125 remove_history(where_history());
126 break;
127 }
128 } while (previous_history());
129 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000130 add_history(str);
131}
132
133
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000134#ifndef V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000135char** ReadLineEditor::AttemptedCompletion(const char* text,
136 int start,
137 int end) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000138 char** result = completion_matches(text, CompletionGenerator);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000139 rl_attempted_completion_over = true;
140 return result;
141}
142
143
144char* ReadLineEditor::CompletionGenerator(const char* text, int state) {
145 static unsigned current_index;
146 static Persistent<Array> current_completions;
147 if (state == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000148 HandleScope scope;
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000149 Local<String> full_text = String::New(rl_line_buffer, rl_point);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000150 Handle<Array> completions =
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000151 Shell::GetCompletions(String::New(text), full_text);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000152 current_completions = Persistent<Array>::New(completions);
153 current_index = 0;
154 }
155 if (current_index < current_completions->Length()) {
156 HandleScope scope;
157 Handle<Integer> index = Integer::New(current_index);
158 Handle<Value> str_obj = current_completions->Get(index);
159 current_index++;
160 String::Utf8Value str(str_obj);
161 return strdup(*str);
162 } else {
163 current_completions.Dispose();
164 current_completions.Clear();
165 return NULL;
166 }
167}
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000168#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000169
170
171} // namespace v8