From 641f9dd1055d04239795ab4fbe35d3e4768f7348 Mon Sep 17 00:00:00 2001 From: niteskum Date: Wed, 10 Apr 2019 18:42:38 +0530 Subject: [PATCH 01/11] LSP Find References Feature --- src/brackets.js | 1 + src/extensions/default/PhpTooling/main.js | 8 +- src/features/FindReferencesManager.js | 151 ++++++++++++++++++++++ src/features/keyboard.json | 13 ++ src/languageTools/DefaultProviders.js | 66 ++++++++++ src/nls/root/strings.js | 5 +- src/search/SearchResultsView.js | 14 +- 7 files changed, 253 insertions(+), 5 deletions(-) create mode 100644 src/features/FindReferencesManager.js create mode 100644 src/features/keyboard.json diff --git a/src/brackets.js b/src/brackets.js index 4365249ef05..a9935b1589b 100644 --- a/src/brackets.js +++ b/src/brackets.js @@ -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"); diff --git a/src/extensions/default/PhpTooling/main.js b/src/extensions/default/PhpTooling/main.js index d2ecc966bb1..59b89d521d1 100755 --- a/src/extensions/default/PhpTooling/main.js +++ b/src/extensions/default/PhpTooling/main.js @@ -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, @@ -61,7 +62,8 @@ define(function (require, exports, module) { chProvider, phProvider, lProvider, - jdProvider; + jdProvider, + refProvider; PreferencesManager.definePreference("php", "object", phpConfig, { description: Strings.DESCRIPTION_PHP_TOOLING_CONFIGURATION @@ -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) diff --git a/src/features/FindReferencesManager.js b/src/features/FindReferencesManager.js new file mode 100644 index 00000000000..d90b856d2b7 --- /dev/null +++ b/src/features/FindReferencesManager.js @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2013 - present Adobe Systems Incorporated. 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 = "showrReferences", + KeyboardPrefs = JSON.parse(require("text!features/keyboard.json")); + + var searchModel = new SearchModel(), + _resultsView; + + function _getReferences(provider, hostEditor, pos) { + var result = new $.Deferred(); + + 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}); + //searchModel.fireChanged(); + 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, + referencesProvider, + defaultErrorMsg = ""; + + 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); + + // Use default error message if none other provided + errorMsg = errorMsg || defaultErrorMsg; + + // If one of them will provide a widget, show it inline once ready + if (referencespromise) { + referencespromise.done(function () { + _resultsView.open(); + }).fail(function () { + editor.displayErrorMessageAtCursor(errorMsg); + result.reject(); + }); + } else { + 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 () { + + var model = searchModel; + _resultsView = new SearchResultsView( + model, + "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; +}); diff --git a/src/features/keyboard.json b/src/features/keyboard.json new file mode 100644 index 00000000000..635d176d1dc --- /dev/null +++ b/src/features/keyboard.json @@ -0,0 +1,13 @@ +{ + "findAllReferences": [ + { + "key": "Ctrl-Shift-R", "platform": "mac" + }, + { + "key": "Ctrl-Shift-R", "platform": "win" + }, + { + "key": "Ctrl-Shift-R", "platform": "linux" + } + ] +} \ No newline at end of file diff --git a/src/languageTools/DefaultProviders.js b/src/languageTools/DefaultProviders.js index 6339ace3277..54b171bbeef 100644 --- a/src/languageTools/DefaultProviders.js +++ b/src/languageTools/DefaultProviders.js @@ -30,6 +30,7 @@ define(function (require, exports, module) { var _ = brackets.getModule("thirdparty/lodash"); var EditorManager = require('editor/EditorManager'), + DocumentManager = require('document/DocumentManager'), ExtensionUtils = require("utils/ExtensionUtils"), CommandManager = require("command/CommandManager"), Commands = require("command/Commands"), @@ -402,8 +403,73 @@ define(function (require, exports, module) { return this._results.get(filePath); }; + function ReferencesProvider(client) { + this.client = client; + } + + ReferencesProvider.prototype.hasReferences = function() { + return true; + }; + + ReferencesProvider.prototype.getReferences = function() { + var editor = EditorManager.getActiveEditor(), + pos = editor.getCursorPos(), + docPath = editor.document.file._path, + result = $.Deferred(); + + if (this.client) { + this.client.findReferences({ + filePath: docPath, + cursorPos: pos + }).done(function(msgObj){ + if(msgObj ) { + var referenceModel = {}; + referenceModel.results = {}; + referenceModel.numFiles = 0; + var fulfilled = 0, + queryInfo = ""; + msgObj.forEach((element, i) => { + var filePath = PathConverters.uriToPath(element.uri); + DocumentManager.getDocumentForPath(filePath) + .done(function(doc) { + var startRange = {line: element.range.start.line, ch: element.range.start.character}; + var endRange = {line: element.range.end.line, ch: element.range.end.character}; + var match = { + start: startRange, + end: endRange, + line: doc.getLine(element.range.start.line) + }; + if(!referenceModel.results[filePath]) { + referenceModel.numFiles = referenceModel.numFiles + 1; + referenceModel.results[filePath] = {"matches": []}; + } + if(!queryInfo) { + referenceModel.queryInfo = doc.getRange(startRange, endRange); + } + referenceModel.results[filePath]["matches"].push(match); + }).always(function() { + fulfilled++; + if(fulfilled === msgObj.length) { + referenceModel.numMatches = msgObj.length; + referenceModel.allResultsAvailable = true; + result.resolve(referenceModel); + } + }); + }); + } else { + result.reject(); + } + }).fail(function(){ + result.reject(); + }); + return result.promise(); + } + return result.reject(); + }; + exports.CodeHintsProvider = CodeHintsProvider; exports.ParameterHintsProvider = ParameterHintsProvider; exports.JumpToDefProvider = JumpToDefProvider; exports.LintingProvider = LintingProvider; + exports.ReferencesProvider = ReferencesProvider; }); diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index c66291168a0..d4a368feb2e 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -888,5 +888,8 @@ define({ "OPEN_PREFERENNCES" : "Open Preferences", //Strings for LanguageTools Preferences - LANGUAGE_TOOLS_PREFERENCES : "Preferences for Language Tools" + "LANGUAGE_TOOLS_PREFERENCES" : "Preferences for Language Tools", + "FIND_ALL_REFERENCES" : "Find All References", + "FIND_IN_FILES_REFERENCES" : "references", + "FIND_IN_FILES_REFERENCE" : "reference" }); diff --git a/src/search/SearchResultsView.js b/src/search/SearchResultsView.js index 13eb92790a0..80db2aee3c4 100644 --- a/src/search/SearchResultsView.js +++ b/src/search/SearchResultsView.js @@ -72,14 +72,16 @@ define(function (require, exports, module) { * @param {SearchModel} model The model that this view is showing. * @param {string} panelID The CSS ID to use for the panel. * @param {string} panelName The name to use for the panel, as passed to WorkspaceManager.createBottomPanel(). + * @param {string} type type to indentify if it is reference search or string match serach */ - function SearchResultsView(model, panelID, panelName) { + function SearchResultsView(model, panelID, panelName, type) { var panelHtml = Mustache.render(searchPanelTemplate, {panelID: panelID}); this._panel = WorkspaceManager.createBottomPanel(panelName, $(panelHtml), 100); this._$summary = this._panel.$panel.find(".title"); this._$table = this._panel.$panel.find(".table-container"); this._model = model; + this._searchResultsType = type; } EventDispatcher.makeEventDispatcher(SearchResultsView.prototype); @@ -116,6 +118,9 @@ define(function (require, exports, module) { /** @type {number} The ID we use for timeouts when handling model changes. */ SearchResultsView.prototype._timeoutID = null; + /** @type {string} The ID we use to check id it is refrence serach or match search */ + SearchResultsView.prototype._searchResultsType = null; + /** * @private * Handles when model changes. Updates the view, buffering changes if necessary so as not to churn too much. @@ -344,9 +349,14 @@ define(function (require, exports, module) { SearchResultsView.prototype._showSummary = function () { var count = this._model.countFilesMatches(), lastIndex = this._getLastIndex(count.matches), + typeStr = (count.matches > 1) ? Strings.FIND_IN_FILES_MATCHES : Strings.FIND_IN_FILES_MATCH, filesStr, summary; + if(this._searchResultsType) { + typeStr = (count.matches > 1) ? Strings.FIND_IN_FILES_REFERENCES : Strings.FIND_IN_FILES_REFERENCE; + } + filesStr = StringUtils.format( Strings.FIND_NUM_FILES, count.files, @@ -358,7 +368,7 @@ define(function (require, exports, module) { Strings.FIND_TITLE_SUMMARY, this._model.exceedsMaximum ? Strings.FIND_IN_FILES_MORE_THAN : "", String(count.matches), - (count.matches > 1) ? Strings.FIND_IN_FILES_MATCHES : Strings.FIND_IN_FILES_MATCH, + typeStr, filesStr ); From d8b9a1a4a800dd33839837459fb7fbed1c85db1b Mon Sep 17 00:00:00 2001 From: niteskum Date: Thu, 11 Apr 2019 12:54:58 +0530 Subject: [PATCH 02/11] Addressed bugs --- src/features/FindReferencesManager.js | 14 ++++++++------ src/languageTools/DefaultProviders.js | 2 +- src/nls/root/strings.js | 7 ++++--- src/search/SearchResultsView.js | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/features/FindReferencesManager.js b/src/features/FindReferencesManager.js index d90b856d2b7..c7391e4cabf 100644 --- a/src/features/FindReferencesManager.js +++ b/src/features/FindReferencesManager.js @@ -48,6 +48,10 @@ define(function (require, exports, module) { function _getReferences(provider, hostEditor, pos) { var result = new $.Deferred(); + if(!provider) { + return result.reject(); + } + provider.getReferences(hostEditor, pos) .done(function (rcvdObj) { @@ -72,9 +76,8 @@ define(function (require, exports, module) { pos = editor ? editor.getCursorPos() : null, referencespromise, result = new $.Deferred(), - errorMsg, - referencesProvider, - defaultErrorMsg = ""; + errorMsg = Strings.REFERENCES_NO_RESULTS, + referencesProvider; var language = editor.getLanguageForSelection(), enabledProviders = _providerRegistrationHandler.getProvidersForLanguageId(language.getId()); @@ -88,18 +91,17 @@ define(function (require, exports, module) { referencespromise = _getReferences(referencesProvider, editor, pos); - // Use default error message if none other provided - errorMsg = errorMsg || defaultErrorMsg; - // 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(); } diff --git a/src/languageTools/DefaultProviders.js b/src/languageTools/DefaultProviders.js index 54b171bbeef..a79f23c2ebe 100644 --- a/src/languageTools/DefaultProviders.js +++ b/src/languageTools/DefaultProviders.js @@ -422,7 +422,7 @@ define(function (require, exports, module) { filePath: docPath, cursorPos: pos }).done(function(msgObj){ - if(msgObj ) { + if(msgObj && msgObj.length) { var referenceModel = {}; referenceModel.results = {}; referenceModel.numFiles = 0; diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index d4a368feb2e..3590f36395d 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -888,8 +888,9 @@ define({ "OPEN_PREFERENNCES" : "Open Preferences", //Strings for LanguageTools Preferences - "LANGUAGE_TOOLS_PREFERENCES" : "Preferences for Language Tools", + "LANGUAGE_TOOLS_PREFERENCES" : "Preferences for Language Tools", "FIND_ALL_REFERENCES" : "Find All References", - "FIND_IN_FILES_REFERENCES" : "references", - "FIND_IN_FILES_REFERENCE" : "reference" + "REFERENCES_IN_FILES" : "references", + "REFERENCE_IN_FILES" : "reference", + "REFERENCES_NO_RESULTS" : "No references found" }); diff --git a/src/search/SearchResultsView.js b/src/search/SearchResultsView.js index 80db2aee3c4..2e21decd5bb 100644 --- a/src/search/SearchResultsView.js +++ b/src/search/SearchResultsView.js @@ -354,7 +354,7 @@ define(function (require, exports, module) { summary; if(this._searchResultsType) { - typeStr = (count.matches > 1) ? Strings.FIND_IN_FILES_REFERENCES : Strings.FIND_IN_FILES_REFERENCE; + typeStr = (count.matches > 1) ? Strings.REFERENCES_IN_FILES : Strings.REFERENCE_IN_FILES; } filesStr = StringUtils.format( From 149c705f720d55d9a3ca937734db1e137b5f8803 Mon Sep 17 00:00:00 2001 From: niteskum Date: Thu, 11 Apr 2019 14:07:25 +0530 Subject: [PATCH 03/11] Addressed review comments --- src/features/FindReferencesManager.js | 19 +++++++------------ src/search/SearchResultsView.js | 4 ++-- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/features/FindReferencesManager.js b/src/features/FindReferencesManager.js index c7391e4cabf..cd4e0fa451a 100644 --- a/src/features/FindReferencesManager.js +++ b/src/features/FindReferencesManager.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - present Adobe Systems Incorporated. All rights reserved. + * 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"), @@ -39,7 +39,7 @@ define(function (require, exports, module) { ), removeFindReferencesProvider = _providerRegistrationHandler.removeProvider.bind(_providerRegistrationHandler); - var SHOW_FIND_REFERENCES_CMD_ID = "showrReferences", + var SHOW_FIND_REFERENCES_CMD_ID = "showReferences", KeyboardPrefs = JSON.parse(require("text!features/keyboard.json")); var searchModel = new SearchModel(), @@ -60,21 +60,18 @@ define(function (require, exports, module) { searchModel.numMatches = rcvdObj.numMatches; searchModel.allResultsAvailable = true; searchModel.setQueryInfo({query: rcvdObj.queryInfo, caseSensitive: true, isRegExp: false}); - //searchModel.fireChanged(); result.resolve(); }).fail(function (){ result.reject(); }); - return result.promise(); } function _openReferencesPanel() { - var editor = EditorManager.getActiveEditor(), pos = editor ? editor.getCursorPos() : null, - referencespromise, + referencesPromise, result = new $.Deferred(), errorMsg = Strings.REFERENCES_NO_RESULTS, referencesProvider; @@ -89,11 +86,11 @@ define(function (require, exports, module) { } }); - referencespromise = _getReferences(referencesProvider, editor, pos); + referencesPromise = _getReferences(referencesProvider, editor, pos); // If one of them will provide a widget, show it inline once ready - if (referencespromise) { - referencespromise.done(function () { + if (referencesPromise) { + referencesPromise.done(function () { _resultsView.open(); }).fail(function () { _resultsView.close(); @@ -118,10 +115,8 @@ define(function (require, exports, module) { } AppInit.appReady(function () { - - var model = searchModel; _resultsView = new SearchResultsView( - model, + searchModel, "reference-in-files-results", "reference-in-files.results", "reference" diff --git a/src/search/SearchResultsView.js b/src/search/SearchResultsView.js index 2e21decd5bb..d1798dfded8 100644 --- a/src/search/SearchResultsView.js +++ b/src/search/SearchResultsView.js @@ -118,7 +118,7 @@ define(function (require, exports, module) { /** @type {number} The ID we use for timeouts when handling model changes. */ SearchResultsView.prototype._timeoutID = null; - /** @type {string} The ID we use to check id it is refrence serach or match search */ + /** @type {string} The Id we use to check if it is reference search or match search */ SearchResultsView.prototype._searchResultsType = null; /** @@ -353,7 +353,7 @@ define(function (require, exports, module) { filesStr, summary; - if(this._searchResultsType) { + if(this._searchResultsType === "reference") { typeStr = (count.matches > 1) ? Strings.REFERENCES_IN_FILES : Strings.REFERENCE_IN_FILES; } From 84e791f9aeb302b98cf0061cdb241df512c7df8c Mon Sep 17 00:00:00 2001 From: niteskum Date: Thu, 11 Apr 2019 15:31:05 +0530 Subject: [PATCH 04/11] Addressed review comments --- src/languageTools/DefaultProviders.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/languageTools/DefaultProviders.js b/src/languageTools/DefaultProviders.js index a79f23c2ebe..9220a1f7cde 100644 --- a/src/languageTools/DefaultProviders.js +++ b/src/languageTools/DefaultProviders.js @@ -408,12 +408,21 @@ define(function (require, exports, module) { } ReferencesProvider.prototype.hasReferences = function() { + if (!this.client) { + return false; + } + + var serverCapabilities = this.client.getServerCapabilities(); + if (!serverCapabilities || !serverCapabilities.referencesProvider) { + return false; + } + return true; }; - ReferencesProvider.prototype.getReferences = function() { - var editor = EditorManager.getActiveEditor(), - pos = editor.getCursorPos(), + ReferencesProvider.prototype.getReferences = function(hostEditor, curPos) { + var editor = hostEditor || EditorManager.getActiveEditor(), + pos = curPos || editor ? editor.getCursorPos() : null, docPath = editor.document.file._path, result = $.Deferred(); From f07c8e78b7facc8e2c829606d7b57174234da5fc Mon Sep 17 00:00:00 2001 From: sngrover Date: Thu, 11 Apr 2019 18:06:53 +0530 Subject: [PATCH 05/11] Changes to send data only once per 24 hours --- .../default/HealthData/HealthDataManager.js | 25 +++++++++++-------- src/utils/HealthLogger.js | 7 ++++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/extensions/default/HealthData/HealthDataManager.js b/src/extensions/default/HealthData/HealthDataManager.js index a452a4e5471..e6a72b5a181 100644 --- a/src/extensions/default/HealthData/HealthDataManager.js +++ b/src/extensions/default/HealthData/HealthDataManager.js @@ -308,22 +308,16 @@ define(function (require, exports, module) { isHDTracking = prefs.get("healthDataTracking"), isEventDataAlreadySent; - var options = { - location: { - scope: "default" - } - }; - if (isHDTracking) { - isEventDataAlreadySent = PreferencesManager.getViewState(Eventparams.eventName); - PreferencesManager.setViewState(Eventparams.eventName, 1, options); + isEventDataAlreadySent = HealthLogger.analyticsEventMap.get(Eventparams.eventName); + HealthLogger.analyticsEventMap.set(Eventparams.eventName, true); if (!isEventDataAlreadySent || forceSend) { sendAnalyticsDataToServer(Eventparams) .done(function () { - PreferencesManager.setViewState(Eventparams.eventName, 1, options); + HealthLogger.analyticsEventMap.set(Eventparams.eventName, true); result.resolve(); }).fail(function () { - PreferencesManager.setViewState(Eventparams.eventName, 0, options); + HealthLogger.analyticsEventMap.set(Eventparams.eventName, false); result.reject(); }); } else { @@ -336,6 +330,17 @@ define(function (require, exports, module) { return result.promise(); } + /** + * This function is auto called after 24 hours to empty the map + * Map is used to make sure that we send an event only once per 24 hours + **/ + + function emptyAnalyticsMap() { + HealthLogger.analyticsEventMap.clear(); + setTimeout(emptyAnalyticsMap, ONE_DAY); + } + setTimeout(emptyAnalyticsMap, ONE_DAY); + // Expose a command to test data sending capability, but limit it to dev environment only CommandManager.register("Sends health data and Analytics data for testing purpose", "sendHealthData", function() { if (brackets.config.environment === "stage") { diff --git a/src/utils/HealthLogger.js b/src/utils/HealthLogger.js index 3fd5e3d7e74..53631406101 100644 --- a/src/utils/HealthLogger.js +++ b/src/utils/HealthLogger.js @@ -36,7 +36,8 @@ define(function (require, exports, module) { EventDispatcher = require("utils/EventDispatcher"), HEALTH_DATA_STATE_KEY = "HealthData.Logs", - logHealthData = true; + logHealthData = true, + analyticsEventMap = new Map(); var commonStrings = { USAGE: "usage", FILE_OPEN: "fileOpen", @@ -319,9 +320,10 @@ define(function (require, exports, module) { * needs to be logged- should be a js var compatible string */ function sendAnalyticsData(eventName, eventCategory, eventSubCategory, eventType, eventSubType) { - var isEventDataAlreadySent = PreferencesManager.getViewState(eventName), + var isEventDataAlreadySent = analyticsEventMap.get(eventName), isHDTracking = PreferencesManager.getExtensionPrefs("healthData").get("healthDataTracking"), eventParams = {}; + if (isHDTracking && !isEventDataAlreadySent && eventName && eventCategory) { eventParams = { eventName: eventName, @@ -363,4 +365,5 @@ define(function (require, exports, module) { // A new search context on search bar up-Gives an idea of number of times user did a discrete search exports.SEARCH_NEW = "searchNew"; exports.commonStrings = commonStrings; + exports.analyticsEventMap = analyticsEventMap; }); From 8f1cc7f6ccb90c3e0bad292b9d9d737d5ed49723 Mon Sep 17 00:00:00 2001 From: niteskum Date: Thu, 11 Apr 2019 20:56:27 +0530 Subject: [PATCH 06/11] Adding Unit Test cases and supporting files --- .../PhpTooling/unittest-files/test/test2.php | 17 +++ .../PhpTooling/unittest-files/test/test3.php | 4 +- .../default/PhpTooling/unittests.js | 140 ++++++++++++++++++ 3 files changed, 160 insertions(+), 1 deletion(-) diff --git a/src/extensions/default/PhpTooling/unittest-files/test/test2.php b/src/extensions/default/PhpTooling/unittest-files/test/test2.php index 16651124644..5080a3f3158 100644 --- a/src/extensions/default/PhpTooling/unittest-files/test/test2.php +++ b/src/extensions/default/PhpTooling/unittest-files/test/test2.php @@ -26,5 +26,22 @@ function watchparameterhint() { $A11() fopen("",) watchparameterhint() + + +function watchReferences() { + echo "Hello World!"; +} + +watchReferences(); + +watchReferences(); + + +function ReferencesInMultipleFile() { + echo "Hello World!"; +} + +ReferencesInMultipleFile(); +ReferencesInMultipleFile(); ?> diff --git a/src/extensions/default/PhpTooling/unittest-files/test/test3.php b/src/extensions/default/PhpTooling/unittest-files/test/test3.php index 70981b54d1f..7dc1d365bd2 100644 --- a/src/extensions/default/PhpTooling/unittest-files/test/test3.php +++ b/src/extensions/default/PhpTooling/unittest-files/test/test3.php @@ -7,4 +7,6 @@ class testA protected $B = [ 'A1', 'A2' ]; -} \ No newline at end of file +} + +ReferencesInMultipleFile(); \ No newline at end of file diff --git a/src/extensions/default/PhpTooling/unittests.js b/src/extensions/default/PhpTooling/unittests.js index 722acc5b993..8288f1d616a 100644 --- a/src/extensions/default/PhpTooling/unittests.js +++ b/src/extensions/default/PhpTooling/unittests.js @@ -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 */ @@ -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 }; From d50b154de8ae5fc073d5049dfc38c5f192c28bda Mon Sep 17 00:00:00 2001 From: niteskum Date: Fri, 12 Apr 2019 18:03:06 +0530 Subject: [PATCH 07/11] changed string --- src/nls/root/strings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index 3590f36395d..b47b5e672bd 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -892,5 +892,5 @@ define({ "FIND_ALL_REFERENCES" : "Find All References", "REFERENCES_IN_FILES" : "references", "REFERENCE_IN_FILES" : "reference", - "REFERENCES_NO_RESULTS" : "No references found" + "REFERENCES_NO_RESULTS" : "No References available for current cursor position" }); From 4eb0627634f284b6fbcb8a2298b242e5fde123da Mon Sep 17 00:00:00 2001 From: niteskum Date: Sat, 13 Apr 2019 01:42:53 +0530 Subject: [PATCH 08/11] fixed review comments --- src/languageTools/DefaultProviders.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/languageTools/DefaultProviders.js b/src/languageTools/DefaultProviders.js index ed1b438c71a..39a78541fa3 100644 --- a/src/languageTools/DefaultProviders.js +++ b/src/languageTools/DefaultProviders.js @@ -437,8 +437,7 @@ define(function (require, exports, module) { var referenceModel = {}; referenceModel.results = {}; referenceModel.numFiles = 0; - var fulfilled = 0, - queryInfo = ""; + var fulfilled = 0; msgObj.forEach((element, i) => { var filePath = PathConverters.uriToPath(element.uri); DocumentManager.getDocumentForPath(filePath) @@ -448,13 +447,14 @@ define(function (require, exports, module) { var match = { start: startRange, end: endRange, + highlightOffset: 0, line: doc.getLine(element.range.start.line) }; if(!referenceModel.results[filePath]) { referenceModel.numFiles = referenceModel.numFiles + 1; referenceModel.results[filePath] = {"matches": []}; } - if(!queryInfo) { + if(!referenceModel.queryInfo || pos.line === startRange.line) { referenceModel.queryInfo = doc.getRange(startRange, endRange); } referenceModel.results[filePath]["matches"].push(match); From 226c13b40c65663331b43ea03a9aa99ef933251e Mon Sep 17 00:00:00 2001 From: niteskum Date: Sun, 14 Apr 2019 20:34:49 +0530 Subject: [PATCH 09/11] Addressed review comments --- src/base-config/keyboard.json | 3 + src/command/Commands.js | 1 + src/command/DefaultMenus.js | 2 + src/features/FindReferencesManager.js | 12 +--- src/features/keyboard.json | 13 ----- src/languageTools/DefaultProviders.js | 80 ++++++++++++++++----------- src/search/SearchResultsView.js | 2 +- 7 files changed, 56 insertions(+), 57 deletions(-) delete mode 100644 src/features/keyboard.json diff --git a/src/base-config/keyboard.json b/src/base-config/keyboard.json index aa9c67cd4d5..a685ad61743 100644 --- a/src/base-config/keyboard.json +++ b/src/base-config/keyboard.json @@ -162,6 +162,9 @@ "cmd.findInFiles": [ "Ctrl-Shift-F" ], + "cmd.findAllReferences": [ + "Ctrl-Shift-K" + ], "cmd.replaceInFiles": [ { "key": "Ctrl-Shift-H" diff --git a/src/command/Commands.js b/src/command/Commands.js index dc147eeac6f..61048aa4720 100644 --- a/src/command/Commands.js +++ b/src/command/Commands.js @@ -97,6 +97,7 @@ define(function (require, exports, module) { exports.CMD_REPLACE = "cmd.replace"; // FindReplace.js _replace() exports.CMD_REPLACE_IN_FILES = "cmd.replaceInFiles"; // FindInFilesUI.js _showReplaceBar() exports.CMD_REPLACE_IN_SUBTREE = "cmd.replaceInSubtree"; // FindInFilesUI.js _showReplaceBarForSubtree() + exports.CMD_FIND_ALL_REFERENCES = "cmd.findAllReferences"; // findReferencesManager.js _openReferencesPanel() // VIEW exports.CMD_THEMES_OPEN_SETTINGS = "view.themesOpenSetting"; // MenuCommands.js Settings.open() diff --git a/src/command/DefaultMenus.js b/src/command/DefaultMenus.js index 2eb6f871925..b871d060dab 100644 --- a/src/command/DefaultMenus.js +++ b/src/command/DefaultMenus.js @@ -136,6 +136,7 @@ define(function (require, exports, module) { menu.addMenuItem(Commands.CMD_SKIP_CURRENT_MATCH); menu.addMenuDivider(); menu.addMenuItem(Commands.CMD_FIND_IN_FILES); + menu.addMenuItem(Commands.CMD_FIND_ALL_REFERENCES); menu.addMenuDivider(); menu.addMenuItem(Commands.CMD_REPLACE); menu.addMenuItem(Commands.CMD_REPLACE_IN_FILES); @@ -282,6 +283,7 @@ define(function (require, exports, module) { // editor_cmenu.addMenuItem(Commands.NAVIGATE_JUMPTO_DEFINITION); editor_cmenu.addMenuItem(Commands.TOGGLE_QUICK_EDIT); editor_cmenu.addMenuItem(Commands.TOGGLE_QUICK_DOCS); + editor_cmenu.addMenuItem(Commands.CMD_FIND_ALL_REFERENCES); editor_cmenu.addMenuDivider(); editor_cmenu.addMenuItem(Commands.EDIT_CUT); editor_cmenu.addMenuItem(Commands.EDIT_COPY); diff --git a/src/features/FindReferencesManager.js b/src/features/FindReferencesManager.js index cd4e0fa451a..3069815d45e 100644 --- a/src/features/FindReferencesManager.js +++ b/src/features/FindReferencesManager.js @@ -26,8 +26,8 @@ define(function (require, exports, module) { var AppInit = require("utils/AppInit"), CommandManager = require("command/CommandManager"), + Commands = require("command/Commands"), EditorManager = require("editor/EditorManager"), - Menus = require("command/Menus"), ProviderRegistrationHandler = require("features/PriorityBasedRegistration").RegistrationHandler, SearchResultsView = require("search/SearchResultsView").SearchResultsView, SearchModel = require("search/SearchModel").SearchModel, @@ -39,9 +39,6 @@ define(function (require, exports, module) { ), removeFindReferencesProvider = _providerRegistrationHandler.removeProvider.bind(_providerRegistrationHandler); - var SHOW_FIND_REFERENCES_CMD_ID = "showReferences", - KeyboardPrefs = JSON.parse(require("text!features/keyboard.json")); - var searchModel = new SearchModel(), _resultsView; @@ -135,13 +132,8 @@ define(function (require, exports, module) { _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 - ); }); + CommandManager.register(Strings.FIND_ALL_REFERENCES, Commands.CMD_FIND_ALL_REFERENCES, _openReferencesPanel); exports.registerFindReferencesProvider = registerFindReferencesProvider; exports.removeFindReferencesProvider = removeFindReferencesProvider; diff --git a/src/features/keyboard.json b/src/features/keyboard.json deleted file mode 100644 index 635d176d1dc..00000000000 --- a/src/features/keyboard.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "findAllReferences": [ - { - "key": "Ctrl-Shift-R", "platform": "mac" - }, - { - "key": "Ctrl-Shift-R", "platform": "win" - }, - { - "key": "Ctrl-Shift-R", "platform": "linux" - } - ] -} \ No newline at end of file diff --git a/src/languageTools/DefaultProviders.js b/src/languageTools/DefaultProviders.js index 39a78541fa3..17f3a8347b4 100644 --- a/src/languageTools/DefaultProviders.js +++ b/src/languageTools/DefaultProviders.js @@ -405,6 +405,48 @@ define(function (require, exports, module) { return this._results.get(filePath); }; + function serverRespToSerachModelFormat(msgObj) { + var referenceModel = {}, + result = $.Deferred(); + + if(!(msgObj && msgObj.length && msgObj.cursorPos)) { + return result.reject(); + } + referenceModel.results = {}; + referenceModel.numFiles = 0; + var fulfilled = 0; + msgObj.forEach((element, i) => { + var filePath = PathConverters.uriToPath(element.uri); + DocumentManager.getDocumentForPath(filePath) + .done(function(doc) { + var startRange = {line: element.range.start.line, ch: element.range.start.character}; + var endRange = {line: element.range.end.line, ch: element.range.end.character}; + var match = { + start: startRange, + end: endRange, + highlightOffset: 0, + line: doc.getLine(element.range.start.line) + }; + if(!referenceModel.results[filePath]) { + referenceModel.numFiles = referenceModel.numFiles + 1; + referenceModel.results[filePath] = {"matches": []}; + } + if(!referenceModel.queryInfo || msgObj.cursorPos.line === startRange.line) { + referenceModel.queryInfo = doc.getRange(startRange, endRange); + } + referenceModel.results[filePath]["matches"].push(match); + }).always(function() { + fulfilled++; + if(fulfilled === msgObj.length) { + referenceModel.numMatches = msgObj.length; + referenceModel.allResultsAvailable = true; + result.resolve(referenceModel); + } + }); + }); + return result.promise(); + } + function ReferencesProvider(client) { this.client = client; } @@ -434,39 +476,10 @@ define(function (require, exports, module) { cursorPos: pos }).done(function(msgObj){ if(msgObj && msgObj.length) { - var referenceModel = {}; - referenceModel.results = {}; - referenceModel.numFiles = 0; - var fulfilled = 0; - msgObj.forEach((element, i) => { - var filePath = PathConverters.uriToPath(element.uri); - DocumentManager.getDocumentForPath(filePath) - .done(function(doc) { - var startRange = {line: element.range.start.line, ch: element.range.start.character}; - var endRange = {line: element.range.end.line, ch: element.range.end.character}; - var match = { - start: startRange, - end: endRange, - highlightOffset: 0, - line: doc.getLine(element.range.start.line) - }; - if(!referenceModel.results[filePath]) { - referenceModel.numFiles = referenceModel.numFiles + 1; - referenceModel.results[filePath] = {"matches": []}; - } - if(!referenceModel.queryInfo || pos.line === startRange.line) { - referenceModel.queryInfo = doc.getRange(startRange, endRange); - } - referenceModel.results[filePath]["matches"].push(match); - }).always(function() { - fulfilled++; - if(fulfilled === msgObj.length) { - referenceModel.numMatches = msgObj.length; - referenceModel.allResultsAvailable = true; - result.resolve(referenceModel); - } - }); - }); + msgObj.cursorPos = pos; + serverRespToSerachModelFormat(msgObj) + .done(result.resolve) + .fail(result.reject); } else { result.reject(); } @@ -483,4 +496,5 @@ define(function (require, exports, module) { exports.JumpToDefProvider = JumpToDefProvider; exports.LintingProvider = LintingProvider; exports.ReferencesProvider = ReferencesProvider; + exports.serverRespToSerachModelFormat = serverRespToSerachModelFormat; }); diff --git a/src/search/SearchResultsView.js b/src/search/SearchResultsView.js index d1798dfded8..1822926a26b 100644 --- a/src/search/SearchResultsView.js +++ b/src/search/SearchResultsView.js @@ -72,7 +72,7 @@ define(function (require, exports, module) { * @param {SearchModel} model The model that this view is showing. * @param {string} panelID The CSS ID to use for the panel. * @param {string} panelName The name to use for the panel, as passed to WorkspaceManager.createBottomPanel(). - * @param {string} type type to indentify if it is reference search or string match serach + * @param {string} type type to identify if it is reference search or string match serach */ function SearchResultsView(model, panelID, panelName, type) { var panelHtml = Mustache.render(searchPanelTemplate, {panelID: panelID}); From 6980edffac0a8e4187a9df343b55cd85dbde56f6 Mon Sep 17 00:00:00 2001 From: niteskum Date: Mon, 15 Apr 2019 15:47:44 +0530 Subject: [PATCH 10/11] Changed Shortcut to Ctrl-M --- src/base-config/keyboard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base-config/keyboard.json b/src/base-config/keyboard.json index 9ed81bd913a..3c62fce579a 100644 --- a/src/base-config/keyboard.json +++ b/src/base-config/keyboard.json @@ -163,7 +163,7 @@ "Ctrl-Shift-F" ], "cmd.findAllReferences": [ - "Ctrl-Shift-K" + "Ctrl-M" ], "cmd.replaceInFiles": [ { From 5e041df2570fdd125b1ac9d1def52071deb35583 Mon Sep 17 00:00:00 2001 From: niteskum Date: Mon, 15 Apr 2019 16:05:31 +0530 Subject: [PATCH 11/11] Changed the Shortcut to Shift-F12 --- src/base-config/keyboard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base-config/keyboard.json b/src/base-config/keyboard.json index 3c62fce579a..5d7ea339515 100644 --- a/src/base-config/keyboard.json +++ b/src/base-config/keyboard.json @@ -163,7 +163,7 @@ "Ctrl-Shift-F" ], "cmd.findAllReferences": [ - "Ctrl-M" + "Shift-F12" ], "cmd.replaceInFiles": [ {