ac5526b539f4c727037addc71afe4f8c777dc66a60031f3d9dc4a01d9d285f76e857892d01b0fbc858fc02f05abc714aa2493dab304c1a0335bc0dc67e6949 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  6. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  7. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  8. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  9. return c > 3 && r && Object.defineProperty(target, key, r), r;
  10. };
  11. var __param = (this && this.__param) || function (paramIndex, decorator) {
  12. return function (target, key) { decorator(target, key, paramIndex); }
  13. };
  14. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
  15. function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
  16. return new (P || (P = Promise))(function (resolve, reject) {
  17. function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
  18. function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
  19. function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
  20. step((generator = generator.apply(thisArg, _arguments || [])).next());
  21. });
  22. };
  23. import * as dom from '../../../base/browser/dom.js';
  24. import { CancellationToken } from '../../../base/common/cancellation.js';
  25. import { LinkedList } from '../../../base/common/linkedList.js';
  26. import { ResourceMap } from '../../../base/common/map.js';
  27. import { parse } from '../../../base/common/marshalling.js';
  28. import { Schemas } from '../../../base/common/network.js';
  29. import { normalizePath } from '../../../base/common/resources.js';
  30. import { URI } from '../../../base/common/uri.js';
  31. import { ICodeEditorService } from './codeEditorService.js';
  32. import { ICommandService } from '../../../platform/commands/common/commands.js';
  33. import { EditorOpenSource } from '../../../platform/editor/common/editor.js';
  34. import { extractSelection, matchesScheme, matchesSomeScheme } from '../../../platform/opener/common/opener.js';
  35. let CommandOpener = class CommandOpener {
  36. constructor(_commandService) {
  37. this._commandService = _commandService;
  38. }
  39. open(target, options) {
  40. return __awaiter(this, void 0, void 0, function* () {
  41. if (!matchesScheme(target, Schemas.command)) {
  42. return false;
  43. }
  44. if (!(options === null || options === void 0 ? void 0 : options.allowCommands)) {
  45. // silently ignore commands when command-links are disabled, also
  46. // surpress other openers by returning TRUE
  47. return true;
  48. }
  49. // run command or bail out if command isn't known
  50. if (typeof target === 'string') {
  51. target = URI.parse(target);
  52. }
  53. // execute as command
  54. let args = [];
  55. try {
  56. args = parse(decodeURIComponent(target.query));
  57. }
  58. catch (_a) {
  59. // ignore and retry
  60. try {
  61. args = parse(target.query);
  62. }
  63. catch (_b) {
  64. // ignore error
  65. }
  66. }
  67. if (!Array.isArray(args)) {
  68. args = [args];
  69. }
  70. yield this._commandService.executeCommand(target.path, ...args);
  71. return true;
  72. });
  73. }
  74. };
  75. CommandOpener = __decorate([
  76. __param(0, ICommandService)
  77. ], CommandOpener);
  78. let EditorOpener = class EditorOpener {
  79. constructor(_editorService) {
  80. this._editorService = _editorService;
  81. }
  82. open(target, options) {
  83. return __awaiter(this, void 0, void 0, function* () {
  84. if (typeof target === 'string') {
  85. target = URI.parse(target);
  86. }
  87. const { selection, uri } = extractSelection(target);
  88. target = uri;
  89. if (target.scheme === Schemas.file) {
  90. target = normalizePath(target); // workaround for non-normalized paths (https://github.com/microsoft/vscode/issues/12954)
  91. }
  92. yield this._editorService.openCodeEditor({
  93. resource: target,
  94. options: Object.assign({ selection, source: (options === null || options === void 0 ? void 0 : options.fromUserGesture) ? EditorOpenSource.USER : EditorOpenSource.API }, options === null || options === void 0 ? void 0 : options.editorOptions)
  95. }, this._editorService.getFocusedCodeEditor(), options === null || options === void 0 ? void 0 : options.openToSide);
  96. return true;
  97. });
  98. }
  99. };
  100. EditorOpener = __decorate([
  101. __param(0, ICodeEditorService)
  102. ], EditorOpener);
  103. let OpenerService = class OpenerService {
  104. constructor(editorService, commandService) {
  105. this._openers = new LinkedList();
  106. this._validators = new LinkedList();
  107. this._resolvers = new LinkedList();
  108. this._resolvedUriTargets = new ResourceMap(uri => uri.with({ path: null, fragment: null, query: null }).toString());
  109. this._externalOpeners = new LinkedList();
  110. // Default external opener is going through window.open()
  111. this._defaultExternalOpener = {
  112. openExternal: (href) => __awaiter(this, void 0, void 0, function* () {
  113. // ensure to open HTTP/HTTPS links into new windows
  114. // to not trigger a navigation. Any other link is
  115. // safe to be set as HREF to prevent a blank window
  116. // from opening.
  117. if (matchesSomeScheme(href, Schemas.http, Schemas.https)) {
  118. dom.windowOpenNoOpener(href);
  119. }
  120. else {
  121. window.location.href = href;
  122. }
  123. return true;
  124. })
  125. };
  126. // Default opener: any external, maito, http(s), command, and catch-all-editors
  127. this._openers.push({
  128. open: (target, options) => __awaiter(this, void 0, void 0, function* () {
  129. if ((options === null || options === void 0 ? void 0 : options.openExternal) || matchesSomeScheme(target, Schemas.mailto, Schemas.http, Schemas.https, Schemas.vsls)) {
  130. // open externally
  131. yield this._doOpenExternal(target, options);
  132. return true;
  133. }
  134. return false;
  135. })
  136. });
  137. this._openers.push(new CommandOpener(commandService));
  138. this._openers.push(new EditorOpener(editorService));
  139. }
  140. registerOpener(opener) {
  141. const remove = this._openers.unshift(opener);
  142. return { dispose: remove };
  143. }
  144. registerValidator(validator) {
  145. const remove = this._validators.push(validator);
  146. return { dispose: remove };
  147. }
  148. registerExternalUriResolver(resolver) {
  149. const remove = this._resolvers.push(resolver);
  150. return { dispose: remove };
  151. }
  152. setDefaultExternalOpener(externalOpener) {
  153. this._defaultExternalOpener = externalOpener;
  154. }
  155. registerExternalOpener(opener) {
  156. const remove = this._externalOpeners.push(opener);
  157. return { dispose: remove };
  158. }
  159. open(target, options) {
  160. var _a;
  161. return __awaiter(this, void 0, void 0, function* () {
  162. // check with contributed validators
  163. const targetURI = typeof target === 'string' ? URI.parse(target) : target;
  164. // validate against the original URI that this URI resolves to, if one exists
  165. const validationTarget = (_a = this._resolvedUriTargets.get(targetURI)) !== null && _a !== void 0 ? _a : target;
  166. for (const validator of this._validators) {
  167. if (!(yield validator.shouldOpen(validationTarget, options))) {
  168. return false;
  169. }
  170. }
  171. // check with contributed openers
  172. for (const opener of this._openers) {
  173. const handled = yield opener.open(target, options);
  174. if (handled) {
  175. return true;
  176. }
  177. }
  178. return false;
  179. });
  180. }
  181. resolveExternalUri(resource, options) {
  182. return __awaiter(this, void 0, void 0, function* () {
  183. for (const resolver of this._resolvers) {
  184. try {
  185. const result = yield resolver.resolveExternalUri(resource, options);
  186. if (result) {
  187. if (!this._resolvedUriTargets.has(result.resolved)) {
  188. this._resolvedUriTargets.set(result.resolved, resource);
  189. }
  190. return result;
  191. }
  192. }
  193. catch (_a) {
  194. // noop
  195. }
  196. }
  197. throw new Error('Could not resolve external URI: ' + resource.toString());
  198. });
  199. }
  200. _doOpenExternal(resource, options) {
  201. return __awaiter(this, void 0, void 0, function* () {
  202. //todo@jrieken IExternalUriResolver should support `uri: URI | string`
  203. const uri = typeof resource === 'string' ? URI.parse(resource) : resource;
  204. let externalUri;
  205. try {
  206. externalUri = (yield this.resolveExternalUri(uri, options)).resolved;
  207. }
  208. catch (_a) {
  209. externalUri = uri;
  210. }
  211. let href;
  212. if (typeof resource === 'string' && uri.toString() === externalUri.toString()) {
  213. // open the url-string AS IS
  214. href = resource;
  215. }
  216. else {
  217. // open URI using the toString(noEncode)+encodeURI-trick
  218. href = encodeURI(externalUri.toString(true));
  219. }
  220. if (options === null || options === void 0 ? void 0 : options.allowContributedOpeners) {
  221. const preferredOpenerId = typeof (options === null || options === void 0 ? void 0 : options.allowContributedOpeners) === 'string' ? options === null || options === void 0 ? void 0 : options.allowContributedOpeners : undefined;
  222. for (const opener of this._externalOpeners) {
  223. const didOpen = yield opener.openExternal(href, {
  224. sourceUri: uri,
  225. preferredOpenerId,
  226. }, CancellationToken.None);
  227. if (didOpen) {
  228. return true;
  229. }
  230. }
  231. }
  232. return this._defaultExternalOpener.openExternal(href, { sourceUri: uri }, CancellationToken.None);
  233. });
  234. }
  235. dispose() {
  236. this._validators.clear();
  237. }
  238. };
  239. OpenerService = __decorate([
  240. __param(0, ICodeEditorService),
  241. __param(1, ICommandService)
  242. ], OpenerService);
  243. export { OpenerService };