]>
git.saurik.com Git - cycript.git/blob - Complete.cpp
d822d995adefe9f282ac92c064d735862c7c3c76
   1 /* Cycript - Optimizing JavaScript Compiler/Runtime 
   2  * Copyright (C) 2009-2015  Jay Freeman (saurik) 
   5 /* GNU Affero General Public License, Version 3 {{{ */ 
   7  * This program is free software: you can redistribute it and/or modify 
   8  * it under the terms of the GNU Affero General Public License as published by 
   9  * the Free Software Foundation, either version 3 of the License, or 
  10  * (at your option) any later version. 
  12  * This program is distributed in the hope that it will be useful, 
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  * GNU Affero General Public License for more details. 
  17  * You should have received a copy of the GNU Affero General Public License 
  18  * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  22 #include "cycript.hpp" 
  25 #include "Replace.hpp" 
  28 static CYExpression 
*ParseExpression(CYPool 
&pool
, CYUTF8String code
) { 
  29     std::stringstream stream
; 
  30     stream 
<< '(' << code 
<< ')'; 
  31     CYDriver 
driver(pool
, *stream
.rdbuf()); 
  32     if (driver
.Parse() || !driver
.errors_
.empty()) 
  36     CYContext 
context(options
); 
  38     CYStatement 
*statement(driver
.script_
->code_
); 
  39     _assert(statement 
!= NULL
); 
  40     _assert(statement
->next_ 
== NULL
); 
  42     CYExpress 
*express(dynamic_cast<CYExpress 
*>(driver
.script_
->code_
)); 
  43     _assert(express 
!= NULL
); 
  45     CYParenthetical 
*parenthetical(dynamic_cast<CYParenthetical 
*>(express
->expression_
)); 
  46     _assert(parenthetical 
!= NULL
); 
  48     return parenthetical
->expression_
; 
  51 _visible 
char **CYComplete(const char *word
, const std::string 
&line
, CYUTF8String (*run
)(CYPool 
&pool
, const std::string 
&)) { 
  54     std::stringbuf 
stream(line
); 
  55     CYDriver 
driver(pool
, stream
); 
  59     if (driver
.Parse() || !driver
.errors_
.empty()) 
  62     if (driver
.mode_ 
== CYDriver::AutoNone
) 
  65     CYExpression 
*expression
; 
  68     CYContext 
context(options
); 
  70     std::ostringstream prefix
; 
  72     switch (driver
.mode_
) { 
  73         case CYDriver::AutoPrimary
: 
  74             expression 
= $ 
CYThis(); 
  77         case CYDriver::AutoDirect
: 
  78             expression 
= driver
.context_
; 
  81         case CYDriver::AutoIndirect
: 
  82             expression 
= $ 
CYIndirect(driver
.context_
); 
  85         case CYDriver::AutoMessage
: { 
  86             CYDriver::Context 
&thing(driver
.contexts_
.back()); 
  87             expression 
= $
M($
C1($
V("object_getClass"), thing
.context_
), $
S("messages")); 
  88             for (CYDriver::Context::Words::const_iterator 
part(thing
.words_
.begin()); part 
!= thing
.words_
.end(); ++part
) 
  89                 prefix 
<< (*part
)->word_ 
<< ':'; 
  96     std::string 
begin(prefix
.str()); 
  98     driver
.script_ 
= $ 
CYScript($ 
CYExpress($
C3(ParseExpression(pool
, 
  99     "   function(object, prefix, word) {\n" 
 101     "       var before = prefix.length;\n" 
 103     "       var entire = prefix.length;\n" 
 105     "           for (var name in object)\n" 
 106     "               if (name.substring(0, entire) == prefix)\n" 
 107     "                   names.push(name.substr(before));\n" 
 110     "               var local = Object.getOwnPropertyNames(object);\n" 
 114     "           for (var name of local)\n" 
 115     "               if (name.substring(0, entire) == prefix)\n" 
 116     "                   names.push(name.substr(before));\n" 
 117     "       } while (object = typeof object === 'object' ? Object.getPrototypeOf(object) : object.__proto__);\n" 
 120     ), expression
, $
S(begin
.c_str()), $
S(word
)))); 
 122     driver
.script_
->Replace(context
); 
 125     CYOutput 
out(str
, options
); 
 126     out 
<< *driver
.script_
; 
 128     std::string 
code(str
.str()); 
 129     CYUTF8String 
json(run(pool
, code
)); 
 130     // XXX: if this fails we should not try to parse it 
 132     CYExpression 
*result(ParseExpression(pool
, json
)); 
 136     CYArray 
*array(dynamic_cast<CYArray 
*>(result
->Primitive(context
))); 
 140     // XXX: use an std::set? 
 141     typedef std::vector
<std::string
> Completions
; 
 142     Completions completions
; 
 147     for (CYElement 
*element(array
->elements_
); element 
!= NULL
; ) { 
 148         CYElementValue 
*value(dynamic_cast<CYElementValue 
*>(element
)); 
 149         _assert(value 
!= NULL
); 
 150         element 
= value
->next_
; 
 152         CYString 
*string(dynamic_cast<CYString 
*>(value
->value_
)); 
 153         _assert(string 
!= NULL
); 
 155         std::string completion
; 
 156         if (string
->size_ 
!= 0) 
 157             completion
.assign(string
->value_
, string
->size_
); 
 158         else if (driver
.mode_ 
== CYDriver::AutoMessage
) 
 163         completions
.push_back(completion
); 
 169             size_t limit(completion
.size()), size(common
.size()); 
 171                 common 
= common
.substr(0, limit
); 
 174             for (limit 
= 0; limit 
!= size
; ++limit
) 
 175                 if (common
[limit
] != completion
[limit
]) 
 178                 common 
= common
.substr(0, limit
); 
 182     size_t count(completions
.size()); 
 186     size_t colon(common
.find(':')); 
 187     if (colon 
!= std::string::npos
) 
 188         common 
= common
.substr(0, colon 
+ 1); 
 189     if (completions
.size() == 1) 
 192     char **results(reinterpret_cast<char **>(malloc(sizeof(char *) * (count 
+ 2)))); 
 194     results
[0] = strdup(common
.c_str()); 
 196     for (Completions::const_iterator 
i(completions
.begin()); i 
!= completions
.end(); ++i
) 
 197         results
[++index
] = strdup(i
->c_str()); 
 198     results
[count 
+ 1] = NULL
;