kopia lustrzana https://github.com/c9/core
298 wiersze
10 KiB
JavaScript
298 wiersze
10 KiB
JavaScript
/**
|
|
* File name and definition search for the Cloud9
|
|
*
|
|
* @copyright 2013, Ajax.org B.V.
|
|
*/
|
|
|
|
define(function(require, exports, module) {
|
|
|
|
var Heap = require("./heap");
|
|
|
|
var fileTypes = {
|
|
"js": 1, "json": 11, "css": 5, "less": 5, "scss": 5, "sass": 5, "xml": 11,
|
|
"rdf": 15, "rss": 15, "svg": 5, "wsdl": 11, "xslt": 5, "atom": 5,
|
|
"mathml": 5, "mml": 5, "php": 1, "phtml": 1, "html": 5, "xhtml": 5,
|
|
"coffee": 1, "py": 1, "ru": 1, "gemspec": 5, "rake": 5, "rb": 1, "c": 1,
|
|
"cc": 1, "cpp": 1, "cxx": 1, "h": 2, "hh": 2, "hpp": 2, "cs": 1, "java": 1,
|
|
"clj": 1, "groovy": 1, "logic": 1, "lql": 1, "scala": 1, "ml": 1, "mli": 1, "md": 2,
|
|
"markdown": 2, "textile": 5, "latex": 5, "tex": 5, "ltx": 5, "lua": 1,
|
|
"pl": 1, "pm": 2, "ps1": 1, "cfm": 1, "sql": 2, "sh": 1, "bash": 1,
|
|
"bmp": 10, "djv": 10, "djvu": 10, "gif": 10, "ico": 10, "jpg": 10,
|
|
"jpeg": 10, "pbm": 10, "pgm": 10, "png": 10, "pnm": 10, "ppm": 10,
|
|
"psd": 10, "tiff": 10, "xbm": 10, "xpm": 10,
|
|
"go": 5, "hx": 5, "yaml": 5, "psql": 2
|
|
};
|
|
|
|
/**
|
|
* Search through a list of filenames.
|
|
*/
|
|
module.exports.fileSearch = function(filelist, keyword) {
|
|
if (!keyword) keyword = "";
|
|
|
|
var klen = keyword.length;
|
|
var keywordLower = keyword.toLowerCase();
|
|
|
|
/**
|
|
* FULL MATCHES >= 50
|
|
* full filename with extension 1000
|
|
* name part without the extension 201
|
|
* start of filename 200
|
|
* part of filename 100
|
|
* depth of path (or length to optimize) 200 - 10 * count("/")
|
|
* full part of path 50
|
|
*
|
|
* SCATTERED MATCHES <= 45
|
|
* number of match groups 20 - 3 * #groups
|
|
* path depth 15 - 2 * count("/")
|
|
* match diff 10 - len(diff)
|
|
*
|
|
* Extension weight -1 * lut[ext]
|
|
*/
|
|
|
|
var type = "value";
|
|
var toS = function() {
|
|
return this[type];
|
|
};
|
|
|
|
var newlist = [];
|
|
var l = filelist.length;
|
|
var big = l > 50000;
|
|
|
|
var name, res = big ? [] : new Heap(), value, ext, displayName;
|
|
for (var i = 0, s, j, k, q, p, m, n; i < l; i++) {
|
|
displayName = filelist[i];
|
|
name = displayName.toLowerCase();
|
|
|
|
// We only add items that have the keyword in it's path
|
|
value = 0;
|
|
if ((j = name.lastIndexOf(keywordLower)) > -1) {
|
|
if (big) {
|
|
res.push(displayName);
|
|
continue;
|
|
}
|
|
// We prioritize ones that have the name in the filename
|
|
if (j > (q = name.lastIndexOf("/"))) {
|
|
k = name.lastIndexOf("/" + keywordLower);
|
|
if (k > -1) {
|
|
// We give first prio to full filename matches
|
|
if (name.length == klen + 1 + k)
|
|
value += 1000;
|
|
|
|
// Then to match of name prior to extension
|
|
else if (name.lastIndexOf(".") == k + klen + 1)
|
|
value += 201;
|
|
|
|
// Then to matches from the start of the filename
|
|
else if (k == q)
|
|
value += 200;
|
|
|
|
// Then anywhere in the filename
|
|
else
|
|
value += 100;
|
|
}
|
|
|
|
// The shorter the path depth, the higher prio we give
|
|
value += 200 - Math.min(name.split("/").length * 10, 150);
|
|
}
|
|
// Detect a path search
|
|
else if (keywordLower.indexOf("/") > -1) {
|
|
var idx = keywordLower.lastIndexOf("/");
|
|
var rest = name.substr(j + idx + 1);
|
|
var file = keywordLower.substr(idx + 1);
|
|
|
|
// We give prio to full path matches
|
|
if (j === 0)
|
|
value += 1000;
|
|
|
|
// When searching for a file extension,
|
|
if (file.indexOf(".") > -1) {
|
|
// Prioritize filename matches
|
|
if (rest.indexOf(file) === 0)
|
|
value += 200;
|
|
|
|
// The shorter the filename length, the higher prio we give
|
|
value += 200 - Math.min((rest.length - file.length) * 10, 150);
|
|
}
|
|
// When the full filename is matched, give a higher prio
|
|
else if (rest.substr(file.length).match(/^\..*(\/|$)/))
|
|
value += 201;
|
|
else
|
|
value += 50;
|
|
}
|
|
// Then the rest
|
|
else
|
|
value += 50;
|
|
}
|
|
// Check for spatial matches
|
|
else {
|
|
if (big || name.split("/").length > 10)
|
|
continue;
|
|
|
|
var result;
|
|
result = matchPath(name, keywordLower);
|
|
if (!result.length || result.length > 20)
|
|
continue;
|
|
|
|
var matched = name.substring(result[0].val.length);
|
|
// The less the number of groups matched, the higher prio we give
|
|
value += 20 - Math.min((result.length - 2) * 3, 19);
|
|
// The shorter the path depth, the higher prio we give
|
|
value += 15 - Math.min(name.split("/").length * 2, 14);
|
|
// The shorter the match diff, the higher prio we give
|
|
value += 10 - Math.min(matched.length - keyword.length, 9);
|
|
value += 20; // extension
|
|
}
|
|
|
|
if (value > 0) {
|
|
newlist.push(displayName);
|
|
|
|
// Check extension
|
|
s = name.lastIndexOf(".");
|
|
if (s > -1)
|
|
value -= 10 * (fileTypes[name.substr(s + 1)] || 0) || 20;
|
|
else
|
|
value -= 20;
|
|
|
|
if (res.size() === 100 && value > res.min().value)
|
|
res.pop();
|
|
if (res.size() < 100)
|
|
res.push({
|
|
toString: toS,
|
|
value: value,
|
|
name: displayName
|
|
});
|
|
}
|
|
}
|
|
|
|
if (big) {
|
|
res.newlist = res;
|
|
return res;
|
|
}
|
|
|
|
var ret = [];
|
|
while (res.size())
|
|
ret.unshift(res.pop().name);
|
|
|
|
ret.newlist = newlist;
|
|
|
|
return ret;
|
|
};
|
|
|
|
// function score (e, term) {
|
|
// var c = 0,
|
|
// d = term.length,
|
|
// f = e.length,
|
|
// g, h, i = 1,
|
|
// j;
|
|
// if (e == term) return 1;
|
|
// for (var k = 0, l, m, n, o, p, q; k < d; ++k) {
|
|
// n = term[k], o = e.indexOf(n.toLowerCase()), p = e.indexOf(n.toUpperCase()), q = Math.min(o, p), m = q > -1 ? q : Math.max(o, p);
|
|
// if (m === -1) {
|
|
// return 0;
|
|
// }
|
|
// l = .1, e[m] === n && (l += .1), m === 0 ? (l += .6, k === 0 && (g = 1)) : e.charAt(m - 1) === " " && (l += .8), e = e.substring(m + 1, f), c += l
|
|
// }
|
|
// return h = c / d, j = (h * (d / f) + h) / 2, j /= i, g && j + .15 < 1 && (j += .15), j
|
|
// };
|
|
|
|
var treeSearch = module.exports.treeSearch = function(tree, keyword, caseInsensitive, results, head, indexProperty) {
|
|
if (caseInsensitive)
|
|
keyword = keyword.toLowerCase();
|
|
|
|
results = results || [];
|
|
head = head || 0;
|
|
|
|
for (var i = 0; i < tree.length; i++) {
|
|
var node = tree[i];
|
|
var name = indexProperty
|
|
? node[indexProperty] || ""
|
|
: node.name || node.label || node.caption || (typeof node == "string" ? node : "");
|
|
|
|
if (caseInsensitive)
|
|
name = name.toLowerCase();
|
|
|
|
var index = name.indexOf(keyword);
|
|
if (index === -1) {
|
|
if (node.items && !node.keepChildren)
|
|
results = treeSearch(node.items, keyword, caseInsensitive, results, head);
|
|
continue;
|
|
}
|
|
|
|
var result = node.clone ? node.clone() : {};
|
|
result.items = node.items
|
|
? (result.keepChildren
|
|
? result.items
|
|
: treeSearch(node.items, keyword, caseInsensitive))
|
|
: [];
|
|
|
|
if (!node.clone) {
|
|
for (var p in node) {
|
|
if (node[p] && p !== "items")
|
|
result[p] = node[p];
|
|
}
|
|
}
|
|
|
|
if (index === 0) {
|
|
results.splice(head, 0, result);
|
|
head++;
|
|
}
|
|
else {
|
|
results.push(result);
|
|
}
|
|
}
|
|
return results;
|
|
};
|
|
|
|
var matchPath = module.exports.matchPath = function (path, keyword) {
|
|
var result = [];
|
|
var pathSplits = path.split("/");
|
|
// Optimization
|
|
if (pathSplits.length > 4) {
|
|
pathSplits = [pathSplits.slice(0, pathSplits.length - 4).join("/") + "/"]
|
|
.concat(pathSplits.slice(pathSplits.length - 4, pathSplits.length));
|
|
if (pathSplits[0] == "/")
|
|
pathSplits[0] = "";
|
|
}
|
|
var value = "";
|
|
var k, i, j = -1;
|
|
for (k = pathSplits.length - 1; k >= 0 && !result.length; k--) {
|
|
value = (k > 0 ? "/" : "") + pathSplits[k] + value;
|
|
// find matched parts
|
|
var matchI = null;
|
|
var missI = null;
|
|
for (i = 0, j = 0; i < value.length && j < keyword.length; i++) {
|
|
if (value[i] === keyword[j]) {
|
|
matchI = matchI === null ? i : matchI;
|
|
j++;
|
|
if (missI !== null) {
|
|
result.push({ val: value.substring(missI, i) });
|
|
missI = null;
|
|
}
|
|
}
|
|
else {
|
|
missI = missI === null ? i : missI;
|
|
if (matchI !== null) {
|
|
result.push({ match: true, val: value.substring(matchI, i) });
|
|
matchI = null;
|
|
}
|
|
}
|
|
}
|
|
if (j !== keyword.length) {
|
|
result = [];
|
|
continue;
|
|
}
|
|
|
|
if (missI !== null)
|
|
result.push({ val: value.substring(missI, i) });
|
|
if (matchI !== null)
|
|
result.push({ match: true, val: value.substring(matchI, i) });
|
|
result.push({ val: value.substring(i, value.length) });
|
|
// Add the first non matched part if exists
|
|
if (k)
|
|
result.unshift({ val: pathSplits.slice(0, k).join('/') });
|
|
}
|
|
return result;
|
|
};
|
|
|
|
});
|