Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/sources/SourceFormatter.js

Issue 2888843002: DevTools: fix race when revealing formatted source code (Closed)
Patch Set: rebased Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/devtools/front_end/coverage/CoverageListView.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 Sources.SourceFormatData = class { 5 Sources.SourceFormatData = class {
6 /** 6 /**
7 * @param {!Workspace.UISourceCode} originalSourceCode 7 * @param {!Workspace.UISourceCode} originalSourceCode
8 * @param {!Workspace.UISourceCode} formattedSourceCode 8 * @param {!Workspace.UISourceCode} formattedSourceCode
9 * @param {!Sources.FormatterSourceMapping} mapping 9 * @param {!Sources.FormatterSourceMapping} mapping
10 */ 10 */
(...skipping 18 matching lines...) Expand all
29 29
30 Sources.SourceFormatData._formatDataSymbol = Symbol('formatData'); 30 Sources.SourceFormatData._formatDataSymbol = Symbol('formatData');
31 31
32 Sources.SourceFormatter = class { 32 Sources.SourceFormatter = class {
33 constructor() { 33 constructor() {
34 this._projectId = 'formatter:'; 34 this._projectId = 'formatter:';
35 this._project = new Bindings.ContentProviderBasedProject( 35 this._project = new Bindings.ContentProviderBasedProject(
36 Workspace.workspace, this._projectId, Workspace.projectTypes.Formatter, 'formatter', 36 Workspace.workspace, this._projectId, Workspace.projectTypes.Formatter, 'formatter',
37 true /* isServiceProject */); 37 true /* isServiceProject */);
38 38
39 /** @type {!Map<string, !Workspace.UISourceCode>} */ 39 /** @type {!Map<!Workspace.UISourceCode, !{promise: !Promise<!Sources.Source FormatData>, formatData: ?Sources.SourceFormatData}>} */
40 this._formattedPaths = new Map(); 40 this._formattedSourceCodes = new Map();
41 this._scriptMapping = new Sources.SourceFormatter.ScriptMapping(); 41 this._scriptMapping = new Sources.SourceFormatter.ScriptMapping();
42 this._styleMapping = new Sources.SourceFormatter.StyleMapping(); 42 this._styleMapping = new Sources.SourceFormatter.StyleMapping();
43 Workspace.workspace.addEventListener( 43 Workspace.workspace.addEventListener(
44 Workspace.Workspace.Events.UISourceCodeRemoved, this._onUISourceCodeRemo ved, this); 44 Workspace.Workspace.Events.UISourceCodeRemoved, this._onUISourceCodeRemo ved, this);
45 } 45 }
46 46
47 /** 47 /**
48 * @param {!Common.Event} event 48 * @param {!Common.Event} event
49 */ 49 */
50 _onUISourceCodeRemoved(event) { 50 _onUISourceCodeRemoved(event) {
51 var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data); 51 var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
52 var formattedUISourceCode = this._formattedPaths.get(uiSourceCode.project(). id() + ':' + uiSourceCode.url()); 52 var cacheEntry = this._formattedSourceCodes.get(uiSourceCode);
53 if (formattedUISourceCode) 53 if (cacheEntry && cacheEntry.formatData)
54 this.discardFormattedUISourceCode(formattedUISourceCode); 54 this._discardFormatData(cacheEntry.formatData);
55 this._formattedSourceCodes.remove(uiSourceCode);
55 } 56 }
56 57
57 /** 58 /**
58 * @param {!Workspace.UISourceCode} formattedUISourceCode 59 * @param {!Workspace.UISourceCode} formattedUISourceCode
59 * @return {?Workspace.UISourceCode} 60 * @return {?Workspace.UISourceCode}
60 */ 61 */
61 discardFormattedUISourceCode(formattedUISourceCode) { 62 discardFormattedUISourceCode(formattedUISourceCode) {
62 var formatData = Sources.SourceFormatData._for(formattedUISourceCode); 63 var formatData = Sources.SourceFormatData._for(formattedUISourceCode);
63 if (!formatData) 64 if (!formatData)
64 return null; 65 return null;
65 66 this._discardFormatData(formatData);
66 delete formattedUISourceCode[Sources.SourceFormatData._formatDataSymbol]; 67 this._formattedSourceCodes.remove(formatData.originalSourceCode);
67 this._scriptMapping._setSourceMappingEnabled(formatData, false);
68 this._styleMapping._setSourceMappingEnabled(formatData, false);
69 this._project.removeFile(formattedUISourceCode.url());
70 this._formattedPaths.remove(formatData.originalPath());
71 return formatData.originalSourceCode; 68 return formatData.originalSourceCode;
72 } 69 }
73 70
74 /** 71 /**
72 * @param {!Sources.SourceFormatData} formatData
73 */
74 _discardFormatData(formatData) {
75 delete formatData.formattedSourceCode[Sources.SourceFormatData._formatDataSy mbol];
76 this._scriptMapping._setSourceMappingEnabled(formatData, false);
77 this._styleMapping._setSourceMappingEnabled(formatData, false);
78 this._project.removeFile(formatData.formattedSourceCode.url());
79 }
80
81 /**
75 * @param {!Workspace.UISourceCode} uiSourceCode 82 * @param {!Workspace.UISourceCode} uiSourceCode
76 * @return {boolean} 83 * @return {boolean}
77 */ 84 */
78 hasFormatted(uiSourceCode) { 85 hasFormatted(uiSourceCode) {
79 return this._formattedPaths.has(uiSourceCode.project().id() + ':' + uiSource Code.url()); 86 return this._formattedSourceCodes.has(uiSourceCode);
80 } 87 }
81 88
82 /** 89 /**
83 * @param {!Workspace.UISourceCode} uiSourceCode 90 * @param {!Workspace.UISourceCode} uiSourceCode
84 * @return {!Promise<!Sources.SourceFormatData>} 91 * @return {!Promise<!Sources.SourceFormatData>}
85 */ 92 */
86 async format(uiSourceCode) { 93 async format(uiSourceCode) {
87 var formattedUISourceCode = this._formattedPaths.get(uiSourceCode.project(). id() + ':' + uiSourceCode.url()); 94 var cacheEntry = this._formattedSourceCodes.get(uiSourceCode);
88 if (formattedUISourceCode) 95 if (cacheEntry)
89 return Sources.SourceFormatData._for(formattedUISourceCode); 96 return cacheEntry.promise;
90 97
91 var content = await uiSourceCode.requestContent();
92 var fulfillFormatPromise; 98 var fulfillFormatPromise;
93 var resultPromise = new Promise(fulfill => { 99 var resultPromise = new Promise(fulfill => {
94 fulfillFormatPromise = fulfill; 100 fulfillFormatPromise = fulfill;
95 }); 101 });
96 Sources.Formatter.format( 102 this._formattedSourceCodes.set(uiSourceCode, {promise: resultPromise, format Data: null});
97 uiSourceCode.contentType(), uiSourceCode.mimeType(), content || '', inne rCallback.bind(this)); 103 var content = await uiSourceCode.requestContent();
104 // ------------ ASYNC ------------
105 Sources.Formatter.format(uiSourceCode.contentType(), uiSourceCode.mimeType() , content || '', formatDone.bind(this));
98 return resultPromise; 106 return resultPromise;
99 107
100 /** 108 /**
101 * @this Sources.SourceFormatter 109 * @this Sources.SourceFormatter
102 * @param {string} formattedContent 110 * @param {string} formattedContent
103 * @param {!Sources.FormatterSourceMapping} formatterMapping 111 * @param {!Sources.FormatterSourceMapping} formatterMapping
104 */ 112 */
105 function innerCallback(formattedContent, formatterMapping) { 113 function formatDone(formattedContent, formatterMapping) {
106 var formattedURL = uiSourceCode.url() + ':formatted'; 114 var cacheEntry = this._formattedSourceCodes.get(uiSourceCode);
115 if (!cacheEntry || cacheEntry.promise !== resultPromise)
116 return;
117 var formattedURL;
118 var count = 0;
119 var suffix = '';
120 do {
121 formattedURL = `${uiSourceCode.url()}:formatted${suffix}`;
122 suffix = `:${count++}`;
123 } while (this._project.uiSourceCodeForURL(formattedURL));
107 var contentProvider = 124 var contentProvider =
108 Common.StaticContentProvider.fromString(formattedURL, uiSourceCode.con tentType(), formattedContent); 125 Common.StaticContentProvider.fromString(formattedURL, uiSourceCode.con tentType(), formattedContent);
109 var formattedUISourceCode = 126 var formattedUISourceCode =
110 this._project.addContentProvider(formattedURL, contentProvider, uiSour ceCode.mimeType()); 127 this._project.addContentProvider(formattedURL, contentProvider, uiSour ceCode.mimeType());
111 var formatData = new Sources.SourceFormatData(uiSourceCode, formattedUISou rceCode, formatterMapping); 128 var formatData = new Sources.SourceFormatData(uiSourceCode, formattedUISou rceCode, formatterMapping);
112 formattedUISourceCode[Sources.SourceFormatData._formatDataSymbol] = format Data; 129 formattedUISourceCode[Sources.SourceFormatData._formatDataSymbol] = format Data;
113 this._scriptMapping._setSourceMappingEnabled(formatData, true); 130 this._scriptMapping._setSourceMappingEnabled(formatData, true);
114 this._styleMapping._setSourceMappingEnabled(formatData, true); 131 this._styleMapping._setSourceMappingEnabled(formatData, true);
115 132 cacheEntry.formatData = formatData;
116 var path = formatData.originalPath();
117 this._formattedPaths.set(path, formattedUISourceCode);
118 133
119 for (var decoration of uiSourceCode.allDecorations()) { 134 for (var decoration of uiSourceCode.allDecorations()) {
120 var range = decoration.range(); 135 var range = decoration.range();
121 var startLocation = formatterMapping.originalToFormatted(range.startLine , range.startColumn); 136 var startLocation = formatterMapping.originalToFormatted(range.startLine , range.startColumn);
122 var endLocation = formatterMapping.originalToFormatted(range.endLine, ra nge.endColumn); 137 var endLocation = formatterMapping.originalToFormatted(range.endLine, ra nge.endColumn);
123 138
124 formattedUISourceCode.addDecoration( 139 formattedUISourceCode.addDecoration(
125 new TextUtils.TextRange(startLocation[0], startLocation[1], endLocat ion[0], endLocation[1]), 140 new TextUtils.TextRange(startLocation[0], startLocation[1], endLocat ion[0], endLocation[1]),
126 /** @type {string} */ (decoration.type()), decoration.data()); 141 /** @type {string} */ (decoration.type()), decoration.data());
127 } 142 }
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 headers.forEach(header => header[Sources.SourceFormatData._formatDataSymbo l] = formatData); 302 headers.forEach(header => header[Sources.SourceFormatData._formatDataSymbo l] = formatData);
288 } else { 303 } else {
289 original[this._headersSymbol] = null; 304 original[this._headersSymbol] = null;
290 headers.forEach(header => delete header[Sources.SourceFormatData._formatDa taSymbol]); 305 headers.forEach(header => delete header[Sources.SourceFormatData._formatDa taSymbol]);
291 } 306 }
292 headers.forEach(header => Bindings.cssWorkspaceBinding.updateLocations(heade r)); 307 headers.forEach(header => Bindings.cssWorkspaceBinding.updateLocations(heade r));
293 } 308 }
294 }; 309 };
295 310
296 Sources.sourceFormatter = new Sources.SourceFormatter(); 311 Sources.sourceFormatter = new Sources.SourceFormatter();
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/devtools/front_end/coverage/CoverageListView.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698