- std::istringstream stream(command_ + line);
- CYDriver driver(stream);
-
- driver.auto_ = true;
-
- cy::parser parser(driver);
- Setup(driver, parser);
-
- if (parser.parse() != 0 || !driver.errors_.empty())
- return NULL;
-
- if (driver.mode_ == CYDriver::AutoNone)
- return NULL;
-
- CYExpression *expression;
-
- CYOptions options;
- CYContext context(options);
-
- std::ostringstream prefix;
-
- switch (driver.mode_) {
- case CYDriver::AutoPrimary:
- expression = $ CYThis();
- break;
-
- case CYDriver::AutoDirect:
- expression = driver.context_;
- break;
-
- case CYDriver::AutoIndirect:
- expression = $ CYIndirect(driver.context_);
- break;
-
- case CYDriver::AutoMessage: {
- CYDriver::Context &thing(driver.contexts_.back());
- expression = $M($C1($V("object_getClass"), thing.context_), $S("messages"));
- for (CYDriver::Context::Words::const_iterator part(thing.words_.begin()); part != thing.words_.end(); ++part)
- prefix << (*part)->word_ << ':';
- } break;
-
- default:
- _assert(false);
- }
-
- std::string begin(prefix.str());
-
- driver.program_ = $ CYProgram($ CYExpress($C3(ParseExpression(
- " function(object, prefix, word) {\n"
- " var names = [];\n"
- " var before = prefix.length;\n"
- " prefix += word;\n"
- " var entire = prefix.length;\n"
- " for (var name in object)\n"
- " if (name.substring(0, entire) == prefix)\n"
- " names.push(name.substr(before));\n"
- " return names;\n"
- " }\n"
- ), expression, $S(begin.c_str()), $S(word))));
-
- driver.program_->Replace(context);
-
- std::ostringstream str;
- CYOutput out(str, options);
- out << *driver.program_;
-
- std::string code(str.str());
- CYUTF8String json(Run(pool, client_, code));
- // XXX: if this fails we should not try to parse it
-
- CYExpression *result(ParseExpression(json));
- if (result == NULL)
- return NULL;
-
- CYArray *array(dynamic_cast<CYArray *>(result->Primitive(context)));
- if (array == NULL) {
- *out_ << '\n';
- Output(false, json, out_);
- rl_forced_update_display();
- return NULL;
- }
-
- // XXX: use an std::set?
- typedef std::vector<std::string> Completions;
- Completions completions;
-
- std::string common;
- bool rest(false);
-
- CYForEach (element, array->elements_) {
- CYString *string(dynamic_cast<CYString *>(element->value_));
- _assert(string != NULL);
-
- std::string completion;
- if (string->size_ != 0)
- completion.assign(string->value_, string->size_);
- else if (driver.mode_ == CYDriver::AutoMessage)
- completion = "]";
- else
- continue;
-
- completions.push_back(completion);
-
- if (!rest) {
- common = completion;
- rest = true;
- } else {
- size_t limit(completion.size()), size(common.size());
- if (size > limit)
- common = common.substr(0, limit);
- else
- limit = size;
- for (limit = 0; limit != size; ++limit)
- if (common[limit] != completion[limit])
- break;
- if (limit != size)
- common = common.substr(0, limit);
- }
- }
-
- size_t count(completions.size());
- if (count == 0)
- return NULL;
-
- size_t colon(common.find(':'));
- if (colon != std::string::npos)
- common = common.substr(0, colon + 1);
- if (completions.size() == 1)
- common += ' ';
-
- char **results(reinterpret_cast<char **>(malloc(sizeof(char *) * (count + 2))));
-
- results[0] = strdup(common.c_str());
- size_t index(0);
- for (Completions::const_iterator i(completions.begin()); i != completions.end(); ++i)
- results[++index] = strdup(i->c_str());
- results[count + 1] = NULL;
-
- return results;