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

Side by Side Diff: Source/devtools/front_end/languages/LanguageService.js

Issue 1264133002: Devtools: [WIP] Implement enhanced devtools extension language APIs Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Modify override dropdown to apply to console completions & transpile Created 5 years, 4 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
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @interface
7 */
8 WebInspector.LanguageService = function(){};
9 WebInspector.LanguageService.prototype = {
10 /**
11 * @return {string}
12 */
13 get name() {},
pfeldman 2015/08/13 21:15:46 We don't use getters for the new code.
wes 2015/08/14 00:55:05 Oh, okay. I had seen them around elsewhere and was
pfeldman 2015/08/17 21:15:51 I know, we are slowly getting rid of them wherever
14
15 /**
16 * @param {string} capability
17 * @return {boolean}
18 */
19 handlesCapability: function(capability) { return false; }
pfeldman 2015/08/13 21:15:46 capabilities: function getter instead?
wes 2015/08/14 00:55:05 Possible. I can't really think of a use-case where
20 }
21
22 /**
23 * The language service capabilities list determines what actions are added
24 * to the LanguageService and LanguageService.Handles objects, in addition
25 * to what methods are searched for on providers to fulfill those capabilities
26 */
27 WebInspector.LanguageService.Capabilities = {
28 Transpile: "transpile",
pfeldman 2015/08/13 21:15:46 4 space indent everywhere.
wes 2015/08/14 00:55:05 Ach. At least I was internally consistent to the f
pfeldman 2015/08/17 21:15:51 Nope, we don't have a linter :( We use the Blink c
29 PopulateContextMenu: "populateContextMenu",
30 Completions: "completions",
31 DebuggerCompletions: "debuggerCompletions",
32 };
33
34 /**
35 * @constructor
36 * @extends {WebInspector.Object}
37 */
38 WebInspector.LanguageServiceManager = function() {
39 this._override = {};
40 this._servicesByMime = {};
41
42 for (var key in WebInspector.LanguageService.Capabilities) {
43 var actionName = WebInspector.LanguageService.Capabilities[key];
44 this._servicesByMime[Symbol.for(key)] = {};
45 WebInspector.LanguageService.prototype[actionName] = function() {};
46 }
47
48 var _this = this;
49 function makeHandlesChecker(key) {
50 var actionName = WebInspector.LanguageService.Capabilities[key];
51 return function(mime) {
52 var override = _this._override[actionName];
53 if (typeof override !== "undefined") {
54 return override;
55 }
56 var service = _this._servicesByMime[Symbol.for(key)][mim e];
57 return service;
58 };
59 }
60
61 function makeCapabilityAction(key) {
62 var actionName = WebInspector.LanguageService.Capabilities[key];
63 return function(mime) {
64 var override = _this._override[actionName];
65 if (typeof override !== "undefined") {
66 if (typeof override === "boolean") {
67 if (override) {
68 return Promise.resolve();
69 } else {
70 return Promise.reject("No langua ge service present to handle \""+(key)+"\" for mime \""+(mime)+"\".");
71 }
72 }
73 return override[actionName].apply(override, Arra y.prototype.slice.call(arguments, 1));
74 }
75 if (!_this.handles[actionName](mime)) {
76 return Promise.reject("No language service prese nt to handle \""+(key)+"\" for mime \""+(mime)+"\".");
77 }
78 var service = _this._servicesByMime[Symbol.for(key)][mim e];
79 return service[actionName].apply(service, Array.prototyp e.slice.call(arguments, 1));
80 };
81 }
82
83 for (var key in WebInspector.LanguageService.Capabilities) {
84 _this.handles[WebInspector.LanguageService.Capabilities[key]] = makeHandlesChecker(key);
85 _this[WebInspector.LanguageService.Capabilities[key]] = makeCapa bilityAction(key);
86 }
87 };
88
89 WebInspector.LanguageServiceManager.Events = {
90 ServiceAdded: "onServiceAdded",
91 InferredMimeUpdated: "onInferredMimeUpdated"
92 };
93
94 /**
95 * Stub external API here to satisfy closure compiler - actual implementations
96 * are done in the ctor above. Not sure if there's a better way to type this, wh ile
97 * still making it simple to 'declare' a new optional member to a service
98 */
99 WebInspector.LanguageServiceManager.prototype = {
100
101 handles: {
102 /**
103 * @param {string} mime
104 * @return {?WebInspector.LanguageService}
105 */
106 transpile: function(mime) {return null;},
107
108 /**
109 * @param {string} mime
110 * @return {?WebInspector.LanguageService}
111 */
112 populateContextMenu: function(mime) {return null;},
113
114 /**
115 * @param {string} mime
116 * @return {?WebInspector.LanguageService}
117 */
118 completions: function(mime) {return null;},
119
120 /**
121 * @param {string} mime
122 * @return {?WebInspector.LanguageService}
123 */
124 debuggerCompletions: function(mime) {return null;}
125 },
126
127 /**
128 * @param {!Array<string>} mimes
129 * @param {!WebInspector.LanguageService} service
130 */
131 register: function(mimes, service) {
132 for (var index = 0; index < mimes.length; index++) {
133 var mime = mimes[index];
134 for (var key in WebInspector.LanguageService.Capabilitie s) {
135 var capability = WebInspector.LanguageService.Ca pabilities[key];
136 if (service.handlesCapability(capability)) {
137 this._servicesByMime[Symbol.for(key)][mi me] = service;
138 }
139 }
140
141 this._servicesByMime[mime] = service;
142 }
143 this._onServiceAdded(service, mimes);
144 },
145
146 _onServiceAdded(service, mimes) {
147 this.dispatchEventToListeners(WebInspector.LanguageServiceManage r.Events.ServiceAdded, {service, mimes});
148 },
149
150 /**
151 * @param {string} capability
152 * @param {!WebInspector.LanguageService=} override
153 */
154 disableContextualHandling: function(capability, override) {
155 this._override[capability] = override || false;
156 },
157
158 /**
159 * @param {string} capability
160 */
161 enableContextualHandling: function(capability) {
162 delete this._override[capability];
163 },
164
165 /**
166 * @param {string=} capability
167 * @return {!Array<!WebInspector.LanguageService>}
168 */
169 registered: function(capability) {
170 return [...new Set(Object.keys(capability ? this._servicesByMime [Symbol.for(capability)]||{} : this._servicesByMime).map(k => capability ? this. _servicesByMime[Symbol.for(capability)][k] : this._servicesByMime[k]))];
171 },
172
173 /**
174 * @param {string} mime
175 * @return {?WebInspector.LanguageService}
176 */
177 for: function(mime) {
178 return this._servicesByMime[mime];
179 },
180
181 /**
182 * @param {string} mime
183 * @param {string} input
184 * @param {?{source: string, line: number, column: number}=} location
185 * @return {!Promise<string>}
186 */
187 transpile: function(mime, input, location) {return Promise.reject();},
188
189 /**
190 * @param {string} mime
191 * @param {{source: string, line: number, column: number}} location
192 * @return {!Promise<!Array<{text: string, callback: !Function}>>}
193 */
194 populateContextMenu: function(mime, location) {return Promise.reject();} ,
195
196 /**
197 * @param {string} mime
198 * @param {{source: string, line: number, column: number}} location
199 * @param {string} prefix
200 * @return {!Promise<!Array<{text: string, details: !Promise<{detail: st ring, description: string}>}>>}
201 */
202 completions: function(mime, location, prefix) {return Promise.reject();} ,
203
204 /**
205 * @param {string} mime
206 * @param {string} content
207 * @param {number} cursorOffset
208 * @param {string} prefix
209 * @param {{source: string, line: number, column: number}=} context
210 * @return {!Promise<!Array<{text: string, details: !Promise<{detail: st ring, description: string}>}>>}
211 */
212 debuggerCompletions: function(mime, content, cursorOffset, prefix, conte xt) {return Promise.reject();},
213
214 updateInferredMime: function() {
215 this.dispatchEventToListeners(WebInspector.LanguageServiceManage r.Events.InferredMimeUpdated);
216 },
217
218 __proto__: WebInspector.Object.prototype
219 };
220
221 /**
222 * @constructor
223 * @implements {WebInspector.LanguageService}
224 */
225 WebInspector.LanguageService.CallbackDelegate = function(name, capabilities) {
226 this._name = name;
227
228 for (var key in WebInspector.LanguageService.Capabilities) {
229 var actionName = WebInspector.LanguageService.Capabilities[key];
230 if (!!capabilities[actionName]) {
231 this.appendActionHandler(actionName, capabilities[action Name]);
232 }
233 }
234 };
235
236 WebInspector.LanguageService.CallbackDelegate.prototype = {
237 /**
238 * @override
239 * @return {string}
240 */
241 get name() {
242 return this._name;
243 },
244
245 /**
246 * Given an action and a function expecting a callback for
247 * its final argument, modifies it to return a promise and
248 * appends it to the language service
249 *
250 * @param {string} capability
251 * @param {!Function} func
252 */
253 appendActionHandler: function(capability, func) {
254 var _this = this;
255 this[capability] = function() {
256 var args = arguments;
257 return new Promise(function(resolve, reject) {
258 func.call(_this, ...args, resolve);
259 });
260 };
261 },
262
263 /**
264 * @override
265 * @param {string} capability
266 * @return {boolean}
267 */
268 handlesCapability: function(capability) {
269 return !!this[capability];
270 }
271 };
272
273 /**
274 * @constructor
275 * @param {!Element} selectElement
276 * @param {!Array<string>} capabilities
277 */
278 WebInspector.LanguageServiceModel = function(selectElement, capabilities) {
279 this._capabilities = capabilities;
280 this._selectElement = selectElement;
281 var newOption = createElement("option");
282 newOption.__type = WebInspector.LanguageServiceModel.OptionType.Inferred;
283 newOption.text = WebInspector.UIString("%s (inferred)", WebInspector.UIStrin g("javascript"));
284 this._selectElement.appendChild(newOption);
285
286 var jsOption = createElement("option");
287 jsOption.__type = WebInspector.LanguageServiceModel.OptionType.Builtin;
288 jsOption.text = WebInspector.UIString("javascript");
289 this._selectElement.appendChild(jsOption);
290
291 WebInspector.languageService.registered().forEach(service => {
292 this.addOption(service);
293 });
294
295 WebInspector.languageService.addEventListener(WebInspector.LanguageServi ceManager.Events.ServiceAdded, this._onServiceAdded, this);
296 WebInspector.languageService.addEventListener(WebInspector.LanguageServi ceManager.Events.InferredMimeUpdated, this._onViewSelected, this);
297 this._selectElement.addEventListener("change", this._languageServiceChan ged.bind(this), false);
298 };
299
300 WebInspector.LanguageServiceModel.prototype = {
301 /**
302 * @param {!WebInspector.LanguageService} service
303 */
304 addOption: function(service) {
305 var newOption = createElement("option");
306 newOption.__service = service;
307 newOption.__type = WebInspector.LanguageServiceModel.OptionType. External;
308 newOption.text = service.name
309 this._selectElement.appendChild(newOption);
310 },
311
312 _onServiceAdded: function(evt) {
313 var service = /** @type {!WebInspector.LanguageService} */(evt.d ata.service);
314 this.addOption(service);
315 },
316
317 _onViewSelected: function(evt) {
318 var mime = WebInspector.ResourceType.fromActivePanel();
319 var service = WebInspector.languageService.for(mime);
320 var name = WebInspector.UIString("javascript");
321 if (service) {
322 name = service.name;
323 }
324 var opts = this._selectElement.options;
325 for (var i = 0; i < opts.length; i++) {
326 var option = opts[i];
327 if (option.__type === WebInspector.LanguageServiceModel. OptionType.Inferred) {
328 option.text = WebInspector.UIString("%s (inferre d)", name);
329 }
330 }
331 },
332
333 _languageServiceChanged: function() {
334 var option = this._selectedOption();
335 switch(option.__type) {
336 case WebInspector.LanguageServiceModel.OptionType.Inferr ed:
337 this._capabilities.forEach(c => {
338 WebInspector.languageService.enableContextualHan dling(c);
339 });
340 break;
341 case WebInspector.LanguageServiceModel.OptionType.Builti n:
342 this._capabilities.forEach(c => {
343 WebInspector.languageService.disableContextualHa ndling(c);
344 });
345 break;
346 case WebInspector.LanguageServiceModel.OptionType.Extern al:
347 this._capabilities.forEach(c => {
348 WebInspector.languageService.disableContextualHa ndling(c, option.__service);
349 });
350 break;
351 default:
352 break;
353 }
354 },
355
356 /**
357 * @return {?Element}
358 */
359 _selectedOption: function()
360 {
361 if (this._selectElement.selectedIndex >= 0)
362 return this._selectElement[this._selectElement.selectedIndex];
363 return null;
364 }
365 };
366
367 WebInspector.LanguageServiceModel.OptionType = {
368 Inferred: "Inferred",
369 Builtin: "Builtin",
370 External: "External"
371 };
372
373 WebInspector.languageService = new WebInspector.LanguageServiceManager();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698