12efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org// Copyright 2012 the V8 project authors. All rights reserved.
25a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// Redistribution and use in source and binary forms, with or without
35a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// modification, are permitted provided that the following conditions are
45a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// met:
55a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//
65a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//     * Redistributions of source code must retain the above copyright
75a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//       notice, this list of conditions and the following disclaimer.
85a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//     * Redistributions in binary form must reproduce the above
95a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//       copyright notice, this list of conditions and the following
105a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//       disclaimer in the documentation and/or other materials provided
115a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//       with the distribution.
125a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//     * Neither the name of Google Inc. nor the names of its
135a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//       contributors may be used to endorse or promote products derived
145a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//       from this software without specific prior written permission.
155a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org//
165a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
288bb60585bafbf81564e6b30fcf18c82615a76f95ager@chromium.org#include <cstdio>  // NOLINT
2959297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org#include <string.h> // NOLINT
305c838251403b0be9a882540f1922577abba4c872ager@chromium.org#include <readline/readline.h> // NOLINT
315c838251403b0be9a882540f1922577abba4c872ager@chromium.org#include <readline/history.h> // NOLINT
325a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
333847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com// The readline includes leaves RETURN defined which breaks V8 compilation.
343847bd5ff857259e945a01d75fdb383e2351d166erik.corry@gmail.com#undef RETURN
355a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
365a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org#include "d8.h"
375a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
388bb60585bafbf81564e6b30fcf18c82615a76f95ager@chromium.org// There are incompatibilities between different versions and different
393291210ab99f306b74430ebbc4b7d939629e699fager@chromium.org// implementations of readline.  This smooths out one known incompatibility.
408bb60585bafbf81564e6b30fcf18c82615a76f95ager@chromium.org#if RL_READLINE_VERSION >= 0x0500
418bb60585bafbf81564e6b30fcf18c82615a76f95ager@chromium.org#define completion_matches rl_completion_matches
428bb60585bafbf81564e6b30fcf18c82615a76f95ager@chromium.org#endif
438bb60585bafbf81564e6b30fcf18c82615a76f95ager@chromium.org
448bb60585bafbf81564e6b30fcf18c82615a76f95ager@chromium.org
455a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.orgnamespace v8 {
465a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
475a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
485a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.orgclass ReadLineEditor: public LineEditor {
495a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org public:
505a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { }
512efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org  virtual Handle<String> Prompt(const char* prompt);
526e196bfaf0e555d0c835390bb6ebc0a74484491dulan@chromium.org  virtual bool Open(Isolate* isolate);
535a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  virtual bool Close();
545a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  virtual void AddHistory(const char* str);
552efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org
562efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org  static const char* kHistoryFileName;
572efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org  static const int kMaxHistoryEntries;
582efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org
595a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org private:
6059297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org#ifndef V8_SHARED
615a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  static char** AttemptedCompletion(const char* text, int start, int end);
625a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  static char* CompletionGenerator(const char* text, int state);
6359297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org#endif  // V8_SHARED
645a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  static char kWordBreakCharacters[];
656e196bfaf0e555d0c835390bb6ebc0a74484491dulan@chromium.org
666e196bfaf0e555d0c835390bb6ebc0a74484491dulan@chromium.org  Isolate* isolate_;
675a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org};
685a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
695a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
705a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.orgstatic ReadLineEditor read_line_editor;
715a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.orgchar ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"',
725a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org    '\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(',
735a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org    '\0'};
745a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
755a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
762efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.orgconst char* ReadLineEditor::kHistoryFileName = ".d8_history";
772efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.orgconst int ReadLineEditor::kMaxHistoryEntries = 1000;
782efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org
792efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org
806e196bfaf0e555d0c835390bb6ebc0a74484491dulan@chromium.orgbool ReadLineEditor::Open(Isolate* isolate) {
816e196bfaf0e555d0c835390bb6ebc0a74484491dulan@chromium.org  isolate_ = isolate;
826e196bfaf0e555d0c835390bb6ebc0a74484491dulan@chromium.org
835a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  rl_initialize();
8459297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org
8559297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org#ifdef V8_SHARED
8659297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org  // Don't do completion on shared library mode
8759297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org  // http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC24
8859297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org  rl_bind_key('\t', rl_insert);
8959297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org#else
905a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  rl_attempted_completion_function = AttemptedCompletion;
9159297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org#endif  // V8_SHARED
9259297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org
935a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  rl_completer_word_break_characters = kWordBreakCharacters;
945a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  rl_bind_key('\t', rl_complete);
955a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  using_history();
962efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org  stifle_history(kMaxHistoryEntries);
972efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org  return read_history(kHistoryFileName) == 0;
985a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org}
995a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1005a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1015a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.orgbool ReadLineEditor::Close() {
1022efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org  return write_history(kHistoryFileName) == 0;
1035a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org}
1045a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1055a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1062efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.orgHandle<String> ReadLineEditor::Prompt(const char* prompt) {
10705ed9ddc6ff3a1ab3983c50d378cddfa257869b6jkummerow@chromium.org  char* result = NULL;
10805ed9ddc6ff3a1ab3983c50d378cddfa257869b6jkummerow@chromium.org  {  // Release lock for blocking input.
10905ed9ddc6ff3a1ab3983c50d378cddfa257869b6jkummerow@chromium.org    Unlocker unlock(Isolate::GetCurrent());
11005ed9ddc6ff3a1ab3983c50d378cddfa257869b6jkummerow@chromium.org    result = readline(prompt);
11105ed9ddc6ff3a1ab3983c50d378cddfa257869b6jkummerow@chromium.org  }
1122efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org  if (result != NULL) {
1132efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org    AddHistory(result);
1142efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org  } else {
1152efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org    return Handle<String>();
1162efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org  }
1172efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org  return String::New(result);
1185a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org}
1195a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1205a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1215a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.orgvoid ReadLineEditor::AddHistory(const char* str) {
12234e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  // Do not record empty input.
12334e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  if (strlen(str) == 0) return;
12434e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  // Remove duplicate history entry.
12534e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  history_set_pos(history_length-1);
12634e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  if (current_history()) {
12734e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org    do {
12834e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org      if (strcmp(current_history()->line, str) == 0) {
12934e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org        remove_history(where_history());
13034e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org        break;
13134e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org      }
13234e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org    } while (previous_history());
13334e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  }
1345a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  add_history(str);
1355a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org}
1365a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1375a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
13859297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org#ifndef V8_SHARED
1395a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.orgchar** ReadLineEditor::AttemptedCompletion(const char* text,
1405a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org                                           int start,
1415a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org                                           int end) {
1428bb60585bafbf81564e6b30fcf18c82615a76f95ager@chromium.org  char** result = completion_matches(text, CompletionGenerator);
1435a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  rl_attempted_completion_over = true;
1445a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  return result;
1455a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org}
1465a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1475a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1485a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.orgchar* ReadLineEditor::CompletionGenerator(const char* text, int state) {
1495a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  static unsigned current_index;
1505a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  static Persistent<Array> current_completions;
1516e196bfaf0e555d0c835390bb6ebc0a74484491dulan@chromium.org  Isolate* isolate = read_line_editor.isolate_;
1526e196bfaf0e555d0c835390bb6ebc0a74484491dulan@chromium.org  Locker lock(isolate);
153b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org  HandleScope scope;
154b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org  Handle<Array> completions;
1555a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  if (state == 0) {
1562efb900e7350b14be905abdeab077f3a64c583cfulan@chromium.org    Local<String> full_text = String::New(rl_line_buffer, rl_point);
157b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org    completions = Shell::GetCompletions(isolate, String::New(text), full_text);
158b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org    current_completions.Reset(isolate, completions);
1595a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org    current_index = 0;
160b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org  } else {
161b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org    completions = Local<Array>::New(isolate, current_completions);
1625a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  }
163b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org  if (current_index < completions->Length()) {
1645a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org    Handle<Integer> index = Integer::New(current_index);
165b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org    Handle<Value> str_obj = completions->Get(index);
1665a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org    current_index++;
1675a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org    String::Utf8Value str(str_obj);
1685a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org    return strdup(*str);
1695a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  } else {
1706e196bfaf0e555d0c835390bb6ebc0a74484491dulan@chromium.org    current_completions.Dispose(isolate);
1715a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org    current_completions.Clear();
1725a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org    return NULL;
1735a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org  }
1745a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org}
17559297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org#endif  // V8_SHARED
1765a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1775a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org
1785a8ca6c70c6fc9716f18f6223c98d1fef5752cf6kasperl@chromium.org}  // namespace v8
179