@@ -7,7 +7,7 @@ import { runForEachEditor } from "../util/targetUtils";
77import type { Actions } from "./Actions" ;
88import type { ActionReturnValue } from "./actions.types" ;
99
10- const REGEX = / - ? \d + ( \. \d + ) ? / g;
10+ const REGEX = / - ? [ \d _ ] + ( \. [ \d _ ] + ) ? / g;
1111
1212class IncrementDecrement {
1313 constructor (
@@ -95,51 +95,102 @@ function updateNumber(isIncrement: boolean, text: string): string {
9595}
9696
9797function updateInteger ( isIncrement : boolean , text : string ) : string {
98- const original = parseInt ( text ) ;
98+ const textWithoutUnderscores = text . replaceAll ( "_" , "" ) ;
99+ const original = parseInt ( textWithoutUnderscores ) ;
99100 const diff = 1 ;
100101 const value = original + ( isIncrement ? diff : - diff ) ;
101- return formatNumber ( value , text ) ;
102+ return formatNumber ( value , text , textWithoutUnderscores ) ;
102103}
103104
104105function updateFloat ( isIncrement : boolean , text : string ) : string {
105- const original = parseFloat ( text ) ;
106+ const textWithoutUnderscores = text . replaceAll ( "_" , "" ) ;
107+ const original = parseFloat ( textWithoutUnderscores ) ;
106108 const isPercentage = Math . abs ( original ) <= 1.0 ;
107109 const diff = isPercentage ? 0.1 : 1 ;
108110 const updated = original + ( isIncrement ? diff : - diff ) ;
109111 // Remove precision problems that would add a lot of extra digits
110112 const value = parseFloat ( updated . toPrecision ( 15 ) ) / 1 ;
111- const decimalPlaces = text . split ( "." ) [ 1 ] ?. length ;
112- return formatNumber ( value , text , decimalPlaces ) ;
113+ const decimalPlaces = textWithoutUnderscores . split ( "." ) [ 1 ] ?. length ;
114+ return formatNumber ( value , text , textWithoutUnderscores , decimalPlaces ) ;
113115}
114116
115117function formatNumber (
116118 value : number ,
117119 text : string ,
120+ textWithoutUnderscores : string ,
118121 decimalPlaces ?: number ,
122+ ) : string {
123+ const result = ( ( ) => {
124+ if ( hasLeadingZeros ( textWithoutUnderscores ) ) {
125+ return formatNumberWithLeadingZeros (
126+ value ,
127+ textWithoutUnderscores ,
128+ decimalPlaces ,
129+ ) ;
130+ }
131+
132+ return decimalPlaces != null
133+ ? value . toFixed ( decimalPlaces )
134+ : value . toString ( ) ;
135+ } ) ( ) ;
136+
137+ return formatNumberWithUnderscores ( text , textWithoutUnderscores , result ) ;
138+ }
139+
140+ function formatNumberWithLeadingZeros (
141+ value : number ,
142+ text : string ,
143+ decimalPlaces : number | undefined ,
119144) : string {
120145 const sign = value < 0 ? "-" : "" ;
121146 const absValue = Math . abs ( value ) ;
147+ const integerPartLength = getIntegerPartLength ( text ) ;
148+ const integerPart = Math . floor ( absValue )
149+ . toString ( )
150+ . padStart ( integerPartLength , "0" ) ;
151+
152+ if ( decimalPlaces != null ) {
153+ const fractionPart = ( absValue - Math . floor ( absValue ) )
154+ . toFixed ( decimalPlaces )
155+ // Remove "0."
156+ . slice ( 2 ) ;
157+ return `${ sign } ${ integerPart } .${ fractionPart } ` ;
158+ }
122159
123- if ( hasLeadingZeros ( text ) ) {
124- const integerPartLength = getIntegerPartLength ( text ) ;
125- const integerPart = Math . floor ( absValue )
126- . toString ( )
127- . padStart ( integerPartLength , "0" ) ;
128-
129- if ( decimalPlaces != null ) {
130- const fractionPart = ( absValue - Math . floor ( absValue ) )
131- . toFixed ( decimalPlaces )
132- // Remove "0."
133- . slice ( 2 ) ;
134- return `${ sign } ${ integerPart } .${ fractionPart } ` ;
135- }
160+ return `${ sign } ${ integerPart } ` ;
161+ }
162+
163+ // Reinsert underscores at original positions
164+ function formatNumberWithUnderscores (
165+ original : string ,
166+ originalWithoutUnderscores : string ,
167+ updated : string ,
168+ ) : string {
169+ const underscoreMatches = Array . from ( original . matchAll ( / _ / g) ) ;
170+
171+ if ( underscoreMatches . length === 0 ) {
172+ return updated ;
173+ }
136174
137- return `${ sign } ${ integerPart } ` ;
175+ let resultWithUnderscores = updated ;
176+ const signOffset =
177+ ( updated [ 0 ] === "-" ? 1 : 0 ) - ( original [ 0 ] === "-" ? 1 : 0 ) ;
178+ const intOffset =
179+ getIntegerPartLength ( updated ) -
180+ getIntegerPartLength ( originalWithoutUnderscores ) ;
181+ const offset = signOffset + intOffset ;
182+
183+ for ( const match of underscoreMatches ) {
184+ const index = match . index + offset ;
185+ if ( index < resultWithUnderscores . length ) {
186+ resultWithUnderscores =
187+ resultWithUnderscores . slice ( 0 , index ) +
188+ "_" +
189+ resultWithUnderscores . slice ( index ) ;
190+ }
138191 }
139192
140- return decimalPlaces != null
141- ? value . toFixed ( decimalPlaces )
142- : value . toString ( ) ;
193+ return resultWithUnderscores ;
143194}
144195
145196function hasLeadingZeros ( text : string ) : boolean {
0 commit comments