diff --git a/.cspell.json b/.cspell.json index 67741fc..8c4cc04 100644 --- a/.cspell.json +++ b/.cspell.json @@ -1,6 +1,7 @@ { "words": [ "cout", - "endl" + "endl", + "mathiasfrohlich" ] } diff --git a/.github/workflows/dev-test.yml b/.github/workflows/dev-test.yml index f9bacf4..8609c2f 100644 --- a/.github/workflows/dev-test.yml +++ b/.github/workflows/dev-test.yml @@ -1,6 +1,8 @@ name: Development and Testing on: push: + branches: + - '*' jobs: build: strategy: @@ -25,9 +27,12 @@ jobs: - name: Install dependencies if: steps.cache.outputs.cache-hit != 'true' run: pnpm i --frozen-lockfile --ignore-scripts - - run: xvfb-run -a pnpm test:suite + - run: | + export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket + sudo systemctl start dbus + xvfb-run -a pnpm test:suite:mocha if: runner.os == 'Linux' - - run: pnpm test:suite + - run: pnpm test:suite:mocha if: runner.os != 'Linux' - run: pnpm run test:coverage - run: vsce package --no-dependencies diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..855d5ee --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +sampleWorkspace/ diff --git a/.vscode/launch.json b/.vscode/launch.json index 6e3baa2..c53345c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,21 +5,47 @@ "name": "Extension", "type": "extensionHost", "request": "launch", - "args": ["--disable-extensions", "--extensionDevelopmentPath=${workspaceFolder}"], + "runtimeExecutable": "${execPath}", + "args": [ + "${workspaceRoot}/sampleWorkspace/test.code-workspace", + "--extensionDevelopmentPath=${workspaceFolder}" + ], "outFiles": ["${workspaceFolder}/out/**/*.js"], - "preLaunchTask": "${defaultBuildTask}" + "preLaunchTask": "${defaultBuildTask}", + "sourceMaps": true + }, + { + "name": "Test: e2e", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "testConfiguration": "${workspaceFolder}/.vscode-test-debug.mjs", + "args": [ + "${workspaceFolder}/sampleWorkspace/test.code-workspace", + "--extensionDevelopmentPath=${workspaceFolder}", + ], + "env": { + "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.mocha.json" + }, + "preLaunchTask": "npm: test-compile", + "sourceMaps": true }, { - "name": "Test: All", + "name": "Test: e2e use mocha", "type": "extensionHost", "request": "launch", + "runtimeExecutable": "${execPath}", "args": [ - "--disable-extensions", + "${workspaceFolder}/sampleWorkspace/test.code-workspace", "--extensionDevelopmentPath=${workspaceFolder}", - "--extensionTestsPath=${workspaceFolder}/out/test/testsRunner" + "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" ], + "env": { + "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json" + }, "outFiles": ["${workspaceFolder}/out/test/**/*.js"], - "preLaunchTask": "${defaultBuildTask}" + "preLaunchTask": "npm: test-compile", + "sourceMaps": true }, { "type": "node", diff --git a/CHANGELOG.md b/CHANGELOG.md index cc77102..329aa0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ All notable changes to the "turbo-console-log" extension will be documented in t ## 新增功能 🌱 +- feat: 增加 coffeescript 支持 + +# [3.0.6] + +## 新增功能 🌱 + - feat: 增加几个语言支持 # [3.0.5] diff --git a/README.md b/README.md index 9a117df..226595a 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Properties: - swift - shellscript - lua +- coffeescript ## License diff --git a/package.json b/package.json index 9510a7d..e0891ee 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,10 @@ "name": "turbo-print-log", "displayName": "Turbo Console Log for more language", "description": "选中变量,根据不同语言增加一行变量打印日志", - "version": "3.0.6", + "version": "3.0.7", "publisher": "ygqygq2", "engines": { - "vscode": "^1.85.0" + "vscode": "^1.88.0" }, "icon": "images/icon.png", "categories": [ @@ -153,10 +153,10 @@ "package": "vsce package --no-dependencies", "publish": "vsce publish --no-dependencies", "clean": "rimraf out/", - "test-compile": "npm run clean && tsc -p ./ && npm run compile", - "test": "npm run test-compile && vscode-test", - "test-grep": "vscode-test -f", - "test:suite:mocha": "tsc -p ./ && node out/test/runTests.js", + "test-compile": "npm run clean && tsc -p tsconfig.mocha.json && npm run compile", + "test": "TS_NODE_PROJECT=tsconfig.mocha.json vscode-test", + "test-grep": "TS_NODE_PROJECT=tsconfig.mocha.json vscode-test -f", + "test:suite:mocha": "TS_NODE_PROJECT=tsconfig.mocha.json npm run test-compile && node out/test/runTests.js", "test:suite": "vitest suite --watch=false", "test:unit": "vitest unit --watch=false", "test:coverage": "vitest run --coverage", @@ -174,7 +174,7 @@ "@types/node": "^20.12.7", "@types/sinon": "^17.0.3", "@types/tmp": "^0.2.6", - "@types/vscode": "^1.85.0", + "@types/vscode": "^1.88.0", "@typescript-eslint/eslint-plugin": "^7.7.0", "@typescript-eslint/parser": "^7.7.0", "@vitest/coverage-v8": "^1.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 72a888d..8efa8ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,7 +38,7 @@ devDependencies: specifier: ^0.2.6 version: 0.2.6 '@types/vscode': - specifier: ^1.85.0 + specifier: ^1.88.0 version: 1.88.0 '@typescript-eslint/eslint-plugin': specifier: ^7.7.0 diff --git a/sampleWorkspace/default-settings/.vscode/settings.json b/sampleWorkspace/default-settings/.vscode/settings.json new file mode 100644 index 0000000..efeec38 --- /dev/null +++ b/sampleWorkspace/default-settings/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "turboConsoleLog.wrapLogMessage": false, + "turboConsoleLog.logMessagePrefix": "🚀", + "turboConsoleLog.logMessageSuffix": ":", + "turboConsoleLog.includeFileNameAndLineNum": false, + "turboConsoleLog.addSemicolonInTheEnd": false, + "turboConsoleLog.insertEmptyLineBeforeLogMessage": true, + "turboConsoleLog.insertEmptyLineAfterLogMessage": false, + "turboConsoleLog.delimiterInsideMessage": "~", + "turboConsoleLog.quote": "\"" +} diff --git a/sampleWorkspace/default-settings/no-print-log.coffee b/sampleWorkspace/default-settings/no-print-log.coffee new file mode 100644 index 0000000..3e04d37 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.coffee @@ -0,0 +1 @@ +a = "a" diff --git a/sampleWorkspace/default-settings/no-print-log.cpp b/sampleWorkspace/default-settings/no-print-log.cpp new file mode 100644 index 0000000..4dcbd5e --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.cpp @@ -0,0 +1 @@ +std::string a = "a"; diff --git a/sampleWorkspace/default-settings/no-print-log.cs b/sampleWorkspace/default-settings/no-print-log.cs new file mode 100644 index 0000000..d705c6b --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.cs @@ -0,0 +1 @@ +string a = "a"; diff --git a/sampleWorkspace/default-settings/no-print-log.go b/sampleWorkspace/default-settings/no-print-log.go new file mode 100644 index 0000000..e1933d5 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.go @@ -0,0 +1 @@ +a := "a" diff --git a/sampleWorkspace/default-settings/no-print-log.java b/sampleWorkspace/default-settings/no-print-log.java new file mode 100644 index 0000000..d141744 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.java @@ -0,0 +1 @@ +String a = "a"; diff --git a/sampleWorkspace/default-settings/no-print-log.js b/sampleWorkspace/default-settings/no-print-log.js new file mode 100644 index 0000000..25b4331 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.js @@ -0,0 +1 @@ +const a = 'a'; diff --git a/sampleWorkspace/default-settings/no-print-log.kt b/sampleWorkspace/default-settings/no-print-log.kt new file mode 100644 index 0000000..baf747f --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.kt @@ -0,0 +1 @@ +val a = "a" diff --git a/sampleWorkspace/default-settings/no-print-log.lua b/sampleWorkspace/default-settings/no-print-log.lua new file mode 100644 index 0000000..7288b43 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.lua @@ -0,0 +1 @@ +local a = "a" diff --git a/sampleWorkspace/default-settings/no-print-log.php b/sampleWorkspace/default-settings/no-print-log.php new file mode 100644 index 0000000..39002a0 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.php @@ -0,0 +1 @@ +$a = "a"; diff --git a/sampleWorkspace/default-settings/no-print-log.pl b/sampleWorkspace/default-settings/no-print-log.pl new file mode 100644 index 0000000..17afec1 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.pl @@ -0,0 +1 @@ +my $a = "a"; diff --git a/sampleWorkspace/default-settings/no-print-log.py b/sampleWorkspace/default-settings/no-print-log.py new file mode 100644 index 0000000..3e04d37 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.py @@ -0,0 +1 @@ +a = "a" diff --git a/sampleWorkspace/default-settings/no-print-log.rb b/sampleWorkspace/default-settings/no-print-log.rb new file mode 100644 index 0000000..3e04d37 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.rb @@ -0,0 +1 @@ +a = "a" diff --git a/sampleWorkspace/default-settings/no-print-log.result.coffee b/sampleWorkspace/default-settings/no-print-log.result.coffee new file mode 100644 index 0000000..c928c69 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.coffee @@ -0,0 +1,2 @@ +a = "a" +console.log "🚀 ~ file: no-print-log.copy.coffee:2 ~ a:" + " " + a diff --git a/sampleWorkspace/default-settings/no-print-log.result.cpp b/sampleWorkspace/default-settings/no-print-log.result.cpp new file mode 100644 index 0000000..289ab22 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.cpp @@ -0,0 +1,2 @@ +std::string a = "a"; +std::cout << "🚀 ~ file: no-print-log.copy.cpp:2 ~ a:" << " " << a << std::endl; diff --git a/sampleWorkspace/default-settings/no-print-log.result.cs b/sampleWorkspace/default-settings/no-print-log.result.cs new file mode 100644 index 0000000..1121759 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.cs @@ -0,0 +1,2 @@ +string a = "a"; +Console.WriteLine("🚀 ~ file: no-print-log.copy.cs:2 ~ a:" + " " + a); diff --git a/sampleWorkspace/default-settings/no-print-log.result.go b/sampleWorkspace/default-settings/no-print-log.result.go new file mode 100644 index 0000000..54ddcb4 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.go @@ -0,0 +1,2 @@ +a := "a" +fmt.Println("🚀 ~ file: no-print-log.copy.go:2 ~ a:", a) diff --git a/sampleWorkspace/default-settings/no-print-log.result.java b/sampleWorkspace/default-settings/no-print-log.result.java new file mode 100644 index 0000000..c08ae64 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.java @@ -0,0 +1,2 @@ +String a = "a"; +System.out.println("🚀 ~ file: no-print-log.copy.java:2 ~ a:" + " " + a); diff --git a/sampleWorkspace/default-settings/no-print-log.result.js b/sampleWorkspace/default-settings/no-print-log.result.js new file mode 100644 index 0000000..0886ff3 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.js @@ -0,0 +1,2 @@ +const a = 'a'; +console.log("🚀 ~ file: no-print-log.copy.js:2 ~ a:", a) diff --git a/sampleWorkspace/default-settings/no-print-log.result.kt b/sampleWorkspace/default-settings/no-print-log.result.kt new file mode 100644 index 0000000..1bcd3f7 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.kt @@ -0,0 +1,2 @@ +val a = "a" +println("🚀 ~ file: no-print-log.copy.kt:2 ~ a:" + " " + a) diff --git a/sampleWorkspace/default-settings/no-print-log.result.lua b/sampleWorkspace/default-settings/no-print-log.result.lua new file mode 100644 index 0000000..bbb714a --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.lua @@ -0,0 +1,2 @@ +local a = "a" +print("🚀 ~ file: no-print-log.copy.lua:2 ~ a:", a) diff --git a/sampleWorkspace/default-settings/no-print-log.result.php b/sampleWorkspace/default-settings/no-print-log.result.php new file mode 100644 index 0000000..6e46b76 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.php @@ -0,0 +1,2 @@ +$a = "a"; +echo "🚀 ~ file: no-print-log.result.php:2 ~ \$a:" . " " . $a; diff --git a/sampleWorkspace/default-settings/no-print-log.result.pl b/sampleWorkspace/default-settings/no-print-log.result.pl new file mode 100644 index 0000000..b0f7e62 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.pl @@ -0,0 +1,2 @@ +my $a = "a"; +print "🚀 ~ file: no-print-log.copy.pl:2 ~ \$a:" . " " . $a; diff --git a/sampleWorkspace/default-settings/no-print-log.result.py b/sampleWorkspace/default-settings/no-print-log.result.py new file mode 100644 index 0000000..ffdffd8 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.py @@ -0,0 +1,2 @@ +a = "a" +print("🚀 ~ file: no-print-log.copy.py:2 ~ a:", a) diff --git a/sampleWorkspace/default-settings/no-print-log.result.rb b/sampleWorkspace/default-settings/no-print-log.result.rb new file mode 100644 index 0000000..4a1d9cd --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.rb @@ -0,0 +1,2 @@ +a = "a" +puts "🚀 ~ file: no-print-log.copy.rb:2 ~ a:" + " " + a diff --git a/sampleWorkspace/default-settings/no-print-log.result.rs b/sampleWorkspace/default-settings/no-print-log.result.rs new file mode 100644 index 0000000..e3dc1a7 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.rs @@ -0,0 +1,2 @@ +let a = "a"; +println!("🚀 ~ file: no-print-log.copy.rs:2 ~ a: {}", a); diff --git a/sampleWorkspace/default-settings/no-print-log.result.scala b/sampleWorkspace/default-settings/no-print-log.result.scala new file mode 100644 index 0000000..f44b88d --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.scala @@ -0,0 +1,2 @@ +val a = "a" +println("🚀 ~ file: no-print-log.copy.scala:2 ~ a: " + " " + a) diff --git a/sampleWorkspace/default-settings/no-print-log.result.sh b/sampleWorkspace/default-settings/no-print-log.result.sh new file mode 100644 index 0000000..abf654a --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.sh @@ -0,0 +1,2 @@ +a="a" +echo "🚀 ~ file: no-print-log.copy.sh:2 ~ a:" ${a} diff --git a/sampleWorkspace/default-settings/no-print-log.result.swift b/sampleWorkspace/default-settings/no-print-log.result.swift new file mode 100644 index 0000000..8b779de --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.swift @@ -0,0 +1,2 @@ +var a = "a" +print("🚀 ~ file: no-print-log.copy.swift:2 ~ a:", a) diff --git a/sampleWorkspace/default-settings/no-print-log.result.ts b/sampleWorkspace/default-settings/no-print-log.result.ts new file mode 100644 index 0000000..515a3d7 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.result.ts @@ -0,0 +1,2 @@ +const a = 'a'; +console.log("🚀 ~ file: no-print-log.copy.ts:2 ~ a:", a) diff --git a/sampleWorkspace/default-settings/no-print-log.rs b/sampleWorkspace/default-settings/no-print-log.rs new file mode 100644 index 0000000..e02d7ac --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.rs @@ -0,0 +1 @@ +let a = "a"; diff --git a/sampleWorkspace/default-settings/no-print-log.scala b/sampleWorkspace/default-settings/no-print-log.scala new file mode 100644 index 0000000..baf747f --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.scala @@ -0,0 +1 @@ +val a = "a" diff --git a/sampleWorkspace/default-settings/no-print-log.sh b/sampleWorkspace/default-settings/no-print-log.sh new file mode 100644 index 0000000..2f9a873 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.sh @@ -0,0 +1 @@ +a="a" diff --git a/sampleWorkspace/default-settings/no-print-log.swift b/sampleWorkspace/default-settings/no-print-log.swift new file mode 100644 index 0000000..0550dee --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.swift @@ -0,0 +1 @@ +var a = "a" diff --git a/sampleWorkspace/default-settings/no-print-log.ts b/sampleWorkspace/default-settings/no-print-log.ts new file mode 100644 index 0000000..25b4331 --- /dev/null +++ b/sampleWorkspace/default-settings/no-print-log.ts @@ -0,0 +1 @@ +const a = 'a'; diff --git a/sampleWorkspace/test.code-workspace b/sampleWorkspace/test.code-workspace index 86129ad..e981719 100644 --- a/sampleWorkspace/test.code-workspace +++ b/sampleWorkspace/test.code-workspace @@ -1,10 +1,10 @@ { "folders": [ - { "path": "file-header" }, - { "path": "file-header-project" }, - { "path": "function-comment-for-ts" }, - { "path": "function-comment-for-go" }, + { "path": "default-settings" }, { "path": "workspace" }, ], - "settings": {}, + "settings": { + "mathiasfrohlich.kotlin": true, + "scala-lang.scala": true + } } diff --git a/sampleWorkspace/.vscode/setttings.json b/sampleWorkspace/workspace/.vscode/setttings.json similarity index 100% rename from sampleWorkspace/.vscode/setttings.json rename to sampleWorkspace/workspace/.vscode/setttings.json diff --git a/src/commands/commentAllLogMessages.ts b/src/commands/commentAllLogMessages.ts index a6c9302..683fcfb 100644 --- a/src/commands/commentAllLogMessages.ts +++ b/src/commands/commentAllLogMessages.ts @@ -33,7 +33,7 @@ export function commentAllLogMessagesCommand(): Command { const document: vscode.TextDocument = editor.document; // 检测所有log消息 - const logMessages: Message[] = debugMessage.detectAll( + const logMessages: Message[] = debugMessage.detectAllDebugLine( document, logFunctionToUse(), logMessagePrefix, diff --git a/src/commands/deleteAllLogMessages.ts b/src/commands/deleteAllLogMessages.ts index 962c45e..4ca036d 100644 --- a/src/commands/deleteAllLogMessages.ts +++ b/src/commands/deleteAllLogMessages.ts @@ -27,7 +27,7 @@ export function deleteAllLogMessagesCommand(): Command { const document: vscode.TextDocument = editor.document; // 检测所有日志消息 const logFunctionByLanguageId = debugMessage?.getLanguageProcessor().getLogFunction(logFunction); - const logMessages: Message[] = debugMessage.detectAll( + const logMessages: Message[] = debugMessage.detectAllDebugLine( document, logFunctionByLanguageId, logMessagePrefix, diff --git a/src/commands/displayLogMessage.ts b/src/commands/displayLogMessage.ts index 1a8d308..c095748 100644 --- a/src/commands/displayLogMessage.ts +++ b/src/commands/displayLogMessage.ts @@ -4,7 +4,6 @@ import { logger } from '@/extension'; import { instanceDebugMessage } from '@/utils/instanceDebugMessage'; import { Command, ExtensionProperties } from '../typings'; -import { getTabSize } from '../utils/getTabSize'; // 插入调试日志/更新调试日志行号 export function displayLogMessageCommand(): Command { @@ -24,8 +23,6 @@ export function displayLogMessageCommand(): Command { return; } const { debugMessage } = instanceDebugMessage(editor); - // 获取tab大小 - const tabSize: number | string = getTabSize(editor.options.tabSize); // 获取文档 const document: vscode.TextDocument = editor.document; // 遍历当前选择的范围 @@ -34,13 +31,22 @@ export function displayLogMessageCommand(): Command { const selection: vscode.Selection = editor.selections[index]; // 获取当前选择文本 - // if rangeUnderCursor is undefined, `document.getText(undefined)` will return the entire file. - // 如果rangeUnderCursor为undefined,则返回整个文档 const selectedVar = (selection && document.getText(selection)) || (() => { // 获取当前光标所在单词范围 - const rangeUnderCursor = document.getWordRangeAtPosition(selection.active); + let rangeUnderCursor = document.getWordRangeAtPosition(selection.active); + if (!rangeUnderCursor) { + // 如果没有找到匹配的单词,那么向后查找,直到找到一个空格或引号 + let position = selection.active; + while (position.character < document.lineAt(position.line).text.length) { + position = position.translate(0, 1); + rangeUnderCursor = document.getWordRangeAtPosition(position, /\$\w+|\w+/); + if (rangeUnderCursor) { + break; + } + } + } return (rangeUnderCursor && document.getText(rangeUnderCursor)) || ''; })(); // 获取当前光标所在行 @@ -51,12 +57,11 @@ export function displayLogMessageCommand(): Command { logger.info('Insert debug log'); await editor.edit((editBuilder) => { // 调用debugMessage.insertMessage函数 - debugMessage.insertMessage( + debugMessage.generateAndInsertDebugMessage( editBuilder, document, selectedVar, lineOfSelectedVar, - tabSize, extensionProperties, ); }); diff --git a/src/commands/uncommentAllLogMessages.ts b/src/commands/uncommentAllLogMessages.ts index 182bd99..436af88 100644 --- a/src/commands/uncommentAllLogMessages.ts +++ b/src/commands/uncommentAllLogMessages.ts @@ -21,7 +21,7 @@ export function uncommentAllLogMessagesCommand(): Command { // 检测所有日志消息 const logFunctionByLanguageId = debugMessage?.getLanguageProcessor().getLogFunction(logFunction); - const logMessages: Message[] = debugMessage.detectAll( + const logMessages: Message[] = debugMessage.detectAllDebugLine( document, logFunctionByLanguageId, logMessagePrefix, diff --git a/src/commands/updateLineNumAllLogMessages.ts b/src/commands/updateLineNumAllLogMessages.ts index 3db3721..eac070a 100644 --- a/src/commands/updateLineNumAllLogMessages.ts +++ b/src/commands/updateLineNumAllLogMessages.ts @@ -30,7 +30,7 @@ export function updateLineNumAllLogMessagesCommand(): Command { // 检测所有日志消息 const logFunctionByLanguageId = debugMessage?.getLanguageProcessor().getLogFunction(logFunction); - const logMessages: Message[] = debugMessage.detectAll( + const logMessages: Message[] = debugMessage.detectAllDebugLine( document, logFunctionByLanguageId, logMessagePrefix, diff --git a/src/debug-message/DebugMessage.ts b/src/debug-message/DebugMessage.ts index 474fba0..f8e9dfb 100644 --- a/src/debug-message/DebugMessage.ts +++ b/src/debug-message/DebugMessage.ts @@ -17,17 +17,16 @@ export abstract class DebugMessage { } // 返回消息 - abstract insertMessage( + abstract generateAndInsertDebugMessage( textEditor: TextEditorEdit, document: TextDocument, selectedVar: string, lineOfSelectedVar: number, - tabSize: number, extensionProperties: ExtensionProperties, ): void; // 检测消息 - abstract detectAll( + abstract detectAllDebugLine( document: TextDocument, logFunctionByLanguageId: string, logMessagePrefix: string, diff --git a/src/debug-message/GeneralDebugMessage.ts b/src/debug-message/GeneralDebugMessage.ts index 54cc905..619535a 100644 --- a/src/debug-message/GeneralDebugMessage.ts +++ b/src/debug-message/GeneralDebugMessage.ts @@ -13,13 +13,13 @@ export class GeneralDebugMessage extends DebugMessage { super(languageProcessor); } - // 返回行 - public line(selectionLine: number): number { + // 返回插入行 + public getInsertLine(selectionLine: number): number { return selectionLine + 1; } - // 返回消息前导空格 - public spacesBeforeLogMsg(document: TextDocument, selectedVarLine: number, logMsgLine: number): string { + // 返回消息缩进空格 + public getSpacesBeforeLogMsg(document: TextDocument, selectedVarLine: number, logMsgLine: number): string { const selectedVarTextLine = document.lineAt(selectedVarLine); const selectedVarTextLineFirstNonWhitespaceCharacterIndex = selectedVarTextLine.firstNonWhitespaceCharacterIndex; const spacesBeforeSelectedVarLine = selectedVarTextLine.text @@ -40,11 +40,11 @@ export class GeneralDebugMessage extends DebugMessage { return spacesBeforeSelectedVarLine; } - private baseDebuggingMsg( + private insertDebugMessage( document: TextDocument, textEditor: TextEditorEdit, lineOfLogMsg: number, - debuggingMsg: string, + debugMsgLineContent: string, insertEmptyLineBeforeLogMessage: ExtensionProperties['insertEmptyLineBeforeLogMessage'], insertEmptyLineAfterLogMessage: ExtensionProperties['insertEmptyLineAfterLogMessage'], ): void { @@ -53,42 +53,38 @@ export class GeneralDebugMessage extends DebugMessage { new Position(lineOfLogMsg >= document.lineCount ? document.lineCount : lineOfLogMsg, 0), `${insertEmptyLineBeforeLogMessage ? '\n' : ''}${ lineOfLogMsg === document.lineCount ? '\n' : '' - }${debuggingMsg}\n${insertEmptyLineAfterLogMessage ? '\n' : ''}`, + }${debugMsgLineContent}\n${insertEmptyLineAfterLogMessage ? '\n' : ''}`, ); } // 构造调试消息 - private constructDebuggingMsg( + private generateDebugLineContent( extensionProperties: ExtensionProperties, - debuggingMsgContent: string, + debugMsgContent: string, spacesBeforeMsg: string, ): string { const { logMessagePrefix, quote, addSemicolonInTheEnd, wrapLogMessage } = extensionProperties; - const logStatement = `${this.getLanguageProcessor()?.getPrintString()}${quote}${logMessagePrefix} ${'-'.repeat(debuggingMsgContent.length - 16)}${logMessagePrefix}${quote}`; + // 构造日志语句 + const logStatement = `${this.getLanguageProcessor()?.getPrintString()}${quote}${logMessagePrefix} ${'-'.repeat(debugMsgContent.length - 16)}${logMessagePrefix}${quote}`; + // 根据是否需要在末尾添加分号来构造包装消息 const wrappingMsg = `${logStatement}${addSemicolonInTheEnd ? ';' : ''}`; - const debuggingMsg: string = wrapLogMessage - ? `${spacesBeforeMsg}${wrappingMsg}\n${spacesBeforeMsg}${debuggingMsgContent}\n${spacesBeforeMsg}${wrappingMsg}` - : `${spacesBeforeMsg}${debuggingMsgContent}`; - return debuggingMsg; + // 根据是否需要包装日志消息来构造调试消息 + const debugMsg: string = wrapLogMessage + ? `${spacesBeforeMsg}${wrappingMsg}\n${spacesBeforeMsg}${debugMsgContent}\n${spacesBeforeMsg}${wrappingMsg}` + : `${spacesBeforeMsg}${debugMsgContent}`; + + return debugMsg; } // 构造调试信息内容 - private constructDebuggingMsgContent( + private generateDebugMessage( document: TextDocument, selectedVar: string, - lineOfSelectedVar: number, lineOfLogMsg: number, extensionProperties: Omit, ): string { - // 获取文件名 - const fileName = document.fileName.includes('/') - ? document.fileName.split('/')[document.fileName.split('/').length - 1] - : document.fileName.split('\\')[document.fileName.split('\\').length - 1]; - // 判断是否添加分号 - const semicolon: string = extensionProperties.addSemicolonInTheEnd ? ';' : ''; - // 构建调试信息 - lineOfLogMsg + (extensionProperties.insertEmptyLineBeforeLogMessage ? 2 : 1); const { + addSemicolonInTheEnd, logMessagePrefix, logFunction, quote, @@ -97,61 +93,67 @@ export class GeneralDebugMessage extends DebugMessage { insertEmptyLineBeforeLogMessage, logMessageSuffix, } = extensionProperties; - const logFunctionByLanguageId = this.getLanguageProcessor()?.getLogFunction(logFunction); - const content = `${quote}${logMessagePrefix}${ + + // 获取文件名 + const fileName = document.fileName.includes('/') + ? document.fileName.split('/')[document.fileName.split('/').length - 1] + : document.fileName.split('\\')[document.fileName.split('\\').length - 1]; + // 判断是否添加分号 + const semicolon: string = addSemicolonInTheEnd ? ';' : ''; + // 语言处理器 + const lp = this.getLanguageProcessor(); + // 日志中的行号,如果需要在消息前添加空行,则行号加 2,否则加 1 + lineOfLogMsg = lineOfLogMsg + (insertEmptyLineBeforeLogMessage ? 2 : 1); + // 获取日志输出函数 + const logFunctionByLanguageId = lp?.getLogFunction(logFunction) || ''; + // 处理 logMessagePrefix + const prefix = logMessagePrefix.length !== 0 && logMessagePrefix !== `${delimiterInsideMessage} ` ? ` ${delimiterInsideMessage} ` - : '' - }${ - includeFileNameAndLineNum - ? `file: ${fileName}:${lineOfLogMsg + (insertEmptyLineBeforeLogMessage ? 2 : 1)} ${delimiterInsideMessage} ` - : '' - }${selectedVar}${logMessageSuffix}${quote}${this.getLanguageProcessor()?.getConcatenatedString()}${this.getLanguageProcessor()?.variableToString(selectedVar)}`; - if (!logFunctionByLanguageId) { - return this.getLanguageProcessor()?.getPrintStatement(content, '', semicolon); - } - return this.getLanguageProcessor()?.getPrintStatement(content, logFunctionByLanguageId, semicolon); + : ''; + // 处理 fileNameAndLineNum + const fileNameAndLineNum = includeFileNameAndLineNum + ? `file: ${fileName}:${lineOfLogMsg} ${delimiterInsideMessage} ` + : ''; + // 处理 Rust 特殊情况 + const rustSpecial = lp?.getLanguageId() === 'rust' ? ' {}' : ''; + // 构建 content + const content = `${quote}${logMessagePrefix}${prefix}${fileNameAndLineNum}${selectedVar}${logMessageSuffix}${rustSpecial}${quote}${lp?.getConcatenatedString()}${lp?.variableToString(selectedVar)}`; + return lp?.getPrintStatement(content, logFunctionByLanguageId, semicolon); } - /** - * 生成调试信息并将其添加到文档中 - * - * @param {TextEditorEdit} textEditor - 文本编辑器编辑对象 - * @param {TextDocument} document - 文本文档对象 - * @param {string} selectedVar - 选中的变量 - * @param {number} lineOfSelectedVar - 选中变量所在行号 - * @param {number} tabSize - 制表符大小 - * @param {ExtensionProperties} extensionProperties - 扩展属性 - * @returns {void} - */ - public insertMessage( + // 生成调试信息并将其添加到文档中 + public generateAndInsertDebugMessage( textEditor: TextEditorEdit, document: TextDocument, selectedVar: string, lineOfSelectedVar: number, - tabSize: number, extensionProperties: ExtensionProperties, ): void { - const lineOfLogMsg: number = this.line(lineOfSelectedVar); - const spacesBeforeMsg: string = this.spacesBeforeLogMsg(document, lineOfSelectedVar, lineOfLogMsg); - // 构造调试信息内容 - const debuggingMsgContent: string = this.constructDebuggingMsgContent( + // 日志插入行 + const lineOfLogMsg: number = this.getInsertLine(lineOfSelectedVar); + // 日志插入缩进空格 + const spacesBeforeMsg: string = this.getSpacesBeforeLogMsg(document, lineOfSelectedVar, lineOfLogMsg); + // 生成调试信息内容 + const debugMsgContent: string = this.generateDebugMessage( document, selectedVar, - lineOfSelectedVar, lineOfLogMsg, omit(extensionProperties, ['wrapLogMessage', 'insertEmptyLineAfterLogMessage']), ); - // 构造调试信息 - const debuggingMsg: string = this.constructDebuggingMsg(extensionProperties, debuggingMsgContent, spacesBeforeMsg); - // 获取选中变量的行 - // const selectedVarLine = document.lineAt(lineOfSelectedVar); - // 添加基础调试信息 - this.baseDebuggingMsg( + // 生成调试信息的一行内容,包含空格缩进 + const debugMsgLineContent: string = this.generateDebugLineContent( + extensionProperties, + debugMsgContent, + spacesBeforeMsg, + ); + + // 日志插入文件 + this.insertDebugMessage( document, textEditor, lineOfLogMsg, - debuggingMsg, + debugMsgLineContent, extensionProperties.insertEmptyLineBeforeLogMessage, extensionProperties.insertEmptyLineAfterLogMessage, ); @@ -162,7 +164,7 @@ export class GeneralDebugMessage extends DebugMessage { } // 检测文档中的所有消息 - public detectAll = ( + public detectAllDebugLine = ( document: TextDocument, logFunctionByLanguageId: string, logMessagePrefix: string, @@ -184,7 +186,7 @@ export class GeneralDebugMessage extends DebugMessage { lines: [], }; // 获取消息前导空格 - logMessage.spaces = this.spacesBeforeLogMsg(document, i, i); + logMessage.spaces = this.getSpacesBeforeLogMsg(document, i, i); // 获取关闭括号行号 const closedParenthesisLine = closingContextLine(document, i, BracketType.PARENTHESIS); // 保存多行文本到一起,用于后面匹配 diff --git a/src/debug-message/LanguageProcessor.ts b/src/debug-message/LanguageProcessor.ts index 0121bd6..4b1b8ba 100644 --- a/src/debug-message/LanguageProcessor.ts +++ b/src/debug-message/LanguageProcessor.ts @@ -1,9 +1,16 @@ import { ExtensionProperties } from '@/typings/extension/types'; +import { processVariableName } from '@/utils/utils'; import { LanguageProcessor } from './types'; export class GeneralLanguageProcessor implements LanguageProcessor { - constructor(private readonly languageId: string) {} + constructor(private readonly languageId: string) { + this.languageId = languageId; + } + + public getLanguageId(): string { + return this.languageId; + } // 根据 languageId 获取对应的 logFunction public getLogFunction(logFunction: ExtensionProperties['logFunction']): string { @@ -17,6 +24,7 @@ export class GeneralLanguageProcessor implements LanguageProcessor { switch (this.languageId) { case 'javascript': case 'typescript': + case 'coffeescript': return 'console.log'; case 'python': return 'print'; @@ -37,7 +45,7 @@ export class GeneralLanguageProcessor implements LanguageProcessor { case 'perl': case 'lua': return 'print'; - case 'c++': + case 'cpp': return 'std::cout'; case 'rust': return 'println!'; @@ -49,8 +57,14 @@ export class GeneralLanguageProcessor implements LanguageProcessor { } } - public getPrintStatement(variableName: string, logFunctionByLanguageId?: string, semicolon: string = ''): string { + public getPrintStatement( + variableName: string, + logFunctionByLanguageId?: string, + quote: string = '"', + semicolon: string = '', + ): string { const printFunction = logFunctionByLanguageId || this.getPrintString(); + const isSingleQuote = quote === "'"; switch (this.languageId) { case 'javascript': case 'typescript': @@ -66,44 +80,27 @@ export class GeneralLanguageProcessor implements LanguageProcessor { case 'lua': return `${printFunction}(${variableName})`; case 'php': { - const count = (variableName.match(/\$/g) || []).length; // 统计字符串中的 $ 符号个数 - let escapedVariableName = variableName; - if (count >= 2 && count % 2 === 0) { - const halfCount = count / 2; - let escapedCount = 0; - escapedVariableName = variableName.replace(/\$/g, (match) => { - if (escapedCount < halfCount) { - escapedCount++; - return '\\$'; - } - return match; - }); + if (!isSingleQuote) { + const escapedVariableName = processVariableName(variableName); + return `${printFunction} ${escapedVariableName};`; } - return `${printFunction} ${escapedVariableName};`; + return `${printFunction} ${variableName};`; } case 'perl': { - const count = (variableName.match(/\$/g) || []).length; // 统计字符串中的 $ 符号个数 - let escapedVariableName = variableName; - if (count >= 2 && count % 2 === 0) { - const halfCount = count / 2; - let escapedCount = 0; - escapedVariableName = variableName.replace(/\$/g, (match) => { - if (escapedCount < halfCount) { - escapedCount++; - return '\\$'; - } - return match; - }); + if (!isSingleQuote) { + const escapedVariableName = processVariableName(variableName); + return `${printFunction} ${escapedVariableName};\n`; } - return `${printFunction} ${escapedVariableName};\n`; + return `${printFunction} ${variableName};`; } case 'ruby': case 'shellscript': + case 'coffeescript': return `${printFunction} ${variableName}`; - case 'c++': + case 'cpp': return `${printFunction} << ${variableName} << std::endl;`; case 'rust': - return `${printFunction}!("{}", ${variableName});`; + return `${printFunction}(${variableName});`; default: return `${printFunction}(${variableName})`; } @@ -113,20 +110,21 @@ export class GeneralLanguageProcessor implements LanguageProcessor { switch (this.languageId) { case 'javascript': case 'typescript': - case 'php': case 'csharp': - case 'c++': + case 'cpp': case 'rust': case 'kotlin': case 'scala': + case 'java': + case 'go': + case 'swift': return '//'; case 'python': case 'ruby': case 'perl': - case 'go': - case 'java': - case 'swift': case 'shellscript': + case 'coffeescript': + case 'php': return '#'; case 'lua': return '--'; @@ -143,22 +141,22 @@ export class GeneralLanguageProcessor implements LanguageProcessor { case 'swift': case 'python': case 'rust': - case 'kotlin': - case 'scala': case 'lua': return ', '; case 'java': + case 'kotlin': + case 'scala': case 'csharp': - return ' + '; + case 'coffeescript': case 'ruby': + return ' + " " + '; case 'shellscript': return ' '; case 'perl': - return ' . " " . '; case 'php': - return ' . '; - case 'c++': - return ' << '; + return ' . " " . '; + case 'cpp': + return ' << " " << '; default: return ', '; } @@ -174,11 +172,12 @@ export class GeneralLanguageProcessor implements LanguageProcessor { case 'python': case 'swift': case 'ruby': - case 'c++': + case 'cpp': case 'rust': case 'kotlin': case 'scala': case 'lua': + case 'coffeescript': return `${variableName}`; case 'perl': case 'php': diff --git a/src/debug-message/types.ts b/src/debug-message/types.ts index 7b13507..c6a0b68 100644 --- a/src/debug-message/types.ts +++ b/src/debug-message/types.ts @@ -1,6 +1,7 @@ import { ExtensionProperties } from '@/typings'; export interface LanguageProcessor { + getLanguageId(): string; getLogFunction(logFunction: ExtensionProperties['logFunction']): string; getPrintString(): string; getPrintStatement(variableName: string, logFunctionByLanguageId?: string, semicolon?: string): string; diff --git a/src/test/runTests.ts b/src/test/runTests.ts index 32ddbdd..ac3936d 100644 --- a/src/test/runTests.ts +++ b/src/test/runTests.ts @@ -1,10 +1,20 @@ -import { runTests } from '@vscode/test-electron'; +import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath, runTests } from '@vscode/test-electron'; +import * as cp from 'child_process'; import path from 'path'; -import { createSettings } from './ready'; - async function main() { try { + const vscodeExecutablePath = await downloadAndUnzipVSCode('1.88.0'); + const [cliPath, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); + + const extensions = ['mathiasfrohlich.kotlin', 'scala-lang.scala']; + const installExtensionsArgs = extensions.map((extension) => ['--install-extension', extension]).flat(); + + cp.spawnSync(cliPath, [...args, ...installExtensionsArgs], { + encoding: 'utf-8', + stdio: 'inherit', + }); + // The folder containing the Extension Manifest package.json // Passed to `--extensionDevelopmentPath` const extensionDevelopmentPath = path.resolve(__dirname, '../../'); @@ -14,19 +24,15 @@ async function main() { const extensionTestsPath = path.resolve(__dirname, `./suite/index`); const workspacePath = path.resolve('sampleWorkspace', 'test.code-workspace'); - const userDataDirectory = await createSettings(); - // Download VS Code, unzip it and run the integration test await runTests({ - version: '1.88.0', + vscodeExecutablePath, extensionDevelopmentPath, extensionTestsPath, launchArgs: [workspacePath] .concat(['--skip-welcome']) - .concat(['--disable-extensions']) .concat(['--skip-release-notes']) - .concat(['--enable-proposed-api']) - .concat(['--user-data-dir', userDataDirectory]), + .concat(['--enable-proposed-api']), }); } catch (error) { console.error('Failed to run tests'); diff --git a/src/test/suite/common/executeCommandOnFile.ts b/src/test/suite/common/executeCommandOnFile.ts new file mode 100644 index 0000000..9c07cb2 --- /dev/null +++ b/src/test/suite/common/executeCommandOnFile.ts @@ -0,0 +1,94 @@ +import * as fs from 'fs'; +import path from 'path'; +import * as vscode from 'vscode'; + +import { sleep } from '@/utils/utils'; +import { getWorkspaceFolderUriByName } from '@/utils/vscode-utils'; + +import { CursorPosition } from '../types'; + +/** + * execute command on file + * @param commandName command name + * @param workspaceFolderName workspace folder name + * @param srcFileName path relative to base URI (a workspaceFolder's URI) + * @returns source code and resulting code + */ +export async function executeCommandOnFile( + commandName: string, + workspaceFolderName: string, + srcFileName: string, + cursorPosition: CursorPosition, + shouldRetry = false, +) { + const ext = path.extname(srcFileName); + const testFile = srcFileName.replace(ext, `.copy${ext}`); + const workspace = getWorkspaceFolderUriByName(workspaceFolderName); + const srcAbsPath = path.join(workspace.fsPath, srcFileName); + const testAbsPath = path.join(workspace.fsPath, testFile); + + // 复制文件 + fs.copyFileSync(srcAbsPath, testAbsPath); + // 打开文件 + const doc = await vscode.workspace.openTextDocument(testAbsPath); + await vscode.window.showTextDocument(doc); + // 定位光标 + const editor = vscode.window.activeTextEditor; + if (editor) { + const { line, character } = cursorPosition; + const position = new vscode.Position(line, character); + editor.selection = new vscode.Selection(position, position); + } + + // 执行之前获取文件内容 + const originText = doc.getText(); + + try { + console.time(testFile); + const result = await executeCommandWithRetry({ + commandName, + workspaceFolderName, + doc, + originText, + shouldRetry, + }); + console.timeEnd(testFile); + // 关闭文件 + + return result; + } catch (error) { + console.error('Error executing command:', error); + throw error; + } finally { + if (fs.existsSync(testAbsPath)) { + try { + await fs.promises.unlink(testAbsPath); + console.log(`File [${testFile}] deleted successfully`); + } catch (error) { + console.error('Error deleting file:', error); + } + } + } +} + +async function executeCommandWithRetry(options: { + commandName: string; + workspaceFolderName: string; + doc: vscode.TextDocument; + originText: string; + shouldRetry: boolean; +}) { + const { commandName, workspaceFolderName, doc, originText, shouldRetry } = options; + let actual = ''; + let retryCount = 0; + + do { + await vscode.commands.executeCommand(commandName, { workspaceFolderName }); + // 需要等待一段时间才能获取到结果,而且性能低的时候需要更长时间 + await sleep(1000); + actual = doc.getText(); + retryCount++; + } while (shouldRetry && originText === actual && retryCount < 3); + + return { actual, source: originText }; +} diff --git a/src/test/suite/common/printLogTester.ts b/src/test/suite/common/printLogTester.ts new file mode 100644 index 0000000..68cef46 --- /dev/null +++ b/src/test/suite/common/printLogTester.ts @@ -0,0 +1,28 @@ +import assert from 'assert'; +import { describe, it } from 'mocha'; +import path from 'path'; + +import { getText } from '@/utils/vscode-utils'; + +import { TestInfo } from '../types'; +import { executeCommandOnFile } from './executeCommandOnFile'; + +export function printLogTester(testInfo: TestInfo) { + testInfo.forEach((item) => { + const { testName, workspaceName, files } = item; + describe(`Extension Integration Test: add print log for [${testName}]`, function () { + this.timeout(200000); + files.forEach((fileInfo) => { + const { fileName, cursorPosition } = fileInfo; + const ext = path.extname(fileName); + it(`should add print log for [${ext}] in file ${fileName}`, async () => { + const commandName = 'turboConsoleLog.displayLogMessage'; + const resultFileName = fileName.replace(ext, `.result${ext}`); + const { actual } = await executeCommandOnFile(commandName, workspaceName, fileName, cursorPosition, false); + const expected = await getText(workspaceName, resultFileName); + assert.equal(actual, expected); + }); + }); + }); + }); +} diff --git a/src/test/suite/defaultSettings.test.ts b/src/test/suite/defaultSettings.test.ts new file mode 100644 index 0000000..7515d39 --- /dev/null +++ b/src/test/suite/defaultSettings.test.ts @@ -0,0 +1,30 @@ +import { printLogTester } from './common/printLogTester'; +import { TestInfo } from './types'; + +const testInfo: TestInfo = [ + { + testName: 'defaultSettings', + workspaceName: 'default-settings', + files: [ + { fileName: 'no-print-log.coffee', cursorPosition: { line: 0, character: 0 } }, + { fileName: 'no-print-log.cpp', cursorPosition: { line: 0, character: 12 } }, + { fileName: 'no-print-log.cs', cursorPosition: { line: 0, character: 7 } }, + { fileName: 'no-print-log.go', cursorPosition: { line: 0, character: 0 } }, + { fileName: 'no-print-log.java', cursorPosition: { line: 0, character: 7 } }, + { fileName: 'no-print-log.js', cursorPosition: { line: 0, character: 6 } }, + // { fileName: 'no-print-log.kt', cursorPosition: { line: 0, character: 4 } }, + { fileName: 'no-print-log.lua', cursorPosition: { line: 0, character: 6 } }, + // { fileName: 'no-print-log.php', cursorPosition: { line: 0, character: 6 } }, + // { fileName: 'no-print-log.pl', cursorPosition: { line: 0, character: 3 } }, + { fileName: 'no-print-log.py', cursorPosition: { line: 0, character: 0 } }, + { fileName: 'no-print-log.rb', cursorPosition: { line: 0, character: 0 } }, + { fileName: 'no-print-log.rs', cursorPosition: { line: 0, character: 4 } }, + // { fileName: 'no-print-log.scala', cursorPosition: { line: 0, character: 4 } }, + { fileName: 'no-print-log.sh', cursorPosition: { line: 0, character: 0 } }, + { fileName: 'no-print-log.swift', cursorPosition: { line: 0, character: 4 } }, + { fileName: 'no-print-log.ts', cursorPosition: { line: 0, character: 6 } }, + ], + }, +]; + +printLogTester(testInfo); diff --git a/src/test/suite/displayLogMessage.test.ts b/src/test/suite/displayLogMessage.test.ts deleted file mode 100644 index 19c3efd..0000000 --- a/src/test/suite/displayLogMessage.test.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { Position, Range, Selection, TextDocument, TextEditor, TextEditorEdit, window } from 'vscode'; - -import { displayLogMessageCommand } from '@/commands/displayLogMessage'; -import { ExtensionProperties } from '@/typings'; - -vi.mock('vscode'); -vi.mock('@/extension', () => ({ - logger: { - trace: vi.fn(), - debug: vi.fn(), - info: vi.fn(), - warn: vi.fn(), - error: vi.fn(), - }, -})); - -describe('displayLogMessageCommand', () => { - let mockEditor: TextEditor | undefined; - let mockDocument: TextDocument; - let mockSelection: Selection; - let mockSelections: Selection[]; - let mockEditBuilder: TextEditorEdit; - let mockExtensionProperties: ExtensionProperties; - - beforeEach(() => { - mockExtensionProperties = { - wrapLogMessage: false, - logMessagePrefix: '🚀', - logMessageSuffix: ':', - addSemicolonInTheEnd: true, - insertEmptyLineBeforeLogMessage: false, - insertEmptyLineAfterLogMessage: false, - quote: '"', - delimiterInsideMessage: '~', - includeFileNameAndLineNum: true, - logFunction: {}, - }; - - mockDocument = { - getWordRangeAtPosition: vi - .fn() - .mockReturnValue(new Range(new Position(0, 0), new Position(0, 0))) - .mockReturnValueOnce(new Range(new Position(0, 0), new Position(0, 4))), - getText: vi.fn((range: Range): string => { - if (range.isEmpty) { - return ''; // 未选中字符串,返回空字符串 - } - return 'myVar'; - }), - lineAt: vi.fn().mockImplementation((lineNumber: number) => { - return { - text: 'myVar', // 模拟行的文本内容 - firstNonWhitespaceCharacterIndex: 0, // 模拟行的第一个非空格字符的索引 - range: { - start: { line: lineNumber, character: 0 }, // 模拟行的起始位置 - end: { line: lineNumber, character: 10 }, // 模拟行的结束位置 - }, - }; - }), - lineCount: 10, // 模拟文档的行数 - fileName: 'test.js', - } as unknown as TextDocument; - - mockSelection = new Selection(new Position(0, 0), new Position(0, 4)); - mockSelections = [mockSelection]; - - mockEditBuilder = { - insert: vi.fn(), - } as unknown as TextEditorEdit; - - mockEditor = { - document: mockDocument, - selections: mockSelections, - edit: vi.fn((callback) => { - callback(mockEditBuilder); - return Promise.resolve(true); // 返回一个解析为 true 的 Promise - }), - options: { tabSize: 2 }, - } as unknown as TextEditor; - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - it('应该直接返回,当没有活动编辑器时', async () => { - window.activeTextEditor = undefined; - await displayLogMessageCommand().handler(mockExtensionProperties); - expect(mockEditor!.edit).not.toHaveBeenCalled(); - }); - - it('应该返回调用,当选中字符串时', async () => { - window.activeTextEditor = mockEditor; - await displayLogMessageCommand().handler(mockExtensionProperties); - expect(mockEditor!.edit).toHaveBeenCalledTimes(1); - expect(mockEditor!.edit).toHaveBeenCalledWith(expect.any(Function)); - - expect(mockEditBuilder.insert).toHaveBeenCalledTimes(1); - expect(mockEditBuilder.insert).toHaveBeenCalledWith(expect.any(Position), expect.any(String)); - }); - - it('应该插入调试日志,未选中,但光标放在变量名上时', async () => { - const mockSelection = new Selection(new Position(0, 0), new Position(0, 0)); - mockSelections = [mockSelection]; - window.activeTextEditor = { - ...mockEditor, - ...{ - ...mockDocument, - selections: mockSelections, - }, - } as unknown as TextEditor; - - await displayLogMessageCommand().handler(mockExtensionProperties); - expect(mockEditor!.edit).toHaveBeenCalledTimes(1); - expect(mockEditor!.edit).toHaveBeenCalledWith(expect.any(Function)); - expect(mockEditBuilder.insert).toHaveBeenCalledTimes(1); - expect(mockEditBuilder.insert).toHaveBeenCalledWith(expect.any(Position), expect.any(String)); - }); - - it('应该直接返回,当没有选中字符时和光标没有在字符串旁边时', async () => { - mockSelections = []; - window.activeTextEditor = { - ...mockEditor, - ...{ - ...mockDocument, - selections: mockSelections, - }, - } as unknown as TextEditor; - - await displayLogMessageCommand().handler(mockExtensionProperties); - expect(mockEditor!.edit).not.toHaveBeenCalled(); - }); -}); diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts index 21e940c..de07572 100644 --- a/src/test/suite/index.ts +++ b/src/test/suite/index.ts @@ -2,31 +2,34 @@ import { glob } from 'glob'; import Mocha from 'mocha'; import * as path from 'path'; +// 为了解析别名 +require('tsconfig-paths/register'); +require('ts-node/register'); + export async function run() { + const testsRoot = path.resolve(__dirname, '..'); + // 创建 mocha 实例 const mocha = new Mocha({ - ui: 'tdd', + ui: 'bdd', color: true, - timeout: 10000, }); - const testsRoot = path.resolve(__dirname, '.'); - // 获取所有测试文件 const tsFiles = await glob('**/*.test.js', { cwd: testsRoot }); console.log('获取到以下测试文件:'); - console.log('🚀 ~ file: index.ts:18 ~ tsFiles:', tsFiles); + console.log('🚀 ~ file: index.ts:21 ~ tsFiles:', tsFiles); return new Promise((resolve, reject) => { // 添加测试文件 - tsFiles.forEach((file) => { + tsFiles.forEach((file: string) => { mocha.addFile(path.resolve(testsRoot, file)); }); // 运行测试 mocha.run((failures) => { if (failures > 0) { - reject(); + reject(new Error(`${failures} tests failed.`)); } else { resolve(); } diff --git a/src/test/suite/types.ts b/src/test/suite/types.ts new file mode 100644 index 0000000..b48b2ec --- /dev/null +++ b/src/test/suite/types.ts @@ -0,0 +1,13 @@ +export type CursorPosition = { + line: number; + character: number; +}; + +export type TestInfo = { + testName: string; + workspaceName: string; + files: { + fileName: string; + cursorPosition: CursorPosition; + }[]; +}[]; diff --git a/src/test/unit/debug-message/DebugMessage.spec.ts b/src/test/unit/debug-message/DebugMessage.spec.ts index a5f4cd7..48ce6d9 100644 --- a/src/test/unit/debug-message/DebugMessage.spec.ts +++ b/src/test/unit/debug-message/DebugMessage.spec.ts @@ -6,18 +6,17 @@ import { LanguageProcessor } from '@/debug-message/types'; import { ExtensionProperties, Message } from '@/typings/extension/types'; class TestDebugMessage extends DebugMessage { - insertMessage( + generateAndInsertDebugMessage( _textEditor: TextEditorEdit, _document: TextDocument, _selectedVar: string, _lineOfSelectedVar: number, - _tabSize: number, _extensionProperties: ExtensionProperties, ): void { console.log('insertMessage called'); } - detectAll( + detectAllDebugLine( _document: TextDocument, _logFunctionByLanguageId: string, _logMessagePrefix: string, diff --git a/src/test/unit/debug-message/GeneralDebugMessage.spec.ts b/src/test/unit/debug-message/GeneralDebugMessage.spec.ts index fb9f9b4..0259ce2 100644 --- a/src/test/unit/debug-message/GeneralDebugMessage.spec.ts +++ b/src/test/unit/debug-message/GeneralDebugMessage.spec.ts @@ -17,6 +17,7 @@ describe('DebugMessage', () => { beforeEach(() => { languageProcessor = { + getLanguageId: vi.fn().mockReturnValue('javascript'), getSingleLineCommentSymbol: vi.fn().mockReturnValue('//'), getPrintString: vi.fn().mockReturnValue('console.log'), variableToString: vi.fn().mockReturnValue('value'), @@ -32,7 +33,6 @@ describe('DebugMessage', () => { let document: TextDocument; let selectedVar: string; let lineOfSelectedVar: number; - let tabSize: number; let extensionProperties: ExtensionProperties; beforeEach(() => { @@ -49,7 +49,6 @@ describe('DebugMessage', () => { } as unknown as TextDocument; selectedVar = 'value'; lineOfSelectedVar = 5; - tabSize = 2; extensionProperties = { logMessagePrefix: '🚀', quote: "'", @@ -65,7 +64,13 @@ describe('DebugMessage', () => { }); it('应该在指定行插入调试日志', () => { - debugMessage.insertMessage(textEditor, document, selectedVar, lineOfSelectedVar, tabSize, extensionProperties); + debugMessage.generateAndInsertDebugMessage( + textEditor, + document, + selectedVar, + lineOfSelectedVar, + extensionProperties, + ); // 这里增加换行符,不清楚 vscode 是不是默认插入有换行符,本身这里就是 mock expect(textEditor.insert).toHaveBeenCalledWith( @@ -112,7 +117,7 @@ describe('DebugMessage', () => { }); it('应该返回插入的调试日志数组信息', () => { - const result = debugMessage.detectAll( + const result = debugMessage.detectAllDebugLine( document, logFunctionByLanguageId, logMessagePrefix, diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 0000000..7157dfd --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,24 @@ +/** + * Sleep micro second + * @param ms micro second to sleep + */ +export function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +export function processVariableName(variableName: string) { + const count = (variableName.match(/\$/g) || []).length; // 统计字符串中的 $ 符号个数 + let escapedVariableName = variableName; + if (count >= 2 && count % 2 === 0) { + const halfCount = count / 2; + let escapedCount = 0; + escapedVariableName = variableName.replace(/\$/g, (match) => { + if (escapedCount < halfCount) { + escapedCount++; + return '\\$'; + } + return match; + }); + } + return escapedVariableName; +} diff --git a/src/utils/vscode-utils.ts b/src/utils/vscode-utils.ts new file mode 100644 index 0000000..5fdd3e3 --- /dev/null +++ b/src/utils/vscode-utils.ts @@ -0,0 +1,24 @@ +import * as fs from 'fs-extra'; +import path from 'path'; +import * as vscode from 'vscode'; + +/** + * gets the workspace folder by name + * @param workspaceFolderName Workspace folder name + */ +export const getWorkspaceFolderUriByName = (workspaceFolderName: string) => { + const workspaceFolder = vscode.workspace.workspaceFolders!.find((folder) => { + return folder.name === workspaceFolderName; + }); + if (!workspaceFolder) { + throw new Error('Folder not found in workspace. Did you forget to add the test folder to test.code-workspace?'); + } + return workspaceFolder?.uri || ''; +}; + +export async function getText(workspaceFolderName: string, expectedFile: string) { + const base = getWorkspaceFolderUriByName(workspaceFolderName); + const expectedPath = path.join(base.fsPath, expectedFile); + const expected = await fs.readFile(expectedPath, 'utf8'); + return expected; +} diff --git a/tsconfig.suite.json b/tsconfig.mocha.json similarity index 82% rename from tsconfig.suite.json rename to tsconfig.mocha.json index 0fb7e54..4ec0174 100644 --- a/tsconfig.suite.json +++ b/tsconfig.mocha.json @@ -21,9 +21,11 @@ }, "include": [ "./src/**/*.ts", - "./src/**/*.d.ts", + "./src/test/ready.ts", + "./src/test/runTests.ts", + "./src/test/suite/**/*.ts", "./node_modules/vscode/vscode.d.ts", "./node_modules/vscode/lib/*" ], - "exclude": ["node_modules", ".vscode-test", "out"] + "exclude": ["node_modules", ".vscode-test", "out", "./src/test/unit"] }