Home | History | Annotate | Download | only in src
      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