summaryrefslogtreecommitdiff
path: root/deps/v8/src/d8-readline.cc
blob: 39c93d35de5859f49b3a697b09cec2a2be7108e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdio.h>  // NOLINT
#include <string.h> // NOLINT
#include <readline/readline.h> // NOLINT
#include <readline/history.h> // NOLINT

// The readline includes leaves RETURN defined which breaks V8 compilation.
#undef RETURN

#include "src/d8.h"

// There are incompatibilities between different versions and different
// implementations of readline.  This smooths out one known incompatibility.
#if RL_READLINE_VERSION >= 0x0500
#define completion_matches rl_completion_matches
#endif


namespace v8 {


class ReadLineEditor: public LineEditor {
 public:
  ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { }
  virtual Handle<String> Prompt(const char* prompt);
  virtual bool Open(Isolate* isolate);
  virtual bool Close();
  virtual void AddHistory(const char* str);

  static const char* kHistoryFileName;
  static const int kMaxHistoryEntries;

 private:
#ifndef V8_SHARED
  static char** AttemptedCompletion(const char* text, int start, int end);
  static char* CompletionGenerator(const char* text, int state);
#endif  // V8_SHARED
  static char kWordBreakCharacters[];

  Isolate* isolate_;
};


static ReadLineEditor read_line_editor;
char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"',
    '\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(',
    '\0'};


const char* ReadLineEditor::kHistoryFileName = ".d8_history";
const int ReadLineEditor::kMaxHistoryEntries = 1000;


bool ReadLineEditor::Open(Isolate* isolate) {
  isolate_ = isolate;

  rl_initialize();

#ifdef V8_SHARED
  // Don't do completion on shared library mode
  // http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC24
  rl_bind_key('\t', rl_insert);
#else
  rl_attempted_completion_function = AttemptedCompletion;
#endif  // V8_SHARED

  rl_completer_word_break_characters = kWordBreakCharacters;
  rl_bind_key('\t', rl_complete);
  using_history();
  stifle_history(kMaxHistoryEntries);
  return read_history(kHistoryFileName) == 0;
}


bool ReadLineEditor::Close() {
  return write_history(kHistoryFileName) == 0;
}


Handle<String> ReadLineEditor::Prompt(const char* prompt) {
  char* result = NULL;
  result = readline(prompt);
  if (result == NULL) return Handle<String>();
  AddHistory(result);
  return String::NewFromUtf8(isolate_, result);
}


void ReadLineEditor::AddHistory(const char* str) {
  // Do not record empty input.
  if (strlen(str) == 0) return;
  // Remove duplicate history entry.
  history_set_pos(history_length-1);
  if (current_history()) {
    do {
      if (strcmp(current_history()->line, str) == 0) {
        remove_history(where_history());
        break;
      }
    } while (previous_history());
  }
  add_history(str);
}


#ifndef V8_SHARED
char** ReadLineEditor::AttemptedCompletion(const char* text,
                                           int start,
                                           int end) {
  char** result = completion_matches(text, CompletionGenerator);
  rl_attempted_completion_over = true;
  return result;
}


char* ReadLineEditor::CompletionGenerator(const char* text, int state) {
  static unsigned current_index;
  static Persistent<Array> current_completions;
  Isolate* isolate = read_line_editor.isolate_;
  HandleScope scope(isolate);
  Handle<Array> completions;
  if (state == 0) {
    Local<String> full_text = String::NewFromUtf8(isolate,
                                                  rl_line_buffer,
                                                  String::kNormalString,
                                                  rl_point);
    completions = Shell::GetCompletions(isolate,
                                        String::NewFromUtf8(isolate, text),
                                        full_text);
    current_completions.Reset(isolate, completions);
    current_index = 0;
  } else {
    completions = Local<Array>::New(isolate, current_completions);
  }
  if (current_index < completions->Length()) {
    Handle<Integer> index = Integer::New(isolate, current_index);
    Handle<Value> str_obj = completions->Get(index);
    current_index++;
    String::Utf8Value str(str_obj);
    return strdup(*str);
  } else {
    current_completions.Reset();
    return NULL;
  }
}
#endif  // V8_SHARED


}  // namespace v8