@@ -14,159 +14,146 @@ 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' ;
17
- import { CancellationToken } from 'vs/base/common/cancellation' ;
18
- import { Disposable } from 'vs/base/common/lifecycle' ;
17
+ import { IDisposable } from 'vs/base/common/lifecycle' ;
19
18
import { ITextModel } from 'vs/editor/common/model' ;
20
- import { CodeAction , CodeActionProvider , CodeActionContext , CodeActionList } from 'vs/editor/common/languages' ;
19
+ import { CodeAction , CodeActionProvider , CodeActionList } from 'vs/editor/common/languages' ;
21
20
import { CodeActionKind } from 'vs/editor/contrib/codeAction/browser/types' ;
22
21
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures' ;
23
22
import { Range , IRange } from 'vs/editor/common/core/range' ;
24
- import { URI } from 'vs/base/common/uri' ;
25
23
import { Selection } from 'vs/editor/common/core/selection' ;
26
24
import { Snippet } from 'vs/workbench/contrib/snippets/browser/snippetsFile' ;
27
25
import { Registry } from 'vs/platform/registry/common/platform' ;
28
26
import { IWorkbenchContributionsRegistry , Extensions as WorkbenchExtensions , IWorkbenchContribution } from 'vs/workbench/common/contributions' ;
29
27
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle' ;
30
28
import { Position } from 'vs/editor/common/core/position' ;
31
- import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
32
- import { EditorInputCapabilities } from 'vs/workbench/common/editor' ;
33
-
34
- const options = {
35
- id : 'editor.action.surroundWithSnippet' ,
36
- title : {
37
- value : localize ( 'label' , 'Surround With Snippet...' ) ,
38
- original : 'Surround With Snippet...'
39
- } ,
40
- precondition : ContextKeyExpr . and (
41
- EditorContextKeys . writable ,
42
- EditorContextKeys . hasNonEmptySelection
43
- ) ,
44
- f1 : true ,
45
- } ;
46
-
47
- const MAX_SNIPPETS_ON_CODE_ACTIONS_MENU = 6 ;
48
-
49
- function makeCodeActionForSnippet ( snippet : Snippet , resource : URI , range : IRange ) : CodeAction {
50
- const title = localize ( 'codeAction' , "Surround With Snippet: {0}" , snippet . name ) ;
51
- return {
52
- title,
53
- edit : {
54
- edits : [
55
- {
56
- versionId : undefined ,
57
- resource : resource ,
58
- textEdit : {
59
- insertAsSnippet : true ,
60
- text : snippet . body ,
61
- range : range
62
- }
63
- }
64
- ]
65
- }
66
- } ;
67
- }
68
-
69
- async function getSurroundableSnippets ( accessor : ServicesAccessor , model : ITextModel | null , position : Position | null ) : Promise < Snippet [ ] > {
70
- if ( ! model ) {
71
- return [ ] ;
72
- }
73
29
74
- const snippetsService = accessor . get ( ISnippetsService ) ;
30
+ async function getSurroundableSnippets ( snippetsService : ISnippetsService , model : ITextModel , position : Position ) : Promise < Snippet [ ] > {
75
31
76
- let languageId : string ;
77
- if ( position ) {
78
- const { lineNumber, column } = position ;
79
- model . tokenization . tokenizeIfCheap ( lineNumber ) ;
80
- languageId = model . getLanguageIdAtPosition ( lineNumber , column ) ;
81
- } else {
82
- languageId = model . getLanguageId ( ) ;
83
- }
32
+ const { lineNumber, column } = position ;
33
+ model . tokenization . tokenizeIfCheap ( lineNumber ) ;
34
+ const languageId = model . getLanguageIdAtPosition ( lineNumber , column ) ;
84
35
85
36
const allSnippets = await snippetsService . getSnippets ( languageId , { includeNoPrefixSnippets : true , includeDisabledSnippets : true } ) ;
86
37
return allSnippets . filter ( snippet => snippet . usesSelection ) ;
87
38
}
88
39
89
- function canExecute ( accessor : ServicesAccessor ) : boolean {
90
- const editorService = accessor . get ( IEditorService ) ;
40
+ class SurroundWithSnippetEditorAction extends EditorAction2 {
91
41
92
- const editor = editorService . activeEditor ;
93
- if ( ! editor || editor . hasCapability ( EditorInputCapabilities . Readonly ) ) {
94
- return false ;
42
+ static readonly options = {
43
+ id : 'editor.action.surroundWithSnippet' ,
44
+ title : {
45
+ value : localize ( 'label' , 'Surround With Snippet...' ) ,
46
+ original : 'Surround With Snippet...'
47
+ }
48
+ } ;
49
+
50
+ constructor ( ) {
51
+ super ( {
52
+ ...SurroundWithSnippetEditorAction . options ,
53
+ precondition : ContextKeyExpr . and (
54
+ EditorContextKeys . writable ,
55
+ EditorContextKeys . hasNonEmptySelection
56
+ ) ,
57
+ f1 : true ,
58
+ } ) ;
95
59
}
96
- const selections = editorService . activeTextEditorControl ?. getSelections ( ) ;
97
- return ! ! selections && selections . length > 0 ;
98
- }
99
60
100
- async function surroundWithSnippet ( accessor : ServicesAccessor , editor : ICodeEditor ) {
101
- const instaService = accessor . get ( IInstantiationService ) ;
102
- const clipboardService = accessor . get ( IClipboardService ) ;
61
+ async runEditorCommand ( accessor : ServicesAccessor , editor : ICodeEditor ) {
62
+ if ( ! editor . hasModel ( ) ) {
63
+ return ;
64
+ }
103
65
104
- if ( ! canExecute ( accessor ) ) {
105
- return ;
106
- }
66
+ const instaService = accessor . get ( IInstantiationService ) ;
67
+ const snippetsService = accessor . get ( ISnippetsService ) ;
68
+ const clipboardService = accessor . get ( IClipboardService ) ;
107
69
108
- const snippets = await getSurroundableSnippets ( accessor , editor . getModel ( ) , editor . getPosition ( ) ) ;
109
- if ( ! snippets . length ) {
110
- return ;
111
- }
70
+ const snippets = await getSurroundableSnippets ( snippetsService , editor . getModel ( ) , editor . getPosition ( ) ) ;
71
+ if ( ! snippets . length ) {
72
+ return ;
73
+ }
112
74
113
- const snippet = await instaService . invokeFunction ( pickSnippet , snippets ) ;
114
- if ( ! snippet ) {
115
- return ;
116
- }
75
+ const snippet = await instaService . invokeFunction ( pickSnippet , snippets ) ;
76
+ if ( ! snippet ) {
77
+ return ;
78
+ }
117
79
118
- let clipboardText : string | undefined ;
119
- if ( snippet . needsClipboard ) {
120
- clipboardText = await clipboardService . readText ( ) ;
121
- }
80
+ let clipboardText : string | undefined ;
81
+ if ( snippet . needsClipboard ) {
82
+ clipboardText = await clipboardService . readText ( ) ;
83
+ }
122
84
123
- SnippetController2 . get ( editor ) ?. insert ( snippet . codeSnippet , { clipboardText } ) ;
85
+ SnippetController2 . get ( editor ) ?. insert ( snippet . codeSnippet , { clipboardText } ) ;
86
+ }
124
87
}
125
88
126
89
127
- registerAction2 ( class SurroundWithSnippetEditorAction extends EditorAction2 {
128
- constructor ( ) {
129
- super ( options ) ;
130
- }
131
- async runEditorCommand ( accessor : ServicesAccessor , editor : ICodeEditor , ...args : any [ ] ) {
132
- await surroundWithSnippet ( accessor , editor ) ;
133
- }
134
- } ) ;
90
+ class SurroundWithSnippetCodeActionProvider implements CodeActionProvider , IWorkbenchContribution {
91
+
92
+ private static readonly _MAX_CODE_ACTIONS = 4 ;
135
93
136
- export class SurroundWithSnippetCodeActionProvider extends Disposable implements CodeActionProvider , IWorkbenchContribution {
137
- private static readonly overflowCodeAction : CodeAction = {
94
+ private static readonly _overflowCommandCodeAction : CodeAction = {
138
95
kind : CodeActionKind . Refactor . value ,
139
- title : options . title . value ,
96
+ title : SurroundWithSnippetEditorAction . options . title . value ,
140
97
command : {
141
- id : options . id ,
142
- title : options . title . value ,
98
+ id : SurroundWithSnippetEditorAction . options . id ,
99
+ title : SurroundWithSnippetEditorAction . options . title . value ,
143
100
} ,
144
101
} ;
145
102
103
+ private readonly _registration : IDisposable ;
104
+
146
105
constructor (
106
+ @ISnippetsService private readonly _snippetService : ISnippetsService ,
147
107
@ILanguageFeaturesService languageFeaturesService : ILanguageFeaturesService ,
148
- @IInstantiationService private readonly instaService : IInstantiationService ,
149
108
) {
150
- super ( ) ;
151
- this . _register ( languageFeaturesService . codeActionProvider . register ( '*' , this ) ) ;
109
+ this . _registration = languageFeaturesService . codeActionProvider . register ( '*' , this ) ;
152
110
}
153
111
154
- async provideCodeActions ( model : ITextModel , range : Range | Selection , context : CodeActionContext , token : CancellationToken ) : Promise < CodeActionList > {
155
- if ( ! this . instaService . invokeFunction ( canExecute ) ) {
156
- return { actions : [ ] , dispose : ( ) => { } } ;
157
- }
112
+ dispose ( ) : void {
113
+ this . _registration . dispose ( ) ;
114
+ }
158
115
159
- const snippets = await this . instaService . invokeFunction ( accessor => getSurroundableSnippets ( accessor , model , range . getEndPosition ( ) ) ) ;
116
+ async provideCodeActions ( model : ITextModel , range : Range | Selection ) : Promise < CodeActionList | undefined > {
117
+
118
+ const snippets = await getSurroundableSnippets ( this . _snippetService , model , range . getEndPosition ( ) ) ;
160
119
if ( ! snippets . length ) {
161
- return { actions : [ ] , dispose : ( ) => { } } ;
120
+ return undefined ;
121
+ }
122
+
123
+ const actions : CodeAction [ ] = [ ] ;
124
+ const hasMore = snippets . length > SurroundWithSnippetCodeActionProvider . _MAX_CODE_ACTIONS ;
125
+ const len = Math . min ( snippets . length , SurroundWithSnippetCodeActionProvider . _MAX_CODE_ACTIONS ) ;
126
+
127
+ for ( let i = 0 ; i < len ; i ++ ) {
128
+ actions . push ( this . _makeCodeActionForSnippet ( snippets [ i ] , model , range ) ) ;
129
+ }
130
+ if ( hasMore ) {
131
+ actions . push ( SurroundWithSnippetCodeActionProvider . _overflowCommandCodeAction ) ;
162
132
}
163
133
return {
164
- actions : snippets . length <= MAX_SNIPPETS_ON_CODE_ACTIONS_MENU
165
- ? snippets . map ( x => makeCodeActionForSnippet ( x , model . uri , range ) )
166
- : [ SurroundWithSnippetCodeActionProvider . overflowCodeAction ] ,
167
- dispose : ( ) => { }
134
+ actions,
135
+ dispose ( ) { }
136
+ } ;
137
+ }
138
+
139
+ private _makeCodeActionForSnippet ( snippet : Snippet , model : ITextModel , range : IRange ) : CodeAction {
140
+ return {
141
+ title : localize ( 'codeAction' , "Surround With: {0}" , snippet . name ) ,
142
+ kind : CodeActionKind . Refactor . value ,
143
+ edit : {
144
+ edits : [ {
145
+ versionId : model . getVersionId ( ) ,
146
+ resource : model . uri ,
147
+ textEdit : {
148
+ range,
149
+ text : snippet . body ,
150
+ insertAsSnippet : true ,
151
+ }
152
+ } ]
153
+ }
168
154
} ;
169
155
}
170
156
}
171
157
158
+ registerAction2 ( SurroundWithSnippetEditorAction ) ;
172
159
Registry . as < IWorkbenchContributionsRegistry > ( WorkbenchExtensions . Workbench ) . registerWorkbenchContribution ( SurroundWithSnippetCodeActionProvider , LifecyclePhase . Restored ) ;
0 commit comments