languageFeatures.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import * as cssService from './_deps/vscode-css-languageservice/cssLanguageService.js';
  6. import { languages, editor, Uri, Range, MarkerSeverity } from './fillers/monaco-editor-core.js';
  7. // --- diagnostics --- ---
  8. var DiagnosticsAdapter = /** @class */ (function () {
  9. function DiagnosticsAdapter(_languageId, _worker, defaults) {
  10. var _this = this;
  11. this._languageId = _languageId;
  12. this._worker = _worker;
  13. this._disposables = [];
  14. this._listener = Object.create(null);
  15. var onModelAdd = function (model) {
  16. var modeId = model.getModeId();
  17. if (modeId !== _this._languageId) {
  18. return;
  19. }
  20. var handle;
  21. _this._listener[model.uri.toString()] = model.onDidChangeContent(function () {
  22. window.clearTimeout(handle);
  23. handle = window.setTimeout(function () { return _this._doValidate(model.uri, modeId); }, 500);
  24. });
  25. _this._doValidate(model.uri, modeId);
  26. };
  27. var onModelRemoved = function (model) {
  28. editor.setModelMarkers(model, _this._languageId, []);
  29. var uriStr = model.uri.toString();
  30. var listener = _this._listener[uriStr];
  31. if (listener) {
  32. listener.dispose();
  33. delete _this._listener[uriStr];
  34. }
  35. };
  36. this._disposables.push(editor.onDidCreateModel(onModelAdd));
  37. this._disposables.push(editor.onWillDisposeModel(onModelRemoved));
  38. this._disposables.push(editor.onDidChangeModelLanguage(function (event) {
  39. onModelRemoved(event.model);
  40. onModelAdd(event.model);
  41. }));
  42. defaults.onDidChange(function (_) {
  43. editor.getModels().forEach(function (model) {
  44. if (model.getModeId() === _this._languageId) {
  45. onModelRemoved(model);
  46. onModelAdd(model);
  47. }
  48. });
  49. });
  50. this._disposables.push({
  51. dispose: function () {
  52. for (var key in _this._listener) {
  53. _this._listener[key].dispose();
  54. }
  55. }
  56. });
  57. editor.getModels().forEach(onModelAdd);
  58. }
  59. DiagnosticsAdapter.prototype.dispose = function () {
  60. this._disposables.forEach(function (d) { return d && d.dispose(); });
  61. this._disposables = [];
  62. };
  63. DiagnosticsAdapter.prototype._doValidate = function (resource, languageId) {
  64. this._worker(resource)
  65. .then(function (worker) {
  66. return worker.doValidation(resource.toString());
  67. })
  68. .then(function (diagnostics) {
  69. var markers = diagnostics.map(function (d) { return toDiagnostics(resource, d); });
  70. var model = editor.getModel(resource);
  71. if (model && model.getModeId() === languageId) {
  72. editor.setModelMarkers(model, languageId, markers);
  73. }
  74. })
  75. .then(undefined, function (err) {
  76. console.error(err);
  77. });
  78. };
  79. return DiagnosticsAdapter;
  80. }());
  81. export { DiagnosticsAdapter };
  82. function toSeverity(lsSeverity) {
  83. switch (lsSeverity) {
  84. case cssService.DiagnosticSeverity.Error:
  85. return MarkerSeverity.Error;
  86. case cssService.DiagnosticSeverity.Warning:
  87. return MarkerSeverity.Warning;
  88. case cssService.DiagnosticSeverity.Information:
  89. return MarkerSeverity.Info;
  90. case cssService.DiagnosticSeverity.Hint:
  91. return MarkerSeverity.Hint;
  92. default:
  93. return MarkerSeverity.Info;
  94. }
  95. }
  96. function toDiagnostics(resource, diag) {
  97. var code = typeof diag.code === 'number' ? String(diag.code) : diag.code;
  98. return {
  99. severity: toSeverity(diag.severity),
  100. startLineNumber: diag.range.start.line + 1,
  101. startColumn: diag.range.start.character + 1,
  102. endLineNumber: diag.range.end.line + 1,
  103. endColumn: diag.range.end.character + 1,
  104. message: diag.message,
  105. code: code,
  106. source: diag.source
  107. };
  108. }
  109. // --- completion ------
  110. function fromPosition(position) {
  111. if (!position) {
  112. return void 0;
  113. }
  114. return { character: position.column - 1, line: position.lineNumber - 1 };
  115. }
  116. function fromRange(range) {
  117. if (!range) {
  118. return void 0;
  119. }
  120. return {
  121. start: {
  122. line: range.startLineNumber - 1,
  123. character: range.startColumn - 1
  124. },
  125. end: { line: range.endLineNumber - 1, character: range.endColumn - 1 }
  126. };
  127. }
  128. function toRange(range) {
  129. if (!range) {
  130. return void 0;
  131. }
  132. return new Range(range.start.line + 1, range.start.character + 1, range.end.line + 1, range.end.character + 1);
  133. }
  134. function isInsertReplaceEdit(edit) {
  135. return (typeof edit.insert !== 'undefined' &&
  136. typeof edit.replace !== 'undefined');
  137. }
  138. function toCompletionItemKind(kind) {
  139. var mItemKind = languages.CompletionItemKind;
  140. switch (kind) {
  141. case cssService.CompletionItemKind.Text:
  142. return mItemKind.Text;
  143. case cssService.CompletionItemKind.Method:
  144. return mItemKind.Method;
  145. case cssService.CompletionItemKind.Function:
  146. return mItemKind.Function;
  147. case cssService.CompletionItemKind.Constructor:
  148. return mItemKind.Constructor;
  149. case cssService.CompletionItemKind.Field:
  150. return mItemKind.Field;
  151. case cssService.CompletionItemKind.Variable:
  152. return mItemKind.Variable;
  153. case cssService.CompletionItemKind.Class:
  154. return mItemKind.Class;
  155. case cssService.CompletionItemKind.Interface:
  156. return mItemKind.Interface;
  157. case cssService.CompletionItemKind.Module:
  158. return mItemKind.Module;
  159. case cssService.CompletionItemKind.Property:
  160. return mItemKind.Property;
  161. case cssService.CompletionItemKind.Unit:
  162. return mItemKind.Unit;
  163. case cssService.CompletionItemKind.Value:
  164. return mItemKind.Value;
  165. case cssService.CompletionItemKind.Enum:
  166. return mItemKind.Enum;
  167. case cssService.CompletionItemKind.Keyword:
  168. return mItemKind.Keyword;
  169. case cssService.CompletionItemKind.Snippet:
  170. return mItemKind.Snippet;
  171. case cssService.CompletionItemKind.Color:
  172. return mItemKind.Color;
  173. case cssService.CompletionItemKind.File:
  174. return mItemKind.File;
  175. case cssService.CompletionItemKind.Reference:
  176. return mItemKind.Reference;
  177. }
  178. return mItemKind.Property;
  179. }
  180. function toTextEdit(textEdit) {
  181. if (!textEdit) {
  182. return void 0;
  183. }
  184. return {
  185. range: toRange(textEdit.range),
  186. text: textEdit.newText
  187. };
  188. }
  189. function toCommand(c) {
  190. return c && c.command === 'editor.action.triggerSuggest' ? { id: c.command, title: c.title, arguments: c.arguments } : undefined;
  191. }
  192. var CompletionAdapter = /** @class */ (function () {
  193. function CompletionAdapter(_worker) {
  194. this._worker = _worker;
  195. }
  196. Object.defineProperty(CompletionAdapter.prototype, "triggerCharacters", {
  197. get: function () {
  198. return ['/', '-', ':'];
  199. },
  200. enumerable: false,
  201. configurable: true
  202. });
  203. CompletionAdapter.prototype.provideCompletionItems = function (model, position, context, token) {
  204. var resource = model.uri;
  205. return this._worker(resource)
  206. .then(function (worker) {
  207. return worker.doComplete(resource.toString(), fromPosition(position));
  208. })
  209. .then(function (info) {
  210. if (!info) {
  211. return;
  212. }
  213. var wordInfo = model.getWordUntilPosition(position);
  214. var wordRange = new Range(position.lineNumber, wordInfo.startColumn, position.lineNumber, wordInfo.endColumn);
  215. var items = info.items.map(function (entry) {
  216. var item = {
  217. label: entry.label,
  218. insertText: entry.insertText || entry.label,
  219. sortText: entry.sortText,
  220. filterText: entry.filterText,
  221. documentation: entry.documentation,
  222. detail: entry.detail,
  223. command: toCommand(entry.command),
  224. range: wordRange,
  225. kind: toCompletionItemKind(entry.kind)
  226. };
  227. if (entry.textEdit) {
  228. if (isInsertReplaceEdit(entry.textEdit)) {
  229. item.range = {
  230. insert: toRange(entry.textEdit.insert),
  231. replace: toRange(entry.textEdit.replace)
  232. };
  233. }
  234. else {
  235. item.range = toRange(entry.textEdit.range);
  236. }
  237. item.insertText = entry.textEdit.newText;
  238. }
  239. if (entry.additionalTextEdits) {
  240. item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit);
  241. }
  242. if (entry.insertTextFormat === cssService.InsertTextFormat.Snippet) {
  243. item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet;
  244. }
  245. return item;
  246. });
  247. return {
  248. isIncomplete: info.isIncomplete,
  249. suggestions: items
  250. };
  251. });
  252. };
  253. return CompletionAdapter;
  254. }());
  255. export { CompletionAdapter };
  256. function isMarkupContent(thing) {
  257. return (thing && typeof thing === 'object' && typeof thing.kind === 'string');
  258. }
  259. function toMarkdownString(entry) {
  260. if (typeof entry === 'string') {
  261. return {
  262. value: entry
  263. };
  264. }
  265. if (isMarkupContent(entry)) {
  266. if (entry.kind === 'plaintext') {
  267. return {
  268. value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
  269. };
  270. }
  271. return {
  272. value: entry.value
  273. };
  274. }
  275. return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' };
  276. }
  277. function toMarkedStringArray(contents) {
  278. if (!contents) {
  279. return void 0;
  280. }
  281. if (Array.isArray(contents)) {
  282. return contents.map(toMarkdownString);
  283. }
  284. return [toMarkdownString(contents)];
  285. }
  286. // --- hover ------
  287. var HoverAdapter = /** @class */ (function () {
  288. function HoverAdapter(_worker) {
  289. this._worker = _worker;
  290. }
  291. HoverAdapter.prototype.provideHover = function (model, position, token) {
  292. var resource = model.uri;
  293. return this._worker(resource)
  294. .then(function (worker) {
  295. return worker.doHover(resource.toString(), fromPosition(position));
  296. })
  297. .then(function (info) {
  298. if (!info) {
  299. return;
  300. }
  301. return {
  302. range: toRange(info.range),
  303. contents: toMarkedStringArray(info.contents)
  304. };
  305. });
  306. };
  307. return HoverAdapter;
  308. }());
  309. export { HoverAdapter };
  310. // --- document highlights ------
  311. function toDocumentHighlightKind(kind) {
  312. switch (kind) {
  313. case cssService.DocumentHighlightKind.Read:
  314. return languages.DocumentHighlightKind.Read;
  315. case cssService.DocumentHighlightKind.Write:
  316. return languages.DocumentHighlightKind.Write;
  317. case cssService.DocumentHighlightKind.Text:
  318. return languages.DocumentHighlightKind.Text;
  319. }
  320. return languages.DocumentHighlightKind.Text;
  321. }
  322. var DocumentHighlightAdapter = /** @class */ (function () {
  323. function DocumentHighlightAdapter(_worker) {
  324. this._worker = _worker;
  325. }
  326. DocumentHighlightAdapter.prototype.provideDocumentHighlights = function (model, position, token) {
  327. var resource = model.uri;
  328. return this._worker(resource)
  329. .then(function (worker) {
  330. return worker.findDocumentHighlights(resource.toString(), fromPosition(position));
  331. })
  332. .then(function (entries) {
  333. if (!entries) {
  334. return;
  335. }
  336. return entries.map(function (entry) {
  337. return {
  338. range: toRange(entry.range),
  339. kind: toDocumentHighlightKind(entry.kind)
  340. };
  341. });
  342. });
  343. };
  344. return DocumentHighlightAdapter;
  345. }());
  346. export { DocumentHighlightAdapter };
  347. // --- definition ------
  348. function toLocation(location) {
  349. return {
  350. uri: Uri.parse(location.uri),
  351. range: toRange(location.range)
  352. };
  353. }
  354. var DefinitionAdapter = /** @class */ (function () {
  355. function DefinitionAdapter(_worker) {
  356. this._worker = _worker;
  357. }
  358. DefinitionAdapter.prototype.provideDefinition = function (model, position, token) {
  359. var resource = model.uri;
  360. return this._worker(resource)
  361. .then(function (worker) {
  362. return worker.findDefinition(resource.toString(), fromPosition(position));
  363. })
  364. .then(function (definition) {
  365. if (!definition) {
  366. return;
  367. }
  368. return [toLocation(definition)];
  369. });
  370. };
  371. return DefinitionAdapter;
  372. }());
  373. export { DefinitionAdapter };
  374. // --- references ------
  375. var ReferenceAdapter = /** @class */ (function () {
  376. function ReferenceAdapter(_worker) {
  377. this._worker = _worker;
  378. }
  379. ReferenceAdapter.prototype.provideReferences = function (model, position, context, token) {
  380. var resource = model.uri;
  381. return this._worker(resource)
  382. .then(function (worker) {
  383. return worker.findReferences(resource.toString(), fromPosition(position));
  384. })
  385. .then(function (entries) {
  386. if (!entries) {
  387. return;
  388. }
  389. return entries.map(toLocation);
  390. });
  391. };
  392. return ReferenceAdapter;
  393. }());
  394. export { ReferenceAdapter };
  395. // --- rename ------
  396. function toWorkspaceEdit(edit) {
  397. if (!edit || !edit.changes) {
  398. return void 0;
  399. }
  400. var resourceEdits = [];
  401. for (var uri in edit.changes) {
  402. var _uri = Uri.parse(uri);
  403. // let edits: languages.TextEdit[] = [];
  404. for (var _i = 0, _a = edit.changes[uri]; _i < _a.length; _i++) {
  405. var e = _a[_i];
  406. resourceEdits.push({
  407. resource: _uri,
  408. edit: {
  409. range: toRange(e.range),
  410. text: e.newText
  411. }
  412. });
  413. }
  414. }
  415. return {
  416. edits: resourceEdits
  417. };
  418. }
  419. var RenameAdapter = /** @class */ (function () {
  420. function RenameAdapter(_worker) {
  421. this._worker = _worker;
  422. }
  423. RenameAdapter.prototype.provideRenameEdits = function (model, position, newName, token) {
  424. var resource = model.uri;
  425. return this._worker(resource)
  426. .then(function (worker) {
  427. return worker.doRename(resource.toString(), fromPosition(position), newName);
  428. })
  429. .then(function (edit) {
  430. return toWorkspaceEdit(edit);
  431. });
  432. };
  433. return RenameAdapter;
  434. }());
  435. export { RenameAdapter };
  436. // --- document symbols ------
  437. function toSymbolKind(kind) {
  438. var mKind = languages.SymbolKind;
  439. switch (kind) {
  440. case cssService.SymbolKind.File:
  441. return mKind.Array;
  442. case cssService.SymbolKind.Module:
  443. return mKind.Module;
  444. case cssService.SymbolKind.Namespace:
  445. return mKind.Namespace;
  446. case cssService.SymbolKind.Package:
  447. return mKind.Package;
  448. case cssService.SymbolKind.Class:
  449. return mKind.Class;
  450. case cssService.SymbolKind.Method:
  451. return mKind.Method;
  452. case cssService.SymbolKind.Property:
  453. return mKind.Property;
  454. case cssService.SymbolKind.Field:
  455. return mKind.Field;
  456. case cssService.SymbolKind.Constructor:
  457. return mKind.Constructor;
  458. case cssService.SymbolKind.Enum:
  459. return mKind.Enum;
  460. case cssService.SymbolKind.Interface:
  461. return mKind.Interface;
  462. case cssService.SymbolKind.Function:
  463. return mKind.Function;
  464. case cssService.SymbolKind.Variable:
  465. return mKind.Variable;
  466. case cssService.SymbolKind.Constant:
  467. return mKind.Constant;
  468. case cssService.SymbolKind.String:
  469. return mKind.String;
  470. case cssService.SymbolKind.Number:
  471. return mKind.Number;
  472. case cssService.SymbolKind.Boolean:
  473. return mKind.Boolean;
  474. case cssService.SymbolKind.Array:
  475. return mKind.Array;
  476. }
  477. return mKind.Function;
  478. }
  479. var DocumentSymbolAdapter = /** @class */ (function () {
  480. function DocumentSymbolAdapter(_worker) {
  481. this._worker = _worker;
  482. }
  483. DocumentSymbolAdapter.prototype.provideDocumentSymbols = function (model, token) {
  484. var resource = model.uri;
  485. return this._worker(resource)
  486. .then(function (worker) { return worker.findDocumentSymbols(resource.toString()); })
  487. .then(function (items) {
  488. if (!items) {
  489. return;
  490. }
  491. return items.map(function (item) { return ({
  492. name: item.name,
  493. detail: '',
  494. containerName: item.containerName,
  495. kind: toSymbolKind(item.kind),
  496. tags: [],
  497. range: toRange(item.location.range),
  498. selectionRange: toRange(item.location.range)
  499. }); });
  500. });
  501. };
  502. return DocumentSymbolAdapter;
  503. }());
  504. export { DocumentSymbolAdapter };
  505. var DocumentColorAdapter = /** @class */ (function () {
  506. function DocumentColorAdapter(_worker) {
  507. this._worker = _worker;
  508. }
  509. DocumentColorAdapter.prototype.provideDocumentColors = function (model, token) {
  510. var resource = model.uri;
  511. return this._worker(resource)
  512. .then(function (worker) { return worker.findDocumentColors(resource.toString()); })
  513. .then(function (infos) {
  514. if (!infos) {
  515. return;
  516. }
  517. return infos.map(function (item) { return ({
  518. color: item.color,
  519. range: toRange(item.range)
  520. }); });
  521. });
  522. };
  523. DocumentColorAdapter.prototype.provideColorPresentations = function (model, info, token) {
  524. var resource = model.uri;
  525. return this._worker(resource)
  526. .then(function (worker) {
  527. return worker.getColorPresentations(resource.toString(), info.color, fromRange(info.range));
  528. })
  529. .then(function (presentations) {
  530. if (!presentations) {
  531. return;
  532. }
  533. return presentations.map(function (presentation) {
  534. var item = {
  535. label: presentation.label
  536. };
  537. if (presentation.textEdit) {
  538. item.textEdit = toTextEdit(presentation.textEdit);
  539. }
  540. if (presentation.additionalTextEdits) {
  541. item.additionalTextEdits = presentation.additionalTextEdits.map(toTextEdit);
  542. }
  543. return item;
  544. });
  545. });
  546. };
  547. return DocumentColorAdapter;
  548. }());
  549. export { DocumentColorAdapter };
  550. var FoldingRangeAdapter = /** @class */ (function () {
  551. function FoldingRangeAdapter(_worker) {
  552. this._worker = _worker;
  553. }
  554. FoldingRangeAdapter.prototype.provideFoldingRanges = function (model, context, token) {
  555. var resource = model.uri;
  556. return this._worker(resource)
  557. .then(function (worker) { return worker.getFoldingRanges(resource.toString(), context); })
  558. .then(function (ranges) {
  559. if (!ranges) {
  560. return;
  561. }
  562. return ranges.map(function (range) {
  563. var result = {
  564. start: range.startLine + 1,
  565. end: range.endLine + 1
  566. };
  567. if (typeof range.kind !== 'undefined') {
  568. result.kind = toFoldingRangeKind(range.kind);
  569. }
  570. return result;
  571. });
  572. });
  573. };
  574. return FoldingRangeAdapter;
  575. }());
  576. export { FoldingRangeAdapter };
  577. function toFoldingRangeKind(kind) {
  578. switch (kind) {
  579. case cssService.FoldingRangeKind.Comment:
  580. return languages.FoldingRangeKind.Comment;
  581. case cssService.FoldingRangeKind.Imports:
  582. return languages.FoldingRangeKind.Imports;
  583. case cssService.FoldingRangeKind.Region:
  584. return languages.FoldingRangeKind.Region;
  585. }
  586. }
  587. var SelectionRangeAdapter = /** @class */ (function () {
  588. function SelectionRangeAdapter(_worker) {
  589. this._worker = _worker;
  590. }
  591. SelectionRangeAdapter.prototype.provideSelectionRanges = function (model, positions, token) {
  592. var resource = model.uri;
  593. return this._worker(resource)
  594. .then(function (worker) { return worker.getSelectionRanges(resource.toString(), positions.map(fromPosition)); })
  595. .then(function (selectionRanges) {
  596. if (!selectionRanges) {
  597. return;
  598. }
  599. return selectionRanges.map(function (selectionRange) {
  600. var result = [];
  601. while (selectionRange) {
  602. result.push({ range: toRange(selectionRange.range) });
  603. selectionRange = selectionRange.parent;
  604. }
  605. return result;
  606. });
  607. });
  608. };
  609. return SelectionRangeAdapter;
  610. }());
  611. export { SelectionRangeAdapter };