4
4
AutoCompleteNode ,
5
5
AutoCompleteTree ,
6
6
ConstantWord ,
7
+ Token ,
7
8
WordCompletion ,
8
9
} from "../constraintMenu/AutoCompletion" ;
9
10
import { SModelElementImpl , SModelRootImpl , SParentElementImpl , SPortImpl } from "sprotty" ;
@@ -76,7 +77,7 @@ export const assignemntLanguageMonarchDefinition: monaco.languages.IMonarchLangu
76
77
} ;
77
78
78
79
interface ReplaceableAbstractWord extends AbstractWord {
79
- replaceWord : ( text : string , old : string , replacement : string ) => string ;
80
+ replaceWord ( text : string , old : string , replacement : string ) : string ;
80
81
}
81
82
82
83
type WordOrReplacableWord = ReplaceableAbstractWord | AbstractWord ;
@@ -85,6 +86,60 @@ export class ReplaceAutoCompleteTree extends AutoCompleteTree {
85
86
constructor ( protected roots : AutoCompleteNode < WordOrReplacableWord > [ ] ) {
86
87
super ( roots ) ;
87
88
}
89
+
90
+ public replace ( lines : string [ ] , old : string , replacement : string ) : string [ ] {
91
+ const tokens = this . tokenize ( lines ) ;
92
+ const replaced = this . replaceToken ( this . roots , tokens , 0 , old , replacement ) ;
93
+ const newLines : string [ ] = [ ] ;
94
+ let currentLine = "" ;
95
+ for ( let i = 0 ; i < tokens . length ; i ++ ) {
96
+ const token = tokens [ i ] ;
97
+ const newText = replaced [ i ] ;
98
+ currentLine += newText ;
99
+ currentLine += token . whiteSpaceAfter || "" ;
100
+ if ( i == tokens . length - 1 || tokens [ i + 1 ] . line !== token . line ) {
101
+ newLines . push ( currentLine ) ;
102
+ currentLine = "" ;
103
+ }
104
+ }
105
+ return newLines ;
106
+ }
107
+
108
+ private replaceToken (
109
+ nodes : AutoCompleteNode < WordOrReplacableWord > [ ] ,
110
+ tokens : Token [ ] ,
111
+ index : number ,
112
+ old : string ,
113
+ replacement : string ,
114
+ skipStartCheck = false ,
115
+ ) : string [ ] {
116
+ if ( index >= tokens . length ) {
117
+ return [ ] ;
118
+ }
119
+ // check for new start
120
+ if ( ! skipStartCheck && tokens [ index ] . column == 1 ) {
121
+ const matchesAnyRoot = this . roots . some ( ( n ) => n . word . verifyWord ( tokens [ index ] . text ) . length === 0 ) ;
122
+ if ( matchesAnyRoot ) {
123
+ return this . replaceToken ( this . roots , tokens , index , old , replacement , true ) ;
124
+ }
125
+ }
126
+ let text = tokens [ index ] . text ;
127
+ for ( const n of nodes ) {
128
+ if ( ( n . word as ReplaceableAbstractWord ) . replaceWord ) {
129
+ text = ( n . word as ReplaceableAbstractWord ) . replaceWord ( text , old , replacement ) ;
130
+ }
131
+ }
132
+ return [
133
+ text ,
134
+ ...this . replaceToken (
135
+ nodes . flatMap ( ( n ) => n . children ) ,
136
+ tokens ,
137
+ index + 1 ,
138
+ old ,
139
+ replacement ,
140
+ ) ,
141
+ ] ;
142
+ }
88
143
}
89
144
90
145
export namespace TreeBuilder {
@@ -277,7 +332,11 @@ class LabelListWord implements ReplaceableAbstractWord {
277
332
completionOptions ( word : string ) : WordCompletion [ ] {
278
333
const parts = word . split ( "," ) ;
279
334
const lastPart = parts [ parts . length - 1 ] ;
280
- return this . labelWord . completionOptions ( lastPart ) ;
335
+ const prefixLength = parts . slice ( 0 , - 1 ) . reduce ( ( acc , part ) => acc + part . length + 1 , 0 ) ; // +1 for the commas
336
+ return this . labelWord . completionOptions ( lastPart ) . map ( ( c ) => ( {
337
+ ...c ,
338
+ startOffset : prefixLength + ( c . startOffset ?? 0 ) ,
339
+ } ) ) ;
281
340
}
282
341
283
342
verifyWord ( word : string ) : string [ ] {
@@ -298,7 +357,8 @@ class LabelListWord implements ReplaceableAbstractWord {
298
357
299
358
class InputWord extends InputAwareWord implements ReplaceableAbstractWord {
300
359
completionOptions ( ) : WordCompletion [ ] {
301
- return this . getAvailableInputs ( ) . map ( ( input ) => ( {
360
+ const inputs = this . getAvailableInputs ( ) ;
361
+ return inputs . map ( ( input ) => ( {
302
362
insertText : input ,
303
363
kind : monaco . languages . CompletionItemKind . Variable ,
304
364
} ) ) ;
@@ -313,9 +373,8 @@ class InputWord extends InputAwareWord implements ReplaceableAbstractWord {
313
373
}
314
374
315
375
replaceWord ( text : string , old : string , replacement : string ) {
316
- const availableInputs = this . getAvailableInputs ( ) ;
317
- if ( availableInputs . includes ( old ) ) {
318
- return text . replace ( old , replacement ) ;
376
+ if ( text == old ) {
377
+ return replacement ;
319
378
}
320
379
return text ;
321
380
}
0 commit comments