]>
git.saurik.com Git - cycript.git/blob - Complete.cpp
1 /* Cycript - The Truly Universal Scripting Language
2 * Copyright (C) 2009-2016 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_
<< ':';
92 case CYDriver::AutoResolve
:
93 expression
= $
M(driver
.context_
, $
S("$cyr"));
100 std::string
begin(prefix
.str());
102 driver
.script_
= $
CYScript($
CYExpress($
C3(ParseExpression(pool
,
103 " function(object, prefix, word) {\n"
105 " var before = prefix.length;\n"
107 " var entire = prefix.length;\n"
109 " for (var name in object)\n"
110 " if (name.substring(0, entire) == prefix)\n"
111 " names.push(name.substr(before));\n"
113 " if (object.hasOwnProperty(\"cy$complete\")) {\n"
114 " names = names.concat(object.cy$complete(prefix));\n"
118 " var local = Object.getOwnPropertyNames(object);\n"
122 " for (var name of local)\n"
123 " if (name.substring(0, entire) == prefix)\n"
124 " names.push(name.substr(before));\n"
125 " } while (object = typeof object === 'object' ? Object.getPrototypeOf(object) : object.__proto__);\n"
128 ), expression
, $
S(begin
.c_str()), $
S(word
))));
130 driver
.script_
->Replace(context
);
133 CYOutput
out(str
, options
);
134 out
<< *driver
.script_
;
136 std::string
code(str
.str());
137 CYUTF8String
json(run(pool
, code
));
138 // XXX: if this fails we should not try to parse it
140 CYExpression
*result(ParseExpression(pool
, json
));
144 CYArray
*array(dynamic_cast<CYArray
*>(result
->Primitive(context
)));
148 // XXX: use an std::set?
149 typedef std::vector
<std::string
> Completions
;
150 Completions completions
;
155 for (CYElement
*element(array
->elements_
); element
!= NULL
; ) {
156 CYElementValue
*value(dynamic_cast<CYElementValue
*>(element
));
157 _assert(value
!= NULL
);
158 element
= value
->next_
;
160 CYString
*string(dynamic_cast<CYString
*>(value
->value_
));
161 _assert(string
!= NULL
);
163 std::string completion
;
164 if (string
->size_
!= 0)
165 completion
.assign(string
->value_
, string
->size_
);
166 else if (driver
.mode_
== CYDriver::AutoMessage
)
171 completions
.push_back(completion
);
177 size_t limit(completion
.size()), size(common
.size());
179 common
= common
.substr(0, limit
);
182 for (limit
= 0; limit
!= size
; ++limit
)
183 if (common
[limit
] != completion
[limit
])
186 common
= common
.substr(0, limit
);
190 size_t count(completions
.size());
194 size_t colon(common
.find(':'));
195 if (colon
!= std::string::npos
)
196 common
= common
.substr(0, colon
+ 1);
197 if (completions
.size() == 1)
200 char **results(reinterpret_cast<char **>(malloc(sizeof(char *) * (count
+ 2))));
202 results
[0] = strdup(common
.c_str());
204 for (Completions::const_iterator
i(completions
.begin()); i
!= completions
.end(); ++i
)
205 results
[++index
] = strdup(i
->c_str());
206 results
[count
+ 1] = NULL
;