From 6b1ff9e65d11891d8641b1471b989c628610922a Mon Sep 17 00:00:00 2001 From: Emile Contal Date: Sun, 12 Mar 2017 00:31:10 -0800 Subject: [PATCH 1/4] ignore extensions --- lib/config.js | 6 ++++++ lib/models.js | 8 ++++++++ lib/view.js | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/config.js b/lib/config.js index 30ac035..a488903 100644 --- a/lib/config.js +++ b/lib/config.js @@ -45,5 +45,11 @@ export let config = { details.`, type: 'boolean', default: false, + }, + ignoredFiles: { + title: "Ignore files with these extensions", + description: "Don't show files with the given extensions.", + type: 'string', + default: '.pyc,~', } }; diff --git a/lib/models.js b/lib/models.js index 8e66872..ccf62ca 100644 --- a/lib/models.js +++ b/lib/models.js @@ -58,6 +58,14 @@ export class Path { return this.stat ? !this.stat.isDirectory() : null; } + isVisible() { + ignoredExtensions = config.get('ignoredFiles').split(','); + for( i in ignoredExtensions) { + if(this.fragment.endsWith(ignoredExtensions[i])) return false; + } + return true; + } + isProjectDirectory() { return atom.project.getPaths().indexOf(this.absolute) !== -1; } diff --git a/lib/view.js b/lib/view.js index 0586b86..ea073da 100644 --- a/lib/view.js +++ b/lib/view.js @@ -235,7 +235,7 @@ export default class AdvancedOpenFileView { // Split list into directories and files and sort them. paths = paths.sort(Path.compare); let directoryPaths = paths.filter((path) => path.isDirectory()); - let filePaths = paths.filter((path) => path.isFile()); + let filePaths = paths.filter((path) => path.isFile() && path.isVisible()); this._appendToPathList(directoryPaths); this._appendToPathList(filePaths); } else { From 665be8d6269c8184608e67146893a9e30eb2524a Mon Sep 17 00:00:00 2001 From: Emile Contal Date: Sun, 26 Nov 2017 22:16:40 -0800 Subject: [PATCH 2/4] isVisible should return true is ignoredFiles is undefined --- lib/models.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/models.js b/lib/models.js index ccf62ca..91b0249 100644 --- a/lib/models.js +++ b/lib/models.js @@ -59,7 +59,9 @@ export class Path { } isVisible() { - ignoredExtensions = config.get('ignoredFiles').split(','); + ignoredFiles = config.get('ignoredFiles'); + if (!ignoredFiles) return true; + ignoredExtensions = ignoredFiles.split(','); for( i in ignoredExtensions) { if(this.fragment.endsWith(ignoredExtensions[i])) return false; } From 853686e69e6ae737b6da6071edd082c6b870ef8f Mon Sep 17 00:00:00 2001 From: Emile Contal Date: Sat, 9 Dec 2017 17:22:40 -0800 Subject: [PATCH 3/4] use globs instead of suffix. Use minimatch to optimize performances (matching library used internally by npm) --- lib/config.js | 13 ++++++++----- lib/models.js | 22 ++++++++++++---------- lib/utils.js | 17 +++++++++++++++++ lib/view.js | 2 +- package.json | 1 + 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/lib/config.js b/lib/config.js index a488903..1ffda1e 100644 --- a/lib/config.js +++ b/lib/config.js @@ -46,10 +46,13 @@ export let config = { type: 'boolean', default: false, }, - ignoredFiles: { - title: "Ignore files with these extensions", - description: "Don't show files with the given extensions.", - type: 'string', - default: '.pyc,~', + ignoredPatterns: { + title: 'Ignore patterns', + description: 'Array of glob patterns to hide matching filenames.', + type: 'array', + default: ['*.pyc', '*.pyo'], + items: { + type: 'string', + }, } }; diff --git a/lib/models.js b/lib/models.js index 91b0249..d3ed8dd 100644 --- a/lib/models.js +++ b/lib/models.js @@ -13,6 +13,7 @@ import { cachedProperty, defineImmutable, getProjectPath, + ignoredPatterns, preferredSeparatorFor } from './utils'; @@ -58,16 +59,6 @@ export class Path { return this.stat ? !this.stat.isDirectory() : null; } - isVisible() { - ignoredFiles = config.get('ignoredFiles'); - if (!ignoredFiles) return true; - ignoredExtensions = ignoredFiles.split(','); - for( i in ignoredExtensions) { - if(this.fragment.endsWith(ignoredExtensions[i])) return false; - } - return true; - } - isProjectDirectory() { return atom.project.getPaths().indexOf(this.absolute) !== -1; } @@ -157,6 +148,7 @@ export class Path { } } + filenames = filenames.filter(isVisible) return filenames.map((fn) => new Path(this.directory + fn)); } @@ -249,3 +241,13 @@ function matchFragment(fragment, filename, caseSensitive=false) { return filename.startsWith(fragment); } + +/** + * Return whether the filename is not hidden by the ignoredPatterns config. + */ +function isVisible(filename) { + for (const ignoredPattern of ignoredPatterns()) { + if (ignoredPattern.match(filename)) return false; + } + return true; +} diff --git a/lib/utils.js b/lib/utils.js index c8dcb90..85500f9 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,9 +1,12 @@ /** @babel */ +import minimatch from 'minimatch'; import stdPath from 'path'; import osenv from 'osenv'; +import * as config from './config'; + /** * Generates the return value for the wrapper property on first access @@ -135,3 +138,17 @@ export function closest(selector) { return null; } } + + +/** + * Returns an array of Minimatch instances to test whether a filename + * is ignored. Cache the Minimatch instances instead of re-compiling + * the regexp. + */ +export function ignoredPatterns() { + if (this.minimatches === undefined ) { + const ignoredGlobs = config.get('ignoredPatterns'); + this.minimatches = ignoredGlobs.map((glob) => new minimatch.Minimatch(glob)) + } + return this.minimatches; +} diff --git a/lib/view.js b/lib/view.js index ea073da..0586b86 100644 --- a/lib/view.js +++ b/lib/view.js @@ -235,7 +235,7 @@ export default class AdvancedOpenFileView { // Split list into directories and files and sort them. paths = paths.sort(Path.compare); let directoryPaths = paths.filter((path) => path.isDirectory()); - let filePaths = paths.filter((path) => path.isFile() && path.isVisible()); + let filePaths = paths.filter((path) => path.isFile()); this._appendToPathList(directoryPaths); this._appendToPathList(filePaths); } else { diff --git a/package.json b/package.json index 5464a29..4128b78 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "event-kit": "^1.3.0", "fuzzaldrin-plus": "^0.3.1", "mkdirp": "^0.5.1", + "minimatch": "^3.0.4", "osenv": "^0.1.3", "touch": "^1.0.0" }, From ba1f1ca57213dba398e60aaf602154eb4572aae3 Mon Sep 17 00:00:00 2001 From: Emile Contal Date: Fri, 9 Mar 2018 23:11:26 -0800 Subject: [PATCH 4/4] use StringMap to cache minimap objects from glob string --- lib/utils.js | 23 ++++++++++++++++++----- package.json | 3 ++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index 85500f9..6774c4b 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -2,6 +2,7 @@ import minimatch from 'minimatch'; import stdPath from 'path'; +import StringMap from 'stringmap'; import osenv from 'osenv'; @@ -140,15 +141,27 @@ export function closest(selector) { } +/** + * Return value from StringMap if exists + * otherwise generate value with getValue, set the StringMap and return + */ +export function getOrUpdateStringMap(stringMap, key, getValue) { + if (stringMap.has(key) ) { + return stringMap.get(key); + } + const value = getValue(key); + stringMap.set(key, value); + return value; +} + /** * Returns an array of Minimatch instances to test whether a filename * is ignored. Cache the Minimatch instances instead of re-compiling * the regexp. */ +let _minimatchesCache = StringMap(); export function ignoredPatterns() { - if (this.minimatches === undefined ) { - const ignoredGlobs = config.get('ignoredPatterns'); - this.minimatches = ignoredGlobs.map((glob) => new minimatch.Minimatch(glob)) - } - return this.minimatches; + const ignoredGlobs = config.get('ignoredPatterns') + return ignoredGlobs.map((glob) => getOrUpdateStringMap(_minimatchesCache, glob, (glob) => + new minimatch.Minimatch(glob))) } diff --git a/package.json b/package.json index 4128b78..f0a3114 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,8 @@ "mkdirp": "^0.5.1", "minimatch": "^3.0.4", "osenv": "^0.1.3", - "touch": "^1.0.0" + "touch": "^1.0.0", + "stringmap": "~0.2.2" }, "devDependencies": { "babel": "^5.8.35",