languageFeatures.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  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 htmlService from './_deps/vscode-html-languageservice/htmlLanguageService.js';
  6. import { languages, Uri, Range } from './fillers/monaco-editor-core.js';
  7. // --- completion ------
  8. function fromPosition(position) {
  9. if (!position) {
  10. return void 0;
  11. }
  12. return { character: position.column - 1, line: position.lineNumber - 1 };
  13. }
  14. function fromRange(range) {
  15. if (!range) {
  16. return void 0;
  17. }
  18. return {
  19. start: fromPosition(range.getStartPosition()),
  20. end: fromPosition(range.getEndPosition())
  21. };
  22. }
  23. function toRange(range) {
  24. if (!range) {
  25. return void 0;
  26. }
  27. return new Range(range.start.line + 1, range.start.character + 1, range.end.line + 1, range.end.character + 1);
  28. }
  29. function isInsertReplaceEdit(edit) {
  30. return (typeof edit.insert !== 'undefined' &&
  31. typeof edit.replace !== 'undefined');
  32. }
  33. function toCompletionItemKind(kind) {
  34. var mItemKind = languages.CompletionItemKind;
  35. switch (kind) {
  36. case htmlService.CompletionItemKind.Text:
  37. return mItemKind.Text;
  38. case htmlService.CompletionItemKind.Method:
  39. return mItemKind.Method;
  40. case htmlService.CompletionItemKind.Function:
  41. return mItemKind.Function;
  42. case htmlService.CompletionItemKind.Constructor:
  43. return mItemKind.Constructor;
  44. case htmlService.CompletionItemKind.Field:
  45. return mItemKind.Field;
  46. case htmlService.CompletionItemKind.Variable:
  47. return mItemKind.Variable;
  48. case htmlService.CompletionItemKind.Class:
  49. return mItemKind.Class;
  50. case htmlService.CompletionItemKind.Interface:
  51. return mItemKind.Interface;
  52. case htmlService.CompletionItemKind.Module:
  53. return mItemKind.Module;
  54. case htmlService.CompletionItemKind.Property:
  55. return mItemKind.Property;
  56. case htmlService.CompletionItemKind.Unit:
  57. return mItemKind.Unit;
  58. case htmlService.CompletionItemKind.Value:
  59. return mItemKind.Value;
  60. case htmlService.CompletionItemKind.Enum:
  61. return mItemKind.Enum;
  62. case htmlService.CompletionItemKind.Keyword:
  63. return mItemKind.Keyword;
  64. case htmlService.CompletionItemKind.Snippet:
  65. return mItemKind.Snippet;
  66. case htmlService.CompletionItemKind.Color:
  67. return mItemKind.Color;
  68. case htmlService.CompletionItemKind.File:
  69. return mItemKind.File;
  70. case htmlService.CompletionItemKind.Reference:
  71. return mItemKind.Reference;
  72. }
  73. return mItemKind.Property;
  74. }
  75. function fromCompletionItemKind(kind) {
  76. var mItemKind = languages.CompletionItemKind;
  77. switch (kind) {
  78. case mItemKind.Text:
  79. return htmlService.CompletionItemKind.Text;
  80. case mItemKind.Method:
  81. return htmlService.CompletionItemKind.Method;
  82. case mItemKind.Function:
  83. return htmlService.CompletionItemKind.Function;
  84. case mItemKind.Constructor:
  85. return htmlService.CompletionItemKind.Constructor;
  86. case mItemKind.Field:
  87. return htmlService.CompletionItemKind.Field;
  88. case mItemKind.Variable:
  89. return htmlService.CompletionItemKind.Variable;
  90. case mItemKind.Class:
  91. return htmlService.CompletionItemKind.Class;
  92. case mItemKind.Interface:
  93. return htmlService.CompletionItemKind.Interface;
  94. case mItemKind.Module:
  95. return htmlService.CompletionItemKind.Module;
  96. case mItemKind.Property:
  97. return htmlService.CompletionItemKind.Property;
  98. case mItemKind.Unit:
  99. return htmlService.CompletionItemKind.Unit;
  100. case mItemKind.Value:
  101. return htmlService.CompletionItemKind.Value;
  102. case mItemKind.Enum:
  103. return htmlService.CompletionItemKind.Enum;
  104. case mItemKind.Keyword:
  105. return htmlService.CompletionItemKind.Keyword;
  106. case mItemKind.Snippet:
  107. return htmlService.CompletionItemKind.Snippet;
  108. case mItemKind.Color:
  109. return htmlService.CompletionItemKind.Color;
  110. case mItemKind.File:
  111. return htmlService.CompletionItemKind.File;
  112. case mItemKind.Reference:
  113. return htmlService.CompletionItemKind.Reference;
  114. }
  115. return htmlService.CompletionItemKind.Property;
  116. }
  117. function toTextEdit(textEdit) {
  118. if (!textEdit) {
  119. return void 0;
  120. }
  121. return {
  122. range: toRange(textEdit.range),
  123. text: textEdit.newText
  124. };
  125. }
  126. function toCommand(c) {
  127. return c && c.command === 'editor.action.triggerSuggest' ? { id: c.command, title: c.title, arguments: c.arguments } : undefined;
  128. }
  129. var CompletionAdapter = /** @class */ (function () {
  130. function CompletionAdapter(_worker) {
  131. this._worker = _worker;
  132. }
  133. Object.defineProperty(CompletionAdapter.prototype, "triggerCharacters", {
  134. get: function () {
  135. return ['.', ':', '<', '"', '=', '/'];
  136. },
  137. enumerable: false,
  138. configurable: true
  139. });
  140. CompletionAdapter.prototype.provideCompletionItems = function (model, position, context, token) {
  141. var resource = model.uri;
  142. return this._worker(resource)
  143. .then(function (worker) {
  144. return worker.doComplete(resource.toString(), fromPosition(position));
  145. })
  146. .then(function (info) {
  147. if (!info) {
  148. return;
  149. }
  150. var wordInfo = model.getWordUntilPosition(position);
  151. var wordRange = new Range(position.lineNumber, wordInfo.startColumn, position.lineNumber, wordInfo.endColumn);
  152. var items = info.items.map(function (entry) {
  153. var item = {
  154. label: entry.label,
  155. insertText: entry.insertText || entry.label,
  156. sortText: entry.sortText,
  157. filterText: entry.filterText,
  158. documentation: entry.documentation,
  159. command: toCommand(entry.command),
  160. detail: entry.detail,
  161. range: wordRange,
  162. kind: toCompletionItemKind(entry.kind)
  163. };
  164. if (entry.textEdit) {
  165. if (isInsertReplaceEdit(entry.textEdit)) {
  166. item.range = {
  167. insert: toRange(entry.textEdit.insert),
  168. replace: toRange(entry.textEdit.replace)
  169. };
  170. }
  171. else {
  172. item.range = toRange(entry.textEdit.range);
  173. }
  174. item.insertText = entry.textEdit.newText;
  175. }
  176. if (entry.additionalTextEdits) {
  177. item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit);
  178. }
  179. if (entry.insertTextFormat === htmlService.InsertTextFormat.Snippet) {
  180. item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet;
  181. }
  182. return item;
  183. });
  184. return {
  185. isIncomplete: info.isIncomplete,
  186. suggestions: items
  187. };
  188. });
  189. };
  190. return CompletionAdapter;
  191. }());
  192. export { CompletionAdapter };
  193. // --- hover ------
  194. function isMarkupContent(thing) {
  195. return (thing &&
  196. typeof thing === 'object' &&
  197. typeof thing.kind === 'string');
  198. }
  199. function toMarkdownString(entry) {
  200. if (typeof entry === 'string') {
  201. return {
  202. value: entry
  203. };
  204. }
  205. if (isMarkupContent(entry)) {
  206. if (entry.kind === 'plaintext') {
  207. return {
  208. value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
  209. };
  210. }
  211. return {
  212. value: entry.value
  213. };
  214. }
  215. return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' };
  216. }
  217. function toMarkedStringArray(contents) {
  218. if (!contents) {
  219. return void 0;
  220. }
  221. if (Array.isArray(contents)) {
  222. return contents.map(toMarkdownString);
  223. }
  224. return [toMarkdownString(contents)];
  225. }
  226. var HoverAdapter = /** @class */ (function () {
  227. function HoverAdapter(_worker) {
  228. this._worker = _worker;
  229. }
  230. HoverAdapter.prototype.provideHover = function (model, position, token) {
  231. var resource = model.uri;
  232. return this._worker(resource)
  233. .then(function (worker) {
  234. return worker.doHover(resource.toString(), fromPosition(position));
  235. })
  236. .then(function (info) {
  237. if (!info) {
  238. return;
  239. }
  240. return {
  241. range: toRange(info.range),
  242. contents: toMarkedStringArray(info.contents)
  243. };
  244. });
  245. };
  246. return HoverAdapter;
  247. }());
  248. export { HoverAdapter };
  249. // --- document highlights ------
  250. function toHighlighKind(kind) {
  251. var mKind = languages.DocumentHighlightKind;
  252. switch (kind) {
  253. case htmlService.DocumentHighlightKind.Read:
  254. return mKind.Read;
  255. case htmlService.DocumentHighlightKind.Write:
  256. return mKind.Write;
  257. case htmlService.DocumentHighlightKind.Text:
  258. return mKind.Text;
  259. }
  260. return mKind.Text;
  261. }
  262. var DocumentHighlightAdapter = /** @class */ (function () {
  263. function DocumentHighlightAdapter(_worker) {
  264. this._worker = _worker;
  265. }
  266. DocumentHighlightAdapter.prototype.provideDocumentHighlights = function (model, position, token) {
  267. var resource = model.uri;
  268. return this._worker(resource)
  269. .then(function (worker) { return worker.findDocumentHighlights(resource.toString(), fromPosition(position)); })
  270. .then(function (items) {
  271. if (!items) {
  272. return;
  273. }
  274. return items.map(function (item) { return ({
  275. range: toRange(item.range),
  276. kind: toHighlighKind(item.kind)
  277. }); });
  278. });
  279. };
  280. return DocumentHighlightAdapter;
  281. }());
  282. export { DocumentHighlightAdapter };
  283. // --- document symbols ------
  284. function toSymbolKind(kind) {
  285. var mKind = languages.SymbolKind;
  286. switch (kind) {
  287. case htmlService.SymbolKind.File:
  288. return mKind.Array;
  289. case htmlService.SymbolKind.Module:
  290. return mKind.Module;
  291. case htmlService.SymbolKind.Namespace:
  292. return mKind.Namespace;
  293. case htmlService.SymbolKind.Package:
  294. return mKind.Package;
  295. case htmlService.SymbolKind.Class:
  296. return mKind.Class;
  297. case htmlService.SymbolKind.Method:
  298. return mKind.Method;
  299. case htmlService.SymbolKind.Property:
  300. return mKind.Property;
  301. case htmlService.SymbolKind.Field:
  302. return mKind.Field;
  303. case htmlService.SymbolKind.Constructor:
  304. return mKind.Constructor;
  305. case htmlService.SymbolKind.Enum:
  306. return mKind.Enum;
  307. case htmlService.SymbolKind.Interface:
  308. return mKind.Interface;
  309. case htmlService.SymbolKind.Function:
  310. return mKind.Function;
  311. case htmlService.SymbolKind.Variable:
  312. return mKind.Variable;
  313. case htmlService.SymbolKind.Constant:
  314. return mKind.Constant;
  315. case htmlService.SymbolKind.String:
  316. return mKind.String;
  317. case htmlService.SymbolKind.Number:
  318. return mKind.Number;
  319. case htmlService.SymbolKind.Boolean:
  320. return mKind.Boolean;
  321. case htmlService.SymbolKind.Array:
  322. return mKind.Array;
  323. }
  324. return mKind.Function;
  325. }
  326. var DocumentSymbolAdapter = /** @class */ (function () {
  327. function DocumentSymbolAdapter(_worker) {
  328. this._worker = _worker;
  329. }
  330. DocumentSymbolAdapter.prototype.provideDocumentSymbols = function (model, token) {
  331. var resource = model.uri;
  332. return this._worker(resource)
  333. .then(function (worker) { return worker.findDocumentSymbols(resource.toString()); })
  334. .then(function (items) {
  335. if (!items) {
  336. return;
  337. }
  338. return items.map(function (item) { return ({
  339. name: item.name,
  340. detail: '',
  341. containerName: item.containerName,
  342. kind: toSymbolKind(item.kind),
  343. tags: [],
  344. range: toRange(item.location.range),
  345. selectionRange: toRange(item.location.range)
  346. }); });
  347. });
  348. };
  349. return DocumentSymbolAdapter;
  350. }());
  351. export { DocumentSymbolAdapter };
  352. var DocumentLinkAdapter = /** @class */ (function () {
  353. function DocumentLinkAdapter(_worker) {
  354. this._worker = _worker;
  355. }
  356. DocumentLinkAdapter.prototype.provideLinks = function (model, token) {
  357. var resource = model.uri;
  358. return this._worker(resource)
  359. .then(function (worker) { return worker.findDocumentLinks(resource.toString()); })
  360. .then(function (items) {
  361. if (!items) {
  362. return;
  363. }
  364. return {
  365. links: items.map(function (item) { return ({
  366. range: toRange(item.range),
  367. url: item.target
  368. }); })
  369. };
  370. });
  371. };
  372. return DocumentLinkAdapter;
  373. }());
  374. export { DocumentLinkAdapter };
  375. function fromFormattingOptions(options) {
  376. return {
  377. tabSize: options.tabSize,
  378. insertSpaces: options.insertSpaces
  379. };
  380. }
  381. var DocumentFormattingEditProvider = /** @class */ (function () {
  382. function DocumentFormattingEditProvider(_worker) {
  383. this._worker = _worker;
  384. }
  385. DocumentFormattingEditProvider.prototype.provideDocumentFormattingEdits = function (model, options, token) {
  386. var resource = model.uri;
  387. return this._worker(resource).then(function (worker) {
  388. return worker
  389. .format(resource.toString(), null, fromFormattingOptions(options))
  390. .then(function (edits) {
  391. if (!edits || edits.length === 0) {
  392. return;
  393. }
  394. return edits.map(toTextEdit);
  395. });
  396. });
  397. };
  398. return DocumentFormattingEditProvider;
  399. }());
  400. export { DocumentFormattingEditProvider };
  401. var DocumentRangeFormattingEditProvider = /** @class */ (function () {
  402. function DocumentRangeFormattingEditProvider(_worker) {
  403. this._worker = _worker;
  404. }
  405. DocumentRangeFormattingEditProvider.prototype.provideDocumentRangeFormattingEdits = function (model, range, options, token) {
  406. var resource = model.uri;
  407. return this._worker(resource).then(function (worker) {
  408. return worker
  409. .format(resource.toString(), fromRange(range), fromFormattingOptions(options))
  410. .then(function (edits) {
  411. if (!edits || edits.length === 0) {
  412. return;
  413. }
  414. return edits.map(toTextEdit);
  415. });
  416. });
  417. };
  418. return DocumentRangeFormattingEditProvider;
  419. }());
  420. export { DocumentRangeFormattingEditProvider };
  421. var RenameAdapter = /** @class */ (function () {
  422. function RenameAdapter(_worker) {
  423. this._worker = _worker;
  424. }
  425. RenameAdapter.prototype.provideRenameEdits = function (model, position, newName, token) {
  426. var resource = model.uri;
  427. return this._worker(resource)
  428. .then(function (worker) {
  429. return worker.doRename(resource.toString(), fromPosition(position), newName);
  430. })
  431. .then(function (edit) {
  432. return toWorkspaceEdit(edit);
  433. });
  434. };
  435. return RenameAdapter;
  436. }());
  437. export { RenameAdapter };
  438. function toWorkspaceEdit(edit) {
  439. if (!edit || !edit.changes) {
  440. return void 0;
  441. }
  442. var resourceEdits = [];
  443. for (var uri in edit.changes) {
  444. var _uri = Uri.parse(uri);
  445. for (var _i = 0, _a = edit.changes[uri]; _i < _a.length; _i++) {
  446. var e = _a[_i];
  447. resourceEdits.push({
  448. resource: _uri,
  449. edit: {
  450. range: toRange(e.range),
  451. text: e.newText
  452. }
  453. });
  454. }
  455. }
  456. return {
  457. edits: resourceEdits
  458. };
  459. }
  460. var FoldingRangeAdapter = /** @class */ (function () {
  461. function FoldingRangeAdapter(_worker) {
  462. this._worker = _worker;
  463. }
  464. FoldingRangeAdapter.prototype.provideFoldingRanges = function (model, context, token) {
  465. var resource = model.uri;
  466. return this._worker(resource)
  467. .then(function (worker) { return worker.getFoldingRanges(resource.toString(), context); })
  468. .then(function (ranges) {
  469. if (!ranges) {
  470. return;
  471. }
  472. return ranges.map(function (range) {
  473. var result = {
  474. start: range.startLine + 1,
  475. end: range.endLine + 1
  476. };
  477. if (typeof range.kind !== 'undefined') {
  478. result.kind = toFoldingRangeKind(range.kind);
  479. }
  480. return result;
  481. });
  482. });
  483. };
  484. return FoldingRangeAdapter;
  485. }());
  486. export { FoldingRangeAdapter };
  487. function toFoldingRangeKind(kind) {
  488. switch (kind) {
  489. case htmlService.FoldingRangeKind.Comment:
  490. return languages.FoldingRangeKind.Comment;
  491. case htmlService.FoldingRangeKind.Imports:
  492. return languages.FoldingRangeKind.Imports;
  493. case htmlService.FoldingRangeKind.Region:
  494. return languages.FoldingRangeKind.Region;
  495. }
  496. }
  497. var SelectionRangeAdapter = /** @class */ (function () {
  498. function SelectionRangeAdapter(_worker) {
  499. this._worker = _worker;
  500. }
  501. SelectionRangeAdapter.prototype.provideSelectionRanges = function (model, positions, token) {
  502. var resource = model.uri;
  503. return this._worker(resource)
  504. .then(function (worker) { return worker.getSelectionRanges(resource.toString(), positions.map(fromPosition)); })
  505. .then(function (selectionRanges) {
  506. if (!selectionRanges) {
  507. return;
  508. }
  509. return selectionRanges.map(function (selectionRange) {
  510. var result = [];
  511. while (selectionRange) {
  512. result.push({ range: toRange(selectionRange.range) });
  513. selectionRange = selectionRange.parent;
  514. }
  515. return result;
  516. });
  517. });
  518. };
  519. return SelectionRangeAdapter;
  520. }());
  521. export { SelectionRangeAdapter };