diff --git a/sampleWorkspace/function-comment-for-go/function-none-params-with-return.go b/sampleWorkspace/function-comment-for-go/function-none-params-with-return.go new file mode 100644 index 0000000..a492e6a --- /dev/null +++ b/sampleWorkspace/function-comment-for-go/function-none-params-with-return.go @@ -0,0 +1,3 @@ +func testFunc() (string) { + return "test" +} diff --git a/sampleWorkspace/function-comment-for-go/function-none-params-with-return.result.go b/sampleWorkspace/function-comment-for-go/function-none-params-with-return.result.go new file mode 100644 index 0000000..2ab3216 --- /dev/null +++ b/sampleWorkspace/function-comment-for-go/function-none-params-with-return.result.go @@ -0,0 +1,7 @@ +/** + * @description + * @return default {string} + */ +func testFunc() (string) { + return "test" +} diff --git a/sampleWorkspace/function-comment-for-go/function-none-params-without-return.go b/sampleWorkspace/function-comment-for-go/function-none-params-without-return.go new file mode 100644 index 0000000..f60177e --- /dev/null +++ b/sampleWorkspace/function-comment-for-go/function-none-params-without-return.go @@ -0,0 +1,3 @@ +func testFunc() { + fmt.Println("test") +} diff --git a/sampleWorkspace/function-comment-for-go/function-none-params-without-return.result.go b/sampleWorkspace/function-comment-for-go/function-none-params-without-return.result.go new file mode 100644 index 0000000..302dcfb --- /dev/null +++ b/sampleWorkspace/function-comment-for-go/function-none-params-without-return.result.go @@ -0,0 +1,6 @@ +/** + * @description + */ +func testFunc() { + fmt.Println("test") +} diff --git a/sampleWorkspace/function-comment-for-go/function-with-params-type-with-return.go b/sampleWorkspace/function-comment-for-go/function-with-params-type-with-return.go new file mode 100644 index 0000000..4066733 --- /dev/null +++ b/sampleWorkspace/function-comment-for-go/function-with-params-type-with-return.go @@ -0,0 +1,3 @@ +func funcName(param1 string, param2 []int) (r1 string, r2 []int) { + return param1, param2 +} diff --git a/sampleWorkspace/function-comment-for-go/function-with-params-type-with-return.result.go b/sampleWorkspace/function-comment-for-go/function-with-params-type-with-return.result.go new file mode 100644 index 0000000..bd85d34 --- /dev/null +++ b/sampleWorkspace/function-comment-for-go/function-with-params-type-with-return.result.go @@ -0,0 +1,10 @@ +/** + * @description + * @return r1 {string} + * @return r2 {[]int} + * @param param1 {string} + * @param param2 {[]int} + */ +func funcName(param1 string, param2 []int) (r1 string, r2 []int) { + return param1, param2 +} diff --git a/sampleWorkspace/function-comment-for-go/function-with-params-type-without-return.go b/sampleWorkspace/function-comment-for-go/function-with-params-type-without-return.go new file mode 100644 index 0000000..dcadcf8 --- /dev/null +++ b/sampleWorkspace/function-comment-for-go/function-with-params-type-without-return.go @@ -0,0 +1,3 @@ +func funcName(param1 string, param2 []int) { + return param1, param2 +} diff --git a/sampleWorkspace/function-comment-for-go/function-with-params-type-without-return.result.go b/sampleWorkspace/function-comment-for-go/function-with-params-type-without-return.result.go new file mode 100644 index 0000000..4470d42 --- /dev/null +++ b/sampleWorkspace/function-comment-for-go/function-with-params-type-without-return.result.go @@ -0,0 +1,8 @@ +/** + * @description + * @param param1 {string} + * @param param2 {[]int} + */ +func funcName(param1 string, param2 []int) { + return param1, param2 +} diff --git a/sampleWorkspace/function-comment-for-go/function-with-params-type.go b/sampleWorkspace/function-comment-for-go/function-with-params-type.go deleted file mode 100644 index 090ac52..0000000 --- a/sampleWorkspace/function-comment-for-go/function-with-params-type.go +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @description - * @return default {auto} - * @param param1 {string} - * @param param2 {int} - */ -func funcName(param1 string, param2 int) { - fmt.Println("Hello, World!") -} diff --git a/sampleWorkspace/function-comment-for-ts/variable-function-with-params-type-update.result.ts b/sampleWorkspace/function-comment-for-ts/variable-function-with-params-type-update.result.ts index f0aa37f..7b1c524 100644 --- a/sampleWorkspace/function-comment-for-ts/variable-function-with-params-type-update.result.ts +++ b/sampleWorkspace/function-comment-for-ts/variable-function-with-params-type-update.result.ts @@ -1,8 +1,8 @@ /** - * @description - * @return default {string} - * @param a {string} - * @param b {{key: string}} + * @description test + * @return default {string} returnValue + * @param a {string} stringA + * @param b {{key: string}} stringB */ const func = function(a: string, b: {key: string}): string { console.log(a + b); diff --git a/src/fileheader/FileheaderManager.ts b/src/fileheader/FileheaderManager.ts index 72c5714..402127f 100644 --- a/src/fileheader/FileheaderManager.ts +++ b/src/fileheader/FileheaderManager.ts @@ -178,7 +178,7 @@ export class FileheaderManager { range, ) || { paramsInfo: {}, - returnInfo: { default: { type: '', description: '' } }, + returnInfo: {}, descriptionInfo: '', }; const functionCommentInfo = parser?.generateFunctionCommentInfo( @@ -187,7 +187,7 @@ export class FileheaderManager { ); if (functionCommentInfo) { - const originFunctionComment = generateFunctionComment(originFunctionInfo); + const originFunctionComment = generateFunctionComment(originFunctionInfo, true); const functionComment = generateFunctionComment(functionCommentInfo); // 函数注释没有变化 if (originFunctionComment === functionComment) { diff --git a/src/function-params-parser/GoProvider.ts b/src/function-params-parser/GoProvider.ts index f3a98e2..3bd75d5 100644 --- a/src/function-params-parser/GoProvider.ts +++ b/src/function-params-parser/GoProvider.ts @@ -3,8 +3,11 @@ import * as vscode from 'vscode'; import { ConfigManager } from '@/configuration/ConfigManager'; import { logger } from '@/extension'; import { LanguageFunctionCommentSettings } from '@/typings/types'; +import { escapeRegexString } from '@/utils/str'; +import { extractFunctionParamsString } from './extractFunctionParamsString'; import { FunctionParamsParser } from './FunctionParamsParser'; +import { splitParams } from './go-splitParams'; import { FunctionParamsInfo, ParamsInfo, ReturnInfo } from './types'; function matchNormalFunction( @@ -16,25 +19,30 @@ function matchNormalFunction( params: ParamsInfo; } { const { defaultReturnName = 'default' } = languageSettings; - let returnType = {}; + const returnType: ReturnInfo = {}; let matched = false; - const params: ParamsInfo = {}; + let params: ParamsInfo = {}; - // 普通写法,一个小括号一个大括号,可能有参数,可能有一个返回值,但返回值没有命令,没有括号 - const functionPattern = /func\s+([a-zA-Z0-9_]+)\s*\((.*?)\)\s*([a-zA-Z0-9_]+)?\s*{[\s\S]*?}/m; + // 提取参数括号里的字符串 + const functionParamsStr = extractFunctionParamsString(functionDefinition); + const functionParamsRegStr = escapeRegexString(functionParamsStr); + // 普通写法,一个小括号一个大括号,参数使用上面变量,可能有一个返回值,但返回值没有命名,没有括号 + const functionPattern = new RegExp( + `func\\s+([a-zA-Z0-9_]+)\\s*\\(${functionParamsRegStr}\\)\\s*([a-zA-Z0-9_]+)?\\s*{[\\s\\S]*?}`, + 'm', + ); const match = functionPattern.exec(functionDefinition); if (match) { matched = true; - returnType = { [defaultReturnName]: { type: match[3], description: '' } }; - - const paramsString = match[2]; - const paramsArray = paramsString.split(','); - for (const param of paramsArray) { - const [name, type] = param.trim().split(' '); - params[name] = { type, description: '' }; + const returnString = match[2]; + if (returnString) { + const returnTypeStr = returnString.trim(); + returnType[defaultReturnName] = { type: returnTypeStr, description: '' }; } + + params = splitParams(functionParamsStr, languageSettings); } return { matched, returnType, params }; @@ -48,32 +56,25 @@ function matchMultiReturnTypeFunction( returnType: ReturnInfo; params: ParamsInfo; } { - const { defaultReturnName = 'default' } = languageSettings; - const returnType: ReturnInfo = {}; + let returnType: ReturnInfo = {}; let matched = false; - const params: ParamsInfo = {}; + let params: ParamsInfo = {}; - // 函数可能有参数,一定有一个或多个返回值,返回值可能有命名,也可能无命名,但一定有括号包住返回值 - const functionPattern = /func\s+([a-zA-Z0-9_]+)\s*\((.*?)\)\s*\((.*?)\)\s*{[\s\S]*?}/m; + const functionParamsStr = extractFunctionParamsString(functionDefinition); + const functionParamsRegStr = escapeRegexString(functionParamsStr); + // 函数参数使用上面变量,一定有一个或多个返回值,返回值可能有命名,也可能无命名,但一定有括号包住返回值 + const functionPattern = new RegExp( + `func\\s+([a-zA-Z0-9_]+)\\s*\\(${functionParamsRegStr}\\)\\s*\\((.*?)\\)\\s*{[\\s\\S]*?}`, + 'm', + ); const match = functionPattern.exec(functionDefinition); if (match) { matched = true; + params = splitParams(functionParamsStr, languageSettings); - const paramsString = match[2]; - const paramsArray = paramsString.split(','); - for (const param of paramsArray) { - const [name, type] = param.trim().split(' '); - params[name] = { type, description: '' }; - } - - const returnString = match[3]; - const returnArray = returnString.split(','); - let defaultCount = 0; - for (const ret of returnArray) { - const [name, type] = ret.trim().split(' '); - returnType[name || `${defaultReturnName}${defaultCount++}`] = { type, description: '' }; - } + const returnString = match[2] || ''; + returnType = splitParams(returnString, languageSettings); } return { matched, returnType, params }; @@ -87,31 +88,26 @@ function matchBindTypeFunction( returnType: ReturnInfo; params: ParamsInfo; } { - const { defaultReturnName = 'default' } = languageSettings; - const returnType: ReturnInfo = {}; + let returnType: ReturnInfo = {}; let matched = false; - const params: ParamsInfo = {}; + let params: ParamsInfo = {}; - // 绑定到类型的函数,可能有参数,可能有一个或多个返回值,返回值可能有命名 - const functionPattern = - /func\s+\((.*?)\s*\*\s*([a-zA-Z0-9_]+)\)\s*([a-zA-Z0-9_]+)\s*\((.*?)\)\s*\((.*?)\)\s*{[\s\S]*?}/m; + const functionParamsStr = extractFunctionParamsString(functionDefinition); + const functionParamsRegStr = escapeRegexString(functionParamsStr); + // 绑定到类型的函数,参数使用上面变量,可能有一个或多个返回值,返回值可能有命名 + const functionPattern = new RegExp( + `func\\s+([a-zA-Z0-9_]+)\\s*\\(${functionParamsRegStr}\\)\\s*\\((.*?)\\)\\s*{[\\s\\S]*?}`, + 'm', + ); const match = functionPattern.exec(functionDefinition); if (match) { matched = true; - const paramsString = match[4]; - const paramsArray = paramsString.split(','); - for (const param of paramsArray) { - const [name, type] = param.trim().split(' '); - params[name] = { type, description: '' }; - } + const functionParamsStr = match[4] || ''; + params = splitParams(functionParamsStr, languageSettings); const returnString = match[5]; - const returnArray = returnString.split(','); - for (const ret of returnArray) { - const [name, type] = ret.trim().split(' '); - returnType[name || defaultReturnName] = { type, description: '' }; - } + returnType = splitParams(returnString, languageSettings); } return { matched, returnType, params }; @@ -133,18 +129,14 @@ function matchFunction( let params: ParamsInfo = {}; const matchers = [matchNormalFunction, matchMultiReturnTypeFunction, matchBindTypeFunction]; - const result = matchers - .map((matcher) => matcher(functionDefinition, languageSettings)) - .find((result) => result.matched); - if (result?.matched) { - matched = result.matched; - params = result.params; - if ( - Object.keys(result.returnType).length === 1 && - defaultReturnName in result.returnType && - result.returnType?.[defaultReturnName]?.type !== undefined - ) { + + for (const matcher of matchers) { + const result = matcher(functionDefinition, languageSettings); + if (result.matched) { + matched = result.matched; + params = result.params; returnType = result.returnType; + break; } } diff --git a/src/function-params-parser/extractFunctionParamsString.ts b/src/function-params-parser/extractFunctionParamsString.ts new file mode 100644 index 0000000..bc2873f --- /dev/null +++ b/src/function-params-parser/extractFunctionParamsString.ts @@ -0,0 +1,23 @@ +export function extractFunctionParamsString(functionDefinition: string): string { + let bracketCount = 0; + let paramsStartIndex = 0; + let paramsEndIndex = 0; + + for (let i = 0; i < functionDefinition.length; i++) { + const char = functionDefinition[i]; + if (char === '(') { + if (bracketCount === 0) { + paramsStartIndex = i + 1; + } + bracketCount++; + } else if (char === ')') { + bracketCount--; + if (bracketCount === 0) { + paramsEndIndex = i; + break; + } + } + } + + return functionDefinition.slice(paramsStartIndex, paramsEndIndex); +} diff --git a/src/function-params-parser/go-splitParams.ts b/src/function-params-parser/go-splitParams.ts new file mode 100644 index 0000000..55c0f4b --- /dev/null +++ b/src/function-params-parser/go-splitParams.ts @@ -0,0 +1,46 @@ +import { LanguageFunctionCommentSettings } from '@/typings/types'; + +import { ParamsInfo } from './types'; + +export function splitParams( + paramsStr: string, + languageSettings: LanguageFunctionCommentSettings, +): ParamsInfo { + const { defaultParamType = 'any', defaultReturnName = 'default' } = languageSettings; + let bracketCount = 0; + let paramStartIndex = 0; + let defaultCount = 0; + const params: ParamsInfo = {}; + for (let i = 0; i < paramsStr?.length; i++) { + const char = paramsStr[i]; + if (char === '(' || char === '[' || char === '{' || char === '<') { + bracketCount++; + } else if (char === ')' || char === ']' || char === '}' || char === '>') { + bracketCount--; + } else if ( + (char === ',' && bracketCount === 0) || + (i === paramsStr.length - 1 && bracketCount === 0) + ) { + const paramStr = paramsStr + .slice(paramStartIndex, i === paramsStr.length - 1 ? i + 1 : i) + .trim(); + const paramPattern = /^(\w+)?\s*(.*)$/; + const match = paramPattern.exec(paramStr); + if (match) { + let name, type; + if (match[2]) { + name = + match[1] || + (defaultCount > 0 ? `${defaultReturnName}${defaultCount++}` : defaultReturnName); + type = match[2].trim() || defaultParamType; + } else { + name = defaultCount > 0 ? `${defaultReturnName}${defaultCount++}` : defaultReturnName; + type = match[1].trim() || defaultParamType; + } + params[name] = { type, description: '' }; + } + paramStartIndex = i + 1; + } + } + return params; +} diff --git a/src/test/suite/go-functionComment.test.ts b/src/test/suite/go-functionComment.test.ts new file mode 100644 index 0000000..7ea798f --- /dev/null +++ b/src/test/suite/go-functionComment.test.ts @@ -0,0 +1,17 @@ +import { functionCommentTester } from './common/functionCommentTester'; +import { TestInfo } from './types'; + +const testInfo: TestInfo = [ + { + testName: 'go-function', + workspaceName: 'function-comment-for-go', + files: [ + { fileName: 'function-none-params-with-return.go', cursorLine: 0 }, + { fileName: 'function-none-params-without-return.go', cursorLine: 0 }, + { fileName: 'function-with-params-type-with-return.go', cursorLine: 0 }, + { fileName: 'function-with-params-type-without-return.go', cursorLine: 0 }, + ], + }, +]; + +functionCommentTester(testInfo); diff --git a/src/utils/vscode-utils.ts b/src/utils/vscode-utils.ts index ccee7c2..86447ca 100644 --- a/src/utils/vscode-utils.ts +++ b/src/utils/vscode-utils.ts @@ -273,9 +273,22 @@ export function updateBlockCommentState( return isInsideBlockComment; } -export function generateFunctionComment(functionCommentInfo: FunctionCommentInfo): string { +export function generateFunctionComment( + functionCommentInfo: FunctionCommentInfo, + isOrigin: boolean = false, +): string { const { paramsInfo, returnInfo, descriptionInfo } = functionCommentInfo; + if (isOrigin) { + if ( + Object.keys(paramsInfo).length === 0 && + Object.keys(returnInfo).length === 0 && + !descriptionInfo + ) { + return ''; + } + } + let functionComment = '/**\n'; functionComment += ` * @description ${descriptionInfo}\n`;