@@ -10,7 +10,7 @@ import { findFirstMin } from '../../../../../../../base/common/arraysFind.js';
1010import { DisposableStore , toDisposable } from '../../../../../../../base/common/lifecycle.js' ;
1111import { derived , derivedObservableWithCache , derivedOpts , IObservable , IReader , observableValue , transaction } from '../../../../../../../base/common/observable.js' ;
1212import { OS } from '../../../../../../../base/common/platform.js' ;
13- import { getIndentationLength , splitLines } from '../../../../../../../base/common/strings.js' ;
13+ import { splitLines } from '../../../../../../../base/common/strings.js' ;
1414import { URI } from '../../../../../../../base/common/uri.js' ;
1515import { MenuEntryActionViewItem } from '../../../../../../../platform/actions/browser/menuEntryActionViewItem.js' ;
1616import { ICodeEditor } from '../../../../../../browser/editorBrowser.js' ;
@@ -26,6 +26,8 @@ import { TextReplacement, TextEdit } from '../../../../../../common/core/edits/t
2626import { RangeMapping } from '../../../../../../common/diff/rangeMapping.js' ;
2727import { ITextModel } from '../../../../../../common/model.js' ;
2828import { indentOfLine } from '../../../../../../common/model/textModel.js' ;
29+ import { CharCode } from '../../../../../../../base/common/charCode.js' ;
30+ import { BugIndicatingError } from '../../../../../../../base/common/errors.js' ;
2931
3032export function maxContentWidthInRange ( editor : ObservableCodeEditor , range : LineRange , reader : IReader | undefined ) : number {
3133 editor . layoutInfo . read ( reader ) ;
@@ -183,12 +185,51 @@ function offsetRangeToRange(columnOffsetRange: OffsetRange, startPos: Position):
183185 ) ;
184186}
185187
186- export function createReindentEdit ( text : string , range : LineRange ) : TextEdit {
188+ /**
189+ * Calculates the indentation size (in spaces) of a given line,
190+ * interpreting tabs as the specified tab size.
191+ */
192+ function getIndentationSize ( line : string , tabSize : number ) : number {
193+ let currentSize = 0 ;
194+ loop: for ( let i = 0 , len = line . length ; i < len ; i ++ ) {
195+ switch ( line . charCodeAt ( i ) ) {
196+ case CharCode . Tab : currentSize += tabSize ; break ;
197+ case CharCode . Space : currentSize ++ ; break ;
198+ default : break loop;
199+ }
200+ }
201+ // if currentSize % tabSize !== 0,
202+ // then there are spaces which are not part of the indentation
203+ return currentSize - ( currentSize % tabSize ) ;
204+ }
205+
206+ /**
207+ * Calculates the number of characters at the start of a line that correspond to a given indentation size,
208+ * taking into account both tabs and spaces.
209+ */
210+ function indentSizeToIndentLength ( line : string , indentSize : number , tabSize : number ) : number {
211+ let remainingSize = indentSize - ( indentSize % tabSize ) ;
212+ let i = 0 ;
213+ for ( ; i < line . length ; i ++ ) {
214+ if ( remainingSize === 0 ) {
215+ break ;
216+ }
217+ switch ( line . charCodeAt ( i ) ) {
218+ case CharCode . Tab : remainingSize -= tabSize ; break ;
219+ case CharCode . Space : remainingSize -- ; break ;
220+ default : throw new BugIndicatingError ( 'Unexpected character found while calculating indent length' ) ;
221+ }
222+ }
223+ return i ;
224+ }
225+
226+ export function createReindentEdit ( text : string , range : LineRange , tabSize : number ) : TextEdit {
187227 const newLines = splitLines ( text ) ;
188228 const edits : TextReplacement [ ] = [ ] ;
189- const minIndent = findFirstMin ( range . mapToLineArray ( l => getIndentationLength ( newLines [ l - 1 ] ) ) , numberComparator ) ! ;
229+ const minIndentSize = findFirstMin ( range . mapToLineArray ( l => getIndentationSize ( newLines [ l - 1 ] , tabSize ) ) , numberComparator ) ! ;
190230 range . forEach ( lineNumber => {
191- edits . push ( new TextReplacement ( offsetRangeToRange ( new OffsetRange ( 0 , minIndent ) , new Position ( lineNumber , 1 ) ) , '' ) ) ;
231+ const indentLength = indentSizeToIndentLength ( newLines [ lineNumber - 1 ] , minIndentSize , tabSize ) ;
232+ edits . push ( new TextReplacement ( offsetRangeToRange ( new OffsetRange ( 0 , indentLength ) , new Position ( lineNumber , 1 ) ) , '' ) ) ;
192233 } ) ;
193234 return new TextEdit ( edits ) ;
194235}
0 commit comments