From 12456de6e6c09ec0c91ef9146443a097c1fe1979 Mon Sep 17 00:00:00 2001 From: RaymondLim Date: Fri, 21 Feb 2014 11:59:19 -0800 Subject: [PATCH 01/14] Initial implementation search exclusion using project-based view setting. --- src/search/FindInFiles.js | 41 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js index ce8ec3a9b03..75e79fd2e92 100644 --- a/src/search/FindInFiles.js +++ b/src/search/FindInFiles.js @@ -50,6 +50,7 @@ define(function (require, exports, module) { Commands = require("command/Commands"), Strings = require("strings"), StringUtils = require("utils/StringUtils"), + PreferencesManager = require("preferences/PreferencesManager"), ProjectManager = require("project/ProjectManager"), DocumentModule = require("document/Document"), DocumentManager = require("document/DocumentManager"), @@ -65,7 +66,8 @@ define(function (require, exports, module) { KeyEvent = require("utils/KeyEvent"), AppInit = require("utils/AppInit"), StatusBar = require("widgets/StatusBar"), - ModalBar = require("widgets/ModalBar").ModalBar; + ModalBar = require("widgets/ModalBar").ModalBar, + globmatch = require("thirdparty/globmatch"); var searchDialogTemplate = require("text!htmlContent/findinfiles-bar.html"), searchPanelTemplate = require("text!htmlContent/search-panel.html"), @@ -122,6 +124,11 @@ define(function (require, exports, module) { **/ var _fileSystemChangeHandler; + /** + * @type {Array.} a list of files/folder exclusions to be used in 'find in files' + **/ + var _exclusionGlobs = []; + /** * @private * Returns a regular expression from the given query and shows an error in the modal-bar if it was invalid @@ -692,6 +699,22 @@ define(function (require, exports, module) { return result.promise(); } + function _getExclusionGlobs() { + return _exclusionGlobs; + } + + function _updateExclusionGlobs(globs) { + var context = { location : { scope: "user", + layer: "project" } }; + + // TODO: limit to 10 exclusions in globs + _exclusionGlobs = globs; + + // Use context to store it in project-based view state +// PreferencesManager.setViewState("search.exclusion", _exclusionGlobs); + _exclusionGlobs = PreferencesManager.setViewState("search.exclusion", _exclusionGlobs, context); + } + /** * Used to filter out image files when building a list of file in which to * search. Ideally this would filter out ALL binary files. @@ -700,6 +723,15 @@ define(function (require, exports, module) { * @return {boolean} Whether or not the entry's contents should be searched */ function _findInFilesFilter(entry) { + var globCounter; + for (globCounter = 0; globCounter < _exclusionGlobs.length; globCounter++) { + var glob = _exclusionGlobs[globCounter]; + + if (globmatch(entry.fullPath, glob)) { + return false; + } + } + var language = LanguageManager.getLanguageForPath(entry.fullPath); return !language.isBinary(); } @@ -720,8 +752,13 @@ define(function (require, exports, module) { } var scopeName = currentScope ? currentScope.fullPath : ProjectManager.getProjectRoot().fullPath, - perfTimer = PerfUtils.markStart("FindIn: " + scopeName + " - " + query); + perfTimer = PerfUtils.markStart("FindIn: " + scopeName + " - " + query), + context = { location : { scope: "user", + layer: "project" } }; + // Use context to get it from project-based view state +// _exclusionGlobs = PreferencesManager.getViewState("search.exclusion") || []; + _exclusionGlobs = PreferencesManager.getViewState("search.exclusion", context) || []; ProjectManager.getAllFiles(_findInFilesFilter, true) .then(function (fileListResult) { var doSearch = _doSearchInOneFile.bind(undefined, _addSearchMatches); From 56e70d652a0e2763f047d28d75a15aa711cdf019 Mon Sep 17 00:00:00 2001 From: RaymondLim Date: Fri, 21 Feb 2014 12:56:39 -0800 Subject: [PATCH 02/14] Remove an incorrect assignment. --- src/search/FindInFiles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js index 75e79fd2e92..9023ffad2bf 100644 --- a/src/search/FindInFiles.js +++ b/src/search/FindInFiles.js @@ -712,7 +712,7 @@ define(function (require, exports, module) { // Use context to store it in project-based view state // PreferencesManager.setViewState("search.exclusion", _exclusionGlobs); - _exclusionGlobs = PreferencesManager.setViewState("search.exclusion", _exclusionGlobs, context); + PreferencesManager.setViewState("search.exclusion", _exclusionGlobs, context); } /** From d960b63f5d40cfa82a6dabf3ef08fc40bf39d6d8 Mon Sep 17 00:00:00 2001 From: RaymondLim Date: Fri, 21 Feb 2014 16:37:15 -0800 Subject: [PATCH 03/14] Switch to global view state instead of project-based one and also limit it to ten globs. --- src/search/FindInFiles.js | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js index 9023ffad2bf..971017017ab 100644 --- a/src/search/FindInFiles.js +++ b/src/search/FindInFiles.js @@ -704,19 +704,20 @@ define(function (require, exports, module) { } function _updateExclusionGlobs(globs) { - var context = { location : { scope: "user", - layer: "project" } }; - - // TODO: limit to 10 exclusions in globs - _exclusionGlobs = globs; - - // Use context to store it in project-based view state -// PreferencesManager.setViewState("search.exclusion", _exclusionGlobs); - PreferencesManager.setViewState("search.exclusion", _exclusionGlobs, context); + if (globs && _.isArray(globs)) { + // Limit to 10 exclusions in globs before writing out + _exclusionGlobs = globs.slice(0, 10); + PreferencesManager.setViewState("search.exclusion", _exclusionGlobs); + } else { + // Remove all exclusions + _exclusionGlobs = []; + PreferencesManager.setViewState("search.exclusion", _exclusionGlobs); + } } /** - * Used to filter out image files when building a list of file in which to + * Used to filter out files that match to exclusion glob strings, + * and then filter out image files when building a list of file in which to * search. Ideally this would filter out ALL binary files. * @private * @param {FileSystemEntry} entry The entry to test @@ -724,6 +725,7 @@ define(function (require, exports, module) { */ function _findInFilesFilter(entry) { var globCounter; + for (globCounter = 0; globCounter < _exclusionGlobs.length; globCounter++) { var glob = _exclusionGlobs[globCounter]; @@ -752,13 +754,9 @@ define(function (require, exports, module) { } var scopeName = currentScope ? currentScope.fullPath : ProjectManager.getProjectRoot().fullPath, - perfTimer = PerfUtils.markStart("FindIn: " + scopeName + " - " + query), - context = { location : { scope: "user", - layer: "project" } }; + perfTimer = PerfUtils.markStart("FindIn: " + scopeName + " - " + query); - // Use context to get it from project-based view state -// _exclusionGlobs = PreferencesManager.getViewState("search.exclusion") || []; - _exclusionGlobs = PreferencesManager.getViewState("search.exclusion", context) || []; + _exclusionGlobs = PreferencesManager.getViewState("search.exclusion") || []; ProjectManager.getAllFiles(_findInFilesFilter, true) .then(function (fileListResult) { var doSearch = _doSearchInOneFile.bind(undefined, _addSearchMatches); From f87f488f12fefe94069a02f091c7151ec137c19f Mon Sep 17 00:00:00 2001 From: RaymondLim Date: Sun, 23 Feb 2014 09:32:23 -0800 Subject: [PATCH 04/14] Fix JSLint error for extra trailing whitespaces. --- src/search/FindInFiles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js index 971017017ab..4a6348d8bb2 100644 --- a/src/search/FindInFiles.js +++ b/src/search/FindInFiles.js @@ -67,7 +67,7 @@ define(function (require, exports, module) { AppInit = require("utils/AppInit"), StatusBar = require("widgets/StatusBar"), ModalBar = require("widgets/ModalBar").ModalBar, - globmatch = require("thirdparty/globmatch"); + globmatch = require("thirdparty/globmatch"); var searchDialogTemplate = require("text!htmlContent/findinfiles-bar.html"), searchPanelTemplate = require("text!htmlContent/search-panel.html"), From eb580f1259b49cb5846201ff03095e56d73bd52f Mon Sep 17 00:00:00 2001 From: Peter Flynn Date: Mon, 24 Feb 2014 12:56:16 -0700 Subject: [PATCH 05/14] First pass at UI for Find in Files exclusion filters. Not wired up to seach implementation or prefs yet. Changes the search bar to use ModalBar's autoClose behavior; no longer assumes its code is the only thing to ever close the bar. Adds a new API to ModalBar to allow the search bar to be 'locked open' when it would normally close, as Find in Files needs for its no-results state and when the filter editor dialog is open. --- src/htmlContent/findinfiles-bar.html | 4 + src/nls/root/strings.js | 8 ++ src/search/FileFilters.js | 117 +++++++++++++++++++++ src/search/FindInFiles.js | 27 +++-- src/styles/brackets.less | 18 ++++ src/styles/brackets_patterns_override.less | 23 ++++ src/widgets/ModalBar.js | 12 +++ 7 files changed, 199 insertions(+), 10 deletions(-) create mode 100644 src/search/FileFilters.js diff --git a/src/htmlContent/findinfiles-bar.html b/src/htmlContent/findinfiles-bar.html index d3a699f22e9..e85f475f40b 100644 --- a/src/htmlContent/findinfiles-bar.html +++ b/src/htmlContent/findinfiles-bar.html @@ -7,4 +7,8 @@
{{{label}}}
+ + +
+ \ No newline at end of file diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index 6ceb06fd583..19428e27624 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -166,6 +166,14 @@ define({ "FIND_IN_FILES_EXPAND_COLLAPSE" : "Ctrl/Cmd click to expand/collapse all", "ERROR_FETCHING_UPDATE_INFO_TITLE" : "Error getting update info", "ERROR_FETCHING_UPDATE_INFO_MSG" : "There was a problem getting the latest update information from the server. Please make sure you are connected to the internet and try again.", + + // File exclusion filters + "NO_FILE_FILTER" : "No filter", + "EDIT_FILE_FILTER" : "Edit filter...", + "FILE_FILTER_INSTRUCTIONS" : "Exclude files and folders matching any of the following strings / substrings or globs. Enter each string on a new line.", + "FILE_FILTER_LIST_PREFIX" : "except", + "FILE_FILTER_CLIPPED_SUFFIX" : "and {0} more", + /** * ProjectManager diff --git a/src/search/FileFilters.js b/src/search/FileFilters.js new file mode 100644 index 00000000000..90739fdb2bb --- /dev/null +++ b/src/search/FileFilters.js @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2014 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. + * + */ + +/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */ +/*global define, $, window, Mustache */ + +/** + * Utilities for managing file-set filters, as used in Find in Files. + * Includes both UI for selecting/editing filters, as well as the actual file-filtering implementation. + */ +define(function (require, exports, module) { + "use strict"; + + var _ = require("thirdparty/lodash"), + DefaultDialogs = require("widgets/DefaultDialogs"), + Dialogs = require("widgets/Dialogs"), + StringUtils = require("utils/StringUtils"), + Strings = require("strings"); + + /** + * Each filter is a single string composed of one or more \n-separated glob strings. + * @return {!Array.} + */ + function getFilters() { + // FIXME: hook up to preferences + return [ + "node_modules", + "node_modules\n*.ttf\njquery-ui" + ]; + } + + + function editFilter(filter) { + var globInfoURL = "https://github.com/adobe/brackets/wiki/How-to-Use-Brackets"; // FIXME: link to a dedicated wiki page + var html = StringUtils.format(Strings.FILE_FILTER_INSTRUCTIONS, globInfoURL) + + ""; + var buttons = [ + { className : Dialogs.DIALOG_BTN_CLASS_PRIMARY, id: Dialogs.DIALOG_BTN_OK, text: Strings.OK }, + { className : Dialogs.DIALOG_BTN_CLASS_NORMAL, id: Dialogs.DIALOG_BTN_CANCEL, text: Strings.CANCEL } + ]; + var dialog = Dialogs.showModalDialog(DefaultDialogs.DIALOG_ID_INFO, "Edit Filter", html, buttons); + + dialog.getElement().find(".exclusions-editor").val(filter); + + return dialog.getPromise(); + } + + + function populateDropdown($select) { + $select.empty(); + + function addOption(filter, label) { + var $option = $("