atom-nuclide
Version:
A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.
243 lines (207 loc) • 9.35 kB
JavaScript
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var readFileContents = _asyncToGenerator(function* (uri) {
var localPath = (_commonsNodeNuclideUri2 || _commonsNodeNuclideUri()).default.getPath(uri);
var contents = undefined;
try {
contents = (yield (0, (_nuclideRemoteConnection2 || _nuclideRemoteConnection()).getFileSystemServiceByNuclideUri)(uri).readFile(localPath)).toString('utf8');
} catch (e) {
(0, (_nuclideLogging2 || _nuclideLogging()).getLogger)().error('find-references: could not load file ' + uri, e);
return null;
}
return contents;
});
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { var callNext = step.bind(null, 'next'); var callThrow = step.bind(null, 'throw'); function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(callNext, callThrow); } } callNext(); }); }; }
/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the LICENSE file in
* the root directory of this source tree.
*/
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var _commonsNodeCollection2;
function _commonsNodeCollection() {
return _commonsNodeCollection2 = require('../../commons-node/collection');
}
var _nuclideLogging2;
function _nuclideLogging() {
return _nuclideLogging2 = require('../../nuclide-logging');
}
var _nuclideRemoteConnection2;
function _nuclideRemoteConnection() {
return _nuclideRemoteConnection2 = require('../../nuclide-remote-connection');
}
var _commonsNodeNuclideUri2;
function _commonsNodeNuclideUri() {
return _commonsNodeNuclideUri2 = _interopRequireDefault(require('../../commons-node/nuclideUri'));
}
var FRAGMENT_GRAMMARS = {
'text.html.hack': 'source.hackfragment',
'text.html.php': 'source.hackfragment'
};
function compareLocation(x, y) {
var lineDiff = x.line - y.line;
if (lineDiff) {
return lineDiff;
}
return x.column - y.column;
}
function compareReference(x, y) {
return compareLocation(x.start, y.start) || compareLocation(x.end, y.end);
}
function addReferenceGroup(groups, references, startLine, endLine) {
if (references.length) {
groups.push({ references: references, startLine: startLine, endLine: endLine });
}
}
var FindReferencesModel = (function () {
/**
* @param basePath Base path of the project. Used to display paths in a friendly way.
* @param symbolName The name of the symbol we're finding references for.
* @param references A list of references to `symbolName`.
* @param options See `FindReferencesOptions`.
*/
function FindReferencesModel(basePath, symbolName, references, options) {
_classCallCheck(this, FindReferencesModel);
this._basePath = basePath;
this._symbolName = symbolName;
this._referenceCount = references.length;
this._options = options || {};
this._groupReferencesByFile(references);
}
/**
* The main public entry point.
* Returns a list of references, grouped by file (with previews),
* according to the given offset and limit.
* References in each file are grouped together if they're adjacent.
*/
_createClass(FindReferencesModel, [{
key: 'getFileReferences',
value: _asyncToGenerator(function* (offset, limit) {
var fileReferences = yield Promise.all(this._references.slice(offset, offset + limit).map(this._makeFileReferences.bind(this)));
return (0, (_commonsNodeCollection2 || _commonsNodeCollection()).arrayCompact)(fileReferences);
})
}, {
key: 'getBasePath',
value: function getBasePath() {
return this._basePath;
}
}, {
key: 'getSymbolName',
value: function getSymbolName() {
return this._symbolName;
}
}, {
key: 'getReferenceCount',
value: function getReferenceCount() {
return this._referenceCount;
}
}, {
key: 'getFileCount',
value: function getFileCount() {
return this._references.length;
}
}, {
key: 'getPreviewContext',
value: function getPreviewContext() {
return this._options.previewContext || 1;
}
}, {
key: '_groupReferencesByFile',
value: function _groupReferencesByFile(references) {
// 1. Group references by file.
var refsByFile = new Map();
for (var reference of references) {
var fileReferences = refsByFile.get(reference.uri);
if (fileReferences == null) {
refsByFile.set(reference.uri, fileReferences = []);
}
fileReferences.push(reference);
}
// 2. Group references within each file.
this._references = [];
for (var entry of refsByFile) {
var _entry = _slicedToArray(entry, 2);
var fileUri = _entry[0];
var entryReferences = _entry[1];
entryReferences.sort(compareReference);
// Group references that are <= 1 line apart together.
var groups = [];
var curGroup = [];
var curStartLine = -11;
var curEndLine = -11;
for (var ref of entryReferences) {
if (ref.start.line <= curEndLine + 1 + this.getPreviewContext()) {
// Remove references with the same range (happens in C++ with templates)
if (curGroup.length > 0 && compareReference(curGroup[curGroup.length - 1], ref) !== 0) {
curGroup.push(ref);
curEndLine = Math.max(curEndLine, ref.end.line);
} else {
this._referenceCount--;
}
} else {
addReferenceGroup(groups, curGroup, curStartLine, curEndLine);
curGroup = [ref];
curStartLine = ref.start.line;
curEndLine = ref.end.line;
}
}
addReferenceGroup(groups, curGroup, curStartLine, curEndLine);
this._references.push([fileUri, groups]);
}
// Finally, sort by file name.
this._references.sort(function (x, y) {
return x[0].localeCompare(y[0]);
});
}
/**
* Fetch file previews and expand line ranges with context.
*/
}, {
key: '_makeFileReferences',
value: _asyncToGenerator(function* (fileReferences) {
var _this = this;
var uri = fileReferences[0];
var refGroups = fileReferences[1];
var fileContents = yield readFileContents(uri);
if (!fileContents) {
return null;
}
var fileLines = fileContents.split('\n');
var previewText = [];
refGroups = refGroups.map(function (group) {
var references = group.references;
var startLine = group.startLine;
var endLine = group.endLine;
// Expand start/end lines with context.
startLine = Math.max(startLine - _this.getPreviewContext(), 1);
endLine = Math.min(endLine + _this.getPreviewContext(), fileLines.length);
// However, don't include blank lines.
while (startLine < endLine && fileLines[startLine - 1] === '') {
startLine++;
}
while (startLine < endLine && fileLines[endLine - 1] === '') {
endLine--;
}
previewText.push(fileLines.slice(startLine - 1, endLine).join('\n'));
return { references: references, startLine: startLine, endLine: endLine };
});
var grammar = atom.grammars.selectGrammar(uri, fileContents);
var fragmentGrammar = FRAGMENT_GRAMMARS[grammar.scopeName];
if (fragmentGrammar) {
grammar = atom.grammars.grammarForScopeName(fragmentGrammar) || grammar;
}
return {
uri: uri,
grammar: grammar,
previewText: previewText,
refGroups: refGroups
};
})
}]);
return FindReferencesModel;
})();
module.exports = FindReferencesModel;
// Lines of context to show around each preview block. Defaults to 1.