1
1
import * as vscode from 'vscode'
2
- import { getActiveRegularEditor } from '@zardoy/vscode-utils'
3
- import { registerExtensionCommand } from 'vscode-framework'
2
+ import { getActiveRegularEditor , rangeToSelection } from '@zardoy/vscode-utils'
3
+ import { getExtensionCommandId , registerExtensionCommand , VSCodeQuickPickItem } from 'vscode-framework'
4
4
import { showQuickPick } from '@zardoy/vscode-utils/build/quickPick'
5
+ import _ from 'lodash'
6
+ import { compact } from '@zardoy/utils'
5
7
import { RequestOptionsTypes , RequestResponseTypes } from '../typescript/src/ipcTypes'
6
8
import { sendCommand } from './sendCommand'
7
- import { tsRangeToVscode } from './util'
9
+ import { tsRangeToVscode , tsRangeToVscodeSelection } from './util'
8
10
9
11
export default ( ) => {
10
12
registerExtensionCommand ( 'removeFunctionArgumentsTypesInSelection' , async ( ) => {
@@ -55,45 +57,51 @@ export default () => {
55
57
editor . selection = new vscode . Selection ( currentValueRange . start , currentValueRange . end )
56
58
} )
57
59
58
- registerExtensionCommand ( 'pickAndInsertFunctionArguments' , async ( ) => {
59
- const editor = getActiveRegularEditor ( )
60
- if ( ! editor ) return
61
- const result = await sendCommand < RequestResponseTypes [ 'pickAndInsertFunctionArguments' ] > ( 'pickAndInsertFunctionArguments' )
62
- if ( ! result ) return
60
+ const nodePicker = async < T > ( data : T [ ] , renderItem : ( item : T ) => Omit < VSCodeQuickPickItem , 'value' > & { nodeRange : [ number , number ] } ) => {
61
+ const editor = vscode . window . activeTextEditor !
63
62
const originalSelections = editor . selections
64
-
65
- const renderArgs = ( args : Array < [ name : string , type : string ] > ) => `${ args . map ( ( [ name , type ] ) => ( type ? `${ name } : ${ type } ` : name ) ) . join ( ', ' ) } `
66
-
67
63
let revealBack = true
68
- const selectedFunction = await showQuickPick (
69
- result . functions . map ( func => {
70
- const [ name , _decl , args ] = func
64
+
65
+ // todo-p1 button to merge nodes with duplicated contents (e.g. same strings)
66
+ const selected = await showQuickPick (
67
+ data . map ( item => {
68
+ const custom = renderItem ( item )
71
69
return {
72
- label : name ,
73
- value : func ,
74
- description : `(${ renderArgs ( args ) } )` ,
70
+ ...custom ,
71
+ value : item ,
75
72
buttons : [
76
73
{
77
74
iconPath : new vscode . ThemeIcon ( 'go-to-file' ) ,
78
75
tooltip : 'Go to declaration' ,
76
+ action : 'goToStartPos' ,
77
+ } ,
78
+ {
79
+ iconPath : new vscode . ThemeIcon ( 'arrow-both' ) ,
80
+ tooltip : 'Add to selection' ,
81
+ action : 'addSelection' ,
79
82
} ,
80
83
] ,
81
84
}
82
85
} ) ,
83
86
{
84
- onDidTriggerItemButton ( event ) {
87
+ title : 'Select node...' ,
88
+ onDidTriggerItemButton ( { item, button } ) {
89
+ const { action } = button as any
90
+ const sel = tsRangeToVscodeSelection ( editor . document , ( item as any ) . nodeRange )
85
91
revealBack = false
86
- this . hide ( )
87
- const pos = editor . document . positionAt ( event . item . value [ 1 ] [ 0 ] )
88
- editor . selection = new vscode . Selection ( pos , pos )
89
- editor . revealRange ( editor . selection , vscode . TextEditorRevealType . InCenterIfOutsideViewport )
92
+ if ( action === 'goToStartPos' ) {
93
+ editor . selection = new vscode . Selection ( sel . start , sel . start )
94
+ editor . revealRange ( editor . selection , vscode . TextEditorRevealType . InCenterIfOutsideViewport )
95
+ this . hide ( )
96
+ } else {
97
+ editor . selections = [ ...editor . selections , sel ]
98
+ }
90
99
} ,
91
100
onDidChangeFirstActive ( item ) {
92
- const pos = editor . document . positionAt ( item . value [ 1 ] [ 0 ] )
101
+ const pos = editor . document . positionAt ( ( item as any ) . nodeRange [ 0 ] )
93
102
editor . selection = new vscode . Selection ( pos , pos )
94
103
editor . revealRange ( editor . selection , vscode . TextEditorRevealType . InCenterIfOutsideViewport )
95
104
} ,
96
- onDidShow ( ) { } ,
97
105
matchOnDescription : true ,
98
106
} ,
99
107
)
@@ -102,6 +110,23 @@ export default () => {
102
110
editor . revealRange ( editor . selection )
103
111
}
104
112
113
+ return selected
114
+ }
115
+
116
+ registerExtensionCommand ( 'pickAndInsertFunctionArguments' , async ( ) => {
117
+ const editor = getActiveRegularEditor ( )
118
+ if ( ! editor ) return
119
+ const result = await sendCommand < RequestResponseTypes [ 'pickAndInsertFunctionArguments' ] > ( 'pickAndInsertFunctionArguments' )
120
+ if ( ! result ) return
121
+
122
+ const renderArgs = ( args : Array < [ name : string , type : string ] > ) => `${ args . map ( ( [ name , type ] ) => ( type ? `${ name } : ${ type } ` : name ) ) . join ( ', ' ) } `
123
+
124
+ const selectedFunction = await nodePicker ( result . functions , ( [ name , decl , args ] ) => ( {
125
+ label : name ,
126
+ description : `(${ renderArgs ( args ) } )` ,
127
+ nodeRange : decl ,
128
+ } ) )
129
+
105
130
if ( ! selectedFunction ) return
106
131
const selectedArgs = await showQuickPick (
107
132
selectedFunction [ 2 ] . map ( arg => {
@@ -130,4 +155,64 @@ export default () => {
130
155
}
131
156
} )
132
157
} )
158
+
159
+ registerExtensionCommand ( 'goToNodeBySyntaxKind' , async ( _arg , { filterWithSelection = false } : { filterWithSelection ?: boolean } = { } ) => {
160
+ const editor = vscode . window . activeTextEditor
161
+ if ( ! editor ) return
162
+ const { document } = editor
163
+ const result = await sendCommand < RequestResponseTypes [ 'filterBySyntaxKind' ] > ( 'filterBySyntaxKind' )
164
+ if ( ! result ) return
165
+ // todo optimize
166
+ if ( filterWithSelection ) {
167
+ result . nodesByKind = Object . fromEntries (
168
+ compact (
169
+ Object . entries ( result . nodesByKind ) . map ( ( [ kind , nodes ] ) => {
170
+ const filteredNodes = nodes . filter ( ( { range : tsRange } ) =>
171
+ editor . selections . some ( sel => sel . contains ( tsRangeToVscode ( document , tsRange ) ) ) ,
172
+ )
173
+ if ( filteredNodes . length === 0 ) return
174
+ return [ kind , filteredNodes ]
175
+ } ) ,
176
+ ) ,
177
+ )
178
+ }
179
+
180
+ const selectedKindNodes = await showQuickPick (
181
+ _ . sortBy ( Object . entries ( result . nodesByKind ) , ( [ , nodes ] ) => nodes . length )
182
+ . reverse ( )
183
+ . map ( ( [ kind , nodes ] ) => ( {
184
+ label : kind ,
185
+ description : nodes . length . toString ( ) ,
186
+ value : nodes ,
187
+ buttons : [
188
+ {
189
+ iconPath : new vscode . ThemeIcon ( 'arrow-both' ) ,
190
+ tooltip : 'Select all nodes of this kind' ,
191
+ } ,
192
+ ] ,
193
+ } ) ) ,
194
+ {
195
+ onDidTriggerItemButton ( button ) {
196
+ editor . selections = button . item . value . map ( ( { range } ) => tsRangeToVscodeSelection ( document , range ) )
197
+ this . hide ( )
198
+ } ,
199
+ } ,
200
+ )
201
+ if ( ! selectedKindNodes ) return
202
+ const selectedNode = await nodePicker ( selectedKindNodes , node => ( {
203
+ label : document
204
+ . getText ( tsRangeToVscode ( document , node . range ) )
205
+ . trim ( )
206
+ . replace ( / \r ? \n \s + / g, ' ' ) ,
207
+ nodeRange : node . range ,
208
+ value : node ,
209
+ } ) )
210
+ if ( ! selectedNode ) return
211
+ editor . selection = tsRangeToVscodeSelection ( document , selectedNode . range )
212
+ editor . revealRange ( editor . selection )
213
+ } )
214
+
215
+ registerExtensionCommand ( 'goToNodeBySyntaxKindWithinSelection' , async ( ) => {
216
+ await vscode . commands . executeCommand ( getExtensionCommandId ( 'goToNodeBySyntaxKind' ) , { filterWithSelection : true } )
217
+ } )
133
218
}
0 commit comments