Skip to content

Commit 54c6227

Browse files
authored
Adding doxygen comment generation (#9656)
1 parent 41303ed commit 54c6227

File tree

6 files changed

+162
-4
lines changed

6 files changed

+162
-4
lines changed

Extension/package.json

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2333,6 +2333,24 @@
23332333
"markdownDescription": "%c_cpp.configuration.simplifyStructuredComments.markdownDescription%",
23342334
"scope": "application"
23352335
},
2336+
"C_Cpp.autocompleteDoxygenComment":{
2337+
"type":"boolean",
2338+
"default":true,
2339+
"description": "%c_cpp.configuration.autocompleteDoxygenComment.description%",
2340+
"scope": "resource"
2341+
},
2342+
"C_Cpp.generatedDoxygenCommentStyle": {
2343+
"type":"string",
2344+
"enum":[
2345+
"///",
2346+
"/**",
2347+
"/*!",
2348+
"//!"
2349+
],
2350+
"default":"/**",
2351+
"description": "%c_cpp.configuration.generatedDoxygenCommentStyle.description%",
2352+
"scope": "resource"
2353+
},
23362354
"C_Cpp.commentContinuationPatterns": {
23372355
"type": "array",
23382356
"default": [
@@ -2876,7 +2894,13 @@
28762894
"command": "C_Cpp.AddDebugConfiguration",
28772895
"title": "%c_cpp.command.AddDebugConfiguration.title%",
28782896
"category": "C/C++",
2879-
"icon": "$(debug-configure)"
2897+
"icon": "$(debug-configure)"
2898+
},
2899+
{
2900+
"command": "C_Cpp.GenerateDoxygenComment",
2901+
"title":"%c_cpp.command.GenerateDoxygenComment.title%",
2902+
"category":"C/C++"
2903+
28802904
}
28812905
],
28822906
"keybindings": [
@@ -4901,6 +4925,11 @@
49014925
"command": "C_Cpp.AddDebugConfiguration",
49024926
"when": "editorLangId == 'c' && config.C_Cpp.debugShortcut && BuildAndDebug.isSourceFile && BuildAndDebug.isFolderOpen || editorLangId == 'cpp' && config.C_Cpp.debugShortcut && BuildAndDebug.isSourceFile && BuildAndDebug.isFolderOpen || editorLangId == 'cuda-cpp' && config.C_Cpp.debugShortcut && BuildAndDebug.isSourceFile && BuildAndDebug.isFolderOpen",
49034927
"group": "custom2@3"
4928+
},
4929+
{
4930+
"command": "C_Cpp.GenerateDoxygenComment",
4931+
"when": "editorLangId == 'c' || editorLangId == 'cpp' || editorLangId == 'cuda-cpp'",
4932+
"group": "custom2@3"
49044933
}
49054934
],
49064935
"commandPalette": [

Extension/package.nls.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"c_cpp.command.BuildAndDebugFile.title": "Debug C/C++ File",
2929
"c_cpp.command.BuildAndRunFile.title": "Run C/C++ File",
3030
"c_cpp.command.AddDebugConfiguration.title": "Add Debug Configuration",
31+
"c_cpp.command.GenerateDoxygenComment.title": "Generate Doxygen Comment",
3132
"c_cpp.configuration.maxConcurrentThreads.markdownDescription": { "message": "The maximum number of concurrent threads to use for language service processing. The value is a hint and may not always be used. The default of `null` (empty) uses the number of logical processors available.", "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." ] },
3233
"c_cpp.configuration.maxCachedProcesses.markdownDescription": { "message": "The maximum number of cached processes to use for language service processing. The default of `null` (empty) uses twice the number of logical processors available.", "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." ] },
3334
"c_cpp.configuration.maxMemory.markdownDescription": { "message": "The maximum memory (in MB) available for language service processing. Fewer processes will be cached and run concurrently after this memory usage is exceeded. The default of `null` (empty) uses the system's free memory.", "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." ] },
@@ -184,6 +185,8 @@
184185
"c_cpp.configuration.preferredPathSeparator.markdownDescription": { "message": "The character used as a path separator for `#include` auto-completion results.", "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." ] },
185186
"c_cpp.configuration.simplifyStructuredComments.markdownDescription": { "message": "If `true`, tooltips of hover and auto-complete will only display certain labels of structured comments. Otherwise, all comments are displayed.", "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." ] },
186187
"c_cpp.configuration.commentContinuationPatterns.items.anyof.string.markdownDescription": { "message": "The pattern that begins a multiline or single line comment block. The continuation pattern defaults to ` * ` for multiline comment blocks or this string for single line comment blocks.", "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." ] },
188+
"c_cpp.configuration.autocompleteDoxygenComment.description": "Controls whether to automatically insert the Doxygen comment after typing the chosen comment style.",
189+
"c_cpp.configuration.generatedDoxygenCommentStyle.description": "The string of characters used as the starting line of the Doxygen comment.",
187190
"c_cpp.configuration.commentContinuationPatterns.items.anyof.object.begin.description": "The pattern that begins a multiline or single line comment block.",
188191
"c_cpp.configuration.commentContinuationPatterns.items.anyof.object.continue.description": "The text that will be inserted on the next line when Enter is pressed inside a multiline or single line comment block.",
189192
"c_cpp.configuration.commentContinuationPatterns.description": "Defines the editor behavior for when the Enter key is pressed inside a multiline or single line comment block.",

