@@ -293,11 +293,11 @@ export class CMakeListsModifier implements vscode.Disposable {
293
293
294
294
const cmakeDocument = sourceList . document ;
295
295
const insertPos = sourceList . insertPosition ;
296
- const prefix = await indentPrefix ( sourceList . invocation , insertPos ) ;
296
+ const indent = freshLineIndent ( sourceList . invocation , insertPos ) ;
297
297
const newSourceArgument = quoteArgument ( sourceList . relativePath ( newSourceUri ) ) ;
298
298
const edit = new vscode . WorkspaceEdit ( ) ;
299
299
edit . insert (
300
- cmakeDocument . uri , insertPos , `${ prefix } ${ newSourceArgument } ` ,
300
+ cmakeDocument . uri , insertPos , `\n ${ indent } ${ newSourceArgument } ` ,
301
301
{
302
302
label : 'CMake: Add new source file' ,
303
303
needsConfirmation : settings . addNewSourceFiles === 'ask'
@@ -1298,41 +1298,107 @@ async function quickPick<T>(
1298
1298
return selected . payload ;
1299
1299
}
1300
1300
1301
- async function indentPrefix ( invocation : CommandInvocation , insertPos : vscode . Position ) {
1302
- const activeEditor = vscode . window . activeTextEditor ;
1303
- // Wish this didn't flash the CMake file in the UI, but the API doesn't
1304
- // expose another way to get the inferred indentation.
1305
- const editor = await vscode . window . showTextDocument (
1306
- invocation . document , {
1307
- preview : true ,
1308
- preserveFocus : true
1301
+ function freshLineIndent ( invocation : CommandInvocation , insertPos : vscode . Position ) {
1302
+ const currentLine = invocation . document . lineAt ( insertPos . line ) ;
1303
+ const currentLineIndent =
1304
+ currentLine . text . slice ( 0 , currentLine . firstNonWhitespaceCharacterIndex ) ;
1305
+
1306
+ if ( invocation . line !== insertPos . line ) {
1307
+ // Just keep the current indentation
1308
+ return currentLineIndent ;
1309
+ }
1310
+
1311
+ const guessed = guessIndentConfig ( invocation . document ) ;
1312
+ const currentLineIndentSize = Array . from ( currentLineIndent )
1313
+ . reduce ( ( n , c ) => n + ( c === '\t' ? guessed . tabSize : 1 ) , 0 ) ;
1314
+ const freshLineIndentSize = currentLineIndentSize + guessed . indentSize ;
1315
+
1316
+ if ( guessed . insertSpaces ) {
1317
+ return ' ' . repeat ( freshLineIndentSize ) ;
1318
+ }
1319
+
1320
+ const tabs = Math . floor ( freshLineIndentSize / guessed . tabSize ) ;
1321
+ const spaces = freshLineIndentSize % guessed . tabSize ;
1322
+ return '\t' . repeat ( tabs ) + ' ' . repeat ( spaces ) ;
1323
+ }
1324
+
1325
+ interface IndentConfig {
1326
+ tabSize : number ;
1327
+ indentSize : number ;
1328
+ insertSpaces : boolean ;
1329
+ }
1330
+
1331
+ function guessIndentConfig ( document : vscode . TextDocument ) : IndentConfig {
1332
+ const { tabSize, indentSize, insertSpaces } = indentSettings ( document ) ;
1333
+
1334
+ let tabs = false ;
1335
+ let minSpaces = 0 ; let maxSpaces = 0 ;
1336
+ for ( const line of documentLines ( document ) ) {
1337
+ const indent = line . text . slice ( 0 , line . firstNonWhitespaceCharacterIndex ) ;
1338
+ if ( indent . startsWith ( '\t' ) ) {
1339
+ tabs = true ;
1340
+ } else if ( indent . startsWith ( ' ' ) ) {
1341
+ const matches = indent . match ( '^( *)' ) as RegExpMatchArray ;
1342
+ const spacesSize = matches [ 1 ] . length ;
1343
+ if ( ! minSpaces || spacesSize < minSpaces ) {
1344
+ minSpaces = spacesSize ;
1345
+ }
1346
+ if ( spacesSize > maxSpaces ) {
1347
+ maxSpaces = spacesSize ;
1348
+ }
1309
1349
}
1310
- ) ;
1311
- const tabSize = editor . options . tabSize as number ;
1312
- const indentSize = editor . options . indentSize as number ;
1313
- const insertSpaces = editor . options . insertSpaces ;
1314
- if ( activeEditor ) {
1315
- await vscode . window . showTextDocument ( activeEditor . document ) ;
1316
- }
1317
- const thisLine = invocation . document . lineAt ( insertPos . line ) ;
1318
- const thisLineIndent = thisLine . text . slice ( 0 , thisLine . firstNonWhitespaceCharacterIndex ) ;
1319
- const thisLineIndentSize = Array . from ( thisLineIndent )
1320
- . reduce ( ( n , c ) => n + ( c === '\t' ? tabSize : 1 ) , 0 ) ;
1321
- const insertingOnFirstLineOfInvocation = invocation . line === insertPos . line ;
1322
- const freshLineIndentSize = insertingOnFirstLineOfInvocation
1323
- ? thisLineIndentSize + indentSize
1324
- : thisLineIndentSize ;
1325
- let tabs ;
1326
- let spaces ;
1327
- if ( insertSpaces ) {
1328
- tabs = 0 ;
1329
- spaces = freshLineIndentSize ;
1330
- } else {
1331
- spaces = freshLineIndentSize % tabSize ;
1332
- tabs = Math . floor ( freshLineIndentSize / tabSize ) ;
1333
1350
}
1334
- const freshLineIndent = '\t' . repeat ( tabs ) + ' ' . repeat ( spaces ) ;
1335
- return `\n${ freshLineIndent } ` ;
1351
+
1352
+ const spaces = ! ! maxSpaces ;
1353
+
1354
+ if ( spaces && tabs ) {
1355
+ return {
1356
+ tabSize : maxSpaces + minSpaces ,
1357
+ indentSize : minSpaces ,
1358
+ insertSpaces : false
1359
+ } ;
1360
+ }
1361
+ if ( spaces && ! tabs ) {
1362
+ return {
1363
+ tabSize,
1364
+ indentSize : minSpaces ,
1365
+ insertSpaces : true
1366
+ } ;
1367
+ }
1368
+ if ( ! spaces && tabs ) {
1369
+ return {
1370
+ tabSize,
1371
+ indentSize,
1372
+ insertSpaces : false
1373
+ } ;
1374
+ }
1375
+
1376
+ // document contained no indented lines, fall back to workspace settings
1377
+ return {
1378
+ tabSize,
1379
+ indentSize,
1380
+ insertSpaces
1381
+ } ;
1382
+ }
1383
+
1384
+ /**
1385
+ * Get the IndentConfig from the workspace configuration
1386
+ */
1387
+ function indentSettings ( document : vscode . TextDocument , languageId : string = 'cmake' ) : IndentConfig {
1388
+ const config = vscode . workspace . getConfiguration (
1389
+ 'editor' , { uri : document . uri , languageId } ) ;
1390
+ const tabSize = config . get < number > ( 'tabSize' , 8 ) ;
1391
+ const indentSizeRaw = config . get < number | 'tabSize' > ( 'indentSize' , 4 ) ;
1392
+ const indentSize = indentSizeRaw === 'tabSize' ? tabSize : indentSizeRaw ;
1393
+ const insertSpaces = config . get < boolean > ( 'insertSpaces' , false ) ;
1394
+
1395
+ return { tabSize, indentSize, insertSpaces } ;
1396
+ }
1397
+
1398
+ function * documentLines ( document : vscode . TextDocument ) : Generator < vscode . TextLine > {
1399
+ for ( let i = 0 ; i < document . lineCount ; i ++ ) {
1400
+ yield document . lineAt ( i ) ;
1401
+ }
1336
1402
}
1337
1403
1338
1404
function compareSortKeys ( aKeys : ( number | string ) [ ] , bKeys : ( number | string ) [ ] ) : number {
0 commit comments