in public/src/autocomplete.js [602:816]
function getCurrentMethodAndTokenPaths(pos) {
var tokenIter = editor.iterForPosition(pos.row, pos.column);
var startPos = pos;
var bodyTokenPath = [], last_var = "", first_scope = true, ret = {};
var STATES = {
looking_for_key: 0, // looking for a key but without jumping over anything but white space and colon.
looking_for_scope_start: 1, // skip everything until scope start
start: 3
};
var state = STATES.start;
// initialization problems -
var t = tokenIter.getCurrentToken();
if (t) {
if (startPos.column == 0) {
// if we are at the beginning of the line, the current token is the one after cursor, not before which
// deviates from the standard.
t = tokenIter.stepBackward();
state = STATES.looking_for_scope_start;
}
}
else {
if (startPos.column == 0) {
// empty lines do no have tokens, move one back
t = tokenIter.stepBackward();
state = STATES.start;
}
}
var walkedSomeBody = false;
// climb one scope at a time and get the scope key
for (; t && t.type.indexOf("url") == -1 && t.type != "method"; t = tokenIter.stepBackward()) {
if (t.type != "whitespace") {
walkedSomeBody = true;
} // marks we saw something
switch (t.type) {
case "variable":
if (state == STATES.looking_for_key) {
bodyTokenPath.unshift(t.value.trim().replace(/"/g, ''));
}
state = STATES.looking_for_scope_start; // skip everything until the beginning of this scope
break;
case "paren.lparen":
bodyTokenPath.unshift(t.value);
if (state == STATES.looking_for_scope_start) {
// found it. go look for the relevant key
state = STATES.looking_for_key;
}
break;
case "paren.rparen":
// reset he search for key
state = STATES.looking_for_scope_start;
// and ignore this sub scope..
var parenCount = 1;
t = tokenIter.stepBackward();
while (t && parenCount > 0) {
switch (t.type) {
case "paren.lparen":
parenCount--;
break;
case "paren.rparen":
parenCount++;
break;
}
if (parenCount > 0) {
t = tokenIter.stepBackward();
}
}
if (!t) // oops we run out.. we don't know what's up return null;
{
return {};
}
continue;
case "string":
case "constant.numeric":
case "constant.language.boolean":
case "text":
if (state == STATES.start) {
state = STATES.looking_for_key;
}
else if (state == STATES.looking_for_key) {
state = STATES.looking_for_scope_start;
}
break;
case "punctuation.comma":
if (state == STATES.start) {
state = STATES.looking_for_scope_start;
}
break;
case "punctuation.colon":
case "whitespace":
if (state == STATES.start) {
state = STATES.looking_for_key;
}
break; // skip white space
}
}
if (walkedSomeBody && (!bodyTokenPath || bodyTokenPath.length == 0)) {
// we had some content and still no path -> the cursor is position after a closed body -> no auto complete
return {};
}
if (tokenIter.getCurrentTokenRow() == startPos.row) {
if (t.type === "url.part" || t.type === "url.param" || t.type === "url.value") {
// we are on the same line as cursor and dealing with a url. Current token is not part of the context
t = tokenIter.stepBackward();
}
bodyTokenPath = null; // no not on a body line.
}
ret.bodyTokenPath = bodyTokenPath;
ret.urlTokenPath = [];
ret.urlParamsTokenPath = null;
ret.requestStartRow = tokenIter.getCurrentTokenRow();
var curUrlPart;
while (t && isUrlParamsToken(t)) {
switch (t.type) {
case "url.value":
if (_.isArray(curUrlPart)) {
curUrlPart.unshift(t.value);
}
else if (curUrlPart) {
curUrlPart = [t.value, curUrlPart];
}
else {
curUrlPart = t.value;
}
break;
case "url.comma":
if (!curUrlPart) {
curUrlPart = [];
}
else if (!_.isArray(curUrlPart)) {
curUrlPart = [curUrlPart];
}
break;
case "url.param":
var v = curUrlPart;
curUrlPart = {};
curUrlPart[t.value] = v;
break;
case "url.amp":
case "url.questionmark":
if (!ret.urlParamsTokenPath) {
ret.urlParamsTokenPath = [];
}
ret.urlParamsTokenPath.unshift(curUrlPart || {});
curUrlPart = null;
break;
}
t = tokenIter.stepBackward();
}
curUrlPart = null;
while (t && t.type.indexOf("url") != -1) {
switch (t.type) {
case "url.part":
if (_.isArray(curUrlPart)) {
curUrlPart.unshift(t.value);
}
else if (curUrlPart) {
curUrlPart = [t.value, curUrlPart];
}
else {
curUrlPart = t.value;
}
break;
case "url.comma":
if (!curUrlPart) {
curUrlPart = [];
}
else if (!_.isArray(curUrlPart)) {
curUrlPart = [curUrlPart];
}
break;
case "url.slash":
ret.urlTokenPath.unshift(curUrlPart);
curUrlPart = null;
break;
}
t = editor.parser.prevNonEmptyToken(tokenIter);
}
if (curUrlPart) {
ret.urlTokenPath.unshift(curUrlPart);
}
if (!ret.bodyTokenPath && !ret.urlParamsTokenPath) {
if (ret.urlTokenPath.length > 0) {
// started on the url, first token is current token
ret.otherTokenValues = ret.urlTokenPath.splice(-1)[0];
}
}
else {
// mark the url as completed.
ret.urlTokenPath.push(url_pattern_matcher.URL_PATH_END_MARKER);
}
if (t && t.type == "method") {
ret.method = t.value;
}
return ret;
}