@@ -16,6 +16,69 @@ import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/c
1616import { IOpener , IOpenerService , IValidator , IExternalUriResolver , OpenOptions , ResolveExternalUriOptions , IResolvedExternalUri , IExternalOpener } from 'vs/platform/opener/common/opener' ;
1717import { EditorOpenContext } from 'vs/platform/editor/common/editor' ;
1818
19+ class CommandOpener implements IOpener {
20+
21+ constructor ( @ICommandService private readonly _commandService : ICommandService ) { }
22+
23+ async open ( uri : URI , ) {
24+ // run command or bail out if command isn't known
25+ if ( ! equalsIgnoreCase ( uri . scheme , Schemas . command ) ) {
26+ return false ;
27+ }
28+
29+ if ( ! CommandsRegistry . getCommand ( uri . path ) ) {
30+ throw new Error ( `command '${ uri . path } ' NOT known` ) ;
31+ }
32+
33+ // execute as command
34+ let args : any = [ ] ;
35+ try {
36+ args = parse ( uri . query ) ;
37+ if ( ! Array . isArray ( args ) ) {
38+ args = [ args ] ;
39+ }
40+ } catch ( e ) {
41+ // ignore error
42+ }
43+ await this . _commandService . executeCommand ( uri . path , ...args ) ;
44+ return true ;
45+ }
46+ }
47+
48+ class EditorOpener implements IOpener {
49+
50+ constructor ( @ICodeEditorService private readonly _editorService : ICodeEditorService ) { }
51+
52+ async open ( uri : URI , options ?: OpenOptions ) : Promise < boolean > {
53+
54+ // finally open in editor
55+ let selection : { startLineNumber : number ; startColumn : number ; } | undefined = undefined ;
56+ const match = / ^ L ? ( \d + ) (?: , ( \d + ) ) ? / . exec ( uri . fragment ) ;
57+ if ( match ) {
58+ // support file:///some/file.js#73,84
59+ // support file:///some/file.js#L73
60+ selection = {
61+ startLineNumber : parseInt ( match [ 1 ] ) ,
62+ startColumn : match [ 2 ] ? parseInt ( match [ 2 ] ) : 1
63+ } ;
64+ // remove fragment
65+ uri = uri . with ( { fragment : '' } ) ;
66+ }
67+
68+ if ( uri . scheme === Schemas . file ) {
69+ uri = resources . normalizePath ( uri ) ; // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954)
70+ }
71+
72+ await this . _editorService . openCodeEditor (
73+ { resource : uri , options : { selection, context : options ?. fromUserGesture ? EditorOpenContext . USER : EditorOpenContext . API } } ,
74+ this . _editorService . getFocusedCodeEditor ( ) ,
75+ options ?. openToSide
76+ ) ;
77+
78+ return true ;
79+ }
80+ }
81+
1982export class OpenerService extends Disposable implements IOpenerService {
2083
2184 _serviceBrand : undefined ;
@@ -26,23 +89,35 @@ export class OpenerService extends Disposable implements IOpenerService {
2689 private _externalOpener : IExternalOpener ;
2790
2891 constructor (
29- @ICodeEditorService private readonly _editorService : ICodeEditorService ,
30- @ICommandService private readonly _commandService : ICommandService ,
92+ @ICodeEditorService editorService : ICodeEditorService ,
93+ @ICommandService commandService : ICommandService ,
3194 ) {
3295 super ( ) ;
3396
3497 // Default external opener is going through window.open()
3598 this . _externalOpener = {
3699 openExternal : href => {
37100 dom . windowOpenNoOpener ( href ) ;
38-
39101 return Promise . resolve ( true ) ;
40102 }
41103 } ;
104+
105+ //
106+ this . _openers . push ( { // default: open externally
107+ open : async ( uri : URI , options : OpenOptions | undefined ) : Promise < boolean > => {
108+ const { scheme } = uri ;
109+ if ( options ?. openExternal || equalsIgnoreCase ( scheme , Schemas . mailto ) || equalsIgnoreCase ( scheme , Schemas . http ) || equalsIgnoreCase ( scheme , Schemas . https ) ) {
110+ return this . _doOpenExternal ( uri , options ) ;
111+ }
112+ return false ;
113+ }
114+ } ) ;
115+ this . _openers . push ( new CommandOpener ( commandService ) ) ; // default: run command
116+ this . _openers . push ( new EditorOpener ( editorService ) ) ; // default: open editor
42117 }
43118
44119 registerOpener ( opener : IOpener ) : IDisposable {
45- const remove = this . _openers . push ( opener ) ;
120+ const remove = this . _openers . unshift ( opener ) ;
46121
47122 return { dispose : remove } ;
48123 }
@@ -85,8 +160,7 @@ export class OpenerService extends Disposable implements IOpenerService {
85160 }
86161 }
87162
88- // use default openers
89- return this . _doOpen ( resource , options ) ;
163+ return false ;
90164 }
91165
92166 async resolveExternalUri ( resource : URI , options ?: ResolveExternalUriOptions ) : Promise < IResolvedExternalUri > {
@@ -100,62 +174,6 @@ export class OpenerService extends Disposable implements IOpenerService {
100174 return { resolved : resource , dispose : ( ) => { } } ;
101175 }
102176
103- private async _doOpen ( resource : URI , options : OpenOptions | undefined ) : Promise < boolean > {
104- const { scheme, path, query, fragment } = resource ;
105-
106- if ( options ?. openExternal || equalsIgnoreCase ( scheme , Schemas . mailto ) || equalsIgnoreCase ( scheme , Schemas . http ) || equalsIgnoreCase ( scheme , Schemas . https ) ) {
107- // open externally
108- return this . _doOpenExternal ( resource , options ) ;
109- }
110-
111- if ( equalsIgnoreCase ( scheme , Schemas . command ) ) {
112- // run command or bail out if command isn't known
113- if ( ! CommandsRegistry . getCommand ( path ) ) {
114- throw new Error ( `command '${ path } ' NOT known` ) ;
115- }
116- // execute as command
117- let args : any = [ ] ;
118- try {
119- args = parse ( query ) ;
120- if ( ! Array . isArray ( args ) ) {
121- args = [ args ] ;
122- }
123- } catch ( e ) {
124- // ignore error
125- }
126-
127- await this . _commandService . executeCommand ( path , ...args ) ;
128-
129- return true ;
130- }
131-
132- // finally open in editor
133- let selection : { startLineNumber : number ; startColumn : number ; } | undefined = undefined ;
134- const match = / ^ L ? ( \d + ) (?: , ( \d + ) ) ? / . exec ( fragment ) ;
135- if ( match ) {
136- // support file:///some/file.js#73,84
137- // support file:///some/file.js#L73
138- selection = {
139- startLineNumber : parseInt ( match [ 1 ] ) ,
140- startColumn : match [ 2 ] ? parseInt ( match [ 2 ] ) : 1
141- } ;
142- // remove fragment
143- resource = resource . with ( { fragment : '' } ) ;
144- }
145-
146- if ( resource . scheme === Schemas . file ) {
147- resource = resources . normalizePath ( resource ) ; // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954)
148- }
149-
150- await this . _editorService . openCodeEditor (
151- { resource, options : { selection, context : options ?. fromUserGesture ? EditorOpenContext . USER : EditorOpenContext . API } } ,
152- this . _editorService . getFocusedCodeEditor ( ) ,
153- options ?. openToSide
154- ) ;
155-
156- return true ;
157- }
158-
159177 private async _doOpenExternal ( resource : URI , options : OpenOptions | undefined ) : Promise < boolean > {
160178 const { resolved } = await this . resolveExternalUri ( resource , options ) ;
161179
0 commit comments