From 329649e2db58ee0d9da05db63b01a914d25e86e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Malbr=C3=A1n?= Date: Fri, 9 Aug 2013 05:49:04 -0300 Subject: [PATCH 1/6] Auto update the current find in files results --- src/search/FindInFiles.js | 143 ++++++++++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 13 deletions(-) diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js index e8155d5fa73..4dfdb88c57f 100644 --- a/src/search/FindInFiles.js +++ b/src/search/FindInFiles.js @@ -80,12 +80,18 @@ define(function (require, exports, module) { /** @type {Panel} Bottom panel holding the search results. Initialized in htmlReady() */ var searchResultsPanel; + /** @type {Document} The current editor used to register the change and delete events */ + var currentDocument = null; + /** @type {number} The index of the first result that is displayed */ var currentStart = 0; /** @type {string} The current search query */ var currentQuery = ""; + /** @type {RegExp} The current search query regular expression */ + var currentQueryExpr = null; + /** @type {Array.} An array of the files where it should look or null/empty to search the entire project */ var currentScope = null; @@ -102,7 +108,7 @@ define(function (require, exports, module) { /** * @private * Returns a regular expression from the given query and shows an error in the modal-bar if it was invalid - * @param {!string} query - The query from the modal-bar input + * @param {string} query The query from the modal-bar input * @return {RegExp} */ function _getQueryRegExp(query) { @@ -184,8 +190,8 @@ define(function (require, exports, module) { /** * Shows the search dialog - * @param {?string} initialString Default text to prepopulate the search field with - * @param {?Entry} scope Search scope, or null to search whole project + * @param {string=} initialString Default text to prepopulate the search field with + * @param {Entry=} scope Search scope, or null to search whole project * @returns {$.Promise} that is resolved with the string to search for */ FindInFilesDialog.prototype.showDialog = function (initialString, scope) { @@ -516,8 +522,8 @@ define(function (require, exports, module) { /** * @private - * @param {!FileInfo} fileInfo File in question - * @param {?Entry} scope Search scope, or null if whole project + * @param {!FileInfo} fileInfo File in question + * @param {?Entry} scope Search scope, or null if whole project * @return {boolean} */ function _inScope(fileInfo, scope) { @@ -537,7 +543,7 @@ define(function (require, exports, module) { * @private * Displays a non-modal embedded dialog above the code mirror editor that allows the user to do * a find operation across all files in the project. - * @param {?Entry} scope Project file/subfolder to search within; else searches whole project. + * @param {?Entry} scope Project file/subfolder to search within; else searches whole project. */ function _doFindInFiles(scope) { if (scope instanceof NativeFileSystem.InaccessibleFileEntry) { @@ -554,15 +560,17 @@ define(function (require, exports, module) { searchResults = {}; currentQuery = ""; + currentQueryExpr = null; currentScope = scope; maxHitsFoundInFile = false; dialog.showDialog(initialString, scope) .done(function (query) { if (query) { - currentQuery = query; - var queryExpr = _getQueryRegExp(query); - if (!queryExpr) { + currentQuery = query; + currentQueryExpr = _getQueryRegExp(query); + + if (!currentQueryExpr) { return; } StatusBar.showBusyIndicator(true); @@ -577,7 +585,7 @@ define(function (require, exports, module) { // Search one file DocumentManager.getDocumentForPath(fileInfo.fullPath) .done(function (doc) { - _addSearchMatches(fileInfo.fullPath, doc.getText(), queryExpr); + _addSearchMatches(fileInfo.fullPath, doc.getText(), currentQueryExpr); result.resolve(); }) .fail(function (error) { @@ -629,6 +637,7 @@ define(function (require, exports, module) { } } + /** * @private * Moves the search results from the previous path to the new one and updates the results list, if required @@ -681,6 +690,113 @@ define(function (require, exports, module) { } } + /** + * @private + * Update the result matches every time the content of a file changes + * @param {$.Event} event + * @param {Document} doc The Document that changed, should be the current one + * @param {{from: {line:number,ch:number}, to: {line:number,ch:number}, text: string, next: change}} change + * A linked list as described in the Document constructor + * @param {boolean=} resultsChanged True when the search results changed from a file change + */ + function _fileChangeHandler(event, doc, change, resultsChanged) { + if ($searchResults.is(":visible")) { + var i, diff, matches, + fullPath = doc.file.fullPath, + lines = [], + start = 0, + howMany = 0; + + // There is no from or to positions, so the entire file changed, we must search all over again + if (!change.from || !change.to) { + _addSearchMatches(fullPath, doc.getText(), currentQueryExpr); + _restoreSearchResults(); + + } else { + // Get only the lines that changed + for (i = 0; i < change.text.length; i++) { + lines.push(doc.getLine(change.from.line + i)); + } + + // We need to know how many lines changed to update the rest of the lines + if (change.from.line !== change.to.line) { + diff = change.from.line - change.to.line; + } else { + diff = 0; + } + + if (searchResults[fullPath]) { + // Search the last match before a replacement, the amount of matches deleted and update + // the lines values for all the matches after the change + searchResults[fullPath].matches.forEach(function (item) { + if (item.end.line < change.from.line) { + start++; + } else if (item.end.line <= change.to.line) { + howMany++; + } else { + item.start.line += diff; + item.end.line += diff; + } + }); + + // Delete the lines that where deleted or replaced + if (howMany > 0) { + searchResults[fullPath].matches.splice(start, howMany); + } + resultsChanged = true; + } + + // Searches only over the lines that changed + matches = _getSearchMatches(lines.join("\r\n"), currentQueryExpr); + if (matches && matches.length) { + // Updates the line numbers, since we only searched part of the file + matches.forEach(function (value, key) { + matches[key].start.line += change.from.line; + matches[key].end.line += change.from.line; + }); + + // If the file index exists, add the new matches to the file at the start index found before + if (searchResults[fullPath]) { + Array.prototype.splice.apply(searchResults[fullPath].matches, [start, 0].concat(matches)); + // If not, add the matches to a new file index + } else { + searchResults[fullPath] = { + matches: matches, + collapsed: false + }; + } + resultsChanged = true; + } + + // All the matches where deleted, remove the file from the results + if (searchResults[fullPath] && !searchResults[fullPath].matches.length) { + delete searchResults[fullPath]; + resultsChanged = true; + } + + // This is link to the next change object, so we need to keep searching + if (change.next) { + _fileChangeHandler(event, doc, change.next, resultsChanged); + + // If not we can show the results, but only if something changed + } else if (resultsChanged) { + _restoreSearchResults(); + } + } + } + } + + /** + * @private + * Updates the event listeners when the current document changes + */ + function _currentDocumentChangeHandler() { + $(currentDocument).off("change", _fileChangeHandler); + currentDocument = DocumentManager.getCurrentDocument(); + $(currentDocument).on("change", _fileChangeHandler); + } + + // Initialize items dependent on HTML DOM AppInit.htmlReady(function () { @@ -693,9 +809,10 @@ define(function (require, exports, module) { }); // Initialize: register listeners - $(DocumentManager).on("fileNameChange", _fileNameChangeHandler); - $(DocumentManager).on("pathDeleted", _pathDeletedHandler); - $(ProjectManager).on("beforeProjectClose", _hideSearchResults); + $(DocumentManager).on("fileNameChange", _fileNameChangeHandler); + $(DocumentManager).on("pathDeleted", _pathDeletedHandler); + $(DocumentManager).on("currentDocumentChange", _currentDocumentChangeHandler); + $(ProjectManager).on("beforeProjectClose", _hideSearchResults); // Initialize: command handlers CommandManager.register(Strings.CMD_FIND_IN_FILES, Commands.EDIT_FIND_IN_FILES, _doFindInFiles); From 64246fb73fa5080168d70d23d5c2c322f381ab38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Malbr=C3=A1n?= Date: Sat, 17 Aug 2013 05:40:36 -0300 Subject: [PATCH 2/6] Fixes the Enter (line number updates), Inline Editors changes, just update files in the Current Scope and Restore selected row issues --- src/search/FindInFiles.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js index 8b3bf4650ad..09211f18121 100644 --- a/src/search/FindInFiles.js +++ b/src/search/FindInFiles.js @@ -80,9 +80,6 @@ define(function (require, exports, module) { /** @type {Panel} Bottom panel holding the search results. Initialized in htmlReady() */ var searchResultsPanel; - /** @type {Document} The current editor used to register the change and delete events */ - var currentDocument = null; - /** @type {number} The index of the first result that is displayed */ var currentStart = 0; @@ -632,7 +629,7 @@ define(function (require, exports, module) { _showSearchResults(); $searchContent.scrollTop(scrollTop); - if ($selectedRow) { + if (index) { $selectedRow = $searchContent.find("tr:eq(" + index + ")"); $selectedRow.addClass("selected"); } @@ -723,7 +720,7 @@ define(function (require, exports, module) { if (change.from.line !== change.to.line) { diff = change.from.line - change.to.line; } else { - diff = 0; + diff = lines.length - 1; } if (searchResults[fullPath]) { @@ -789,12 +786,20 @@ define(function (require, exports, module) { /** * @private - * Updates the event listeners when the current document changes + * Updates the event listeners when the current editor changes + * @param {$.Event} event + * @param {Editor} current + * @param {Editor} previous */ - function _currentDocumentChangeHandler() { - $(currentDocument).off("change", _fileChangeHandler); - currentDocument = DocumentManager.getCurrentDocument(); - $(currentDocument).on("change", _fileChangeHandler); + function _currentEditorChangeHandler(event, current, previous) { + if (previous) { + previous.document.releaseRef(); + $(previous.document).off("change", _fileChangeHandler); + } + if (_inScope(current.document.file, currentScope)) { + current.document.addRef(); + $(current.document).on("change", _fileChangeHandler); + } } @@ -810,10 +815,10 @@ define(function (require, exports, module) { }); // Initialize: register listeners - $(DocumentManager).on("fileNameChange", _fileNameChangeHandler); - $(DocumentManager).on("pathDeleted", _pathDeletedHandler); - $(DocumentManager).on("currentDocumentChange", _currentDocumentChangeHandler); - $(ProjectManager).on("beforeProjectClose", _hideSearchResults); + $(DocumentManager).on("fileNameChange", _fileNameChangeHandler); + $(DocumentManager).on("pathDeleted", _pathDeletedHandler); + $(ProjectManager).on("beforeProjectClose", _hideSearchResults); + $(EditorManager).on("activeEditorChange", _currentEditorChangeHandler); // Initialize: command handlers CommandManager.register(Strings.CMD_FIND_IN_FILES, Commands.EDIT_FIND_IN_FILES, _doFindInFiles); From a07b53a415c3d64e91cf4b4247ef1eeddc5f4a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Malbr=C3=A1n?= Date: Tue, 20 Aug 2013 02:20:22 -0300 Subject: [PATCH 3/6] Using a new document change event and a timeout to handle the panel update --- src/document/Document.js | 1 + src/search/FindInFiles.js | 208 ++++++++++++++++++++------------------ 2 files changed, 109 insertions(+), 100 deletions(-) diff --git a/src/document/Document.js b/src/document/Document.js index ea8a7732574..b700a8073de 100644 --- a/src/document/Document.js +++ b/src/document/Document.js @@ -370,6 +370,7 @@ define(function (require, exports, module) { // future, we should fix things so that we either don't need mock documents or that this // is factored so it will just run in both. $(this).triggerHandler("change", [this, changeList]); + $(exports).triggerHandler("documentChange", [this, changeList]); }; /** diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js index 09211f18121..bbdb26d24e2 100644 --- a/src/search/FindInFiles.js +++ b/src/search/FindInFiles.js @@ -49,6 +49,7 @@ define(function (require, exports, module) { Strings = require("strings"), StringUtils = require("utils/StringUtils"), ProjectManager = require("project/ProjectManager"), + DocumentModule = require("document/Document"), DocumentManager = require("document/DocumentManager"), EditorManager = require("editor/EditorManager"), PanelManager = require("view/PanelManager"), @@ -69,7 +70,8 @@ define(function (require, exports, module) { /** @cost Constants used to define the maximum results show per page and found in a single file */ var RESULTS_PER_PAGE = 100, - FIND_IN_FILE_MAX = 300; + FIND_IN_FILE_MAX = 300, + UPDATE_TIMEOUT = 400; /** * Map of all the last search results @@ -95,6 +97,9 @@ define(function (require, exports, module) { /** @type {boolean} True if the matches in a file reached FIND_IN_FILE_MAX */ var maxHitsFoundInFile = false; + /** @type {string} The setTimeout id, used to clear it if required */ + var timeoutID = null; + /** @type {$.Element} jQuery elements used in the search results */ var $searchResults, $searchSummary, @@ -623,15 +628,17 @@ define(function (require, exports, module) { * Shows the search results and tries to restore the previous scroll and selection */ function _restoreSearchResults() { - var scrollTop = $searchContent.scrollTop(), - index = $selectedRow ? $selectedRow.index() : null; - - _showSearchResults(); - - $searchContent.scrollTop(scrollTop); - if (index) { - $selectedRow = $searchContent.find("tr:eq(" + index + ")"); - $selectedRow.addClass("selected"); + if (searchResultsPanel.isVisible()) { + var scrollTop = $searchContent.scrollTop(), + index = $selectedRow ? $selectedRow.index() : null; + + _showSearchResults(); + + $searchContent.scrollTop(scrollTop); + if (index) { + $selectedRow = $searchContent.find("tr:eq(" + index + ")"); + $selectedRow.addClass("selected"); + } } } @@ -690,115 +697,116 @@ define(function (require, exports, module) { /** * @private - * Update the result matches every time the content of a file changes - * @param {$.Event} event + * Update the search results using the given list of changes fr the given document * @param {Document} doc The Document that changed, should be the current one * @param {{from: {line:number,ch:number}, to: {line:number,ch:number}, text: string, next: change}} change * A linked list as described in the Document constructor - * @param {boolean=} resultsChanged True when the search results changed from a file change + * @param {boolean} resultsChanged True when the search results changed from a file change */ - function _fileChangeHandler(event, doc, change, resultsChanged) { - if ($searchResults.is(":visible")) { - var i, diff, matches, - fullPath = doc.file.fullPath, - lines = [], - start = 0, - howMany = 0; - - // There is no from or to positions, so the entire file changed, we must search all over again - if (!change.from || !change.to) { - _addSearchMatches(fullPath, doc.getText(), currentQueryExpr); - _restoreSearchResults(); + function _updateSearchResults(doc, change, resultsChanged) { + var i, diff, matches, + fullPath = doc.file.fullPath, + lines = [], + start = 0, + howMany = 0; - } else { - // Get only the lines that changed - for (i = 0; i < change.text.length; i++) { - lines.push(doc.getLine(change.from.line + i)); - } - - // We need to know how many lines changed to update the rest of the lines - if (change.from.line !== change.to.line) { - diff = change.from.line - change.to.line; - } else { - diff = lines.length - 1; - } - - if (searchResults[fullPath]) { - // Search the last match before a replacement, the amount of matches deleted and update - // the lines values for all the matches after the change - searchResults[fullPath].matches.forEach(function (item) { - if (item.end.line < change.from.line) { - start++; - } else if (item.end.line <= change.to.line) { - howMany++; - } else { - item.start.line += diff; - item.end.line += diff; - } - }); - - // Delete the lines that where deleted or replaced - if (howMany > 0) { - searchResults[fullPath].matches.splice(start, howMany); - } - resultsChanged = true; - } + // There is no from or to positions, so the entire file changed, we must search all over again + if (!change.from || !change.to) { + _addSearchMatches(fullPath, doc.getText(), currentQueryExpr); + resultsChanged = true; + + } else { + // Get only the lines that changed + for (i = 0; i < change.text.length; i++) { + lines.push(doc.getLine(change.from.line + i)); + } - // Searches only over the lines that changed - matches = _getSearchMatches(lines.join("\r\n"), currentQueryExpr); - if (matches && matches.length) { - // Updates the line numbers, since we only searched part of the file - matches.forEach(function (value, key) { - matches[key].start.line += change.from.line; - matches[key].end.line += change.from.line; - }); - - // If the file index exists, add the new matches to the file at the start index found before - if (searchResults[fullPath]) { - Array.prototype.splice.apply(searchResults[fullPath].matches, [start, 0].concat(matches)); - // If not, add the matches to a new file index + // We need to know how many lines changed to update the rest of the lines + if (change.from.line !== change.to.line) { + diff = change.from.line - change.to.line; + } else { + diff = lines.length - 1; + } + + if (searchResults[fullPath]) { + // Search the last match before a replacement, the amount of matches deleted and update + // the lines values for all the matches after the change + searchResults[fullPath].matches.forEach(function (item) { + if (item.end.line < change.from.line) { + start++; + } else if (item.end.line <= change.to.line) { + howMany++; } else { - searchResults[fullPath] = { - matches: matches, - collapsed: false - }; + item.start.line += diff; + item.end.line += diff; } - resultsChanged = true; - } + }); - // All the matches where deleted, remove the file from the results - if (searchResults[fullPath] && !searchResults[fullPath].matches.length) { - delete searchResults[fullPath]; - resultsChanged = true; + // Delete the lines that where deleted or replaced + if (howMany > 0) { + searchResults[fullPath].matches.splice(start, howMany); } + resultsChanged = true; + } + + // Searches only over the lines that changed + matches = _getSearchMatches(lines.join("\r\n"), currentQueryExpr); + if (matches && matches.length) { + // Updates the line numbers, since we only searched part of the file + matches.forEach(function (value, key) { + matches[key].start.line += change.from.line; + matches[key].end.line += change.from.line; + }); - // This is link to the next change object, so we need to keep searching - if (change.next) { - _fileChangeHandler(event, doc, change.next, resultsChanged); - - // If not we can show the results, but only if something changed - } else if (resultsChanged) { - _restoreSearchResults(); + // If the file index exists, add the new matches to the file at the start index found before + if (searchResults[fullPath]) { + Array.prototype.splice.apply(searchResults[fullPath].matches, [start, 0].concat(matches)); + // If not, add the matches to a new file index + } else { + searchResults[fullPath] = { + matches: matches, + collapsed: false + }; } + resultsChanged = true; + } + + // All the matches where deleted, remove the file from the results + if (searchResults[fullPath] && !searchResults[fullPath].matches.length) { + delete searchResults[fullPath]; + resultsChanged = true; + } + + // This is link to the next change object, so we need to keep searching + if (change.next) { + return _updateSearchResults(doc, change.next, resultsChanged); } } + return resultsChanged; } /** * @private - * Updates the event listeners when the current editor changes + * Tries to update the search result on document changes * @param {$.Event} event - * @param {Editor} current - * @param {Editor} previous + * @param {Document} document + * @param {{from: {line:number,ch:number}, to: {line:number,ch:number}, text: string, next: change}} change + * A linked list as described in the Document constructor */ - function _currentEditorChangeHandler(event, current, previous) { - if (previous) { - previous.document.releaseRef(); - $(previous.document).off("change", _fileChangeHandler); - } - if (_inScope(current.document.file, currentScope)) { - current.document.addRef(); - $(current.document).on("change", _fileChangeHandler); + function _documentChangeHandler(event, document, change) { + if (searchResultsPanel.isVisible() && _inScope(document.file, currentScope)) { + var updateResults = _updateSearchResults(document, change, false); + + if (timeoutID) { + window.clearTimeout(timeoutID); + updateResults = true; + } + if (updateResults) { + timeoutID = window.setTimeout(function () { + _restoreSearchResults(); + timeoutID = null; + }, UPDATE_TIMEOUT); + } } } @@ -818,7 +826,7 @@ define(function (require, exports, module) { $(DocumentManager).on("fileNameChange", _fileNameChangeHandler); $(DocumentManager).on("pathDeleted", _pathDeletedHandler); $(ProjectManager).on("beforeProjectClose", _hideSearchResults); - $(EditorManager).on("activeEditorChange", _currentEditorChangeHandler); + $(DocumentModule).on("documentChange", _documentChangeHandler); // Initialize: command handlers CommandManager.register(Strings.CMD_FIND_IN_FILES, Commands.EDIT_FIND_IN_FILES, _doFindInFiles); From d63627e49275188e407156e22a4511d2f0e661e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Malbr=C3=A1n?= Date: Thu, 22 Aug 2013 00:46:51 -0300 Subject: [PATCH 4/6] Only catch document changes when find in files is open --- src/search/FindInFiles.js | 280 +++++++++++++++++++------------------- 1 file changed, 142 insertions(+), 138 deletions(-) diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js index bbdb26d24e2..4b40004cc06 100644 --- a/src/search/FindInFiles.js +++ b/src/search/FindInFiles.js @@ -246,6 +246,7 @@ define(function (require, exports, module) { function _hideSearchResults() { if (searchResultsPanel.isVisible()) { searchResultsPanel.hide(); + $(DocumentModule).off(".findInFiles"); } } @@ -521,7 +522,118 @@ define(function (require, exports, module) { _hideSearchResults(); } } - + + + + /** + * @private + * Shows the search results and tries to restore the previous scroll and selection + */ + function _restoreSearchResults() { + if (searchResultsPanel.isVisible()) { + var scrollTop = $searchContent.scrollTop(), + index = $selectedRow ? $selectedRow.index() : null; + + _showSearchResults(); + + $searchContent.scrollTop(scrollTop); + if (index) { + $selectedRow = $searchContent.find("tr:eq(" + index + ")"); + $selectedRow.addClass("selected"); + } + } + } + + /** + * @private + * Update the search results using the given list of changes fr the given document + * @param {Document} doc The Document that changed, should be the current one + * @param {{from: {line:number,ch:number}, to: {line:number,ch:number}, text: string, next: change}} change + * A linked list as described in the Document constructor + * @param {boolean} resultsChanged True when the search results changed from a file change + */ + function _updateSearchResults(doc, change, resultsChanged) { + var i, diff, matches, + fullPath = doc.file.fullPath, + lines = [], + start = 0, + howMany = 0; + + // There is no from or to positions, so the entire file changed, we must search all over again + if (!change.from || !change.to) { + _addSearchMatches(fullPath, doc.getText(), currentQueryExpr); + resultsChanged = true; + + } else { + // Get only the lines that changed + for (i = 0; i < change.text.length; i++) { + lines.push(doc.getLine(change.from.line + i)); + } + + // We need to know how many lines changed to update the rest of the lines + if (change.from.line !== change.to.line) { + diff = change.from.line - change.to.line; + } else { + diff = lines.length - 1; + } + + if (searchResults[fullPath]) { + // Search the last match before a replacement, the amount of matches deleted and update + // the lines values for all the matches after the change + searchResults[fullPath].matches.forEach(function (item) { + if (item.end.line < change.from.line) { + start++; + } else if (item.end.line <= change.to.line) { + howMany++; + } else { + item.start.line += diff; + item.end.line += diff; + } + }); + + // Delete the lines that where deleted or replaced + if (howMany > 0) { + searchResults[fullPath].matches.splice(start, howMany); + } + resultsChanged = true; + } + + // Searches only over the lines that changed + matches = _getSearchMatches(lines.join("\r\n"), currentQueryExpr); + if (matches && matches.length) { + // Updates the line numbers, since we only searched part of the file + matches.forEach(function (value, key) { + matches[key].start.line += change.from.line; + matches[key].end.line += change.from.line; + }); + + // If the file index exists, add the new matches to the file at the start index found before + if (searchResults[fullPath]) { + Array.prototype.splice.apply(searchResults[fullPath].matches, [start, 0].concat(matches)); + // If not, add the matches to a new file index + } else { + searchResults[fullPath] = { + matches: matches, + collapsed: false + }; + } + resultsChanged = true; + } + + // All the matches where deleted, remove the file from the results + if (searchResults[fullPath] && !searchResults[fullPath].matches.length) { + delete searchResults[fullPath]; + resultsChanged = true; + } + + // This is link to the next change object, so we need to keep searching + if (change.next) { + return _updateSearchResults(doc, change.next, resultsChanged); + } + } + return resultsChanged; + } + /** * @private * @param {!FileInfo} fileInfo File in question @@ -540,7 +652,34 @@ define(function (require, exports, module) { } return true; } - + + /** + * @private + * Tries to update the search result on document changes + * @param {$.Event} event + * @param {Document} document + * @param {{from: {line:number,ch:number}, to: {line:number,ch:number}, text: string, next: change}} change + * A linked list as described in the Document constructor + */ + function _documentChangeHandler(event, document, change) { + if (searchResultsPanel.isVisible() && _inScope(document.file, currentScope)) { + var updateResults = _updateSearchResults(document, change, false); + + if (timeoutID) { + window.clearTimeout(timeoutID); + updateResults = true; + } + if (updateResults) { + timeoutID = window.setTimeout(function () { + _restoreSearchResults(); + timeoutID = null; + }, UPDATE_TIMEOUT); + } + } + } + + + /** * @private * Displays a non-modal embedded dialog above the code mirror editor that allows the user to do @@ -603,6 +742,7 @@ define(function (require, exports, module) { // Done searching all files: show results _showSearchResults(); StatusBar.hideBusyIndicator(); + $(DocumentModule).on("documentChange.findInFiles", _documentChangeHandler); }) .fail(function () { console.log("find in files failed."); @@ -623,26 +763,6 @@ define(function (require, exports, module) { } - /** - * @private - * Shows the search results and tries to restore the previous scroll and selection - */ - function _restoreSearchResults() { - if (searchResultsPanel.isVisible()) { - var scrollTop = $searchContent.scrollTop(), - index = $selectedRow ? $selectedRow.index() : null; - - _showSearchResults(); - - $searchContent.scrollTop(scrollTop); - if (index) { - $selectedRow = $searchContent.find("tr:eq(" + index + ")"); - $selectedRow.addClass("selected"); - } - } - } - - /** * @private * Moves the search results from the previous path to the new one and updates the results list, if required @@ -695,121 +815,6 @@ define(function (require, exports, module) { } } - /** - * @private - * Update the search results using the given list of changes fr the given document - * @param {Document} doc The Document that changed, should be the current one - * @param {{from: {line:number,ch:number}, to: {line:number,ch:number}, text: string, next: change}} change - * A linked list as described in the Document constructor - * @param {boolean} resultsChanged True when the search results changed from a file change - */ - function _updateSearchResults(doc, change, resultsChanged) { - var i, diff, matches, - fullPath = doc.file.fullPath, - lines = [], - start = 0, - howMany = 0; - - // There is no from or to positions, so the entire file changed, we must search all over again - if (!change.from || !change.to) { - _addSearchMatches(fullPath, doc.getText(), currentQueryExpr); - resultsChanged = true; - - } else { - // Get only the lines that changed - for (i = 0; i < change.text.length; i++) { - lines.push(doc.getLine(change.from.line + i)); - } - - // We need to know how many lines changed to update the rest of the lines - if (change.from.line !== change.to.line) { - diff = change.from.line - change.to.line; - } else { - diff = lines.length - 1; - } - - if (searchResults[fullPath]) { - // Search the last match before a replacement, the amount of matches deleted and update - // the lines values for all the matches after the change - searchResults[fullPath].matches.forEach(function (item) { - if (item.end.line < change.from.line) { - start++; - } else if (item.end.line <= change.to.line) { - howMany++; - } else { - item.start.line += diff; - item.end.line += diff; - } - }); - - // Delete the lines that where deleted or replaced - if (howMany > 0) { - searchResults[fullPath].matches.splice(start, howMany); - } - resultsChanged = true; - } - - // Searches only over the lines that changed - matches = _getSearchMatches(lines.join("\r\n"), currentQueryExpr); - if (matches && matches.length) { - // Updates the line numbers, since we only searched part of the file - matches.forEach(function (value, key) { - matches[key].start.line += change.from.line; - matches[key].end.line += change.from.line; - }); - - // If the file index exists, add the new matches to the file at the start index found before - if (searchResults[fullPath]) { - Array.prototype.splice.apply(searchResults[fullPath].matches, [start, 0].concat(matches)); - // If not, add the matches to a new file index - } else { - searchResults[fullPath] = { - matches: matches, - collapsed: false - }; - } - resultsChanged = true; - } - - // All the matches where deleted, remove the file from the results - if (searchResults[fullPath] && !searchResults[fullPath].matches.length) { - delete searchResults[fullPath]; - resultsChanged = true; - } - - // This is link to the next change object, so we need to keep searching - if (change.next) { - return _updateSearchResults(doc, change.next, resultsChanged); - } - } - return resultsChanged; - } - - /** - * @private - * Tries to update the search result on document changes - * @param {$.Event} event - * @param {Document} document - * @param {{from: {line:number,ch:number}, to: {line:number,ch:number}, text: string, next: change}} change - * A linked list as described in the Document constructor - */ - function _documentChangeHandler(event, document, change) { - if (searchResultsPanel.isVisible() && _inScope(document.file, currentScope)) { - var updateResults = _updateSearchResults(document, change, false); - - if (timeoutID) { - window.clearTimeout(timeoutID); - updateResults = true; - } - if (updateResults) { - timeoutID = window.setTimeout(function () { - _restoreSearchResults(); - timeoutID = null; - }, UPDATE_TIMEOUT); - } - } - } - // Initialize items dependent on HTML DOM @@ -826,7 +831,6 @@ define(function (require, exports, module) { $(DocumentManager).on("fileNameChange", _fileNameChangeHandler); $(DocumentManager).on("pathDeleted", _pathDeletedHandler); $(ProjectManager).on("beforeProjectClose", _hideSearchResults); - $(DocumentModule).on("documentChange", _documentChangeHandler); // Initialize: command handlers CommandManager.register(Strings.CMD_FIND_IN_FILES, Commands.EDIT_FIND_IN_FILES, _doFindInFiles); From ec303ce4de3acc9c49cf2ea4450962331d669629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Malbr=C3=A1n?= Date: Fri, 6 Sep 2013 21:57:59 -0300 Subject: [PATCH 5/6] Correctly update the currentStart when removing lots of results. --- src/search/FindInFiles.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js index 3327dd9307b..beb11ef63e8 100644 --- a/src/search/FindInFiles.js +++ b/src/search/FindInFiles.js @@ -555,9 +555,13 @@ define(function (require, exports, module) { */ function _restoreSearchResults() { if (searchResultsPanel.isVisible()) { - var scrollTop = $searchContent.scrollTop(), - index = $selectedRow ? $selectedRow.index() : null; + var scrollTop = $searchContent.scrollTop(), + index = $selectedRow ? $selectedRow.index() : null, + numMatches = _countFilesMatches().matches; + if (currentStart > numMatches) { + currentStart = _getLastCurrentStart(numMatches); + } _showSearchResults(); $searchContent.scrollTop(scrollTop); @@ -821,7 +825,7 @@ define(function (require, exports, module) { * @param {string} path */ function _pathDeletedHandler(event, path) { - var resultsChanged = false, numMatches; + var resultsChanged = false; if (searchResultsPanel.isVisible()) { // Update the search results @@ -834,10 +838,6 @@ define(function (require, exports, module) { // Restore the results if needed if (resultsChanged) { - numMatches = _countFilesMatches().matches; - if (currentStart > numMatches) { - currentStart = _getLastCurrentStart(numMatches); - } _restoreSearchResults(); } } From 8a9bf5e33a5cb03ba4f9bfaec1283eb804bfe7d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Malbr=C3=A1n?= Date: Sat, 14 Sep 2013 13:17:16 -0300 Subject: [PATCH 6/6] Fixed a couple of indentation issues --- src/search/FindInFiles.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js index beb11ef63e8..c32d02e9585 100644 --- a/src/search/FindInFiles.js +++ b/src/search/FindInFiles.js @@ -246,7 +246,7 @@ define(function (require, exports, module) { function _hideSearchResults() { if (searchResultsPanel.isVisible()) { searchResultsPanel.hide(); - $(DocumentModule).off(".findInFiles"); + $(DocumentModule).off(".findInFiles"); } } @@ -549,7 +549,7 @@ define(function (require, exports, module) { - /** + /** * @private * Shows the search results and tries to restore the previous scroll and selection */