1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <stdio.h> // NOLINT 6 #include <string.h> // NOLINT 7 #include <readline/readline.h> // NOLINT 8 #include <readline/history.h> // NOLINT 9 10 // The readline includes leaves RETURN defined which breaks V8 compilation. 11 #undef RETURN 12 13 #include "src/d8.h" 14 15 // There are incompatibilities between different versions and different 16 // implementations of readline. This smooths out one known incompatibility. 17 #if RL_READLINE_VERSION >= 0x0500 18 #define completion_matches rl_completion_matches 19 #endif 20 21 22 namespace v8 { 23 24 25 class ReadLineEditor: public LineEditor { 26 public: 27 ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { } 28 virtual Handle<String> Prompt(const char* prompt); 29 virtual bool Open(Isolate* isolate); 30 virtual bool Close(); 31 virtual void AddHistory(const char* str); 32 33 static const char* kHistoryFileName; 34 static const int kMaxHistoryEntries; 35 36 private: 37 #ifndef V8_SHARED 38 static char** AttemptedCompletion(const char* text, int start, int end); 39 static char* CompletionGenerator(const char* text, int state); 40 #endif // V8_SHARED 41 static char kWordBreakCharacters[]; 42 43 Isolate* isolate_; 44 }; 45 46 47 static ReadLineEditor read_line_editor; 48 char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"', 49 '\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(', 50 '\0'}; 51 52 53 const char* ReadLineEditor::kHistoryFileName = ".d8_history"; 54 const int ReadLineEditor::kMaxHistoryEntries = 1000; 55 56 57 bool ReadLineEditor::Open(Isolate* isolate) { 58 isolate_ = isolate; 59 60 rl_initialize(); 61 62 #ifdef V8_SHARED 63 // Don't do completion on shared library mode 64 // http://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC24 65 rl_bind_key('\t', rl_insert); 66 #else 67 rl_attempted_completion_function = AttemptedCompletion; 68 #endif // V8_SHARED 69 70 rl_completer_word_break_characters = kWordBreakCharacters; 71 rl_bind_key('\t', rl_complete); 72 using_history(); 73 stifle_history(kMaxHistoryEntries); 74 return read_history(kHistoryFileName) == 0; 75 } 76 77 78 bool ReadLineEditor::Close() { 79 return write_history(kHistoryFileName) == 0; 80 } 81 82 83 Handle<String> ReadLineEditor::Prompt(const char* prompt) { 84 char* result = NULL; 85 result = readline(prompt); 86 if (result == NULL) return Handle<String>(); 87 AddHistory(result); 88 return String::NewFromUtf8(isolate_, result); 89 } 90 91 92 void ReadLineEditor::AddHistory(const char* str) { 93 // Do not record empty input. 94 if (strlen(str) == 0) return; 95 // Remove duplicate history entry. 96 history_set_pos(history_length-1); 97 if (current_history()) { 98 do { 99 if (strcmp(current_history()->line, str) == 0) { 100 remove_history(where_history()); 101 break; 102 } 103 } while (previous_history()); 104 } 105 add_history(str); 106 } 107 108 109 #ifndef V8_SHARED 110 char** ReadLineEditor::AttemptedCompletion(const char* text, 111 int start, 112 int end) { 113 char** result = completion_matches(text, CompletionGenerator); 114 rl_attempted_completion_over = true; 115 return result; 116 } 117 118 119 char* ReadLineEditor::CompletionGenerator(const char* text, int state) { 120 static unsigned current_index; 121 static Persistent<Array> current_completions; 122 Isolate* isolate = read_line_editor.isolate_; 123 HandleScope scope(isolate); 124 Handle<Array> completions; 125 if (state == 0) { 126 Local<String> full_text = String::NewFromUtf8(isolate, 127 rl_line_buffer, 128 String::kNormalString, 129 rl_point); 130 completions = Shell::GetCompletions(isolate, 131 String::NewFromUtf8(isolate, text), 132 full_text); 133 current_completions.Reset(isolate, completions); 134 current_index = 0; 135 } else { 136 completions = Local<Array>::New(isolate, current_completions); 137 } 138 if (current_index < completions->Length()) { 139 Handle<Integer> index = Integer::New(isolate, current_index); 140 Handle<Value> str_obj = completions->Get(index); 141 current_index++; 142 String::Utf8Value str(str_obj); 143 return strdup(*str); 144 } else { 145 current_completions.Reset(); 146 return NULL; 147 } 148 } 149 #endif // V8_SHARED 150 151 152 } // namespace v8 153