• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @constructor
33 * @extends {WebInspector.Object}
34 */
35WebInspector.FileSystemMapping = function()
36{
37    WebInspector.Object.call(this);
38    this._fileSystemMappingSetting = WebInspector.settings.createSetting("fileSystemMapping", {});
39    this._excludedFoldersSetting = WebInspector.settings.createSetting("workspaceExcludedFolders", {});
40    var defaultCommonExcludedFolders = [
41        "/\\.git/",
42        "/\\.sass-cache/",
43        "/\\.hg/",
44        "/\\.idea/",
45        "/\\.svn/",
46        "/\\.cache/",
47        "/\\.project/"
48    ];
49    var defaultWinExcludedFolders = [
50        "/Thumbs.db$",
51        "/ehthumbs.db$",
52        "/Desktop.ini$",
53        "/\\$RECYCLE.BIN/"
54    ];
55    var defaultMacExcludedFolders = [
56        "/\\.DS_Store$",
57        "/\\.Trashes$",
58        "/\\.Spotlight-V100$",
59        "/\\.AppleDouble$",
60        "/\\.LSOverride$",
61        "/Icon$",
62        "/\\._.*$"
63    ];
64    var defaultLinuxExcludedFolders = [
65        "/.*~$"
66    ];
67    var defaultExcludedFolders = defaultCommonExcludedFolders;
68    if (WebInspector.isWin())
69        defaultExcludedFolders = defaultExcludedFolders.concat(defaultWinExcludedFolders);
70    else if (WebInspector.isMac())
71        defaultExcludedFolders = defaultExcludedFolders.concat(defaultMacExcludedFolders);
72    else
73        defaultExcludedFolders = defaultExcludedFolders.concat(defaultLinuxExcludedFolders);
74    var defaultExcludedFoldersPattern = defaultExcludedFolders.join("|");
75    WebInspector.settings.workspaceFolderExcludePattern = WebInspector.settings.createRegExpSetting("workspaceFolderExcludePattern", defaultExcludedFoldersPattern, WebInspector.isWin() ? "i" : "");
76    /** @type {!Object.<string, !Array.<!WebInspector.FileSystemMapping.Entry>>} */
77    this._fileSystemMappings = {};
78    /** @type {!Object.<string, !Array.<!WebInspector.FileSystemMapping.ExcludedFolderEntry>>} */
79    this._excludedFolders = {};
80    this._loadFromSettings();
81}
82
83WebInspector.FileSystemMapping.Events = {
84    FileMappingAdded: "FileMappingAdded",
85    FileMappingRemoved: "FileMappingRemoved",
86    ExcludedFolderAdded: "ExcludedFolderAdded",
87    ExcludedFolderRemoved: "ExcludedFolderRemoved"
88}
89
90
91WebInspector.FileSystemMapping.prototype = {
92    _loadFromSettings: function()
93    {
94        var savedMapping = this._fileSystemMappingSetting.get();
95        this._fileSystemMappings = {};
96        for (var fileSystemPath in savedMapping) {
97            var savedFileSystemMappings = savedMapping[fileSystemPath];
98
99            this._fileSystemMappings[fileSystemPath] = [];
100            var fileSystemMappings = this._fileSystemMappings[fileSystemPath];
101
102            for (var i = 0; i < savedFileSystemMappings.length; ++i) {
103                var savedEntry = savedFileSystemMappings[i];
104                var entry = new WebInspector.FileSystemMapping.Entry(savedEntry.fileSystemPath, savedEntry.urlPrefix, savedEntry.pathPrefix);
105                fileSystemMappings.push(entry);
106            }
107        }
108
109        var savedExcludedFolders = this._excludedFoldersSetting.get();
110        this._excludedFolders = {};
111        for (var fileSystemPath in savedExcludedFolders) {
112            var savedExcludedFoldersForPath = savedExcludedFolders[fileSystemPath];
113
114            this._excludedFolders[fileSystemPath] = [];
115            var excludedFolders = this._excludedFolders[fileSystemPath];
116
117            for (var i = 0; i < savedExcludedFoldersForPath.length; ++i) {
118                var savedEntry = savedExcludedFoldersForPath[i];
119                var entry = new WebInspector.FileSystemMapping.ExcludedFolderEntry(savedEntry.fileSystemPath, savedEntry.path);
120                excludedFolders.push(entry);
121            }
122        }
123
124        this._rebuildIndexes();
125    },
126
127    _saveToSettings: function()
128    {
129        var savedMapping = this._fileSystemMappings;
130        this._fileSystemMappingSetting.set(savedMapping);
131
132        var savedExcludedFolders = this._excludedFolders;
133        this._excludedFoldersSetting.set(savedExcludedFolders);
134
135        this._rebuildIndexes();
136    },
137
138    _rebuildIndexes: function()
139    {
140        // We are building an index here to search for the longest url prefix match faster.
141        this._mappingForURLPrefix = {};
142        this._urlPrefixes = [];
143        for (var fileSystemPath in this._fileSystemMappings) {
144            var fileSystemMapping = this._fileSystemMappings[fileSystemPath];
145            for (var i = 0; i < fileSystemMapping.length; ++i) {
146                var entry = fileSystemMapping[i];
147                this._mappingForURLPrefix[entry.urlPrefix] = entry;
148                this._urlPrefixes.push(entry.urlPrefix);
149            }
150        }
151        this._urlPrefixes.sort();
152    },
153
154    /**
155     * @param {string} fileSystemPath
156     */
157    addFileSystem: function(fileSystemPath)
158    {
159        if (this._fileSystemMappings[fileSystemPath])
160            return;
161
162        this._fileSystemMappings[fileSystemPath] = [];
163        this._saveToSettings();
164    },
165
166    /**
167     * @param {string} fileSystemPath
168     */
169    removeFileSystem: function(fileSystemPath)
170    {
171        if (!this._fileSystemMappings[fileSystemPath])
172            return;
173        delete this._fileSystemMappings[fileSystemPath];
174        delete this._excludedFolders[fileSystemPath];
175        this._saveToSettings();
176    },
177
178    /**
179     * @param {string} fileSystemPath
180     * @param {string} urlPrefix
181     * @param {string} pathPrefix
182     */
183    addFileMapping: function(fileSystemPath, urlPrefix, pathPrefix)
184    {
185        var entry = new WebInspector.FileSystemMapping.Entry(fileSystemPath, urlPrefix, pathPrefix);
186        this._fileSystemMappings[fileSystemPath].push(entry);
187        this._saveToSettings();
188        this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.FileMappingAdded, entry);
189    },
190
191    /**
192     * @param {string} fileSystemPath
193     * @param {string} urlPrefix
194     * @param {string} pathPrefix
195     */
196    removeFileMapping: function(fileSystemPath, urlPrefix, pathPrefix)
197    {
198        var entry = this._mappingEntryForPathPrefix(fileSystemPath, pathPrefix);
199        if (!entry)
200            return;
201        this._fileSystemMappings[fileSystemPath].remove(entry);
202        this._saveToSettings();
203        this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.FileMappingRemoved, entry);
204    },
205
206    /**
207     * @param {string} fileSystemPath
208     * @param {string} excludedFolderPath
209     */
210    addExcludedFolder: function(fileSystemPath, excludedFolderPath)
211    {
212        if (!this._excludedFolders[fileSystemPath])
213            this._excludedFolders[fileSystemPath] = [];
214        var entry = new WebInspector.FileSystemMapping.ExcludedFolderEntry(fileSystemPath, excludedFolderPath);
215        this._excludedFolders[fileSystemPath].push(entry);
216        this._saveToSettings();
217        this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.ExcludedFolderAdded, entry);
218    },
219
220    /**
221     * @param {string} fileSystemPath
222     * @param {string} path
223     */
224    removeExcludedFolder: function(fileSystemPath, path)
225    {
226        var entry = this._excludedFolderEntryForPath(fileSystemPath, path);
227        if (!entry)
228            return;
229        this._excludedFolders[fileSystemPath].remove(entry);
230        this._saveToSettings();
231        this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.ExcludedFolderRemoved, entry);
232    },
233
234    /**
235     * @return {!Array.<string>}
236     */
237    fileSystemPaths: function()
238    {
239        return Object.keys(this._fileSystemMappings);
240    },
241
242    /**
243     * @param {string} url
244     * @return {?WebInspector.FileSystemMapping.Entry}
245     */
246    _mappingEntryForURL: function(url)
247    {
248        for (var i = this._urlPrefixes.length - 1; i >= 0; --i) {
249            var urlPrefix = this._urlPrefixes[i];
250            if (url.startsWith(urlPrefix))
251                return this._mappingForURLPrefix[urlPrefix];
252        }
253        return null;
254    },
255
256    /**
257     * @param {string} fileSystemPath
258     * @param {string} path
259     * @return {?WebInspector.FileSystemMapping.ExcludedFolderEntry}
260     */
261    _excludedFolderEntryForPath: function(fileSystemPath, path)
262    {
263        var entries = this._excludedFolders[fileSystemPath];
264        if (!entries)
265            return null;
266
267        for (var i = 0; i < entries.length; ++i) {
268            if (entries[i].path === path)
269                return entries[i];
270        }
271        return null;
272    },
273
274    /**
275     * @param {string} fileSystemPath
276     * @param {string} filePath
277     * @return {?WebInspector.FileSystemMapping.Entry}
278     */
279    _mappingEntryForPath: function(fileSystemPath, filePath)
280    {
281        var entries = this._fileSystemMappings[fileSystemPath];
282        if (!entries)
283            return null;
284
285        var entry = null;
286        for (var i = 0; i < entries.length; ++i) {
287            var pathPrefix = entries[i].pathPrefix;
288            // We are looking for the longest pathPrefix match.
289            if (entry && entry.pathPrefix.length > pathPrefix.length)
290                continue;
291            if (filePath.startsWith(pathPrefix.substr(1)))
292                entry = entries[i];
293        }
294        return entry;
295    },
296
297    /**
298     * @param {string} fileSystemPath
299     * @param {string} pathPrefix
300     * @return {?WebInspector.FileSystemMapping.Entry}
301     */
302    _mappingEntryForPathPrefix: function(fileSystemPath, pathPrefix)
303    {
304        var entries = this._fileSystemMappings[fileSystemPath];
305        for (var i = 0; i < entries.length; ++i) {
306            if (pathPrefix === entries[i].pathPrefix)
307                return entries[i];
308        }
309        return null;
310    },
311
312    /**
313     * @param {string} fileSystemPath
314     * @param {string} folderPath
315     * @return {boolean}
316     */
317    isFileExcluded: function(fileSystemPath, folderPath)
318    {
319        var excludedFolders = this._excludedFolders[fileSystemPath] || [];
320        for (var i = 0; i < excludedFolders.length; ++i) {
321            var entry = excludedFolders[i];
322            if (entry.path === folderPath)
323                return true;
324        }
325        var regex = WebInspector.settings.workspaceFolderExcludePattern.asRegExp();
326        return regex && regex.test(folderPath);
327    },
328
329    /**
330     * @param {string} fileSystemPath
331     * @return {!Array.<!WebInspector.FileSystemMapping.ExcludedFolderEntry>}
332     */
333    excludedFolders: function(fileSystemPath)
334    {
335        var excludedFolders = this._excludedFolders[fileSystemPath];
336        return excludedFolders ? excludedFolders.slice() : [];
337    },
338
339    /**
340     * @param {string} fileSystemPath
341     * @return {!Array.<!WebInspector.FileSystemMapping.Entry>}
342     */
343    mappingEntries: function(fileSystemPath)
344    {
345        return this._fileSystemMappings[fileSystemPath].slice();
346    },
347
348    /**
349     * @param {string} url
350     * @return {boolean}
351     */
352    hasMappingForURL: function(url)
353    {
354        return !!this._mappingEntryForURL(url);
355    },
356
357    /**
358     * @param {string} url
359     * @return {?{fileSystemPath: string, filePath: string}}
360     */
361    fileForURL: function(url)
362    {
363        var entry = this._mappingEntryForURL(url);
364        if (!entry)
365            return null;
366        var file = {};
367        file.fileSystemPath = entry.fileSystemPath;
368        file.filePath = entry.pathPrefix.substr(1) + url.substr(entry.urlPrefix.length);
369        return file;
370    },
371
372    /**
373     * @param {string} fileSystemPath
374     * @param {string} filePath
375     * @return {string}
376     */
377    urlForPath: function(fileSystemPath, filePath)
378    {
379        var entry = this._mappingEntryForPath(fileSystemPath, filePath);
380        if (!entry)
381            return "";
382        return entry.urlPrefix + filePath.substring(entry.pathPrefix.length - 1);
383    },
384
385    /**
386     * @param {string} url
387     */
388    removeMappingForURL: function(url)
389    {
390        var entry = this._mappingEntryForURL(url);
391        if (!entry)
392            return;
393        this._fileSystemMappings[entry.fileSystemPath].remove(entry);
394        this._saveToSettings();
395    },
396
397    /**
398     * @param {string} url
399     * @param {string} fileSystemPath
400     * @param {string} filePath
401     */
402    addMappingForResource: function(url, fileSystemPath, filePath)
403    {
404        var commonPathSuffixLength = 0;
405        var normalizedFilePath = "/" + filePath;
406        for (var i = 0; i < normalizedFilePath.length; ++i) {
407            var filePathCharacter = normalizedFilePath[normalizedFilePath.length - 1 - i];
408            var urlCharacter = url[url.length - 1 - i];
409            if (filePathCharacter !== urlCharacter)
410                break;
411            if (filePathCharacter === "/")
412                commonPathSuffixLength = i;
413        }
414        var pathPrefix = normalizedFilePath.substr(0, normalizedFilePath.length - commonPathSuffixLength);
415        var urlPrefix = url.substr(0, url.length - commonPathSuffixLength);
416        this.addFileMapping(fileSystemPath, urlPrefix, pathPrefix);
417    },
418
419    __proto__: WebInspector.Object.prototype
420}
421
422/**
423 * @constructor
424 * @param {string} fileSystemPath
425 * @param {string} urlPrefix
426 * @param {string} pathPrefix
427 */
428WebInspector.FileSystemMapping.Entry = function(fileSystemPath, urlPrefix, pathPrefix)
429{
430    this.fileSystemPath = fileSystemPath;
431    this.urlPrefix = urlPrefix;
432    this.pathPrefix = pathPrefix;
433}
434
435/**
436 * @constructor
437 * @param {string} fileSystemPath
438 * @param {string} path
439 */
440WebInspector.FileSystemMapping.ExcludedFolderEntry = function(fileSystemPath, path)
441{
442    this.fileSystemPath = fileSystemPath;
443    this.path = path;
444}
445