Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // 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 
     28 
     29 #include <cstdio>  // NOLINT
     30 #include <readline/readline.h> // NOLINT
     31 #include <readline/history.h> // NOLINT
     32 
     33 // The readline includes leaves RETURN defined which breaks V8 compilation.
     34 #undef RETURN
     35 
     36 #include "d8.h"
     37 
     38 
     39 // There are incompatibilities between different versions and different
     40 // implementations of readline.  This smooths out one known incompatibility.
     41 #if RL_READLINE_VERSION >= 0x0500
     42 #define completion_matches rl_completion_matches
     43 #endif
     44 
     45 
     46 namespace v8 {
     47 
     48 
     49 class ReadLineEditor: public LineEditor {
     50  public:
     51   ReadLineEditor() : LineEditor(LineEditor::READLINE, "readline") { }
     52   virtual Handle<String> Prompt(const char* prompt);
     53   virtual bool Open();
     54   virtual bool Close();
     55   virtual void AddHistory(const char* str);
     56 
     57   static const char* kHistoryFileName;
     58   static const int kMaxHistoryEntries;
     59 
     60  private:
     61   static char** AttemptedCompletion(const char* text, int start, int end);
     62   static char* CompletionGenerator(const char* text, int state);
     63   static char kWordBreakCharacters[];
     64 };
     65 
     66 
     67 static ReadLineEditor read_line_editor;
     68 char ReadLineEditor::kWordBreakCharacters[] = {' ', '\t', '\n', '"',
     69     '\\', '\'', '`', '@', '.', '>', '<', '=', ';', '|', '&', '{', '(',
     70     '\0'};
     71 
     72 
     73 const char* ReadLineEditor::kHistoryFileName = ".d8_history";
     74 const int ReadLineEditor::kMaxHistoryEntries = 1000;
     75 
     76 
     77 bool ReadLineEditor::Open() {
     78   rl_initialize();
     79   rl_attempted_completion_function = AttemptedCompletion;
     80   rl_completer_word_break_characters = kWordBreakCharacters;
     81   rl_bind_key('\t', rl_complete);
     82   using_history();
     83   stifle_history(kMaxHistoryEntries);
     84   return read_history(kHistoryFileName) == 0;
     85 }
     86 
     87 
     88 bool ReadLineEditor::Close() {
     89   return write_history(kHistoryFileName) == 0;
     90 }
     91 
     92 
     93 Handle<String> ReadLineEditor::Prompt(const char* prompt) {
     94   char* result = NULL;
     95   {  // Release lock for blocking input.
     96     Unlocker unlock(Isolate::GetCurrent());
     97     result = readline(prompt);
     98   }
     99   if (result != NULL) {
    100     AddHistory(result);
    101   } else {
    102     return Handle<String>();
    103   }
    104   return String::New(result);
    105 }
    106 
    107 
    108 void ReadLineEditor::AddHistory(const char* str) {
    109   // Do not record empty input.
    110   if (strlen(str) == 0) return;
    111   // Remove duplicate history entry.
    112   history_set_pos(history_length-1);
    113   if (current_history()) {
    114     do {
    115       if (strcmp(current_history()->line, str) == 0) {
    116         remove_history(where_history());
    117         break;
    118       }
    119     } while (previous_history());
    120   }
    121   add_history(str);
    122 }
    123 
    124 
    125 char** ReadLineEditor::AttemptedCompletion(const char* text,
    126                                            int start,
    127                                            int end) {
    128   char** result = completion_matches(text, CompletionGenerator);
    129   rl_attempted_completion_over = true;
    130   return result;
    131 }
    132 
    133 
    134 char* ReadLineEditor::CompletionGenerator(const char* text, int state) {
    135   static unsigned current_index;
    136   static Persistent<Array> current_completions;
    137   if (state == 0) {
    138     HandleScope scope;
    139     Local<String> full_text = String::New(rl_line_buffer, rl_point);
    140     Handle<Array> completions =
    141       Shell::GetCompletions(String::New(text), full_text);
    142     current_completions = Persistent<Array>::New(completions);
    143     current_index = 0;
    144   }
    145   if (current_index < current_completions->Length()) {
    146     HandleScope scope;
    147     Handle<Integer> index = Integer::New(current_index);
    148     Handle<Value> str_obj = current_completions->Get(index);
    149     current_index++;
    150     String::Utf8Value str(str_obj);
    151     return strdup(*str);
    152   } else {
    153     current_completions.Dispose();
    154     current_completions.Clear();
    155     return NULL;
    156   }
    157 }
    158 
    159 
    160 }  // namespace v8
    161