]>
git.saurik.com Git - cycript.git/blob - Complete.cpp
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
);
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::istringstream
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"
104 " for (var name in object)\n"
105 " if (name.substring(0, entire) == prefix)\n"
106 " names.push(name.substr(before));\n"
109 ), expression
, $
S(begin
.c_str()), $
S(word
))));
111 driver
.script_
->Replace(context
);
114 CYOutput
out(str
, options
);
115 out
<< *driver
.script_
;
117 std::string
code(str
.str());
118 CYUTF8String
json(run(pool
, code
));
119 // XXX: if this fails we should not try to parse it
121 CYExpression
*result(ParseExpression(pool
, json
));
125 CYArray
*array(dynamic_cast<CYArray
*>(result
->Primitive(context
)));
129 // XXX: use an std::set?
130 typedef std::vector
<std::string
> Completions
;
131 Completions completions
;
136 for (CYElement
*element(array
->elements_
); element
!= NULL
; ) {
137 CYElementValue
*value(dynamic_cast<CYElementValue
*>(element
));
138 _assert(value
!= NULL
);
139 element
= value
->next_
;
141 CYString
*string(dynamic_cast<CYString
*>(value
->value_
));
142 _assert(string
!= NULL
);
144 std::string completion
;
145 if (string
->size_
!= 0)
146 completion
.assign(string
->value_
, string
->size_
);
147 else if (driver
.mode_
== CYDriver::AutoMessage
)
152 completions
.push_back(completion
);
158 size_t limit(completion
.size()), size(common
.size());
160 common
= common
.substr(0, limit
);
163 for (limit
= 0; limit
!= size
; ++limit
)
164 if (common
[limit
] != completion
[limit
])
167 common
= common
.substr(0, limit
);
171 size_t count(completions
.size());
175 size_t colon(common
.find(':'));
176 if (colon
!= std::string::npos
)
177 common
= common
.substr(0, colon
+ 1);
178 if (completions
.size() == 1)
181 char **results(reinterpret_cast<char **>(malloc(sizeof(char *) * (count
+ 2))));
183 results
[0] = strdup(common
.c_str());
185 for (Completions::const_iterator
i(completions
.begin()); i
!= completions
.end(); ++i
)
186 results
[++index
] = strdup(i
->c_str());
187 results
[count
+ 1] = NULL
;