Skip to content

Commit bcf69b0

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 bcf69b0

File tree

5 files changed

+204
-1
lines changed

5 files changed

+204
-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,187 @@
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) =>
41+
this.updateBoardsConfig(config)
42+
),
43+
this.sketchServiceClient.onCurrentSketchDidChange((sketch) =>
44+
this.updateSketchPath(sketch)
45+
),
46+
this.configService.onDidChangeDataDirUri((dataDirUri) =>
47+
this.updateDataDirPath(dataDirUri)
48+
),
49+
this.configService.onDidChangeSketchDirUri((userDirUri) =>
50+
this.updateUserDirPath(userDirUri)
51+
),
52+
this.commandService.onDidExecuteCommand(({ commandId, args }) => {
53+
if (
54+
commandId === 'arduino.languageserver.notifyBuildDidComplete' &&
55+
isObject<Partial<{ buildOutputUri: string }>>(args)
56+
) {
57+
const buildOutputUri = args.buildOutputUri;
58+
if (typeof buildOutputUri === 'string') {
59+
this.updateBuildPath(new URI(buildOutputUri).path.fsPath());
60+
}
61+
}
62+
}),
63+
this.boardsDataStore.onChanged((fqbn) => {
64+
const selectedFqbn =
65+
this.boardsServiceProvider.boardsConfig.selectedBoard?.fqbn;
66+
if (selectedFqbn && fqbn.includes(selectedFqbn)) {
67+
this.updateBoardDetails(selectedFqbn);
68+
}
69+
}),
70+
]);
71+
}
72+
73+
override onReady(): void {
74+
this.boardsServiceProvider.reconciled.then(() => {
75+
this.updateBoardsConfig(this.boardsServiceProvider.boardsConfig);
76+
});
77+
const sketch = this.sketchServiceClient.tryGetCurrentSketch();
78+
this.updateSketchPath(sketch);
79+
if (CurrentSketch.isValid(sketch)) {
80+
this.tryFindBuildPath(sketch).then((buildPath) => {
81+
if (buildPath) {
82+
this.updateBuildPath(buildPath);
83+
}
84+
});
85+
}
86+
this.updateUserDirPath(this.configService.tryGetSketchDirUri());
87+
this.updateDataDirPath(this.configService.tryGetDataDirUri());
88+
}
89+
90+
onStop(): void {
91+
this.toDispose.dispose();
92+
}
93+
94+
private async tryFindBuildPath(sketch: Sketch): Promise<string | undefined> {
95+
const buildPaths = await this.sketchesService.tempBuildPath(sketch);
96+
for (const buildPath of buildPaths) {
97+
try {
98+
const uri = new URI(CodeUri.file(buildPath));
99+
await this.fileService.access(uri);
100+
return buildPath;
101+
} catch {}
102+
}
103+
return undefined;
104+
}
105+
106+
private async updateSketchPath(
107+
sketch: CurrentSketch | undefined
108+
): Promise<void> {
109+
const sketchPath = CurrentSketch.isValid(sketch)
110+
? new URI(sketch.uri).path.fsPath()
111+
: undefined;
112+
return this.updateWorkspaceState({ key: 'sketchPath', value: sketchPath });
113+
}
114+
115+
private async updateBuildPath(buildPath: string | undefined): Promise<void> {
116+
return this.updateWorkspaceState({ key: 'buildPath', value: buildPath });
117+
}
118+
119+
private async updateBoardsConfig(
120+
boardsConfig: BoardsConfig.Config
121+
): Promise<void> {
122+
const fqbn = boardsConfig.selectedBoard?.fqbn;
123+
const port = boardsConfig.selectedPort;
124+
await this.updateFqbn(fqbn);
125+
await this.updateBoardDetails(fqbn);
126+
await this.updatePort(port);
127+
}
128+
129+
private async updateFqbn(fqbn: string | undefined): Promise<void> {
130+
await this.updateWorkspaceState({ key: 'fqbn', value: fqbn });
131+
}
132+
133+
private async updateBoardDetails(fqbn: string | undefined): Promise<void> {
134+
const unset = () =>
135+
this.updateWorkspaceState({ key: 'boardDetails', value: undefined });
136+
if (!fqbn) {
137+
return unset();
138+
}
139+
const [details, persistedData] = await Promise.all([
140+
this.boardsService.getBoardDetails({ fqbn }),
141+
this.boardsDataStore.getData(fqbn),
142+
]);
143+
if (!details) {
144+
return unset();
145+
}
146+
return this.updateWorkspaceState({
147+
key: 'boardDetails',
148+
value: {
149+
...details,
150+
configOptions:
151+
BoardsDataStore.Data.EMPTY === persistedData
152+
? details.configOptions
153+
: persistedData.configOptions.slice(),
154+
},
155+
});
156+
}
157+
158+
private async updatePort(port: Port | undefined): Promise<void> {
159+
return this.updateWorkspaceState({ key: 'port', value: port });
160+
}
161+
162+
private async updateUserDirPath(userDirUri: URI | undefined): Promise<void> {
163+
const userDirPath = userDirUri?.path.fsPath();
164+
return this.updateWorkspaceState({
165+
key: 'userDirPath',
166+
value: userDirPath,
167+
});
168+
}
169+
170+
private async updateDataDirPath(dataDirUri: URI | undefined): Promise<void> {
171+
const dataDirPath = dataDirUri?.path.fsPath();
172+
return this.updateWorkspaceState({
173+
key: 'dataDirPath',
174+
value: dataDirPath,
175+
});
176+
}
177+
178+
private async updateWorkspaceState(
179+
params: UpdateWorkspaceStateParams
180+
): Promise<void> {
181+
await this.hostedPluginSupport.didStart;
182+
return this.commandService.executeCommand(
183+
'vscodeArduinoAPI.updateState',
184+
params
185+
);
186+
}
187+
}

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)