Chromium Code Reviews| OLD | NEW |
|---|---|
| (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(); | |
| OLD | NEW |