4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
6
import { ICodeEditor } from 'vs/editor/browser/editorBrowser' ;
7
- import { EditorAction2 , registerEditorContribution } from 'vs/editor/browser/editorExtensions' ;
7
+ import { EditorAction2 } from 'vs/editor/browser/editorExtensions' ;
8
8
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys' ;
9
9
import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2' ;
10
10
import { localize } from 'vs/nls' ;
11
11
import { registerAction2 } from 'vs/platform/actions/common/actions' ;
12
12
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService' ;
13
- import { ContextKeyExpr , IContextKeyService } from 'vs/platform/contextkey/common/contextkey' ;
13
+ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey' ;
14
14
import { IInstantiationService , ServicesAccessor } from 'vs/platform/instantiation/common/instantiation' ;
15
15
import { pickSnippet } from 'vs/workbench/contrib/snippets/browser/snippetPicker' ;
16
16
import { ISnippetsService } from './snippets.contribution' ;
@@ -23,6 +23,12 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat
23
23
import { Range } from 'vs/editor/common/core/range' ;
24
24
import { Selection } from 'vs/editor/common/core/selection' ;
25
25
import { Snippet } from 'vs/workbench/contrib/snippets/browser/snippetsFile' ;
26
+ import { Registry } from 'vs/platform/registry/common/platform' ;
27
+ import { IWorkbenchContributionsRegistry , Extensions as WorkbenchExtensions , IWorkbenchContribution } from 'vs/workbench/common/contributions' ;
28
+ import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle' ;
29
+ import { Position } from 'vs/editor/common/core/position' ;
30
+ import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
31
+ import { EditorInputCapabilities } from 'vs/workbench/common/editor' ;
26
32
27
33
const options = {
28
34
id : 'editor.action.surroundWithSnippet' ,
@@ -37,72 +43,88 @@ const options = {
37
43
f1 : true ,
38
44
} ;
39
45
40
- class SurroundWithSnippet {
41
- constructor (
42
- private readonly _editor : ICodeEditor ,
43
- @ISnippetsService private readonly _snippetService : ISnippetsService ,
44
- @IClipboardService private readonly _clipboardService : IClipboardService ,
45
- @IContextKeyService private readonly _contextKeyService : IContextKeyService ,
46
- @IInstantiationService private readonly _instaService : IInstantiationService ,
47
- ) { }
48
-
49
- async getSurroundableSnippets ( ) : Promise < Snippet [ ] > {
50
- if ( ! this . _editor . hasModel ( ) ) {
51
- return [ ] ;
52
- }
46
+ const MAX_SNIPPETS_ON_CODE_ACTIONS_MENU = 6 ;
53
47
54
- const model = this . _editor . getModel ( ) ;
55
- const { lineNumber, column } = this . _editor . getPosition ( ) ;
56
- model . tokenization . tokenizeIfCheap ( lineNumber ) ;
57
- const languageId = model . getLanguageIdAtPosition ( lineNumber , column ) ;
48
+ function makeCodeActionForSnippet ( snippet : Snippet ) : CodeAction {
49
+ const title = localize ( 'codeAction' , "Surround With Snippet: {0}" , snippet . name ) ;
50
+ return {
51
+ title,
52
+ command : {
53
+ id : 'editor.action.insertSnippet' ,
54
+ title,
55
+ arguments : [ { name : snippet . name } ]
56
+ } ,
57
+ } ;
58
+ }
58
59
59
- const allSnippets = await this . _snippetService . getSnippets ( languageId , { includeNoPrefixSnippets : true , includeDisabledSnippets : true } ) ;
60
- return allSnippets . filter ( snippet => snippet . usesSelection ) ;
60
+ async function getSurroundableSnippets ( accessor : ServicesAccessor , model : ITextModel | null , position : Position | null ) : Promise < Snippet [ ] > {
61
+ if ( ! model ) {
62
+ return [ ] ;
61
63
}
62
64
63
- canExecute ( ) : boolean {
64
- return this . _contextKeyService . contextMatchesRules ( options . precondition ) ;
65
+ const snippetsService = accessor . get ( ISnippetsService ) ;
66
+
67
+ let languageId : string ;
68
+ if ( position ) {
69
+ const { lineNumber, column } = position ;
70
+ model . tokenization . tokenizeIfCheap ( lineNumber ) ;
71
+ languageId = model . getLanguageIdAtPosition ( lineNumber , column ) ;
72
+ } else {
73
+ languageId = model . getLanguageId ( ) ;
65
74
}
66
75
67
- async run ( ) {
68
- if ( ! this . canExecute ( ) ) {
69
- return ;
70
- }
76
+ const allSnippets = await snippetsService . getSnippets ( languageId , { includeNoPrefixSnippets : true , includeDisabledSnippets : true } ) ;
77
+ return allSnippets . filter ( snippet => snippet . usesSelection ) ;
78
+ }
71
79
72
- const snippets = await this . getSurroundableSnippets ( ) ;
73
- if ( ! snippets . length ) {
74
- return ;
75
- }
80
+ function canExecute ( accessor : ServicesAccessor ) : boolean {
81
+ const editorService = accessor . get ( IEditorService ) ;
76
82
77
- const snippet = await this . _instaService . invokeFunction ( pickSnippet , snippets ) ;
78
- if ( ! snippet ) {
79
- return ;
80
- }
83
+ const editor = editorService . activeEditor ;
84
+ if ( ! editor || editor . hasCapability ( EditorInputCapabilities . Readonly ) ) {
85
+ return false ;
86
+ }
87
+ const selections = editorService . activeTextEditorControl ?. getSelections ( ) ;
88
+ return ! ! selections && selections . length > 0 ;
89
+ }
81
90
82
- let clipboardText : string | undefined ;
83
- if ( snippet . needsClipboard ) {
84
- clipboardText = await this . _clipboardService . readText ( ) ;
85
- }
91
+ async function surroundWithSnippet ( accessor : ServicesAccessor , editor : ICodeEditor ) {
92
+ const instaService = accessor . get ( IInstantiationService ) ;
93
+ const clipboardService = accessor . get ( IClipboardService ) ;
86
94
87
- SnippetController2 . get ( this . _editor ) ?. insert ( snippet . codeSnippet , { clipboardText } ) ;
95
+ if ( ! canExecute ( accessor ) ) {
96
+ return ;
88
97
}
98
+
99
+ const snippets = await getSurroundableSnippets ( accessor , editor . getModel ( ) , editor . getPosition ( ) ) ;
100
+ if ( ! snippets . length ) {
101
+ return ;
102
+ }
103
+
104
+ const snippet = await instaService . invokeFunction ( pickSnippet , snippets ) ;
105
+ if ( ! snippet ) {
106
+ return ;
107
+ }
108
+
109
+ let clipboardText : string | undefined ;
110
+ if ( snippet . needsClipboard ) {
111
+ clipboardText = await clipboardService . readText ( ) ;
112
+ }
113
+
114
+ SnippetController2 . get ( editor ) ?. insert ( snippet . codeSnippet , { clipboardText } ) ;
89
115
}
90
116
91
- class SurroundWithSnippetEditorAction extends EditorAction2 {
117
+
118
+ registerAction2 ( class SurroundWithSnippetEditorAction extends EditorAction2 {
92
119
constructor ( ) {
93
120
super ( options ) ;
94
121
}
95
122
async runEditorCommand ( accessor : ServicesAccessor , editor : ICodeEditor , ...args : any [ ] ) {
96
- const instaService = accessor . get ( IInstantiationService ) ;
97
- const core = instaService . createInstance ( SurroundWithSnippet , editor ) ;
98
- await core . run ( ) ;
123
+ await surroundWithSnippet ( accessor , editor ) ;
99
124
}
100
- }
101
-
102
- registerAction2 ( SurroundWithSnippetEditorAction ) ;
125
+ } ) ;
103
126
104
-
105
- export class SurroundWithSnippetCodeActionProvider extends Disposable implements CodeActionProvider {
127
+ export class SurroundWithSnippetCodeActionProvider extends Disposable implements CodeActionProvider , IWorkbenchContribution {
106
128
private static readonly codeAction : CodeAction = {
107
129
kind : CodeActionKind . Refactor . value ,
108
130
title : options . title . value ,
@@ -112,28 +134,30 @@ export class SurroundWithSnippetCodeActionProvider extends Disposable implements
112
134
} ,
113
135
} ;
114
136
115
- private core : SurroundWithSnippet ;
116
-
117
137
constructor (
118
- editor : ICodeEditor ,
119
138
@ILanguageFeaturesService languageFeaturesService : ILanguageFeaturesService ,
120
- @IInstantiationService instaService : IInstantiationService ,
139
+ @IInstantiationService private readonly instaService : IInstantiationService ,
121
140
) {
122
141
super ( ) ;
123
- this . core = instaService . createInstance ( SurroundWithSnippet , editor ) ;
124
142
this . _register ( languageFeaturesService . codeActionProvider . register ( '*' , this ) ) ;
125
143
}
126
144
127
145
async provideCodeActions ( model : ITextModel , range : Range | Selection , context : CodeActionContext , token : CancellationToken ) : Promise < CodeActionList > {
128
- if ( ! this . core . canExecute ( ) ) {
146
+ if ( ! this . instaService . invokeFunction ( canExecute ) ) {
147
+ return { actions : [ ] , dispose : ( ) => { } } ;
148
+ }
149
+
150
+ const snippets = await this . instaService . invokeFunction ( accessor => getSurroundableSnippets ( accessor , model , range . getEndPosition ( ) ) ) ;
151
+ if ( ! snippets . length ) {
129
152
return { actions : [ ] , dispose : ( ) => { } } ;
130
153
}
131
- const snippets = await this . core . getSurroundableSnippets ( ) ;
132
154
return {
133
- actions : snippets . length ? [ SurroundWithSnippetCodeActionProvider . codeAction ] : [ ] ,
155
+ actions : snippets . length <= MAX_SNIPPETS_ON_CODE_ACTIONS_MENU
156
+ ? snippets . map ( x => makeCodeActionForSnippet ( x ) )
157
+ : [ SurroundWithSnippetCodeActionProvider . codeAction ] ,
134
158
dispose : ( ) => { }
135
159
} ;
136
160
}
137
161
}
138
162
139
- registerEditorContribution ( options . id , SurroundWithSnippetCodeActionProvider ) ;
163
+ Registry . as < IWorkbenchContributionsRegistry > ( WorkbenchExtensions . Workbench ) . registerWorkbenchContribution ( SurroundWithSnippetCodeActionProvider , LifecyclePhase . Restored ) ;
0 commit comments