c9-core/plugins/c9.ide.language.generic/local_completer.js

117 wiersze
4.2 KiB
JavaScript

define(function(require, exports, module) {
var baseLanguageHandler = require('plugins/c9.ide.language/base_handler');
var completeUtil = require("plugins/c9.ide.language/complete_util");
var MAX_SIZE_BYTES = 5 * 1000 * 1000;
var DEFAULT_SPLIT_REGEX = /[^a-zA-Z_0-9\$]+/;
var MAX_SCORE = 1000000;
var TRUNCATE_LINES = 10000;
var completer = module.exports = Object.create(baseLanguageHandler);
completer.handlesLanguage = function(language) {
return true;
};
completer.handlesEditor = function() {
return this.HANDLES_ANY;
};
completer.getMaxFileSizeSupported = function() {
// More than our conservative default
return MAX_SIZE_BYTES;
};
// For the current document, gives scores to identifiers not on frequency, but on distance from the current prefix
function wordDistanceAnalyzer(doc, pos, prefix, suffix) {
var splitRegex = getSplitRegex(pos);
// Get the current document text, skipping the current word
var linesBefore = doc.getLines(Math.max(0, pos.row - TRUNCATE_LINES / 2), pos.row - 1);
var linesAfter = doc.getLines(pos.row + 1, Math.min(doc.getLength(), pos.row + TRUNCATE_LINES / 2));
var textBefore = linesBefore.join("\n");
var textAfter = linesAfter.join("\n");
var line = getFilteredLine(doc.getLine(pos.row), pos.column, prefix, suffix);
// Split entire document into words
var identifiers = textBefore.split(splitRegex);
var prefixPosition = identifiers.length;
identifiers = identifiers.concat(line.split(splitRegex), textAfter.split(splitRegex));
// Find prefix to find other identifiers close it
var identDict = Object.create(null);
for (var i = 0; i < identifiers.length; i++) {
var ident = identifiers[i];
if (ident.length === 0)
continue;
var distance = Math.max(prefixPosition, i) - Math.min(prefixPosition, i);
// Score substracted from 100000 to force descending ordering
if (identDict[ident])
identDict[ident] = Math.max(MAX_SCORE - distance, identDict[ident]);
else
identDict[ident] = MAX_SCORE - distance;
}
return identDict;
}
function getSplitRegex(pos) {
var idRegex = completer.$getIdentifierRegex(pos);
if (!idRegex || !idRegex.source.match(/\[[^^][^\]]*\]/))
return DEFAULT_SPLIT_REGEX;
return new RegExp("[^" + idRegex.source.substr(1, idRegex.source.length - 2) + "]+");
}
function getFilteredLine(line, column, prefix, suffix) {
return line.substr(0, column - prefix.length)
+ line.substr(column + suffix.length);
}
function analyze(doc, pos) {
var line = doc.getLine(pos.row);
var prefix = completeUtil.retrievePrecedingIdentifier(line, pos.column, completer.$getIdentifierRegex());
var suffix = completeUtil.retrieveFollowingIdentifier(line, pos.column, completer.$getIdentifierRegex());
return wordDistanceAnalyzer(doc, pos, prefix, suffix);
}
completer.complete = function(doc, fullAst, pos, options, callback) {
var identDict = analyze(doc, pos);
var line = doc.getLine(pos.row);
var regex = this.$getIdentifierRegex(pos);
var identifier = completeUtil.retrievePrecedingIdentifier(line, pos.column, regex);
var fullIdentifier = identifier + completeUtil.retrieveFollowingIdentifier(line, pos.column, regex);
var allIdentifiers = [];
for (var ident in identDict) {
allIdentifiers.push(ident);
}
var matches = completeUtil.findCompletions(identifier, allIdentifiers);
matches = matches.slice(0, 100); // limits results for performance
var allowSlashes = regex && regex.source.match(/^\[.*\/.*]/);
var allowDollars = regex && regex.source.match(/\$\$/);
callback(null, matches.filter(function(m) {
if (allowDollars) {
return !m.match(allowSlashes ? /^([0-9_\/]|\/[^\/])/ : /^[0-9_\/]/);
}
else {
return !m.match(allowSlashes ? /^([0-9$_\/]|\/[^\/])/ : /^[0-9$_\/]/);
}
}).map(function(m) {
return {
name: m,
replaceText: m,
icon: null,
score: m === fullIdentifier ? MAX_SCORE : identDict[m],
isGeneric: true,
priority: 0,
$source: "local"
};
}));
};
});