diff --git a/Extension/package.json b/Extension/package.json index f65e1a3df2..e1c1f86f5d 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -419,6 +419,12 @@ }, "scope": "resource" }, + "C_Cpp.codeAnalysis.clangTidy.codeAction.formatFixes": { + "type": "boolean", + "description": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.formatFixes.markdownDescription%", + "default": true, + "scope": "resource" + }, "C_Cpp.codeAnalysis.clangTidy.codeAction.showClear": { "type": "string", "description": "%c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.description%", diff --git a/Extension/package.nls.json b/Extension/package.nls.json index ea83e79aa0..859abf6a31 100644 --- a/Extension/package.nls.json +++ b/Extension/package.nls.json @@ -50,6 +50,7 @@ "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllOnly.description": "Show only the 'Clear all' code action (or 'Clear all ' if there is only one type or 'Clear this' if there is only one problem).", "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllType.description": "Show the 'Clear all' code action (if there are multiple problem types) and the 'Clear all ' code action (or 'Clear this' if there is only one problem for the )", "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllTypeAndThis.description": "Show the 'Clear all' (if there are multiple problem types), 'Clear all ' (if there are multiple problems for the ), and 'Clear this' code actions", + "c_cpp.configuration.codeAnalysis.clangTidy.codeAction.formatFixes.markdownDescription": { "message": "If `true`, formatting will be run on the lines changed by 'Fix' code actions.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, "c_cpp.configuration.codeAnalysis.clangTidy.enabled.markdownDescription": { "message": "If `true`, code analysis using `clang-tidy` will be enabled and run automatically if `#C_Cpp.codeAnalysis.runAutomatically#` is `true` (the default).", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, "c_cpp.configuration.codeAnalysis.clangTidy.path.markdownDescription": { "message": "The full path of the `clang-tidy` executable. If not specified, and `clang-tidy` is available in the environment path, that is used. If not found in the environment path, the `clang-tidy` bundled with the extension will be used.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, "c_cpp.configuration.codeAnalysis.clangTidy.config.markdownDescription": { "message": "Specifies a `clang-tidy` configuration in YAML/JSON format: `{Checks: '-*,clang-analyzer-*', CheckOptions: [{key: x, value: y}]}`. When the value is empty, `clang-tidy` will attempt to find a file named `.clang-tidy` for each source file in its parent directories.", "comment": [ "Words 'key' and 'value' in '{key: value, ...}' should be translated, but all other markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] }, diff --git a/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts index 1a82337e07..f9f9491742 100644 --- a/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentFormattingEditProvider.ts @@ -4,7 +4,7 @@ * ------------------------------------------------------------------------------------------ */ import * as vscode from 'vscode'; import { DefaultClient, FormatParams, FormatDocumentRequest } from '../client'; -import { CppSettings, getEditorConfigSettings } from '../settings'; +import { CppSettings, getEditorConfigSettings, OtherSettings } from '../settings'; import { makeVscodeTextEdits } from '../utils'; export class DocumentFormattingEditProvider implements vscode.DocumentFormattingEditProvider { @@ -16,6 +16,30 @@ export class DocumentFormattingEditProvider implements vscode.DocumentFormatting public async provideDocumentFormattingEdits(document: vscode.TextDocument, options: vscode.FormattingOptions, token: vscode.CancellationToken): Promise { await this.client.awaitUntilLanguageClientReady(); const filePath: string = document.uri.fsPath; + const onChanges: string | number | boolean = options.onChanges; + if (onChanges) { + let insertSpacesSet: boolean = false; + let tabSizeSet: boolean = false; + const editor: vscode.TextEditor = await vscode.window.showTextDocument(document, undefined, true); + if (editor.options.insertSpaces && typeof editor.options.insertSpaces === "boolean") { + options.insertSpaces = editor.options.insertSpaces; + insertSpacesSet = true; + } + if (editor.options.tabSize && typeof editor.options.tabSize === "number") { + options.tabSize = editor.options.tabSize; + tabSizeSet = true; + } + + if (!insertSpacesSet || !tabSizeSet) { + const settings: OtherSettings = new OtherSettings(this.client.RootUri); + if (!insertSpacesSet) { + options.insertSpaces = settings.editorInsertSpaces ?? true; + } + if (!tabSizeSet) { + options.tabSize = settings.editorTabSize ?? 4; + } + } + } const settings: CppSettings = new CppSettings(this.client.RootUri); const useVcFormat: boolean = settings.useVcFormat(document); const configCallBack = async (editorConfigSettings: any | undefined) => { @@ -35,7 +59,8 @@ export class DocumentFormattingEditProvider implements vscode.DocumentFormatting character: 0, line: 0 } - } + }, + onChanges: onChanges === true }; // We do not currently pass the CancellationToken to sendRequest // because there is not currently cancellation logic for formatting diff --git a/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts index 01ad323f16..2d9bfd38fe 100644 --- a/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/documentRangeFormattingEditProvider.ts @@ -35,7 +35,8 @@ export class DocumentRangeFormattingEditProvider implements vscode.DocumentRange character: range.end.character, line: range.end.line } - } + }, + onChanges: false }; // We do not currently pass the CancellationToken to sendRequest // because there is not currently cancellation logic for formatting diff --git a/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts b/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts index b4747022f8..c301b11360 100644 --- a/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts +++ b/Extension/src/LanguageServer/Providers/onTypeFormattingEditProvider.ts @@ -35,7 +35,8 @@ export class OnTypeFormattingEditProvider implements vscode.OnTypeFormattingEdit character: 0, line: 0 } - } + }, + onChanges: false }; // We do not currently pass the CancellationToken to sendRequest // because there is not currently cancellation logic for formatting diff --git a/Extension/src/LanguageServer/client.ts b/Extension/src/LanguageServer/client.ts index ea2b6ac80d..42f093bf40 100644 --- a/Extension/src/LanguageServer/client.ts +++ b/Extension/src/LanguageServer/client.ts @@ -312,6 +312,7 @@ export interface FormatParams { tabSize: number; editorConfigSettings: any; useVcFormat: boolean; + onChanges: boolean; } export interface GetFoldingRangesParams { @@ -3028,6 +3029,23 @@ export class DefaultClient implements Client { public async handleFixCodeAnalysisProblems(workspaceEdit: vscode.WorkspaceEdit, refreshSquigglesOnSave: boolean, identifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[]): Promise { if (await vscode.workspace.applyEdit(workspaceEdit)) { + const settings: CppSettings = new CppSettings(this.RootUri); + if (settings.clangTidyCodeActionFormatFixes) { + const editedFiles: Set = new Set(); + for (const entry of workspaceEdit.entries()) { + editedFiles.add(entry[0]); + } + const formatEdits: vscode.WorkspaceEdit = new vscode.WorkspaceEdit(); + for (const uri of editedFiles) { + const formatTextEdits: vscode.TextEdit[] | undefined = await vscode.commands.executeCommand("vscode.executeFormatDocumentProvider", uri, { onChanges: true }); + if (formatTextEdits && formatTextEdits.length > 0) { + formatEdits.set(uri, formatTextEdits); + } + } + if (formatEdits.size > 0) { + await vscode.workspace.applyEdit(formatEdits); + } + } return this.handleRemoveCodeAnalysisProblems(refreshSquigglesOnSave, identifiersAndUris); } } diff --git a/Extension/src/LanguageServer/settings.ts b/Extension/src/LanguageServer/settings.ts index 31ed727940..e83ea9fad8 100644 --- a/Extension/src/LanguageServer/settings.ts +++ b/Extension/src/LanguageServer/settings.ts @@ -189,6 +189,7 @@ export class CppSettings extends Settings { public get clangTidyCodeActionShowDisable(): boolean | undefined { return super.Section.get("codeAnalysis.clangTidy.codeAction.showDisable"); } public get clangTidyCodeActionShowClear(): string { return super.Section.get("codeAnalysis.clangTidy.codeAction.showClear") ?? "AllAndAllType"; } public get clangTidyCodeActionShowDocumentation(): boolean | undefined { return super.Section.get("codeAnalysis.clangTidy.codeAction.showDocumentation"); } + public get clangTidyCodeActionFormatFixes(): boolean { return super.Section.get("codeAnalysis.clangTidy.codeAction.formatFixes") ?? true; } public addClangTidyChecksDisabled(value: string): void { const checks: string[] | undefined = this.clangTidyChecksDisabled; if (checks === undefined) { @@ -808,6 +809,7 @@ export class OtherSettings { } public get editorTabSize(): number | undefined { return vscode.workspace.getConfiguration("editor", this.resource).get("tabSize"); } + public get editorInsertSpaces(): boolean | undefined { return vscode.workspace.getConfiguration("editor", this.resource).get("insertSpaces"); } public get editorAutoClosingBrackets(): string | undefined { return vscode.workspace.getConfiguration("editor", this.resource).get("autoClosingBrackets"); } public get filesEncoding(): string | undefined { return vscode.workspace.getConfiguration("files", { uri: this.resource, languageId: "cpp" }).get("encoding"); } public get filesAssociations(): any { return vscode.workspace.getConfiguration("files").get("associations"); }