1
+ import { commands , window , Position , TextEditor , Selection } from 'vscode'
2
+ import ExplorerProvider from './explorer'
3
+
4
+ export default class Assist {
5
+ private explorer : ExplorerProvider
6
+
7
+ constructor ( explorer : ExplorerProvider ) {
8
+ this . explorer = explorer
9
+ }
10
+
11
+ public register ( ) {
12
+ this . explorer . context . subscriptions . push ( commands . registerCommand ( 'vue-helper.blockSelect' , ( ) => {
13
+ this . blockSelect ( )
14
+ } ) )
15
+ }
16
+
17
+ // 代码块选择
18
+ public blockSelect ( ) {
19
+ let editor = window . activeTextEditor ;
20
+ if ( ! editor ) { return ; }
21
+
22
+ let startPosition = editor . selection . start ;
23
+ let lineTextObj = editor . document . lineAt ( startPosition . line ) ;
24
+ let lineText = lineTextObj . text ;
25
+ if ( lineText . length > 0 && startPosition . character === 0 && lineText [ startPosition . character ] === '[' ) {
26
+ this . selectJsBlock ( editor , lineText . substring ( startPosition . character , lineText . length ) , startPosition , 'array' ) ;
27
+ } else if ( lineText . length > 0 && startPosition . character > 0 && lineText [ startPosition . character - 1 ] === '[' ) {
28
+ this . selectJsBlock ( editor , lineText . substring ( startPosition . character - 1 , lineText . length ) , new Position ( startPosition . line , startPosition . character - 1 ) , 'array' ) ;
29
+ } else if ( lineText . length > 0 && startPosition . character < lineText . length && lineText [ startPosition . character ] === '[' ) {
30
+ this . selectJsBlock ( editor , lineText . substring ( startPosition . character , lineText . length ) , startPosition , 'array' ) ;
31
+ } else if ( lineText . length > 0 && startPosition . character === 0 && lineText [ startPosition . character ] === '{' ) {
32
+ this . selectJsBlock ( editor , lineText . substring ( startPosition . character , lineText . length ) , startPosition , 'json' ) ;
33
+ } else if ( lineText . length > 0 && startPosition . character > 0 && lineText [ startPosition . character - 1 ] === '{' ) {
34
+ this . selectJsBlock ( editor , lineText . substring ( startPosition . character - 1 , lineText . length ) , new Position ( startPosition . line , startPosition . character - 1 ) , 'json' ) ;
35
+ } else if ( lineText . length > 0 && startPosition . character < lineText . length && lineText [ startPosition . character ] === '{' ) {
36
+ this . selectJsBlock ( editor , lineText . substring ( startPosition . character , lineText . length ) , startPosition , 'json' ) ;
37
+ } else if ( lineText . trim ( ) . length > 0 && lineText . trim ( ) [ 0 ] === '<' && startPosition . character <= lineText . indexOf ( '<' ) ) {
38
+ lineText = lineText . substring ( startPosition . character , lineText . length ) ;
39
+ this . selectHtmlBlock ( editor , lineText , startPosition ) ;
40
+ } else if ( lineText . trim ( ) . length > 0 && lineText . trim ( ) [ 0 ] === '<' && startPosition . character <= lineText . indexOf ( '<' ) ) {
41
+ lineText = lineText . substring ( startPosition . character , lineText . length ) ;
42
+ this . selectHtmlBlock ( editor , lineText , startPosition ) ;
43
+ } else if ( / ^ \s * [ \s a - z A - Z : _ - ] * \s * \[ \s * $ / gi. test ( lineText ) ) {
44
+ this . selectJsBlock ( editor , lineText , new Position ( startPosition . line , lineText . length - lineText . replace ( / \s * / , '' ) . length ) , 'array' ) ;
45
+ } else if ( ( lineText . trim ( ) . length > 0 && / ( f u n c t i o n | i f | f o r | w h i l e ) ? .+ \( .* \) \s * { / gi. test ( lineText ) && / ^ \s * ( f u n c t i o n | i f | f o r | w h i l e ) ? \s * $ / g. test ( lineText . substr ( 0 , startPosition . character ) ) )
46
+ || ( / ^ ( \s * [ \s a - z A - Z _ - ] * \( [ \s a - z A - Z _ - ] * \) \s * { \s * ) | ( \s * [ \s a - z A - Z : _ - ] * \s * { \s * ) $ / gi. test ( lineText ) ) && / ^ \s * ( f u n c t i o n | i f | f o r | w h i l e ) ? \s * $ / g. test ( lineText . substr ( 0 , startPosition . character ) ) ) {
47
+ this . selectJsBlock ( editor , lineText , new Position ( startPosition . line , lineText . length - lineText . replace ( / \s * / , '' ) . length ) , 'function' ) ;
48
+ } else {
49
+ // 在本行选择
50
+ this . selectLineBlock ( editor , lineText , startPosition ) ;
51
+ }
52
+ return ;
53
+ }
54
+
55
+ // 选择函数块
56
+ selectJsBlock ( editor : any , lineText : string , startPosition : Position , type : string ) {
57
+ let lineCount = editor . document . lineCount ;
58
+ let lineCurrent = startPosition . line ;
59
+ let braceLeftCount = 0 ;
60
+ let tagLeft = '{' ;
61
+ let tagRight = '}' ;
62
+ if ( type === 'array' ) {
63
+ tagLeft = '[' ;
64
+ tagRight = ']' ;
65
+ }
66
+ while ( lineCurrent <= lineCount ) {
67
+ let pos : number = 0 ;
68
+ while ( ( lineText . indexOf ( tagLeft , pos ) !== - 1 || lineText . indexOf ( tagRight , pos ) !== - 1 ) && pos < lineText . length ) {
69
+ let i = - 1 ;
70
+ // 左标签
71
+ if ( lineText . indexOf ( tagLeft , pos ) !== - 1 ) {
72
+ i = lineText . indexOf ( tagLeft , pos ) ;
73
+ }
74
+ // 右标签
75
+ if ( lineText . indexOf ( tagRight , pos ) !== - 1 ) {
76
+ if ( i === - 1 || i > lineText . indexOf ( tagRight , pos ) ) {
77
+ // 左标签不存在、左右标签都存在,右标签在前
78
+ -- braceLeftCount ;
79
+ pos = lineText . indexOf ( tagRight , pos ) + 1 ;
80
+ } else {
81
+ ++ braceLeftCount ;
82
+ pos = i + 1 ;
83
+ }
84
+ } else {
85
+ // 存在左标签
86
+ if ( i !== - 1 ) {
87
+ ++ braceLeftCount ;
88
+ pos = i + 1 ;
89
+ }
90
+ }
91
+ if ( braceLeftCount === 0 ) {
92
+ break ;
93
+ }
94
+ }
95
+
96
+ if ( braceLeftCount === 0 ) {
97
+ let extra = 0 ;
98
+ let textExtra = editor . document . lineAt ( lineCurrent ) . text ;
99
+ if ( lineCurrent === startPosition . line ) {
100
+ extra = textExtra . indexOf ( lineText ) ;
101
+ }
102
+ if ( type === 'function' && textExtra [ pos + extra - 1 ] === '}' && textExtra [ pos + extra ] === ')' ) {
103
+ extra += 1 ;
104
+ }
105
+ editor . selection = new Selection ( startPosition , new Position ( lineCurrent , pos + extra ) ) ;
106
+ return ;
107
+ }
108
+
109
+ ++ lineCurrent ;
110
+ if ( lineCount >= lineCurrent ) {
111
+ lineText = editor . document . lineAt ( lineCurrent ) . text ;
112
+ }
113
+ }
114
+ return ;
115
+ }
116
+
117
+ // 选择html代码块
118
+ selectHtmlBlock ( editor : any , lineText : string , startPosition : Position ) {
119
+ const ncname = '[a-zA-Z_][\\w\\-\\.]*' ;
120
+ const qnameCapture = '((?:' + ncname + '\\:)?' + ncname + ')' ;
121
+ const startTagOpen = new RegExp ( '^<' + qnameCapture ) ;
122
+ const endTag = new RegExp ( '^(<\\/' + qnameCapture + '[^>]*>)' ) ;
123
+ const comment = / ^ < ! - - / ;
124
+ const commentEnd = '-->' ;
125
+ const lineCount = editor . document . lineCount ;
126
+ let lineCurrent = startPosition . line ;
127
+
128
+ let isNoIncludeTag = false ;
129
+ let tagStack : any = null ;
130
+ let col = lineText . indexOf ( lineText . trim ( ) ) + startPosition . character ;
131
+ let beginPosition = new Position ( startPosition . line , startPosition . character + lineText . length - lineText . replace ( / \s * ( .* ) / , '$1' ) . length ) ;
132
+ lineText = lineText . trim ( ) ;
133
+ let noIncludeTags = [ 'input' , 'img' ] ;
134
+
135
+ while ( lineText ) {
136
+ let textTagPos = lineText . indexOf ( '<' ) ;
137
+ if ( textTagPos === 0 ) {
138
+ let hasEndTag = false ;
139
+ let hasTag = false ;
140
+ if ( comment . test ( lineText ) ) {
141
+ let commentIndex = lineText . indexOf ( commentEnd ) ;
142
+ while ( commentIndex === - 1 && lineCurrent < lineCount ) {
143
+ lineText = editor . document . lineAt ( ++ lineCurrent ) . text ;
144
+ commentIndex = lineText . indexOf ( commentEnd ) ;
145
+ }
146
+ lineText = lineText . substr ( commentIndex + 3 , lineText . length ) ;
147
+ }
148
+ const endTagMatch = lineText . match ( endTag ) ;
149
+ if ( endTagMatch ) {
150
+ hasEndTag = true ;
151
+ if ( Array . isArray ( tagStack ) ) {
152
+ let tagIndex = tagStack . length ;
153
+ if ( tagIndex > 0 ) {
154
+ let isTagMatch = false ;
155
+ while ( tagIndex > 0 && ! isTagMatch ) {
156
+ let tag = tagStack [ tagIndex - 1 ] ;
157
+ if ( tag === endTagMatch [ 2 ] ) {
158
+ isTagMatch = true ;
159
+ }
160
+ tagStack . pop ( ) ;
161
+ -- tagIndex ;
162
+ }
163
+ }
164
+ }
165
+ let endAdvance = lineText . indexOf ( endTagMatch [ 1 ] ) + endTagMatch [ 1 ] . length ;
166
+ col += endAdvance ;
167
+ lineText = lineText . substr ( endAdvance , lineText . length ) ;
168
+ }
169
+
170
+ if ( Array . isArray ( tagStack ) && tagStack . length === 0 ) {
171
+ editor . selection = new Selection ( beginPosition , new Position ( lineCurrent , col ) ) ;
172
+ break ;
173
+ }
174
+
175
+ const startTagMatch = lineText . match ( startTagOpen ) ;
176
+ if ( startTagMatch ) {
177
+ hasTag = true ;
178
+ if ( isNoIncludeTag ) {
179
+ let lineTextCur = editor . document . lineAt ( lineCurrent ) . text ;
180
+ lineText = lineTextCur . substr ( 0 , col ) ;
181
+ let indexLast = lineText . lastIndexOf ( '>' ) ;
182
+ while ( indexLast === - 1 && lineCurrent > 0 ) {
183
+ -- lineCurrent ;
184
+ lineText = editor . document . lineAt ( lineCurrent ) . text ;
185
+ indexLast = lineText . lastIndexOf ( '>' ) ;
186
+ }
187
+ editor . selection = new Selection ( beginPosition , new Position ( lineCurrent , indexLast + 2 ) ) ;
188
+ break ;
189
+ }
190
+ if ( Array . isArray ( tagStack ) ) {
191
+ tagStack . push ( startTagMatch [ 1 ] ) ;
192
+ } else {
193
+ tagStack = [ startTagMatch [ 1 ] ] ;
194
+ if ( noIncludeTags . indexOf ( startTagMatch [ 1 ] ) !== - 1 ) {
195
+ isNoIncludeTag = true ;
196
+ }
197
+ }
198
+ const startAdvance = lineText . indexOf ( startTagMatch [ 1 ] ) + startTagMatch [ 1 ] . length ;
199
+ col += startAdvance ;
200
+ lineText = lineText . substr ( startAdvance , lineText . length ) ;
201
+ }
202
+ if ( lineText . indexOf ( '/>' ) !== - 1 && Array . isArray ( tagStack ) && tagStack . length === 1 ) {
203
+ let tagCloseIndex = lineText . indexOf ( '/>' ) ;
204
+ let prevText = lineText . substr ( 0 , tagCloseIndex + 2 ) ;
205
+ let tagReg = / < ( [ \w - ] + ) ( \s * | ( \s + [ \w - _ : @ \. ] + ( = ( " [ ^ " ] * " | ' [ ^ ' ] * ' ) ) ? ) + ) \s * ( \/ ) ? > / gim;
206
+ if ( ! tagReg . test ( prevText ) ) {
207
+ tagStack . pop ( ) ;
208
+ }
209
+ editor . selection = new Selection ( beginPosition , new Position ( lineCurrent , col + tagCloseIndex + 2 ) ) ;
210
+ break ;
211
+ }
212
+ if ( ! lineText && lineCurrent < lineCount && tagStack . length > 0 ) {
213
+ do {
214
+ ++ lineCurrent ;
215
+ lineText = editor . document . lineAt ( lineCurrent ) . text ;
216
+ } while ( ! lineText && lineCurrent < lineCount ) ;
217
+ col = lineText . indexOf ( lineText . trim ( ) ) ;
218
+ lineText = lineText . trim ( ) ;
219
+ continue ;
220
+ }
221
+ if ( ! hasTag && ! hasEndTag && lineText . length > 0 ) {
222
+ let noTagIndex = lineText . indexOf ( lineText , 1 ) ;
223
+ if ( noTagIndex === - 1 ) {
224
+ if ( lineCurrent < lineCount ) {
225
+ do {
226
+ ++ lineCurrent ;
227
+ lineText = editor . document . lineAt ( lineCurrent ) . text ;
228
+ } while ( ! lineText && lineCurrent < lineCount ) ;
229
+ col = lineText . indexOf ( lineText . trim ( ) ) ;
230
+ lineText = lineText . trim ( ) ;
231
+ } else {
232
+ break ;
233
+ }
234
+ } else {
235
+ lineText = lineText . substr ( noTagIndex , lineText . length ) ;
236
+ }
237
+ }
238
+ } else if ( textTagPos > 0 ) {
239
+ lineText = lineText . substr ( textTagPos , lineText . length ) ;
240
+ col += textTagPos ;
241
+ } else if ( textTagPos < 0 ) {
242
+ if ( lineCurrent < lineCount ) {
243
+ // 一行最前面是否有 />
244
+ if ( lineText . indexOf ( '/>' ) !== - 1 && Array . isArray ( tagStack ) && tagStack . length > 0 ) {
245
+ let tagCloseIndex = lineText . indexOf ( '/>' ) ;
246
+ let prevText = lineText . substr ( 0 , tagCloseIndex + 2 ) ;
247
+ let tagReg = / < ( [ \w - ] + ) ( \s * | ( \s + [ \w - _ : @ \. ] + ( = ( " [ ^ " ] * " | ' [ ^ ' ] * ' ) ) ? ) + ) \s * ( \/ ) ? > / gim;
248
+ if ( ! tagReg . test ( prevText ) ) {
249
+ tagStack . pop ( ) ;
250
+ }
251
+ if ( tagStack . length === 0 ) {
252
+ editor . selection = new Selection ( beginPosition , new Position ( lineCurrent , col + tagCloseIndex + 2 ) ) ;
253
+ break ;
254
+ }
255
+ }
256
+ do {
257
+ ++ lineCurrent ;
258
+ lineText = editor . document . lineAt ( lineCurrent ) . text ;
259
+ if ( lineText . replace ( / \s / gi, '' ) === '' ) {
260
+ lineText = '' ;
261
+ }
262
+ } while ( ! lineText && lineCurrent < lineCount ) ;
263
+ col = lineText . indexOf ( lineText . trim ( ) ) ;
264
+ lineText = lineText . trim ( ) ;
265
+ } else {
266
+ lineText = '' ;
267
+ }
268
+ }
269
+ }
270
+ }
271
+
272
+ selectLineBlock ( editor : TextEditor , lineText : String , startPosition : Position ) {
273
+ // "" '' () {}, >< 空格
274
+ // 1. 遍历左侧查询结束标签
275
+ let TAGS = [ "\"" , "'" , "(" , "{" , "[" , " " , "`" , ">" ] ;
276
+ let TAGS_CLOSE : any = {
277
+ "\"" : "\"" ,
278
+ "'" : "'" ,
279
+ "(" : ")" ,
280
+ "{" : "}" ,
281
+ "[" : "]" ,
282
+ " " : " " ,
283
+ "`" : "`" ,
284
+ ">" : "<"
285
+ } ;
286
+ let pos = startPosition . character - 1 ;
287
+ let endTag = '' ,
288
+ beginPos = 0 ,
289
+ endPos = 0 ,
290
+ inBeginTags : any [ ] = [ ] ,
291
+ includeTags = false ;
292
+ beginPos = pos ;
293
+ while ( pos >= 0 ) {
294
+ if ( TAGS . indexOf ( lineText [ pos ] ) !== - 1 ) {
295
+ endTag = lineText [ pos ] ;
296
+ break ;
297
+ }
298
+ -- pos ;
299
+ }
300
+ if ( beginPos === pos ) {
301
+ includeTags = true ;
302
+ beginPos = pos ;
303
+ } else {
304
+ beginPos = pos + 1 ;
305
+ }
306
+ // 存在结束标签
307
+ if ( endTag . length > 0 ) {
308
+ pos = startPosition . character ;
309
+ if ( endTag === '>' ) {
310
+ while ( pos <= lineText . length && pos >= 0 ) {
311
+ let txt = lineText [ pos ] ;
312
+ if ( ( txt === TAGS_CLOSE [ endTag ] || txt === '>' ) && pos > beginPos ) {
313
+ break ;
314
+ }
315
+ ++ pos ;
316
+ }
317
+ } else {
318
+ while ( pos <= lineText . length && pos >= 0 ) {
319
+ let txt = lineText [ pos ] ;
320
+ if ( inBeginTags . length === 0 && ( txt === TAGS_CLOSE [ endTag ] || txt === '>' ) && pos > beginPos ) {
321
+ break ;
322
+ }
323
+ if ( inBeginTags . length > 0 && TAGS_CLOSE [ inBeginTags [ inBeginTags . length - 1 ] ] === txt ) {
324
+ inBeginTags . pop ( ) ;
325
+ } else if ( TAGS . indexOf ( txt ) !== - 1 && txt !== ' ' ) {
326
+ inBeginTags . push ( txt ) ;
327
+ }
328
+
329
+ ++ pos ;
330
+ }
331
+ }
332
+ }
333
+ includeTags ? ( endPos = pos + 1 ) : ( endPos = pos ) ;
334
+ editor . selection = new Selection ( new Position ( startPosition . line , beginPos ) , new Position ( startPosition . line , endPos ) ) ;
335
+ }
336
+ }
0 commit comments