功能基本可用
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "fmd-c-compiler",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.8",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "fmd-c-compiler",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.8",
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/vscode": "^1.85.0",
|
||||
|
||||
+23
-3
@@ -2,7 +2,7 @@
|
||||
"name": "fmd-c-compiler",
|
||||
"displayName": "FMD C Compiler",
|
||||
"description": "FMD/FT61FC6X 系列 MCU 编译器支持(C.exe 工具链)",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.8",
|
||||
"license": "MIT",
|
||||
"icon": "resources/icon.png",
|
||||
"engines": {
|
||||
@@ -78,6 +78,11 @@
|
||||
{
|
||||
"command": "fmdCompiler.exportEepromHex",
|
||||
"title": "FMD: Export EEPROM HEX"
|
||||
},
|
||||
{
|
||||
"command": "fmdCompiler.regenerateConfig",
|
||||
"title": "FMD: Regenerate VS Code Config",
|
||||
"icon": "$(gear)"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
@@ -98,6 +103,11 @@
|
||||
"command": "fmdCompiler.download",
|
||||
"when": "resourceExtname =~ /\\.[cChH]$/",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "fmdCompiler.regenerateConfig",
|
||||
"when": "resourceExtname =~ /\\.[cChH]$/",
|
||||
"group": "navigation"
|
||||
}
|
||||
],
|
||||
"editor/context": [
|
||||
@@ -125,6 +135,11 @@
|
||||
"command": "fmdCompiler.openEeprom",
|
||||
"when": "resourceExtname =~ /\\.[cChH]$/",
|
||||
"group": "fmd@5"
|
||||
},
|
||||
{
|
||||
"command": "fmdCompiler.regenerateConfig",
|
||||
"when": "resourceExtname =~ /\\.[cChH]$/",
|
||||
"group": "fmd@6"
|
||||
}
|
||||
],
|
||||
"explorer/context": [
|
||||
@@ -152,6 +167,11 @@
|
||||
"command": "fmdCompiler.openEeprom",
|
||||
"when": "resourceExtname == '.prj' || resourceExtname == '.hex'",
|
||||
"group": "fmd@5"
|
||||
},
|
||||
{
|
||||
"command": "fmdCompiler.regenerateConfig",
|
||||
"when": "resourceExtname == '.prj' || resourceExtname =~ /\\.[cChH]$/",
|
||||
"group": "fmd@6"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -186,8 +206,8 @@
|
||||
},
|
||||
"fmdCompiler.outputDir": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "输出目录(留空则与工程同目录)"
|
||||
"default": "build",
|
||||
"description": "输出目录。默认 build 会输出到工程目录下的 build 文件夹;留空则与工程同目录;也可填写绝对路径。"
|
||||
},
|
||||
"fmdCompiler.extraArgs": {
|
||||
"type": "string",
|
||||
|
||||
+10
-2
@@ -70,7 +70,8 @@ export class FmdCompiler {
|
||||
}
|
||||
|
||||
const projectName = projectInfo?.projectName || path.basename(projectDir);
|
||||
const outputDir = cfg.outputDir || projectDir;
|
||||
const outputDir = this.resolveOutputDir(projectDir, cfg.outputDir);
|
||||
fs.mkdirSync(outputDir, { recursive: true });
|
||||
const artifacts = this.getOutputArtifacts(projectDir, projectName, outputDir);
|
||||
|
||||
this.building = true;
|
||||
@@ -229,7 +230,7 @@ export class FmdCompiler {
|
||||
}
|
||||
|
||||
const projectName = projectInfo?.projectName || path.basename(projectDir);
|
||||
const outputDir = cfg.outputDir || projectDir;
|
||||
const outputDir = this.resolveOutputDir(projectDir, cfg.outputDir);
|
||||
return this.getOutputArtifacts(projectDir, projectName, outputDir);
|
||||
}
|
||||
|
||||
@@ -243,6 +244,13 @@ export class FmdCompiler {
|
||||
};
|
||||
}
|
||||
|
||||
private resolveOutputDir(projectDir: string, outputDir: string): string {
|
||||
if (!outputDir) {
|
||||
return projectDir;
|
||||
}
|
||||
return path.isAbsolute(outputDir) ? outputDir : path.join(projectDir, outputDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造编译参数
|
||||
* 基于对 .map 文件的分析,c.exe 是 XC8-style 驱动器
|
||||
|
||||
+366
-4
@@ -36,13 +36,16 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
}),
|
||||
vscode.commands.registerCommand('fmdCompiler.clean', () => compiler.cleanProject()),
|
||||
vscode.commands.registerCommand('fmdCompiler.selectProject', (uri?: vscode.Uri) => {
|
||||
vscode.commands.registerCommand('fmdCompiler.selectProject', async (uri?: vscode.Uri) => {
|
||||
if (uri) {
|
||||
projectManager.setProjectFile(uri.fsPath);
|
||||
vscode.window.showInformationMessage(`已选择工程: ${path.basename(uri.fsPath)}`);
|
||||
} else {
|
||||
projectManager.pickProjectFile();
|
||||
await projectManager.pickProjectFile();
|
||||
}
|
||||
await ensureWorkspaceSettings();
|
||||
ensureCppProperties();
|
||||
ensureGitignore();
|
||||
updateStatusBars();
|
||||
}),
|
||||
vscode.commands.registerCommand('fmdCompiler.openOutput', () => {
|
||||
@@ -59,6 +62,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
vscode.commands.registerCommand('fmdCompiler.readEeprom', () => eepromManager.readEeprom()),
|
||||
vscode.commands.registerCommand('fmdCompiler.writeEeprom', () => eepromManager.writeEeprom()),
|
||||
vscode.commands.registerCommand('fmdCompiler.exportEepromHex', () => eepromManager.exportEepromHex()),
|
||||
vscode.commands.registerCommand('fmdCompiler.regenerateConfig', () => regenerateConfig()),
|
||||
diagnosticsCollection
|
||||
);
|
||||
|
||||
@@ -69,6 +73,8 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
chipStatusBar.command = 'fmdCompiler.selectChip';
|
||||
const downloadStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 98);
|
||||
downloadStatusBar.command = 'fmdCompiler.download';
|
||||
const configStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 97);
|
||||
configStatusBar.command = 'fmdCompiler.regenerateConfig';
|
||||
|
||||
const update = () => {
|
||||
const cfg = getConfig();
|
||||
@@ -79,13 +85,16 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
chipStatusBar.tooltip = '切换 FMD 目标芯片';
|
||||
downloadStatusBar.text = '$(cloud-upload) FMD Download';
|
||||
downloadStatusBar.tooltip = cfg.programmerPath ? `下载程序: ${cfg.programmerPath}` : '未配置烧录工具,点击配置后可下载';
|
||||
configStatusBar.text = '$(gear) FMD Config';
|
||||
configStatusBar.tooltip = '一键重新生成 .gitignore 和 .vscode 配置';
|
||||
statusBar.show();
|
||||
chipStatusBar.show();
|
||||
downloadStatusBar.show();
|
||||
configStatusBar.show();
|
||||
};
|
||||
updateStatusBars = update;
|
||||
updateStatusBars();
|
||||
context.subscriptions.push(statusBar, chipStatusBar, downloadStatusBar);
|
||||
context.subscriptions.push(statusBar, chipStatusBar, downloadStatusBar, configStatusBar);
|
||||
|
||||
// 监听配置变化
|
||||
context.subscriptions.push(
|
||||
@@ -99,6 +108,9 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// 尝试自动找工程文件
|
||||
projectManager.autoDetectProject();
|
||||
ensureWorkspaceSettings();
|
||||
ensureCppProperties();
|
||||
ensureGitignore();
|
||||
updateStatusBars();
|
||||
|
||||
outputChannel.appendLine('[FMD] 插件已激活');
|
||||
@@ -112,6 +124,18 @@ export function deactivate() {
|
||||
|
||||
let updateStatusBars = () => {};
|
||||
|
||||
async function regenerateConfig(): Promise<void> {
|
||||
outputChannel.show(true);
|
||||
outputChannel.appendLine('');
|
||||
outputChannel.appendLine('========== FMD 重新生成 VS Code 配置 ==========');
|
||||
await ensureWorkspaceSettings();
|
||||
ensureCppProperties();
|
||||
ensureGitignore();
|
||||
updateStatusBars();
|
||||
outputChannel.appendLine('========== FMD 配置生成完成 ==========');
|
||||
vscode.window.showInformationMessage('FMD: 已重新生成 .gitignore 和 .vscode 配置');
|
||||
}
|
||||
|
||||
async function setCompilerPath(): Promise<void> {
|
||||
const cfg = getConfig();
|
||||
const files = await vscode.window.showOpenDialog({
|
||||
@@ -191,6 +215,344 @@ async function syncChipFromProject(): Promise<void> {
|
||||
vscode.window.showInformationMessage(`FMD: 已从工程同步芯片: ${projectChip}`);
|
||||
}
|
||||
|
||||
async function ensureWorkspaceSettings(): Promise<void> {
|
||||
const folders = vscode.workspace.workspaceFolders;
|
||||
if (!folders || folders.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const folder of folders) {
|
||||
const settingsDir = path.join(folder.uri.fsPath, '.vscode');
|
||||
const settingsFile = path.join(settingsDir, 'settings.json');
|
||||
let settings: Record<string, unknown> = {};
|
||||
|
||||
try {
|
||||
if (fs.existsSync(settingsFile)) {
|
||||
settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8')) as Record<string, unknown>;
|
||||
}
|
||||
} catch (err) {
|
||||
outputChannel.appendLine(`[警告] 无法解析工作区设置,跳过自动写入: ${settingsFile}: ${err}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
let changed = false;
|
||||
const cfg = getConfig();
|
||||
const projectFile = projectManager.getProjectFile() || findSinglePrjFile(folder.uri.fsPath) || cfg.projectFile;
|
||||
const projectChip = projectFile ? projectManager.getCurrentChip(projectFile) : undefined;
|
||||
|
||||
if (settings['fmdCompiler.outputDir'] === undefined) {
|
||||
settings['fmdCompiler.outputDir'] = 'build';
|
||||
changed = true;
|
||||
}
|
||||
if (settings['fmdCompiler.compilerPath'] === undefined) {
|
||||
settings['fmdCompiler.compilerPath'] = cfg.compilerPath;
|
||||
changed = true;
|
||||
}
|
||||
if (settings['fmdCompiler.chip'] === undefined) {
|
||||
settings['fmdCompiler.chip'] = projectChip || cfg.chip || 'FT61FC6X';
|
||||
changed = true;
|
||||
}
|
||||
if (projectFile && settings['fmdCompiler.projectFile'] === undefined) {
|
||||
settings['fmdCompiler.projectFile'] = projectFile;
|
||||
changed = true;
|
||||
}
|
||||
if (settings['fmdCompiler.autoSaveBeforeBuild'] === undefined) {
|
||||
settings['fmdCompiler.autoSaveBeforeBuild'] = true;
|
||||
changed = true;
|
||||
}
|
||||
if (settings['fmdCompiler.showOutputOnBuild'] === undefined) {
|
||||
settings['fmdCompiler.showOutputOnBuild'] = true;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
fs.mkdirSync(settingsDir, { recursive: true });
|
||||
fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + '\n');
|
||||
outputChannel.appendLine(`[FMD] 已自动生成/更新工作区设置: ${settingsFile}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ensureCppProperties(): void {
|
||||
const folders = vscode.workspace.workspaceFolders;
|
||||
if (!folders || folders.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cfg = getConfig();
|
||||
const compilerInclude = path.join(path.dirname(cfg.compilerPath), '..', 'include');
|
||||
|
||||
for (const folder of folders) {
|
||||
const vscodeDir = path.join(folder.uri.fsPath, '.vscode');
|
||||
const propertiesFile = path.join(vscodeDir, 'c_cpp_properties.json');
|
||||
const projectFile = projectManager.getProjectFile() || findSinglePrjFile(folder.uri.fsPath) || cfg.projectFile;
|
||||
const projectDir = projectFile ? path.dirname(projectFile) : folder.uri.fsPath;
|
||||
const chip = (projectFile ? projectManager.getCurrentChip(projectFile) : undefined) || cfg.chip;
|
||||
const intellisenseHeader = ensureFmdIntellisenseHeader(vscodeDir, compilerInclude, chip);
|
||||
const includePath = [
|
||||
'${workspaceFolder}/**',
|
||||
normalizeForCppProperties(projectDir),
|
||||
normalizeForCppProperties(path.join(projectDir, '**')),
|
||||
normalizeForCppProperties(compilerInclude),
|
||||
];
|
||||
const defines = [
|
||||
`_${chip}`,
|
||||
'__GCC8PRO__',
|
||||
'_CHIP_SELECT_H_',
|
||||
];
|
||||
const forcedInclude = [
|
||||
normalizeForCppProperties(intellisenseHeader),
|
||||
];
|
||||
let properties: {
|
||||
configurations?: Array<Record<string, unknown>>;
|
||||
version?: number;
|
||||
[key: string]: unknown;
|
||||
} = {};
|
||||
|
||||
try {
|
||||
if (fs.existsSync(propertiesFile)) {
|
||||
properties = JSON.parse(fs.readFileSync(propertiesFile, 'utf8'));
|
||||
}
|
||||
} catch (err) {
|
||||
outputChannel.appendLine(`[警告] 无法解析 C/C++ 配置,跳过自动写入: ${propertiesFile}: ${err}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!Array.isArray(properties.configurations) || properties.configurations.length === 0) {
|
||||
properties.configurations = [{
|
||||
name: 'FMD',
|
||||
includePath,
|
||||
defines,
|
||||
forcedInclude,
|
||||
compilerPath: cfg.compilerPath,
|
||||
cStandard: 'c99',
|
||||
intelliSenseMode: 'windows-gcc-x86',
|
||||
}];
|
||||
} else {
|
||||
const configuration = properties.configurations[0];
|
||||
const currentIncludePath = Array.isArray(configuration.includePath) ? configuration.includePath as string[] : [];
|
||||
const currentDefines = Array.isArray(configuration.defines) ? configuration.defines as string[] : [];
|
||||
const currentForcedInclude = Array.isArray(configuration.forcedInclude) ? configuration.forcedInclude as string[] : [];
|
||||
configuration.includePath = mergeUnique(currentIncludePath, includePath);
|
||||
configuration.defines = mergeUnique(currentDefines, defines);
|
||||
configuration.forcedInclude = mergeUnique(currentForcedInclude, forcedInclude);
|
||||
if (!configuration.compilerPath) {
|
||||
configuration.compilerPath = cfg.compilerPath;
|
||||
}
|
||||
if (!configuration.cStandard) {
|
||||
configuration.cStandard = 'c99';
|
||||
}
|
||||
if (!configuration.intelliSenseMode) {
|
||||
configuration.intelliSenseMode = 'windows-gcc-x86';
|
||||
}
|
||||
}
|
||||
|
||||
if (!properties.version) {
|
||||
properties.version = 4;
|
||||
}
|
||||
|
||||
fs.mkdirSync(vscodeDir, { recursive: true });
|
||||
fs.writeFileSync(propertiesFile, JSON.stringify(properties, null, 2) + '\n');
|
||||
outputChannel.appendLine(`[FMD] 已自动生成/更新 C/C++ 头文件路径: ${propertiesFile}`);
|
||||
}
|
||||
}
|
||||
|
||||
function ensureFmdIntellisenseHeader(vscodeDir: string, compilerInclude: string, chip: string): string {
|
||||
fs.mkdirSync(vscodeDir, { recursive: true });
|
||||
const target = path.join(vscodeDir, 'fmd_intellisense.h');
|
||||
const chipHeader = findChipHeader(compilerInclude, chip);
|
||||
const names = chipHeader ? extractChipSymbols(chipHeader) : [];
|
||||
const lines = [
|
||||
'/* Auto-generated by FMD C Compiler extension. */',
|
||||
'/* This file is only for VS Code IntelliSense and is not used by c.exe. */',
|
||||
'#ifndef FMD_INTELLISENSE_H',
|
||||
'#define FMD_INTELLISENSE_H',
|
||||
'',
|
||||
'#ifndef __FMD_INTELLISENSE__',
|
||||
'#define __FMD_INTELLISENSE__ 1',
|
||||
'#endif',
|
||||
'',
|
||||
'#ifndef bit',
|
||||
'typedef unsigned char bit;',
|
||||
'#endif',
|
||||
'',
|
||||
'#ifndef asm',
|
||||
'#define asm(...)',
|
||||
'#endif',
|
||||
'',
|
||||
'#ifndef interrupt',
|
||||
'#define interrupt',
|
||||
'#endif',
|
||||
'',
|
||||
`#ifndef _${chip}`,
|
||||
`#define _${chip}`,
|
||||
'#endif',
|
||||
'',
|
||||
...names.map(name => `extern volatile unsigned char ${name};`),
|
||||
'',
|
||||
'#endif',
|
||||
'',
|
||||
];
|
||||
|
||||
fs.writeFileSync(target, lines.join('\n'));
|
||||
return target;
|
||||
}
|
||||
|
||||
function findChipHeader(compilerInclude: string, chip: string): string | undefined {
|
||||
const candidates = [
|
||||
path.join(compilerInclude, `${chip}.h`),
|
||||
path.join(compilerInclude, `${chip}.H`),
|
||||
];
|
||||
return candidates.find(file => fs.existsSync(file));
|
||||
}
|
||||
|
||||
function extractChipSymbols(chipHeader: string): string[] {
|
||||
const text = fs.readFileSync(chipHeader, 'utf8');
|
||||
const names = new Set<string>();
|
||||
const patterns = [
|
||||
/volatile\s+(?:unsigned\s+char|bit)\s+([A-Za-z_][A-Za-z0-9_]*)\s*@/g,
|
||||
/volatile\s+union\s*\{[\s\S]*?\}\s*([A-Za-z_][A-Za-z0-9_]*)\s*@/g,
|
||||
];
|
||||
|
||||
for (const pattern of patterns) {
|
||||
let m: RegExpExecArray | null;
|
||||
while ((m = pattern.exec(text)) !== null) {
|
||||
names.add(m[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(names).sort();
|
||||
}
|
||||
|
||||
function normalizeForCppProperties(filePath: string): string {
|
||||
return filePath.replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
function mergeUnique(first: string[], second: string[]): string[] {
|
||||
const result: string[] = [];
|
||||
for (const value of [...first, ...second]) {
|
||||
if (value && !result.includes(value)) {
|
||||
result.push(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function ensureGitignore(): void {
|
||||
const folders = vscode.workspace.workspaceFolders;
|
||||
if (!folders || folders.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const patterns = [
|
||||
'.vscode',
|
||||
'**/*.as',
|
||||
'**/*.asm',
|
||||
'**/*.bin',
|
||||
'**/*.cmf',
|
||||
'**/*.cof',
|
||||
'**/*.d',
|
||||
'**/*.hex',
|
||||
'**/*.lpp',
|
||||
'**/*.map',
|
||||
'**/*.obj',
|
||||
'**/*.p1',
|
||||
'**/*.pre',
|
||||
'**/*.rlf',
|
||||
'**/*.sdb',
|
||||
'**/*.sym',
|
||||
'**/*.hxl',
|
||||
'**/*.ini',
|
||||
'**/*.rar',
|
||||
'**/*.o',
|
||||
'**/*.crf',
|
||||
'**/*.htm',
|
||||
'**/*.dep',
|
||||
'**/*.bak',
|
||||
'**/*.lnp',
|
||||
'**/*.lst',
|
||||
'**/*.iex',
|
||||
'**/*.sct',
|
||||
'**/*.scvd',
|
||||
'**/*.uvguix',
|
||||
'**/*.dbg*',
|
||||
'**/*.uvguix.*',
|
||||
'**/.mxproject',
|
||||
'**/*.uvopt',
|
||||
'**/*.uvgui.*',
|
||||
'**/Listings',
|
||||
'**/output',
|
||||
'**/*.zip',
|
||||
];
|
||||
|
||||
const blockStart = '# FMD generated ignores';
|
||||
const blockEnd = '# End FMD generated ignores';
|
||||
const block = [blockStart, ...patterns, blockEnd].join('\n');
|
||||
|
||||
for (const folder of folders) {
|
||||
const gitignoreFile = path.join(folder.uri.fsPath, '.gitignore');
|
||||
let text = '';
|
||||
|
||||
if (fs.existsSync(gitignoreFile)) {
|
||||
text = fs.readFileSync(gitignoreFile, 'utf8');
|
||||
if (text.includes(blockStart) && text.includes(blockEnd)) {
|
||||
const pattern = new RegExp(`${escapeRegExp(blockStart)}[\\s\\S]*?${escapeRegExp(blockEnd)}`);
|
||||
const nextText = text.replace(pattern, block);
|
||||
if (nextText !== text) {
|
||||
fs.writeFileSync(gitignoreFile, ensureTrailingNewline(nextText));
|
||||
outputChannel.appendLine(`[FMD] 已更新 .gitignore: ${gitignoreFile}`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const missing = patterns.filter(p => !hasGitignorePattern(text, p));
|
||||
if (missing.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const prefix = text.trim().length > 0 ? ensureTrailingNewline(text).replace(/\s*$/, '\n\n') : '';
|
||||
fs.writeFileSync(gitignoreFile, `${prefix}${block}\n`);
|
||||
outputChannel.appendLine(`[FMD] 已自动生成/更新 .gitignore: ${gitignoreFile}`);
|
||||
}
|
||||
}
|
||||
|
||||
function hasGitignorePattern(text: string, pattern: string): boolean {
|
||||
return text.split(/\r?\n/).some(line => line.trim() === pattern);
|
||||
}
|
||||
|
||||
function ensureTrailingNewline(text: string): string {
|
||||
return text.endsWith('\n') ? text : text + '\n';
|
||||
}
|
||||
|
||||
function escapeRegExp(value: string): string {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function findSinglePrjFile(folderPath: string): string | undefined {
|
||||
const result: string[] = [];
|
||||
const walk = (dir: string, depth: number) => {
|
||||
if (depth > 2 || result.length > 1) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isFile() && entry.name.toLowerCase().endsWith('.prj')) {
|
||||
result.push(fullPath);
|
||||
} else if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
||||
walk(fullPath, depth + 1);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// 忽略权限错误
|
||||
}
|
||||
};
|
||||
|
||||
walk(folderPath, 0);
|
||||
return result.length === 1 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
function collectChipCandidates(): string[] {
|
||||
const cfg = getConfig();
|
||||
const chips = new Set<string>(['FT61FC6X', cfg.chip]);
|
||||
@@ -224,7 +586,7 @@ export function getConfig() {
|
||||
]),
|
||||
projectFile: cfg.get<string>('projectFile', ''),
|
||||
chip: cfg.get<string>('chip', 'FT61FC6X'),
|
||||
outputDir: cfg.get<string>('outputDir', ''),
|
||||
outputDir: cfg.get<string>('outputDir', 'build'),
|
||||
extraArgs: cfg.get<string>('extraArgs', ''),
|
||||
autoSaveBeforeBuild: cfg.get<boolean>('autoSaveBeforeBuild', true),
|
||||
showOutputOnBuild: cfg.get<boolean>('showOutputOnBuild', true),
|
||||
|
||||
Reference in New Issue
Block a user