Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

LSP Find References Feature #14693

Merged
merged 14 commits into from
Apr 15, 2019
1 change: 1 addition & 0 deletions src/brackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ define(function (require, exports, module) {
//load language features
require("features/ParameterHintsManager");
require("features/JumpToDefManager");
require("features/FindReferencesManager");

// Load modules that self-register and just need to get included in the main project
require("command/DefaultMenus");
Expand Down
8 changes: 6 additions & 2 deletions src/extensions/default/PhpTooling/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ define(function (require, exports, module) {
CodeHintManager = brackets.getModule("editor/CodeHintManager"),
ParameterHintManager = brackets.getModule("features/ParameterHintsManager"),
JumpToDefManager = brackets.getModule("features/JumpToDefManager"),
FindReferencesManager = brackets.getModule("features/FindReferencesManager"),
CodeInspection = brackets.getModule("language/CodeInspection"),
DefaultProviders = brackets.getModule("languageTools/DefaultProviders"),
CodeHintsProvider = require("CodeHintsProvider").CodeHintsProvider,
Expand Down Expand Up @@ -61,7 +62,8 @@ define(function (require, exports, module) {
chProvider,
phProvider,
lProvider,
jdProvider;
jdProvider,
refProvider;
shubhsnov marked this conversation as resolved.
Show resolved Hide resolved

PreferencesManager.definePreference("php", "object", phpConfig, {
description: Strings.DESCRIPTION_PHP_TOOLING_CONFIGURATION
Expand Down Expand Up @@ -101,11 +103,13 @@ define(function (require, exports, module) {
chProvider = new CodeHintsProvider(_client),
phProvider = new DefaultProviders.ParameterHintsProvider(_client),
lProvider = new DefaultProviders.LintingProvider(_client),
jdProvider = new DefaultProviders.JumpToDefProvider(_client);
jdProvider = new DefaultProviders.JumpToDefProvider(_client),
refProvider = new DefaultProviders.ReferencesProvider(_client);

JumpToDefManager.registerJumpToDefProvider(jdProvider, ["php"], 0);
CodeHintManager.registerHintProvider(chProvider, ["php"], 0);
ParameterHintManager.registerHintProvider(phProvider, ["php"], 0);
FindReferencesManager.registerFindReferencesProvider(refProvider, ["php"], 0);
CodeInspection.register(["php"], {
name: "",
scanFileAsync: lProvider.getInspectionResultsAsync.bind(lProvider)
Expand Down
17 changes: 17 additions & 0 deletions src/extensions/default/PhpTooling/unittest-files/test/test2.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,22 @@ function watchparameterhint() {
$A11()
fopen("",)
watchparameterhint()


function watchReferences() {
echo "Hello World!";
}

watchReferences();

watchReferences();


function ReferencesInMultipleFile() {
echo "Hello World!";
}

ReferencesInMultipleFile();

ReferencesInMultipleFile();
?>
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ class testA
protected $B = [
'A1', 'A2'
];
}
}

ReferencesInMultipleFile();
140 changes: 140 additions & 0 deletions src/extensions/default/PhpTooling/unittests.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,40 @@ define(function (require, exports, module) {

}

function expectReferences(referencesExpected) {
var refPromise,
results = null,
complete = false;
runs(function () {
refPromise = (new DefaultProviders.ReferencesProvider(phpToolingExtension.getClient())).getReferences();
refPromise.done(function (resp) {
complete = true;
results = resp;
}).fail(function(){
complete = true;
});
});

waitsFor(function () {
return complete;
}, "Expected Reference Promise did not resolve", 3000);

if(referencesExpected === null) {
expect(results).toBeNull();
return;
}

runs(function() {
expect(results.numFiles).toBe(referencesExpected.numFiles);
expect(results.numMatches).toBe(referencesExpected.numMatches);
expect(results.allResultsAvailable).toBe(referencesExpected.allResultsAvailable);
expect(results.results).not.toBeNull();
for(var key in results.keys) {
expect(results.results.key).toBe(referencesExpected.results.key);
}
});
}

/**
* Check the presence of Error Prompt on Brackets Window
*/
Expand Down Expand Up @@ -476,6 +510,112 @@ define(function (require, exports, module) {
});
});

it("should not show any references", function () {
var start = { line: 6, ch: 4 };

runs(function () {
testEditor = EditorManager.getActiveEditor();
testEditor.setCursorPos(start);
expectReferences(null);
});
});

it("should show reference present in single file", function () {
var start = { line: 22, ch: 18 },
results = {};

runs(function () {
testEditor = EditorManager.getActiveEditor();
testEditor.setCursorPos(start);
results[testFolder + "test/test2.php"] = {matches: [
{
start: {line: 27, ch: 0},
end: {line: 27, ch: 18},
line: "watchparameterhint()"
}
]
};
expectReferences({
numFiles: 1,
numMatches: 1,
allResultsAvailable: true,
queryInfo: "watchparameterhint",
keys: [testFolder + "test/test2.php"],
results: results
});
});
});

it("should show references present in single file", function () {
var start = { line: 34, ch: 8 },
results = {};

runs(function () {
testEditor = EditorManager.getActiveEditor();
testEditor.setCursorPos(start);
results[testFolder + "test/test2.php"] = {matches: [
{
start: {line: 34, ch: 0},
end: {line: 34, ch: 17},
line: "watchReferences();"
},
{
start: {line: 36, ch: 0},
end: {line: 36, ch: 17},
line: "watchReferences();"
}
]
};
expectReferences({
numFiles: 1,
numMatches: 2,
allResultsAvailable: true,
queryInfo: "watchparameterhint",
keys: [testFolder + "test/test2.php"],
results: results
});
});
});

it("should show references present in multiple files", function () {
var start = { line: 39, ch: 21 },
results = {};

runs(function () {
testEditor = EditorManager.getActiveEditor();
testEditor.setCursorPos(start);
results[testFolder + "test/test2.php"] = {matches: [
{
start: {line: 34, ch: 0},
end: {line: 34, ch: 26},
line: "watchReferences();"
},
{
start: {line: 36, ch: 0},
end: {line: 36, ch: 26},
line: "watchReferences();"
}
]
};
results[testFolder + "test/test3.php"] = {matches: [
{
start: {line: 11, ch: 0},
end: {line: 11, ch: 26},
line: "watchReferences();"
}
]
};
expectReferences({
numFiles: 2,
numMatches: 3,
allResultsAvailable: true,
queryInfo: "watchparameterhint",
keys: [testFolder + "test/test2.php", testFolder + "test/test3.php"],
results: results
});
});
});

it("should jump to earlier defined variable", function () {
var start = { line: 4, ch: 2 };

Expand Down
148 changes: 148 additions & 0 deletions src/features/FindReferencesManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Copyright (c) 2019 - present Adobe. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/

define(function (require, exports, module) {
"use strict";

var AppInit = require("utils/AppInit"),
CommandManager = require("command/CommandManager"),
EditorManager = require("editor/EditorManager"),
Menus = require("command/Menus"),
ProviderRegistrationHandler = require("features/PriorityBasedRegistration").RegistrationHandler,
SearchResultsView = require("search/SearchResultsView").SearchResultsView,
SearchModel = require("search/SearchModel").SearchModel,
Strings = require("strings");

var _providerRegistrationHandler = new ProviderRegistrationHandler(),
registerFindReferencesProvider = _providerRegistrationHandler.registerProvider.bind(
_providerRegistrationHandler
),
removeFindReferencesProvider = _providerRegistrationHandler.removeProvider.bind(_providerRegistrationHandler);

var SHOW_FIND_REFERENCES_CMD_ID = "showReferences",
shubhsnov marked this conversation as resolved.
Show resolved Hide resolved
KeyboardPrefs = JSON.parse(require("text!features/keyboard.json"));

var searchModel = new SearchModel(),
_resultsView;

function _getReferences(provider, hostEditor, pos) {
var result = new $.Deferred();

if(!provider) {
shubhsnov marked this conversation as resolved.
Show resolved Hide resolved
return result.reject();
}

provider.getReferences(hostEditor, pos)
.done(function (rcvdObj) {

searchModel.results = rcvdObj.results;
searchModel.numFiles = rcvdObj.numFiles;
searchModel.numMatches = rcvdObj.numMatches;
searchModel.allResultsAvailable = true;
searchModel.setQueryInfo({query: rcvdObj.queryInfo, caseSensitive: true, isRegExp: false});
result.resolve();
}).fail(function (){
result.reject();
});
return result.promise();

}

function _openReferencesPanel() {
var editor = EditorManager.getActiveEditor(),
pos = editor ? editor.getCursorPos() : null,
referencesPromise,
result = new $.Deferred(),
errorMsg = Strings.REFERENCES_NO_RESULTS,
referencesProvider;

var language = editor.getLanguageForSelection(),
enabledProviders = _providerRegistrationHandler.getProvidersForLanguageId(language.getId());

enabledProviders.some(function (item, index) {
if (item.provider.hasReferences(editor)) {
referencesProvider = item.provider;
return true;
}
});

referencesPromise = _getReferences(referencesProvider, editor, pos);

// If one of them will provide a widget, show it inline once ready
if (referencesPromise) {
referencesPromise.done(function () {
_resultsView.open();
}).fail(function () {
_resultsView.close();
editor.displayErrorMessageAtCursor(errorMsg);
result.reject();
});
} else {
_resultsView.close();
editor.displayErrorMessageAtCursor(errorMsg);
result.reject();
}

return result.promise();
}

/**
* @private
* Clears any previous search information, removing update listeners and clearing the model.
*/
function _clearSearch() {
searchModel.clear();
}

AppInit.appReady(function () {
shubhsnov marked this conversation as resolved.
Show resolved Hide resolved
_resultsView = new SearchResultsView(
searchModel,
"reference-in-files-results",
"reference-in-files.results",
"reference"
);
_resultsView
.on("close", function () {
_clearSearch();
})
.on("getNextPage", function () {
if (searchModel.hasResults()) {
_resultsView.showNextPage();
}
})
.on("getLastPage", function () {
if (searchModel.hasResults()) {
_resultsView.showLastPage();
}
});

CommandManager.register(Strings.FIND_ALL_REFERENCES, SHOW_FIND_REFERENCES_CMD_ID, _openReferencesPanel);
Menus.getContextMenu(Menus.ContextMenuIds.EDITOR_MENU).addMenuItem(
SHOW_FIND_REFERENCES_CMD_ID,
KeyboardPrefs.findAllReferences
);
});

exports.registerFindReferencesProvider = registerFindReferencesProvider;
exports.removeFindReferencesProvider = removeFindReferencesProvider;
});
13 changes: 13 additions & 0 deletions src/features/keyboard.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
shubhsnov marked this conversation as resolved.
Show resolved Hide resolved
"findAllReferences": [
{
"key": "Ctrl-Shift-R", "platform": "mac"
},
{
"key": "Ctrl-Shift-R", "platform": "win"
},
{
shubhsnov marked this conversation as resolved.
Show resolved Hide resolved
"key": "Ctrl-Shift-R", "platform": "linux"
}
]
}
Loading