@@ -293,11 +293,11 @@ export class CMakeListsModifier implements vscode.Disposable {
293293
294294 const cmakeDocument = sourceList . document ;
295295 const insertPos = sourceList . insertPosition ;
296- const prefix = await indentPrefix ( sourceList . invocation , insertPos ) ;
296+ const indent = freshLineIndent ( sourceList . invocation , insertPos ) ;
297297 const newSourceArgument = quoteArgument ( sourceList . relativePath ( newSourceUri ) ) ;
298298 const edit = new vscode . WorkspaceEdit ( ) ;
299299 edit . insert (
300- cmakeDocument . uri , insertPos , `${ prefix } ${ newSourceArgument } ` ,
300+ cmakeDocument . uri , insertPos , `\n ${ indent } ${ newSourceArgument } ` ,
301301 {
302302 label : 'CMake: Add new source file' ,
303303 needsConfirmation : settings . addNewSourceFiles === 'ask'
@@ -1298,41 +1298,107 @@ async function quickPick<T>(
12981298 return selected . payload ;
12991299}
13001300
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+ }
13091349 }
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 ) ;
13331350 }
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+ }
13361402}
13371403
13381404function compareSortKeys ( aKeys : ( number | string ) [ ] , bKeys : ( number | string ) [ ] ) : number {
0 commit comments