@@ -12,71 +12,74 @@ interface bracketMapType {
12
12
[ k : string ] : string
13
13
}
14
14
15
- const bracketMap : bracketMapType = {
15
+ const quotes = [ "'" , '"' , '`' ]
16
+ const parenthesis = [ '(' , '[' , '{' , ')' , ']' , '}' , '<' , '>' ]
17
+
18
+ const closeToOpen : bracketMapType = {
16
19
')' : '(' ,
17
20
']' : '[' ,
18
21
'}' : '{' ,
22
+ '>' : '<' ,
19
23
}
20
24
21
- export const calculateBracketsLevel = ( code : string , isRightContext : boolean = false ) => {
22
- const bracketCounts : Map < string , number > = new Map ( [
23
- [ '(' , 0 ] ,
24
- [ '[' , 0 ] ,
25
- [ '{' , 0 ] ,
26
- ] )
27
- const bracketsIndexLevel = [ ]
28
-
29
- for ( let i = 0 ; i < code . length ; i ++ ) {
30
- const char = code [ i ]
31
- if ( bracketCounts . has ( char ) ) {
32
- const count = bracketCounts . get ( char ) || 0
33
- const newCount = count + 1
34
- bracketCounts . set ( char , newCount )
35
- bracketsIndexLevel . push ( {
36
- char,
37
- count : newCount ,
38
- idx : i ,
39
- } )
40
- } else if ( char in bracketMap ) {
41
- const correspondingBracket = bracketMap [ char as keyof bracketMapType ]
42
- const count = bracketCounts . get ( correspondingBracket ) || 0
43
- const newCount = count === 0 ? 0 : count - 1
44
- bracketCounts . set ( bracketMap [ char ] , newCount )
45
- bracketsIndexLevel . push ( {
46
- char : correspondingBracket ,
47
- count : newCount ,
48
- idx : i ,
49
- } )
50
- } else if ( isRightContext && ! ( char in bracketMap ) && ! bracketCounts . has ( char ) && ! / \s / . test ( char ) ) {
51
- // we can stop processing right context when we encounter a char that is not a bracket nor white space
52
- break
53
- }
54
- }
55
- return bracketsIndexLevel
25
+ const openToClose : bracketMapType = {
26
+ '(' : ')' ,
27
+ '[' : ']' ,
28
+ '{' : '}' ,
29
+ '<' : '>' ,
56
30
}
57
31
58
- export const getBracketsToRemove = ( recommendation : string , rightContext : string ) => {
59
- const recommendationBrackets = calculateBracketsLevel ( recommendation )
60
- const rightContextBrackets = calculateBracketsLevel ( rightContext , true )
61
- let i = 0
62
- let j = 0
63
- const toBeRemoved = [ ]
32
+ /**
33
+ * @param endPosition: end position of the recommendation
34
+ * @param startPosition: start position of the recommendation
35
+ */
36
+ export async function handleExtraBrackets (
37
+ editor : vscode . TextEditor ,
38
+ recommendation : string ,
39
+ endPosition : vscode . Position ,
40
+ startPosition : vscode . Position
41
+ ) {
42
+ const endOffset = editor . document . offsetAt ( endPosition )
43
+ const startOffset = editor . document . offsetAt ( startPosition )
44
+ const leftContext = editor . document . getText (
45
+ new vscode . Range (
46
+ startPosition ,
47
+ editor . document . positionAt ( Math . max ( startOffset - CodeWhispererConstants . charactersLimit , 0 ) )
48
+ )
49
+ )
64
50
65
- while ( i < recommendationBrackets . length && j < rightContextBrackets . length ) {
66
- const { char : char1 , count : level1 } = recommendationBrackets [ i ]
67
- const { char : char2 , count : level2 , idx : idx2 } = rightContextBrackets [ j ]
68
- if ( char1 !== char2 || level1 !== level2 ) {
69
- i ++
70
- continue
71
- }
72
- toBeRemoved . push ( idx2 )
73
- i ++
74
- j ++
51
+ const rightContext = editor . document . getText (
52
+ new vscode . Range (
53
+ editor . document . positionAt ( endOffset ) ,
54
+ editor . document . positionAt ( endOffset + CodeWhispererConstants . charactersLimit )
55
+ )
56
+ )
57
+ const bracketsToRemove = getBracketsToRemove (
58
+ editor ,
59
+ recommendation ,
60
+ leftContext ,
61
+ rightContext ,
62
+ endPosition ,
63
+ startPosition
64
+ )
65
+
66
+ const quotesToRemove = getQuotesToRemove (
67
+ editor ,
68
+ recommendation ,
69
+ leftContext ,
70
+ rightContext ,
71
+ endPosition ,
72
+ startPosition
73
+ )
74
+
75
+ const symbolsToRemove = [ ...bracketsToRemove , ...quotesToRemove ]
76
+
77
+ if ( symbolsToRemove . length ) {
78
+ await removeBracketsFromRightContext ( editor , symbolsToRemove , endPosition )
75
79
}
76
- return toBeRemoved
77
80
}
78
81
79
- export const removeBracketsFromRightContext = async (
82
+ const removeBracketsFromRightContext = async (
80
83
editor : vscode . TextEditor ,
81
84
idxToRemove : number [ ] ,
82
85
endPosition : vscode . Position
@@ -110,20 +113,154 @@ export const removeBracketsFromRightContext = async (
110
113
}
111
114
}
112
115
113
- export async function handleExtraBrackets (
116
+ function getBracketsToRemove (
114
117
editor : vscode . TextEditor ,
115
118
recommendation : string ,
116
- endPosition : vscode . Position
119
+ leftContext : string ,
120
+ rightContext : string ,
121
+ end : vscode . Position ,
122
+ start : vscode . Position
117
123
) {
118
- const end = editor . document . offsetAt ( endPosition )
119
- const rightContext = editor . document . getText (
120
- new vscode . Range (
121
- editor . document . positionAt ( end ) ,
122
- editor . document . positionAt ( end + CodeWhispererConstants . charactersLimit )
123
- )
124
- )
125
- const bracketsToRemove = getBracketsToRemove ( recommendation , rightContext )
126
- if ( bracketsToRemove . length ) {
127
- await removeBracketsFromRightContext ( editor , bracketsToRemove , endPosition )
124
+ const unpairedClosingsInReco = nonClosedClosingParen ( recommendation )
125
+ const unpairedOpeningsInLeftContext = nonClosedOpneingParen ( leftContext , unpairedClosingsInReco . length )
126
+ const unpairedClosingsInRightContext = nonClosedClosingParen ( rightContext )
127
+
128
+ const toRemove : number [ ] = [ ]
129
+
130
+ let i = 0
131
+ let j = 0
132
+ let k = 0
133
+ while ( i < unpairedOpeningsInLeftContext . length && j < unpairedClosingsInReco . length ) {
134
+ const opening = unpairedOpeningsInLeftContext [ i ]
135
+ const closing = unpairedClosingsInReco [ j ]
136
+
137
+ const isPaired = closeToOpen [ closing . char ] === opening . char
138
+ const rightContextCharToDelete = unpairedClosingsInRightContext [ k ]
139
+
140
+ if ( isPaired ) {
141
+ if ( rightContextCharToDelete && rightContextCharToDelete . char === closing . char ) {
142
+ const rightContextStart = editor . document . offsetAt ( end ) + 1
143
+ const symbolPosition = editor . document . positionAt (
144
+ rightContextStart + rightContextCharToDelete . strOffset
145
+ )
146
+ const lineCnt = recommendation . split ( '\n' ) . length - 1
147
+ const isSameline = symbolPosition . line - lineCnt === start . line
148
+
149
+ if ( isSameline ) {
150
+ toRemove . push ( rightContextCharToDelete . strOffset )
151
+ }
152
+
153
+ k ++
154
+ }
155
+ }
156
+
157
+ i ++
158
+ j ++
159
+ }
160
+
161
+ return toRemove
162
+ }
163
+
164
+ function getQuotesToRemove (
165
+ editor : vscode . TextEditor ,
166
+ recommendation : string ,
167
+ leftContext : string ,
168
+ rightContext : string ,
169
+ endPosition : vscode . Position ,
170
+ startPosition : vscode . Position
171
+ ) {
172
+ let leftQuote : string | undefined = undefined
173
+ let leftIndex : number | undefined = undefined
174
+ for ( let i = leftContext . length - 1 ; i >= 0 ; i -- ) {
175
+ const char = leftContext [ i ]
176
+ if ( quotes . includes ( char ) ) {
177
+ leftQuote = char
178
+ leftIndex = leftContext . length - i
179
+ break
180
+ }
181
+ }
182
+
183
+ let rightQuote : string | undefined = undefined
184
+ let rightIndex : number | undefined = undefined
185
+ for ( let i = 0 ; i < rightContext . length ; i ++ ) {
186
+ const char = rightContext [ i ]
187
+ if ( quotes . includes ( char ) ) {
188
+ rightQuote = char
189
+ rightIndex = i
190
+ break
191
+ }
192
+ }
193
+
194
+ let quoteCountInReco = 0
195
+ if ( leftQuote && rightQuote && leftQuote === rightQuote ) {
196
+ for ( const char of recommendation ) {
197
+ if ( quotes . includes ( char ) && char === leftQuote ) {
198
+ quoteCountInReco ++
199
+ }
200
+ }
201
+ }
202
+
203
+ if ( leftIndex !== undefined && rightIndex !== undefined && quoteCountInReco % 2 !== 0 ) {
204
+ const p = editor . document . positionAt ( editor . document . offsetAt ( endPosition ) + rightIndex )
205
+
206
+ if ( endPosition . line === startPosition . line && endPosition . line === p . line ) {
207
+ return [ rightIndex ]
208
+ }
209
+ }
210
+
211
+ return [ ]
212
+ }
213
+
214
+ function nonClosedOpneingParen ( str : string , cnt ?: number ) : { char : string ; strOffset : number } [ ] {
215
+ const resultSet : { char : string ; strOffset : number } [ ] = [ ]
216
+ const stack : string [ ] = [ ]
217
+
218
+ for ( let i = str . length - 1 ; i >= 0 ; i -- ) {
219
+ const char = str [ i ]
220
+ if ( char ! in parenthesis ) {
221
+ continue
222
+ }
223
+
224
+ if ( char in closeToOpen ) {
225
+ stack . push ( char )
226
+ if ( cnt && cnt === resultSet . length ) {
227
+ return resultSet
228
+ }
229
+ } else if ( char in openToClose ) {
230
+ if ( stack . length !== 0 && stack [ stack . length - 1 ] === openToClose [ char ] ) {
231
+ stack . pop ( )
232
+ } else {
233
+ resultSet . push ( { char : char , strOffset : i } )
234
+ }
235
+ }
128
236
}
237
+
238
+ return resultSet
239
+ }
240
+
241
+ function nonClosedClosingParen ( str : string , cnt ?: number ) : { char : string ; strOffset : number } [ ] {
242
+ const resultSet : { char : string ; strOffset : number } [ ] = [ ]
243
+ const stack : string [ ] = [ ]
244
+
245
+ for ( let i = 0 ; i < str . length ; i ++ ) {
246
+ const char = str [ i ]
247
+ if ( char ! in parenthesis ) {
248
+ continue
249
+ }
250
+
251
+ if ( char in openToClose ) {
252
+ stack . push ( char )
253
+ if ( cnt && cnt === resultSet . length ) {
254
+ return resultSet
255
+ }
256
+ } else if ( char in closeToOpen ) {
257
+ if ( stack . length !== 0 && stack [ stack . length - 1 ] === closeToOpen [ char ] ) {
258
+ stack . pop ( )
259
+ } else {
260
+ resultSet . push ( { char : char , strOffset : i } )
261
+ }
262
+ }
263
+ }
264
+
265
+ return resultSet
129
266
}
0 commit comments