Skip to content

Commit 95097a0

Browse files
committed
feat: set the Arduino context as workspaceState
Set the VS Code `workspaceState` on fqbn, port, and sketch path changes. VS Code extensions can read this cached state. Signed-off-by: dankeboy36 <[email protected]>
1 parent 31deeeb commit 95097a0

File tree

5 files changed

+173
-1
lines changed

5 files changed

+173
-1
lines changed

Diff for: arduino-ide-extension/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
"temp-dir": "^2.0.0",
106106
"tree-kill": "^1.2.1",
107107
"util": "^0.12.5",
108+
"vscode-arduino-api": "^0.1.0",
108109
"which": "^1.3.1"
109110
},
110111
"devDependencies": {

Diff for: arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ import { FileResourceResolver as TheiaFileResourceResolver } from '@theia/filesy
354354
import { StylingParticipant } from '@theia/core/lib/browser/styling-service';
355355
import { MonacoEditorMenuContribution } from './theia/monaco/monaco-menu';
356356
import { MonacoEditorMenuContribution as TheiaMonacoEditorMenuContribution } from '@theia/monaco/lib/browser/monaco-menu';
357+
import { UpdateArduinoContext } from './contributions/update-arduino-context';
357358

358359
// Hack to fix copy/cut/paste issue after electron version update in Theia.
359360
// https://github.com/eclipse-theia/theia/issues/12487
@@ -747,6 +748,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
747748
Contribution.configure(bind, Account);
748749
Contribution.configure(bind, CloudSketchbookContribution);
749750
Contribution.configure(bind, CreateCloudCopy);
751+
Contribution.configure(bind, UpdateArduinoContext);
750752

751753
bindContributionProvider(bind, StartupTaskProvider);
752754
bind(StartupTaskProvider).toService(BoardsServiceProvider); // to reuse the boards config in another window
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import { DisposableCollection } from '@theia/core/lib/common/disposable';
2+
import { isObject } from '@theia/core/lib/common/types';
3+
import URI from '@theia/core/lib/common/uri';
4+
import { inject, injectable } from '@theia/core/shared/inversify';
5+
import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin';
6+
import type { ArduinoState } from 'vscode-arduino-api';
7+
import { URI as CodeUri } from 'vscode-uri';
8+
import type { Port, Sketch } from '../../common/protocol';
9+
import { BoardsService } from '../../common/protocol';
10+
import type { BoardsConfig } from '../boards/boards-config';
11+
import { BoardsDataStore } from '../boards/boards-data-store';
12+
import { BoardsServiceProvider } from '../boards/boards-service-provider';
13+
import { CurrentSketch } from '../sketches-service-client-impl';
14+
import { SketchContribution } from './contribution';
15+
16+
interface UpdateWorkspaceStateParams {
17+
readonly key: keyof ArduinoState;
18+
readonly value: ArduinoState[keyof ArduinoState];
19+
}
20+
21+
/**
22+
* Contribution for setting the VS Code [`workspaceState`](https://code.visualstudio.com/api/references/vscode-api#workspace) on Arduino IDE context changes, such as FQBN, selected port, and sketch path changes via commands.
23+
* See [`vscode-arduino-api`](https://www.npmjs.com/package/vscode-arduino-api) for more details.
24+
*/
25+
@injectable()
26+
export class UpdateArduinoContext extends SketchContribution {
27+
@inject(BoardsService)
28+
private readonly boardsService: BoardsService;
29+
@inject(BoardsServiceProvider)
30+
private readonly boardsServiceProvider: BoardsServiceProvider;
31+
@inject(BoardsDataStore)
32+
private readonly boardsDataStore: BoardsDataStore;
33+
@inject(HostedPluginSupport)
34+
private readonly hostedPluginSupport: HostedPluginSupport;
35+
36+
private readonly toDispose = new DisposableCollection();
37+
38+
override onStart(): void {
39+
this.toDispose.pushAll([
40+
this.boardsServiceProvider.onBoardsConfigChanged((config) => this.updateBoardsConfig(config)),
41+
this.sketchServiceClient.onCurrentSketchDidChange((sketch) => this.updateSketchPath(sketch)),
42+
this.configService.onDidChangeDataDirUri((dataDirUri) => this.updateDataDirPath(dataDirUri)),
43+
this.configService.onDidChangeSketchDirUri((userDirUri) => this.updateUserDirPath(userDirUri)),
44+
this.commandService.onDidExecuteCommand(({ commandId, args }) => {
45+
if (commandId === 'arduino.languageserver.notifyBuildDidComplete' && isObject<Partial<{ buildOutputUri: string }>>(args)) {
46+
const buildOutputUri = args.buildOutputUri;
47+
if (typeof buildOutputUri === 'string') {
48+
this.updateBuildPath(new URI(buildOutputUri).path.fsPath());
49+
}
50+
}
51+
}),
52+
this.boardsDataStore.onChanged(fqbn => {
53+
const selectedFqbn = this.boardsServiceProvider.boardsConfig.selectedBoard?.fqbn;
54+
if (selectedFqbn && fqbn.includes(selectedFqbn)) {
55+
this.updateBoardDetails(selectedFqbn);
56+
}
57+
})
58+
]);
59+
}
60+
61+
override onReady(): void {
62+
this.boardsServiceProvider.reconciled.then(() => {
63+
this.updateBoardsConfig(this.boardsServiceProvider.boardsConfig);
64+
});
65+
const sketch = this.sketchServiceClient.tryGetCurrentSketch();
66+
this.updateSketchPath(sketch);
67+
if (CurrentSketch.isValid(sketch)) {
68+
this.tryFindBuildPath(sketch).then(buildPath => {
69+
if (buildPath) {
70+
this.updateBuildPath(buildPath);
71+
}
72+
})
73+
}
74+
this.updateUserDirPath(this.configService.tryGetSketchDirUri());
75+
this.updateDataDirPath(this.configService.tryGetDataDirUri());
76+
}
77+
78+
onStop(): void {
79+
this.toDispose.dispose();
80+
}
81+
82+
private async tryFindBuildPath(sketch: Sketch): Promise<string | undefined> {
83+
const buildPaths = await this.sketchesService.tempBuildPath(sketch);
84+
for (const buildPath of buildPaths) {
85+
try {
86+
const uri = new URI(CodeUri.file(buildPath));
87+
await this.fileService.access(uri)
88+
return buildPath;
89+
} catch {}
90+
}
91+
return undefined;
92+
}
93+
94+
private async updateSketchPath(
95+
sketch: CurrentSketch | undefined
96+
): Promise<void> {
97+
const sketchPath = CurrentSketch.isValid(sketch)
98+
? new URI(sketch.uri).path.fsPath()
99+
: undefined;
100+
return this.updateWorkspaceState({ key: 'sketchPath', value: sketchPath })
101+
}
102+
103+
private async updateBuildPath(
104+
buildPath: string | undefined
105+
): Promise<void> {
106+
return this.updateWorkspaceState({ key: 'buildPath', value: buildPath });
107+
}
108+
109+
private async updateBoardsConfig(
110+
boardsConfig: BoardsConfig.Config
111+
): Promise<void> {
112+
const fqbn = boardsConfig.selectedBoard?.fqbn
113+
const port = boardsConfig.selectedPort;
114+
await this.updateFqbn(fqbn);
115+
await this.updateBoardDetails(fqbn);
116+
await this.updatePort(port);
117+
}
118+
119+
private async updateFqbn(fqbn: string | undefined): Promise<void> {
120+
await this.updateWorkspaceState({ key: 'fqbn', value: fqbn });
121+
}
122+
123+
private async updateBoardDetails(fqbn: string | undefined): Promise<void> {
124+
const unset = () => this.updateWorkspaceState({ key: 'boardDetails', value: undefined });
125+
if (!fqbn) {
126+
return unset();
127+
}
128+
const [details, persistedData] = await Promise.all([
129+
this.boardsService.getBoardDetails({ fqbn }),
130+
this.boardsDataStore.getData(fqbn)
131+
])
132+
if (!details) {
133+
return unset();
134+
}
135+
return this.updateWorkspaceState({ key: 'boardDetails', value: { ...details, configOptions: BoardsDataStore.Data.EMPTY === persistedData ? details.configOptions : persistedData.configOptions.slice() } });
136+
}
137+
138+
private async updatePort(port: Port | undefined): Promise<void> {
139+
return this.updateWorkspaceState({ key: 'port', value: port });
140+
}
141+
142+
private async updateUserDirPath(userDirUri: URI | undefined): Promise<void> {
143+
const userDirPath = userDirUri?.path.fsPath();
144+
return this.updateWorkspaceState({ key: 'userDirPath', value: userDirPath });
145+
}
146+
147+
private async updateDataDirPath(dataDirUri: URI | undefined): Promise<void> {
148+
const dataDirPath = dataDirUri?.path.fsPath();
149+
return this.updateWorkspaceState({ key: 'dataDirPath', value: dataDirPath });
150+
}
151+
152+
private async updateWorkspaceState(params: UpdateWorkspaceStateParams): Promise<void> {
153+
await this.hostedPluginSupport.didStart;
154+
return this.commandService.executeCommand('vscodeArduinoAPI.updateState', params);
155+
}
156+
}

Diff for: package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"watch": "lerna run watch --parallel",
4444
"test": "lerna run test",
4545
"test:slow": "lerna run test:slow",
46-
"download:plugins": "theia download:plugins",
46+
"download:plugins": "theia download:plugins --ignore-errors",
4747
"update:version": "node ./scripts/update-version.js",
4848
"i18n:generate": "theia nls-extract -e vscode -f \"+(arduino-ide-extension|electron-app|plugins)/**/*.ts?(x)\" -o ./i18n/en.json",
4949
"i18n:check": "yarn i18n:generate && git add -N ./i18n && git diff --exit-code ./i18n",
@@ -70,6 +70,7 @@
7070
"theiaPluginsDir": "plugins",
7171
"theiaPlugins": {
7272
"vscode-builtin-cpp": "https://open-vsx.org/api/vscode/cpp/1.52.1/file/vscode.cpp-1.52.1.vsix",
73+
"vscode-arduino-api": "https://github.com/dankeboy36/vscode-arduino-api/releases/download/0.1.0/vscode-arduino-api-0.1.0.vsix",
7374
"vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/vscode-arduino-tools-0.0.2-beta.8.vsix",
7475
"vscode-builtin-json": "https://open-vsx.org/api/vscode/json/1.46.1/file/vscode.json-1.46.1.vsix",
7576
"vscode-builtin-json-language-features": "https://open-vsx.org/api/vscode/json-language-features/1.46.1/file/vscode.json-language-features-1.46.1.vsix",

Diff for: yarn.lock

+12
Original file line numberDiff line numberDiff line change
@@ -3216,6 +3216,11 @@
32163216
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-7.0.5.tgz#b1d2f772142a301538fae9bdf9cf15b9f2573a29"
32173217
integrity sha512-hKB88y3YHL8oPOs/CNlaXtjWn93+Bs48sDQR37ZUqG2tLeCS7EA1cmnkKsuQsub9OKEB/y/Rw9zqJqqNSbqVlQ==
32183218

3219+
"@types/vscode@^1.78.0":
3220+
version "1.78.0"
3221+
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.78.0.tgz#b5600abce8855cf21fb32d0857bcd084b1f83069"
3222+
integrity sha512-LJZIJpPvKJ0HVQDqfOy6W4sNKUBBwyDu1Bs8chHBZOe9MNuKTJtidgZ2bqjhmmWpUb0TIIqv47BFUcVmAsgaVA==
3223+
32193224
"@types/which@^1.3.1":
32203225
version "1.3.2"
32213226
resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf"
@@ -14959,6 +14964,13 @@ vinyl@^2.2.1:
1495914964
remove-trailing-separator "^1.0.1"
1496014965
replace-ext "^1.0.0"
1496114966

14967+
vscode-arduino-api@^0.1.0:
14968+
version "0.1.0"
14969+
resolved "https://registry.yarnpkg.com/vscode-arduino-api/-/vscode-arduino-api-0.1.0.tgz#0aabf9cc98b95cbf8cb67c18ad72c4ee43f09a26"
14970+
integrity sha512-CSr2Qm9xhfLAHT2LH6Wh1tyQ9NMoLggA1Ys1uplR+aw1IpB+PEv3JEf5LV2QyQpLiyqrDwyOI7HkXGAm1p7AkQ==
14971+
dependencies:
14972+
"@types/vscode" "^1.78.0"
14973+
1496214974
1496314975
version "8.1.0"
1496414976
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz#cb9989c65e219e18533cc38e767611272d274c94"

0 commit comments

Comments
 (0)