Skip to content

Commit ce84178

Browse files
authored
Merge pull request #12 from BernardXiong/dev
增加选择当前bsp功能
2 parents 87668b5 + 9f1158b commit ce84178

File tree

8 files changed

+233
-49
lines changed

8 files changed

+233
-49
lines changed

package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@
9898
"command": "extension.openTerminalProject",
9999
"title": "Open RT-Thread Terminal",
100100
"icon": "$(console)"
101+
},
102+
{
103+
"command": "extension.handleTreeItemClick",
104+
"title": "Handle Tree Item Click"
101105
}
102106
],
103107
"menus": {
@@ -119,11 +123,6 @@
119123
}
120124
],
121125
"view/item/context": [
122-
{
123-
"command": "extension.switchProject",
124-
"when": "view == projectFilesId && viewItem == project_bsp",
125-
"group": "inline"
126-
},
127126
{
128127
"command": "extension.fastBuildProject",
129128
"when": "view == projectFilesId && viewItem == project_bsp",

src/dock.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as vscode from 'vscode';
33
import os from 'os';
44
import fs from 'fs';
55
import { getWorkspaceFolder, isRTThreadProject, isRTThreadWorksapce } from './api';
6-
import { buildGroupsTree, buildProjectTree, buildEmptyProjectTree, ProjectTreeItem, listFolderTreeItem, buildBSPTree } from './project/tree';
6+
import { buildGroupsTree, buildProjectTree, buildEmptyProjectTree, ProjectTreeItem, listFolderTreeItem, buildBSPTree, setTreeDataChangeEmitter } from './project/tree';
77
import { cmds } from './cmds/index';
88

99
class CmdTreeDataProvider implements vscode.TreeDataProvider<vscode.TreeItem> {
@@ -188,6 +188,10 @@ class ProjectFilesDataProvider implements vscode.TreeDataProvider<ProjectTreeIte
188188
private _onDidChangeTreeData: vscode.EventEmitter<ProjectTreeItem | undefined> = new vscode.EventEmitter<ProjectTreeItem | undefined>();
189189
readonly onDidChangeTreeData: vscode.Event<ProjectTreeItem | undefined> = this._onDidChangeTreeData.event;
190190

191+
getTreeDataChangeEmitter(): vscode.EventEmitter<ProjectTreeItem | undefined> {
192+
return this._onDidChangeTreeData;
193+
}
194+
191195
getTreeItem(element: ProjectTreeItem): vscode.TreeItem {
192196
return element;
193197
}
@@ -291,6 +295,8 @@ export function initDockView(context: vscode.ExtensionContext) {
291295
treeDataProvider: _projectFilesDataProvider, showCollapseAll: true
292296
});
293297

298+
setTreeDataChangeEmitter(_projectFilesDataProvider.getTreeDataChangeEmitter());
299+
294300
context.subscriptions.push(view);
295301
vscode.commands.registerCommand('extension.refreshRTThread', () => refreshProjectFilesAndGroups());
296302

src/extension.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { setupVEnv } from './venv';
1414
import { initAPI } from './api';
1515
import { openWorkspaceProjectsWebview } from './webviews/project';
1616
import { initProjectTree } from './project/tree';
17+
import { DecorationProvider } from './project/fileDecorationProvider';
18+
import { getCurrentProjectInWorkspace } from './webviews/project';
1719

1820
let _context: vscode.ExtensionContext;
1921

@@ -47,6 +49,14 @@ export async function activate(context: vscode.ExtensionContext) {
4749
isRTThreadWorksapce = true;
4850
vscode.commands.executeCommand('setContext', 'isRTThreadWorksapce', true);
4951
context.workspaceState.update('isRTThreadWorksapce', isRTThreadWorksapce);
52+
53+
new DecorationProvider(context);
54+
55+
// get current project from workspace.json file
56+
let currentProject = getCurrentProjectInWorkspace();
57+
if (currentProject) {
58+
DecorationProvider.getInstance().markFile(vscode.Uri.file(currentProject));
59+
}
5060
}
5161
}
5262
else {

src/project/cmd.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import * as os from 'os';
22
import * as fs from 'fs';
3+
import * as vscode from 'vscode';
34

45
import { getWorkspaceFolder } from '../api';
56
import { executeCommand } from '../terminal';
7+
import { readWorkspaceJson, writeWorkspaceJson } from '../webviews/project';
68

79
let _currentProject: string = '';
810

@@ -40,6 +42,16 @@ export function openTerminalProject(arg: any) {
4042
export function setCurrentProject(arg: any) {
4143
if (arg) {
4244
_currentProject = arg.fn;
45+
46+
let cmd = 'scons -C ' + arg.fn + ' --target=vsc_workspace';
47+
executeCommand(cmd);
48+
49+
// update workspace.json file
50+
let workspaceJson = readWorkspaceJson();
51+
if (workspaceJson) {
52+
workspaceJson.currentProject = arg.fn;
53+
writeWorkspaceJson(workspaceJson);
54+
}
4355
}
4456

4557
return;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import {
2+
CancellationToken,
3+
Event,
4+
EventEmitter,
5+
ExtensionContext,
6+
FileDecoration,
7+
FileDecorationProvider,
8+
ThemeColor,
9+
Uri,
10+
window,
11+
} from "vscode";
12+
13+
export class DecorationProvider implements FileDecorationProvider {
14+
private readonly _onDidChangeFileDecorations: EventEmitter<Uri | Uri[]> =
15+
new EventEmitter<Uri | Uri[]>();
16+
readonly onDidChangeFileDecorations: Event<Uri | Uri[]> =
17+
this._onDidChangeFileDecorations.event;
18+
public markedFiles: Set<string> = new Set<string>();
19+
private static instance: DecorationProvider;
20+
21+
constructor(context: ExtensionContext) {
22+
// 注册文件装饰提供者
23+
context.subscriptions.push(
24+
window.registerFileDecorationProvider(this),
25+
);
26+
27+
DecorationProvider.instance = this;
28+
}
29+
30+
static getInstance(): DecorationProvider {
31+
return DecorationProvider.instance;
32+
}
33+
34+
provideFileDecoration(uri: Uri, token: CancellationToken): FileDecoration | undefined {
35+
if (token.isCancellationRequested) {
36+
return;
37+
}
38+
39+
if (this.markedFiles.has(uri.fsPath)) {
40+
return {
41+
propagate: true,
42+
badge: "📌",
43+
color: new ThemeColor("terminal.ansiCyan"),
44+
};
45+
}
46+
}
47+
48+
public async markFile(uri: Uri) {
49+
if (!this.markedFiles.has(uri.fsPath)) {
50+
this.markedFiles.add(uri.fsPath);
51+
this._onDidChangeFileDecorations.fire(uri);
52+
}
53+
}
54+
55+
public async unmarkFile(uri: Uri) {
56+
if (this.markedFiles.has(uri.fsPath)) {
57+
this.markedFiles.delete(uri.fsPath);
58+
this._onDidChangeFileDecorations.fire(uri);
59+
}
60+
}
61+
62+
public async unmarkAllFiles() {
63+
this.markedFiles.clear();
64+
}
65+
}

src/project/tree.ts

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import path from 'path';
22
import * as vscode from 'vscode';
33
import fs from 'fs';
44
import { getWorkspaceFolder, getExtensionPath } from '../api';
5+
import { DecorationProvider } from './fileDecorationProvider';
56

67
/*
78
* contexType -> contextValue as following value:
@@ -11,6 +12,12 @@ import { getWorkspaceFolder, getExtensionPath } from '../api';
1112
* project_bsp
1213
*/
1314

15+
// 全局变量记录当前选中的project_bsp项目
16+
let currentSelectedBspItem: ProjectTreeItem | null = null;
17+
18+
// 添加树视图刷新事件发射器
19+
let _onDidChangeTreeData: vscode.EventEmitter<ProjectTreeItem | undefined> | null = null;
20+
1421
export class ProjectTreeItem extends vscode.TreeItem {
1522
children: ProjectTreeItem[];
1623
fn: string = '';
@@ -58,12 +65,16 @@ export class ProjectTreeItem extends vscode.TreeItem {
5865
else if (contextType == 'project_bsp') {
5966
this.command = {
6067
title: this.name,
61-
command: 'extension.switchProject',
68+
command: 'extension.handleTreeItemClick',
6269
tooltip: this.name,
6370
arguments: [
6471
this
6572
]
6673
};
74+
75+
// with resourceUri, the item will be rendered as a file icon
76+
// then the item can be marked with a decoration
77+
this.resourceUri = vscode.Uri.file(this.fn);
6778
}
6879
}
6980
}
@@ -333,7 +344,47 @@ export function initProjectTree(context:vscode.ExtensionContext) {
333344
vscode.commands.registerCommand('extension.openTerminalProject', (arg) => {
334345
openTerminalProject(arg);
335346
});
336-
vscode.commands.registerCommand('extension.switchProject', (arg) => {
337-
setCurrentProject(arg);
347+
348+
// Add double-clicked
349+
let lastClickTime = 0;
350+
let lastClickedItem: ProjectTreeItem | null = null;
351+
352+
vscode.commands.registerCommand('extension.handleTreeItemClick', (item: ProjectTreeItem) => {
353+
const currentTime = Date.now();
354+
const doubleClickThreshold = 500; // 500ms内的两次点击被认为是双击
355+
356+
if (item.contextType === 'project_bsp') {
357+
if (lastClickedItem === item && (currentTime - lastClickTime) < doubleClickThreshold) {
358+
if (currentSelectedBspItem && currentSelectedBspItem.fn === item.fn) {
359+
return;
360+
}
361+
362+
// double clicked
363+
if (currentSelectedBspItem && currentSelectedBspItem.fn != item.fn) {
364+
DecorationProvider.getInstance().unmarkFile(vscode.Uri.file(currentSelectedBspItem.fn));
365+
}
366+
367+
currentSelectedBspItem = item;
368+
DecorationProvider.getInstance().markFile(vscode.Uri.file(item.fn));
369+
setCurrentProject(item);
370+
371+
if (_onDidChangeTreeData) {
372+
_onDidChangeTreeData.fire(undefined);
373+
}
374+
375+
// reset status
376+
lastClickTime = 0;
377+
lastClickedItem = null;
378+
} else {
379+
// one-clicked, just record it.
380+
lastClickTime = currentTime;
381+
lastClickedItem = item;
382+
}
383+
}
338384
});
339385
}
386+
387+
// 导出函数用于设置树视图刷新事件发射器
388+
export function setTreeDataChangeEmitter(emitter: vscode.EventEmitter<ProjectTreeItem | undefined>) {
389+
_onDidChangeTreeData = emitter;
390+
}

src/vue/projects/App.vue

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
可以在感兴趣的BSP/工程项上✔,然后保存配置,将会在侧边栏中显示对应列表。<br>
66
<hr>
77

8-
<el-button @click="reloadBSPProjects" hidden>加载列表</el-button>
9-
<el-button @click="collapseAll">折叠全部列表</el-button>
10-
11-
<el-button type="primary" @click="saveBSPProjects">保存列表配置</el-button>
8+
<div style="text-align: right; margin-bottom: 10px;">
9+
<el-button @click="reloadBSPProjects" style="display: none;">加载列表</el-button>
10+
<el-button @click="collapseAll">折叠全部列表</el-button>
11+
<el-button type="primary" @click="saveBSPProjects">保存列表配置</el-button>
12+
</div>
1213

1314
<el-table ref="tableRef" v-loading="loading" :data="tableData" style="width: 100%" row-key="id"
1415
:expand-row-keys="expandedRowKeys">
@@ -20,7 +21,7 @@
2021
</template>
2122

2223
<script setup lang="ts">
23-
import { onMounted, ref } from 'vue';
24+
import { onMounted, ref, nextTick } from 'vue';
2425
import { imgUrl } from '../assets/img';
2526
import { sendCommand } from '../api/vscode';
2627
@@ -42,9 +43,11 @@ const reloadBSPProjects = () => {
4243
4344
const saveBSPProjects = () => {
4445
let args:string[] = [];
45-
const selectedRows = tableRef.value.getSelectionRows();
46-
if (selectedRows.length > 0) {
47-
args = selectedRows.map(row => row.path);
46+
if (tableRef.value) {
47+
const selectedRows = (tableRef.value as any).getSelectionRows();
48+
if (selectedRows.length > 0) {
49+
args = selectedRows.map(row => row.path);
50+
}
4851
}
4952
5053
sendCommand('saveBSPProjects', [args]);
@@ -59,14 +62,20 @@ onMounted(() => {
5962
6063
switch (message.command) {
6164
case 'updateProjects':
62-
// console.log(message);
6365
tableData.value = message.data.dirs;
6466
let stars:string[] = message.data.stars;
65-
tableData.value.forEach((item, index) => {
66-
if (stars.includes(item.path)) {
67-
tableRef.value?.toggleRowSelection({ id: item.id }, true)
68-
}
67+
68+
// 使用 nextTick 确保 DOM 更新完成后再执行选择操作
69+
nextTick(() => {
70+
tableData.value.forEach((item, index) => {
71+
if (stars.includes(item.path)) {
72+
if (tableRef.value) {
73+
(tableRef.value as any).toggleRowSelection(item, true);
74+
}
75+
}
76+
});
6977
});
78+
7079
loading.value = false; // 停止加载动画
7180
break;
7281

0 commit comments

Comments
 (0)