diff --git a/CHANGELOG.md b/CHANGELOG.md index 5368b53..b05a21a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ All notable version changes will be recorded in this file. *** +### [v3.25.3] revision + +**Improve**: + - `Debug`: Support 'attach' mode for 'one-click' debugging. + +*** + ### [v3.25.2] revision **Improve**: diff --git a/lang/stc.flash.verify.json b/lang/stc.flash.verify.json index 4b42924..400d994 100644 --- a/lang/stc.flash.verify.json +++ b/lang/stc.flash.verify.json @@ -68,7 +68,7 @@ ] }, "oscFreq": { - "markdownDescription": "`[可忽略]` 芯片时钟速度 KHz,**只用于 STC15 系列**", + "markdownDescription": "`[可忽略]` 芯片时钟速度 KHz", "anyOf": [ { "type": "string", diff --git a/package.json b/package.json index 3960fe1..397c048 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "homepage": "https://em-ide.com", "license": "MIT", "description": "A mcu development environment for 8051/AVR/STM8/Cortex-M/MIPS/RISC-V", - "version": "3.25.2", + "version": "3.25.3", "preview": false, "engines": { "vscode": "^1.67.0" @@ -550,6 +550,15 @@ "light": "./res/icon/Run_16x.svg" } }, + { + "command": "eide.debug.start.attach", + "category": "eide", + "title": "%eide.project.debug.start.attach%", + "icon": { + "dark": "./res/icon/Run_blue_16x.svg", + "light": "./res/icon/Run_blue_16x.svg" + } + }, { "command": "eide.refresh.external_tools_index", "category": "eide", @@ -1344,6 +1353,11 @@ "when": "viewItem == SOLUTION && view == cl.eide.view.projects", "group": "2_build@3" }, + { + "command": "eide.debug.start.attach", + "when": "viewItem == SOLUTION && view == cl.eide.view.projects", + "group": "2_build@4" + }, { "command": "eide.project.uploadToDevice", "when": "viewItem == SOLUTION && view == cl.eide.view.projects", diff --git a/package.nls.json b/package.nls.json index d653b08..0872aa0 100644 --- a/package.nls.json +++ b/package.nls.json @@ -32,7 +32,8 @@ "eide.project.modify.files.options": "Show Extra Options Of All Source Files", "eide.project.import.ext.project.src.struct": "Import SourceFile Tree From Other Project", "eide.project.generate_builder_params": "Generate builder.params", - "eide.project.debug.start": "Start Debugging (Cortex-Debug)", + "eide.project.debug.start": "Start Debugging", + "eide.project.debug.start.attach": "Start Debugging (attach)", "eide.prj.menus.main.static-check": "Static Check", "eide.prj.menus.sub.static-check.cppcheck": "Run Cppcheck", diff --git a/package.nls.zh-CN.json b/package.nls.zh-CN.json index 4d62d19..d70f431 100644 --- a/package.nls.zh-CN.json +++ b/package.nls.zh-CN.json @@ -32,7 +32,8 @@ "eide.project.modify.files.options": "查看所有源文件的附加编译参数", "eide.project.import.ext.project.src.struct": "从其他 IDE 的项目中导入源文件树", "eide.project.generate_builder_params": "生成 builder.params", - "eide.project.debug.start": "启动调试(Cortex-Debug)", + "eide.project.debug.start": "启动调试", + "eide.project.debug.start.attach": "启动调试 (附加)", "eide.prj.menus.main.static-check": "静态检查", "eide.prj.menus.sub.static-check.cppcheck": "执行 Cppcheck", diff --git a/src/extension.ts b/src/extension.ts index e9a24ef..5af2fbb 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -133,6 +133,10 @@ export async function activate(context: vscode.ExtensionContext) { startDebugging() .catch(err => GlobalEvent.emit('error', err)); })); + subscriptions.push(vscode.commands.registerCommand('eide.debug.start.attach', () => { + startDebugging(true) + .catch(err => GlobalEvent.emit('error', err)); + })); // internal command // TODO @@ -1911,7 +1915,7 @@ class ExternalDebugConfigProvider implements vscode.DebugConfigurationProvider { provideDebugConfigurations(folder: vscode.WorkspaceFolder | undefined, token?: vscode.CancellationToken): vscode.ProviderResult { - const result: vscode.DebugConfiguration[] = []; + let result: vscode.DebugConfiguration[] = []; if (!folder) return result; @@ -2034,6 +2038,16 @@ class ExternalDebugConfigProvider implements vscode.DebugConfigurationProvider { return dbgCfg; }; + const newAttachDebugCfg = (cfgtocopy: any) => { + const nCfg = JSON.parse(JSON.stringify(cfgtocopy)); + nCfg['name'] += '(attach)'; + nCfg['request'] = 'attach'; + if (nCfg['type'] === 'cortex-debug') { + nCfg['runToEntryPoint'] = undefined; + } + return nCfg; + }; + const fmtOpenocdCfgPath = (type: 'interface' | 'target', path: string) => { let cfgpath = path.startsWith('${workspaceFolder}/') ? path.replace('${workspaceFolder}/', '') @@ -2066,6 +2080,7 @@ class ExternalDebugConfigProvider implements vscode.DebugConfigurationProvider { dbgCfg['serialNumber'] = m[1]; } result.push(dbgCfg); + result.push(newAttachDebugCfg(dbgCfg)); } else if (flashertype == 'OpenOCD') { @@ -2081,6 +2096,7 @@ class ExternalDebugConfigProvider implements vscode.DebugConfigurationProvider { dbgCfg['configFiles'] = ocdCfgs; dbgCfg['serverpath'] = settingManager.getOpenOCDExePath(); result.push(dbgCfg); + result.push(newAttachDebugCfg(dbgCfg)); } else if (flashertype == 'pyOCD') { @@ -2098,13 +2114,17 @@ class ExternalDebugConfigProvider implements vscode.DebugConfigurationProvider { } } if (flasherCfg.otherCmds) - cliArgs.push(flasherCfg.otherCmds); + utility.parseCliArgs(flasherCfg.otherCmds) + .forEach(s => cliArgs.push(s)) if (flasherCfg.speed) { cliArgs.push('-f'); cliArgs.push(flasherCfg.speed); } dbgCfg['serverArgs'] = cliArgs; + // pyocd not support livewatch + dbgCfg['liveWatch']['enabled'] = false; result.push(dbgCfg); + result.push(newAttachDebugCfg(dbgCfg)); } else if (flashertype == 'STLink') { @@ -2145,6 +2165,7 @@ class ExternalDebugConfigProvider implements vscode.DebugConfigurationProvider { dbgCfg['stlinkPath'] = gdbserverPath; dbgCfg['stm32cubeprogrammer'] = cubeProgramerPath; result.push(dbgCfg); + result.push(newAttachDebugCfg(dbgCfg)); } else if (flashertype == 'probe-rs') { @@ -2181,6 +2202,7 @@ class ExternalDebugConfigProvider implements vscode.DebugConfigurationProvider { } } result.push(dbgCfg); + result.push(newAttachDebugCfg(dbgCfg)); } // else if (flashertype == 'STVP') { @@ -2218,13 +2240,13 @@ class ExternalDebugConfigProvider implements vscode.DebugConfigurationProvider { // filter by debugType if (this.debuggerType) - return result.filter(cfg => cfg.type == this.debuggerType); + result = result.filter(cfg => cfg.type == this.debuggerType); return result; } } -async function startDebugging() { +async function startDebugging(attach?: boolean) { const prj = projectExplorer.getActiveProject(); if (!prj) { @@ -2238,9 +2260,17 @@ async function startDebugging() { index: 0 }; - const cfgs = await (new ExternalDebugConfigProvider()) - .provideDebugConfigurations(vscWorkspaceFolder); - if (cfgs && cfgs.length > 0) { + const provider = new ExternalDebugConfigProvider(); + let cfgs = await provider.provideDebugConfigurations(vscWorkspaceFolder); + if (!cfgs) + return; + + if (attach) + cfgs = cfgs.filter(cfg => cfg.request === 'attach'); + else + cfgs = cfgs.filter(cfg => cfg.request === 'launch'); + + if (cfgs.length > 0) { let cfg = cfgs[0]; if (cfgs.length > 1) { const val = await vscode.window.showQuickPick(cfgs.map(e => e.name), { diff --git a/src/utility.ts b/src/utility.ts index e691245..8ec6907 100644 --- a/src/utility.ts +++ b/src/utility.ts @@ -49,6 +49,45 @@ export const TIME_ONE_MINUTE = 60 * 1000; export const TIME_ONE_HOUR = 3600 * 1000; export const TIME_ONE_DAY = 24 * 3600 * 1000; +export function parseCliArgs(cliStr: string): string[] { + + let argsLi: string[] = []; + let inQuote = false; + let curArg = ''; + + for(let char_ of cliStr) { + // is a "..." start or end + if (char_ === '"' && (curArg.length === 0 || curArg[curArg.length - 1] !== '\\')) { + if (inQuote) { + inQuote = false; + if (curArg && curArg.trim() !== '') + argsLi.push(curArg); + curArg = ''; + } else { + inQuote = true; + } + continue; // skip '"' + } + // in "..." region + if (inQuote) { + curArg += char_; + } else { // out "..." region + if (char_ === ' ' || char_ === '\t') { + if (curArg && curArg.trim() !== '') + argsLi.push(curArg); + curArg = ''; + } else { + curArg += char_; + } + } + } + + if (curArg && curArg.trim() !== '') + argsLi.push(curArg); + + return argsLi; +} + export async function probers_install(cwd?: string) { let commandLine: string;