44 AutoCompleteNode ,
55 AutoCompleteTree ,
66 ConstantWord ,
7+ Token ,
78 WordCompletion ,
89} from "../constraintMenu/AutoCompletion" ;
910import { SModelElementImpl , SModelRootImpl , SParentElementImpl , SPortImpl } from "sprotty" ;
@@ -76,7 +77,7 @@ export const assignemntLanguageMonarchDefinition: monaco.languages.IMonarchLangu
7677} ;
7778
7879interface ReplaceableAbstractWord extends AbstractWord {
79- replaceWord : ( text : string , old : string , replacement : string ) => string ;
80+ replaceWord ( text : string , old : string , replacement : string ) : string ;
8081}
8182
8283type WordOrReplacableWord = ReplaceableAbstractWord | AbstractWord ;
@@ -85,6 +86,60 @@ export class ReplaceAutoCompleteTree extends AutoCompleteTree {
8586 constructor ( protected roots : AutoCompleteNode < WordOrReplacableWord > [ ] ) {
8687 super ( roots ) ;
8788 }
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+ }
88143}
89144
90145export namespace TreeBuilder {
@@ -277,7 +332,11 @@ class LabelListWord implements ReplaceableAbstractWord {
277332 completionOptions ( word : string ) : WordCompletion [ ] {
278333 const parts = word . split ( "," ) ;
279334 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+ } ) ) ;
281340 }
282341
283342 verifyWord ( word : string ) : string [ ] {
@@ -298,7 +357,8 @@ class LabelListWord implements ReplaceableAbstractWord {
298357
299358class InputWord extends InputAwareWord implements ReplaceableAbstractWord {
300359 completionOptions ( ) : WordCompletion [ ] {
301- return this . getAvailableInputs ( ) . map ( ( input ) => ( {
360+ const inputs = this . getAvailableInputs ( ) ;
361+ return inputs . map ( ( input ) => ( {
302362 insertText : input ,
303363 kind : monaco . languages . CompletionItemKind . Variable ,
304364 } ) ) ;
@@ -313,9 +373,8 @@ class InputWord extends InputAwareWord implements ReplaceableAbstractWord {
313373 }
314374
315375 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 ;
319378 }
320379 return text ;
321380 }
0 commit comments