2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 * @param {!WebInspector.IsolatedFileSystemManager} isolatedFileSystemManager
34 * @param {!WebInspector.Workspace} workspace
36 WebInspector.FileSystemWorkspaceBinding = function(isolatedFileSystemManager, workspace)
38 this._isolatedFileSystemManager = isolatedFileSystemManager;
39 this._workspace = workspace;
40 this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemAdded, this._fileSystemAdded, this);
41 this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemRemoved, this._fileSystemRemoved, this);
42 /** @type {!StringMap.<!WebInspector.FileSystemWorkspaceBinding.FileSystem>} */
43 this._boundFileSystems = new StringMap();
45 /** @type {!Object.<number, function(!Array.<string>)>} */
47 /** @type {!Object.<number, !WebInspector.Progress>} */
48 this._progresses = {};
51 WebInspector.FileSystemWorkspaceBinding._scriptExtensions = ["js", "java", "coffee", "ts", "dart"].keySet();
52 WebInspector.FileSystemWorkspaceBinding._styleSheetExtensions = ["css", "scss", "sass", "less"].keySet();
53 WebInspector.FileSystemWorkspaceBinding._documentExtensions = ["htm", "html", "asp", "aspx", "phtml", "jsp"].keySet();
55 WebInspector.FileSystemWorkspaceBinding._lastRequestId = 0;
58 * @param {string} fileSystemPath
61 WebInspector.FileSystemWorkspaceBinding.projectId = function(fileSystemPath)
63 return "filesystem:" + fileSystemPath;
66 WebInspector.FileSystemWorkspaceBinding.prototype = {
68 * @param {!WebInspector.Event} event
70 _fileSystemAdded: function(event)
72 var fileSystem = /** @type {!WebInspector.IsolatedFileSystem} */ (event.data);
73 var boundFileSystem = new WebInspector.FileSystemWorkspaceBinding.FileSystem(this, fileSystem, this._workspace);
74 this._boundFileSystems.put(fileSystem.normalizedPath(), boundFileSystem);
78 * @param {!WebInspector.Event} event
80 _fileSystemRemoved: function(event)
82 var fileSystem = /** @type {!WebInspector.IsolatedFileSystem} */ (event.data);
83 var boundFileSystem = this._boundFileSystems.get(fileSystem.normalizedPath());
84 boundFileSystem.dispose();
85 this._boundFileSystems.remove(fileSystem.normalizedPath());
89 * @param {string} projectId
92 fileSystemPath: function(projectId)
94 var fileSystemPath = projectId.substr("filesystem:".length);
95 var normalizedPath = WebInspector.IsolatedFileSystem.normalizePath(fileSystemPath);
96 var boundFileSystem = this._boundFileSystems.get(normalizedPath);
97 return projectId.substr("filesystem:".length);
105 return ++WebInspector.FileSystemWorkspaceBinding._lastRequestId;
109 * @param {function(!Array.<string>)} callback
112 registerCallback: function(callback)
114 var requestId = this._nextId();
115 this._callbacks[requestId] = callback;
120 * @param {!WebInspector.Progress} progress
123 registerProgress: function(progress)
125 var requestId = this._nextId();
126 this._progresses[requestId] = progress;
131 * @param {number} requestId
132 * @param {string} fileSystemPath
133 * @param {number} totalWork
135 indexingTotalWorkCalculated: function(requestId, fileSystemPath, totalWork)
137 var progress = this._progresses[requestId];
140 progress.setTotalWork(totalWork);
144 * @param {number} requestId
145 * @param {string} fileSystemPath
146 * @param {number} worked
148 indexingWorked: function(requestId, fileSystemPath, worked)
150 var progress = this._progresses[requestId];
153 progress.worked(worked);
157 * @param {number} requestId
158 * @param {string} fileSystemPath
160 indexingDone: function(requestId, fileSystemPath)
162 var progress = this._progresses[requestId];
166 delete this._progresses[requestId];
170 * @param {number} requestId
171 * @param {string} fileSystemPath
172 * @param {!Array.<string>} files
174 searchCompleted: function(requestId, fileSystemPath, files)
176 var callback = this._callbacks[requestId];
179 callback.call(null, files);
180 delete this._callbacks[requestId];
186 * @implements {WebInspector.ProjectDelegate}
187 * @param {!WebInspector.IsolatedFileSystem} isolatedFileSystem
188 * @param {!WebInspector.Workspace} workspace
189 * @param {!WebInspector.FileSystemWorkspaceBinding} fileSystemWorkspaceBinding
191 WebInspector.FileSystemWorkspaceBinding.FileSystem = function(fileSystemWorkspaceBinding, isolatedFileSystem, workspace)
193 this._fileSystemWorkspaceBinding = fileSystemWorkspaceBinding;
194 this._fileSystem = isolatedFileSystem;
195 this._fileSystemURL = "file://" + this._fileSystem.normalizedPath() + "/";
196 this._workspace = workspace;
198 this._projectId = WebInspector.FileSystemWorkspaceBinding.projectId(this._fileSystem.path());
199 console.assert(!this._workspace.project(this._projectId));
200 this._projectStore = this._workspace.addProject(this._projectId, this);
204 WebInspector.FileSystemWorkspaceBinding.FileSystem.prototype = {
210 return WebInspector.projectTypes.FileSystem;
216 fileSystemPath: function()
218 return this._fileSystem.path();
224 displayName: function()
226 var normalizedPath = this._fileSystem.normalizedPath();
227 return normalizedPath.substr(normalizedPath.lastIndexOf("/") + 1);
231 * @param {string} path
234 _filePathForPath: function(path)
240 * @param {string} path
241 * @param {function(?string)} callback
243 requestFileContent: function(path, callback)
245 var filePath = this._filePathForPath(path);
246 this._fileSystem.requestFileContent(filePath, callback);
250 * @param {string} path
251 * @param {function(?Date, ?number)} callback
253 requestMetadata: function(path, callback)
255 var filePath = this._filePathForPath(path);
256 this._fileSystem.requestMetadata(filePath, callback);
262 canSetFileContent: function()
268 * @param {string} path
269 * @param {string} newContent
270 * @param {function(?string)} callback
272 setFileContent: function(path, newContent, callback)
274 var filePath = this._filePathForPath(path);
275 this._fileSystem.setFileContent(filePath, newContent, callback.bind(this, ""));
281 canRename: function()
287 * @param {string} path
288 * @param {string} newName
289 * @param {function(boolean, string=, string=, string=, !WebInspector.ResourceType=)} callback
291 rename: function(path, newName, callback)
293 var filePath = this._filePathForPath(path);
294 this._fileSystem.renameFile(filePath, newName, innerCallback.bind(this));
297 * @param {boolean} success
298 * @param {string=} newName
299 * @this {WebInspector.FileSystemWorkspaceBinding.FileSystem}
301 function innerCallback(success, newName)
304 callback(false, newName);
307 var validNewName = /** @type {string} */ (newName);
308 console.assert(validNewName);
309 var slash = filePath.lastIndexOf("/");
310 var parentPath = filePath.substring(0, slash);
311 filePath = parentPath + "/" + validNewName;
312 var newURL = this._workspace.urlForPath(this._fileSystem.path(), filePath);
313 var extension = this._extensionForPath(validNewName);
314 var newOriginURL = this._fileSystemURL + filePath
315 var newContentType = this._contentTypeForExtension(extension);
316 callback(true, validNewName, newURL, newOriginURL, newContentType);
321 * @param {string} path
322 * @param {string} query
323 * @param {boolean} caseSensitive
324 * @param {boolean} isRegex
325 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback
327 searchInFileContent: function(path, query, caseSensitive, isRegex, callback)
329 var filePath = this._filePathForPath(path);
330 this._fileSystem.requestFileContent(filePath, contentCallback);
333 * @param {?string} content
335 function contentCallback(content)
338 if (content !== null)
339 result = WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex);
345 * @param {!WebInspector.ProjectSearchConfig} searchConfig
346 * @param {!WebInspector.Progress} progress
347 * @param {function(!Array.<string>)} callback
349 findFilesMatchingSearchRequest: function(searchConfig, progress, callback)
352 var queriesToRun = searchConfig.queries().slice();
353 if (!queriesToRun.length)
354 queriesToRun.push("");
355 progress.setTotalWork(queriesToRun.length);
356 searchNextQuery.call(this);
359 * @this {WebInspector.FileSystemWorkspaceBinding.FileSystem}
361 function searchNextQuery()
363 if (!queriesToRun.length) {
364 matchFileQueries.call(null, result);
367 var query = queriesToRun.shift();
368 this._searchInPath(searchConfig.isRegex() ? "" : query, progress, innerCallback.bind(this));
372 * @param {!Array.<string>} files
373 * @this {WebInspector.FileSystemWorkspaceBinding.FileSystem}
375 function innerCallback(files)
377 files = files.sort();
382 result = result.intersectOrdered(files, String.naturalOrderComparator);
383 searchNextQuery.call(this);
387 * @param {!Array.<string>} files
389 function matchFileQueries(files)
391 files = files.filter(searchConfig.filePathMatchesFileQuery.bind(searchConfig));
398 * @param {string} query
399 * @param {!WebInspector.Progress} progress
400 * @param {function(!Array.<string>)} callback
402 _searchInPath: function(query, progress, callback)
404 var requestId = this._fileSystemWorkspaceBinding.registerCallback(innerCallback.bind(this));
405 InspectorFrontendHost.searchInPath(requestId, this._fileSystem.path(), query);
408 * @param {!Array.<string>} files
409 * @this {WebInspector.FileSystemWorkspaceBinding.FileSystem}
411 function innerCallback(files)
414 * @param {string} fullPath
415 * @this {WebInspector.FileSystemWorkspaceBinding.FileSystem}
417 function trimAndNormalizeFileSystemPath(fullPath)
419 var trimmedPath = fullPath.substr(this._fileSystem.path().length + 1);
420 if (WebInspector.isWin())
421 trimmedPath = trimmedPath.replace(/\\/g, "/");
425 files = files.map(trimAndNormalizeFileSystemPath.bind(this));
432 * @param {!WebInspector.Progress} progress
434 indexContent: function(progress)
436 progress.setTotalWork(1);
437 var requestId = this._fileSystemWorkspaceBinding.registerProgress(progress);
438 progress.addEventListener(WebInspector.Progress.Events.Canceled, this._indexingCanceled.bind(this, requestId));
439 InspectorFrontendHost.indexPath(requestId, this._fileSystem.path());
443 * @param {number} requestId
445 _indexingCanceled: function(requestId)
447 InspectorFrontendHost.stopIndexing(requestId);
451 * @param {string} path
454 _extensionForPath: function(path)
456 var extensionIndex = path.lastIndexOf(".");
457 if (extensionIndex === -1)
459 return path.substring(extensionIndex + 1).toLowerCase();
463 * @param {string} extension
464 * @return {!WebInspector.ResourceType}
466 _contentTypeForExtension: function(extension)
468 if (WebInspector.FileSystemWorkspaceBinding._scriptExtensions[extension])
469 return WebInspector.resourceTypes.Script;
470 if (WebInspector.FileSystemWorkspaceBinding._styleSheetExtensions[extension])
471 return WebInspector.resourceTypes.Stylesheet;
472 if (WebInspector.FileSystemWorkspaceBinding._documentExtensions[extension])
473 return WebInspector.resourceTypes.Document;
474 return WebInspector.resourceTypes.Other;
479 this._fileSystem.requestFilesRecursive("", this._addFile.bind(this));
483 * @param {string} path
485 refresh: function(path)
487 this._fileSystem.requestFilesRecursive(path, this._addFile.bind(this));
491 * @param {string} path
493 excludeFolder: function(path)
495 this._fileSystemWorkspaceBinding._isolatedFileSystemManager.mapping().addExcludedFolder(this._fileSystem.path(), path);
499 * @param {string} path
500 * @param {?string} name
501 * @param {string} content
502 * @param {function(?string)} callback
504 createFile: function(path, name, content, callback)
506 this._fileSystem.createFile(path, name, innerCallback.bind(this));
510 * @param {?string} filePath
511 * @this {WebInspector.FileSystemWorkspaceBinding.FileSystem}
513 function innerCallback(filePath)
519 createFilePath = filePath;
521 contentSet.call(this);
524 this._fileSystem.setFileContent(filePath, content, contentSet.bind(this));
528 * @this {WebInspector.FileSystemWorkspaceBinding.FileSystem}
530 function contentSet()
532 this._addFile(createFilePath);
533 callback(createFilePath);
538 * @param {string} path
540 deleteFile: function(path)
542 this._fileSystem.deleteFile(path);
543 this._removeFile(path);
548 this._fileSystemWorkspaceBinding._isolatedFileSystemManager.removeFileSystem(this._fileSystem.path());
552 * @param {string} filePath
554 _addFile: function(filePath)
557 console.assert(false);
559 var slash = filePath.lastIndexOf("/");
560 var parentPath = filePath.substring(0, slash);
561 var name = filePath.substring(slash + 1);
563 var url = this._workspace.urlForPath(this._fileSystem.path(), filePath);
564 var extension = this._extensionForPath(name);
565 var contentType = this._contentTypeForExtension(extension);
567 var fileDescriptor = new WebInspector.FileDescriptor(parentPath, name, this._fileSystemURL + filePath, url, contentType);
568 this._projectStore.addFile(fileDescriptor);
572 * @param {string} path
574 _removeFile: function(path)
576 this._projectStore.removeFile(path);
581 this._workspace.removeProject(this._projectId);
586 * @type {!WebInspector.FileSystemWorkspaceBinding}
588 WebInspector.fileSystemWorkspaceBinding;