Extension/src/LanguageServer/client.ts

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,22 @@ interface GoToDirectiveInGroupParams {
401401
next: boolean;
402402
};
403403

404+
export interface GenerateDoxygenCommentParams {
405+
uri: string;
406+
position: Position;
407+
isCodeAction: boolean;
408+
isCursorAboveSignatureLine: boolean;
409+
}
410+
411+
export interface GenerateDoxygenCommentResult {
412+
contents: string;
413+
initPosition: Position;
414+
finalInsertionLine: number;
415+
finalCursorPosition: Position;
416+
fileVersion: number;
417+
isCursorAboveSignatureLine: boolean;
418+
}
419+
404420
interface SetTemporaryTextDocumentLanguageParams {
405421
path: string;
406422
isC: boolean;
@@ -444,6 +460,7 @@ export const FormatDocumentRequest: RequestType<FormatParams, TextEdit[], void>
444460
export const FormatRangeRequest: RequestType<FormatParams, TextEdit[], void> = new RequestType<FormatParams, TextEdit[], void>('cpptools/formatRange');
445461
export const FormatOnTypeRequest: RequestType<FormatParams, TextEdit[], void> = new RequestType<FormatParams, TextEdit[], void>('cpptools/formatOnType');
446462
const GoToDirectiveInGroupRequest: RequestType<GoToDirectiveInGroupParams, Position | undefined, void> = new RequestType<GoToDirectiveInGroupParams, Position | undefined, void>('cpptools/goToDirectiveInGroup');
463+
const GenerateDoxygenCommentRequest: RequestType<GenerateDoxygenCommentParams, GenerateDoxygenCommentResult | undefined, void> = new RequestType<GenerateDoxygenCommentParams, GenerateDoxygenCommentResult, void>('cpptools/generateDoxygenComment');
447464

448465
// Notifications to the server
449466
const DidOpenNotification: NotificationType<DidOpenTextDocumentParams> = new NotificationType<DidOpenTextDocumentParams>('textDocument/didOpen');
@@ -500,6 +517,8 @@ const IntelliSenseSetupNotification: NotificationType<IntelliSenseSetup> = new N
500517
const SetTemporaryTextDocumentLanguageNotification: NotificationType<SetTemporaryTextDocumentLanguageParams> = new NotificationType<SetTemporaryTextDocumentLanguageParams>('cpptools/setTemporaryTextDocumentLanguage');
501518
const ReportCodeAnalysisProcessedNotification: NotificationType<number> = new NotificationType<number>('cpptools/reportCodeAnalysisProcessed');
502519
const ReportCodeAnalysisTotalNotification: NotificationType<number> = new NotificationType<number>('cpptools/reportCodeAnalysisTotal');
520+
const DoxygenCommentGeneratedNotification: NotificationType<GenerateDoxygenCommentResult> = new NotificationType<GenerateDoxygenCommentResult>('cpptools/insertDoxygenComment');
521+
503522
let failureMessageShown: boolean = false;
504523

505524
export interface ReferencesCancellationState {
@@ -647,6 +666,7 @@ export interface Client {
647666
handleConfigurationEditUICommand(viewColumn?: vscode.ViewColumn): void;
648667
handleAddToIncludePathCommand(path: string): void;
649668
handleGoToDirectiveInGroup(next: boolean): Promise<void>;
669+
handleGenerateDoxygenComment(initCursorLine: number | undefined, initCursorColumn: number | undefined, line: number | undefined, column: number | undefined, insertNewLineAtBeginning: boolean | undefined): Promise<void>;
650670
handleCheckForCompiler(): Promise<void>;
651671
handleRunCodeAnalysisOnActiveFile(): Promise<void>;
652672
handleRunCodeAnalysisOnOpenFiles(): Promise<void>;
@@ -977,6 +997,8 @@ export class DefaultClient implements Client {
977997
const settings_suggestSnippets: (boolean | undefined)[] = [];
978998
const settings_exclusionPolicy: (string | undefined)[] = [];
979999
const settings_preferredPathSeparator: (string | undefined)[] = [];
1000+
const settings_generatedDoxygenCommentStyle: (string | undefined)[] = [];
1001+
const settings_autocompleteDoxygenComment: (boolean | undefined)[] = [];
9801002
const settings_defaultSystemIncludePath: (string[] | undefined)[] = [];
9811003
const settings_intelliSenseCachePath: (string | undefined)[] = [];
9821004
const settings_intelliSenseCacheSize: (number | undefined)[] = [];
@@ -1144,6 +1166,8 @@ export class DefaultClient implements Client {
11441166
settings_suggestSnippets.push(setting.suggestSnippets);
11451167
settings_exclusionPolicy.push(setting.exclusionPolicy);
11461168
settings_preferredPathSeparator.push(setting.preferredPathSeparator);
1169+
settings_generatedDoxygenCommentStyle.push(setting.generatedDoxygenCommentStyle);
1170+
settings_autocompleteDoxygenComment.push(setting.autocompleteDoxygenComment);
11471171
settings_defaultSystemIncludePath.push(setting.defaultSystemIncludePath);
11481172
settings_intelliSenseCachePath.push(util.resolveCachePath(setting.intelliSenseCachePath, this.AdditionalEnvironment));
11491173
settings_intelliSenseCacheSize.push(setting.intelliSenseCacheSize);
@@ -1328,6 +1352,8 @@ export class DefaultClient implements Client {
13281352
enhancedColorization: settings_enhancedColorization,
13291353
suggestSnippets: settings_suggestSnippets,
13301354
simplifyStructuredComments: workspaceSettings.simplifyStructuredComments,
1355+
generatedDoxygenCommentStyle: settings_generatedDoxygenCommentStyle,
1356+
autocompleteDoxygenComment: settings_autocompleteDoxygenComment,
13311357
loggingLevel: workspaceSettings.loggingLevel,
13321358
workspaceParsingPriority: workspaceSettings.workspaceParsingPriority,
13331359
workspaceSymbols: workspaceSettings.workspaceSymbols,
@@ -2131,6 +2157,7 @@ export class DefaultClient implements Client {
21312157
this.languageClient.onNotification(SetTemporaryTextDocumentLanguageNotification, (e) => this.setTemporaryTextDocumentLanguage(e));
21322158
this.languageClient.onNotification(ReportCodeAnalysisProcessedNotification, (e) => this.updateCodeAnalysisProcessed(e));
21332159
this.languageClient.onNotification(ReportCodeAnalysisTotalNotification, (e) => this.updateCodeAnalysisTotal(e));
2160+
this.languageClient.onNotification(DoxygenCommentGeneratedNotification, (e) => this.insertDoxygenComment(e));
21342161
setupOutputHandlers();
21352162
}
21362163

@@ -2615,6 +2642,32 @@ export class DefaultClient implements Client {
26152642
this.model.codeAnalysisTotal.Value = total;
26162643
}
26172644

2645+
private async insertDoxygenComment(result: GenerateDoxygenCommentResult): Promise<void> {
2646+
const editor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
2647+
if (!editor) {
2648+
return;
2649+
}
2650+
const currentFileVersion: number | undefined = openFileVersions.get(editor.document.uri.toString());
2651+
// Insert the comment only if the cursor has not moved
2652+
if (result.fileVersion === currentFileVersion &&
2653+
result.initPosition.line === editor.selection.active.line &&
2654+
result.initPosition.character === editor.selection.active.character &&
2655+
result.contents.length > 1) {
2656+
const workspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit();
2657+
const edits: vscode.TextEdit[] = [];
2658+
const maxColumn: number = 99999999;
2659+
const newRange: vscode.Range = new vscode.Range(editor.selection.start.line, 0, editor.selection.end.line, maxColumn);
2660+
edits.push(new vscode.TextEdit(newRange, result?.contents));
2661+
workspaceEdit.set(editor.document.uri, edits);
2662+
await vscode.workspace.applyEdit(workspaceEdit);
2663+
2664+
// Set the cursor position after @brief
2665+
const newPosition: vscode.Position = new vscode.Position(result.finalCursorPosition.line, result.finalCursorPosition.character);
2666+
const newSelection: vscode.Selection = new vscode.Selection(newPosition, newPosition);
2667+
editor.selection = newSelection;
2668+
}
2669+
}
2670+
26182671
private doneInitialCustomBrowseConfigurationCheck: boolean = false;
26192672

26202673
private onConfigurationsChanged(cppProperties: configs.CppProperties): void {
@@ -2960,7 +3013,6 @@ export class DefaultClient implements Client {
29603013
position: editor.selection.active,
29613014
next: next
29623015
};
2963-
29643016
await this.awaitUntilLanguageClientReady();
29653017
const response: Position | undefined = await this.languageClient.sendRequest(GoToDirectiveInGroupRequest, params);
29663018
if (response) {
@@ -2977,6 +3029,75 @@ export class DefaultClient implements Client {
29773029
}
29783030
}
29793031

3032+
public async handleGenerateDoxygenComment(initCursorLine: number | undefined, initCursorColumn: number | undefined, adjustedLine: number | undefined, adjustedColmn: number | undefined, isCursorAboveSignatureLine: boolean): Promise<void> {
3033+
const editor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
3034+
if (!editor) {
3035+
return;
3036+
}
3037+
3038+
if (editor.document.uri.scheme !== "file") {
3039+
return;
3040+
}
3041+
3042+
if (!(editor.document.languageId === "c" || editor.document.languageId === "cpp" || editor.document.languageId === "cuda-cpp")) {
3043+
return;
3044+
}
3045+
3046+
const isCodeAction: boolean = (adjustedLine !== undefined && adjustedLine !== undefined);
3047+
const initCursorPosition: vscode.Position = isCodeAction ? new vscode.Position(initCursorLine ?? 0, initCursorColumn ?? 0) : editor.selection.active;
3048+
const params: GenerateDoxygenCommentParams = {
3049+
uri: editor.document.uri.toString(),
3050+
position: isCodeAction ? new vscode.Position(adjustedLine ?? 0, adjustedColmn ?? 0) : editor.selection.active,
3051+
isCodeAction: isCodeAction,
3052+
isCursorAboveSignatureLine: isCursorAboveSignatureLine
3053+
};
3054+
await this.awaitUntilLanguageClientReady();
3055+
const currentFileVersion: number | undefined = openFileVersions.get(params.uri);
3056+
if (currentFileVersion === undefined) {
3057+
return;
3058+
}
3059+
const result: GenerateDoxygenCommentResult | undefined = await this.languageClient.sendRequest(GenerateDoxygenCommentRequest, params);
3060+
// Insert the comment only if the comment has contents and the cursor has not moved
3061+
if (result !== undefined &&
3062+
initCursorPosition.line === editor.selection.active.line &&
3063+
initCursorPosition.character === editor.selection.active.character &&
3064+
result.fileVersion !== undefined &&
3065+
result.fileVersion === currentFileVersion &&
3066+
result.contents && result.contents.length > 1) {
3067+
const workspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit();
3068+
const edits: vscode.TextEdit[] = [];
3069+
const maxColumn: number = 99999999;
3070+
let newRange: vscode.Range;
3071+
const cursorOnEmptyLineAboveSignature: boolean = result.isCursorAboveSignatureLine;
3072+
// The reason why we need to set different range is because if cursor is immediately above the signature line, we want the comments to be inserted at the line of cursor and to replace everything on the line.
3073+
// If the cursor is on the signature line or is inside the boby, the comment will be inserted on the same line of the signature and it shouldn't replace the content of the signature line.
3074+
if (cursorOnEmptyLineAboveSignature) {
3075+
if (isCodeAction) {
3076+
// The reson why we cannot use finalInsertionLine is because the line number sent from the result is not correct.
3077+
// In most cases, the finalInsertionLine is the line of the signature line.
3078+
newRange = new vscode.Range(initCursorPosition.line, 0, initCursorPosition.line, maxColumn);
3079+
} else {
3080+
newRange = new vscode.Range(result.finalInsertionLine, 0, result.finalInsertionLine, maxColumn);
3081+
}
3082+
} else {
3083+
newRange = new vscode.Range(result.finalInsertionLine, 0, result.finalInsertionLine, 0);
3084+
}
3085+
edits.push(new vscode.TextEdit(newRange, result?.contents));
3086+
workspaceEdit.set(editor.document.uri, edits);
3087+
await vscode.workspace.applyEdit(workspaceEdit);
3088+
// Set the cursor position after @brief
3089+
let newPosition: vscode.Position;
3090+
if (cursorOnEmptyLineAboveSignature && isCodeAction) {
3091+
newPosition = new vscode.Position(result.finalCursorPosition.line - 1, result.finalCursorPosition.character);
3092+
} else {
3093+
newPosition = new vscode.Position(result.finalCursorPosition.line, result.finalCursorPosition.character);
3094+
}
3095+
const newSelection: vscode.Selection = new vscode.Selection(newPosition, newPosition);
3096+
editor.selection = newSelection;
3097+
}
3098+
3099+
}
3100+
29803101
public async handleCheckForCompiler(): Promise<void> {
29813102
await this.awaitUntilLanguageClientReady();
29823103
const compilers: configs.KnownCompiler[] | undefined = await this.getKnownCompilers();
@@ -3017,7 +3138,7 @@ export class DefaultClient implements Client {
30173138

30183139
public async handleRunCodeAnalysisOnAllFiles(): Promise<void> {
30193140
await this.awaitUntilLanguageClientReady();
3020-
this.languageClient.sendNotification(CodeAnalysisNotification, { scope: CodeAnalysisScope.AllFiles });
3141+
this.languageClient.sendNotification(CodeAnalysisNotification, { scope: CodeAnalysisScope.AllFiles });
30213142
}
30223143

30233144
public async handleRemoveAllCodeAnalysisProblems(): Promise<void> {
@@ -3254,6 +3375,7 @@ class NullClient implements Client {
32543375
handleConfigurationEditUICommand(viewColumn?: vscode.ViewColumn): void { }
32553376
handleAddToIncludePathCommand(path: string): void { }
32563377
handleGoToDirectiveInGroup(next: boolean): Promise<void> { return Promise.resolve(); }
3378+
handleGenerateDoxygenComment(): Promise<void> { return Promise.resolve(); }
32573379
handleCheckForCompiler(): Promise<void> { return Promise.resolve(); }
32583380
handleRunCodeAnalysisOnActiveFile(): Promise<void> { return Promise.resolve(); }
32593381
handleRunCodeAnalysisOnOpenFiles(): Promise<void> { return Promise.resolve(); }

0 commit comments

Comments
 (0)