1
1
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application' ;
2
+ import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state' ;
2
3
import { StorageService } from '@theia/core/lib/browser/storage-service' ;
4
+ import type {
5
+ Command ,
6
+ CommandContribution ,
7
+ CommandRegistry ,
8
+ } from '@theia/core/lib/common/command' ;
3
9
import { DisposableCollection } from '@theia/core/lib/common/disposable' ;
4
10
import { Emitter , Event } from '@theia/core/lib/common/event' ;
5
11
import { ILogger } from '@theia/core/lib/common/logger' ;
@@ -10,12 +16,23 @@ import {
10
16
BoardsService ,
11
17
ConfigOption ,
12
18
Programmer ,
19
+ isBoardIdentifierChangeEvent ,
13
20
} from '../../common/protocol' ;
14
21
import { notEmpty } from '../../common/utils' ;
22
+ import type {
23
+ StartupTask ,
24
+ StartupTaskProvider ,
25
+ } from '../../electron-common/startup-task' ;
15
26
import { NotificationCenter } from '../notification-center' ;
27
+ import { BoardsServiceProvider } from './boards-service-provider' ;
16
28
17
29
@injectable ( )
18
- export class BoardsDataStore implements FrontendApplicationContribution {
30
+ export class BoardsDataStore
31
+ implements
32
+ FrontendApplicationContribution ,
33
+ StartupTaskProvider ,
34
+ CommandContribution
35
+ {
19
36
@inject ( ILogger )
20
37
@named ( 'store' )
21
38
private readonly logger : ILogger ;
@@ -28,44 +45,101 @@ export class BoardsDataStore implements FrontendApplicationContribution {
28
45
// In other words, store the data (such as the board configs) per sketch, not per IDE2 installation. https://github.com/arduino/arduino-ide/issues/2240
29
46
@inject ( StorageService )
30
47
private readonly storageService : StorageService ;
48
+ @inject ( BoardsServiceProvider )
49
+ private readonly boardsServiceProvider : BoardsServiceProvider ;
50
+ @inject ( FrontendApplicationStateService )
51
+ private readonly appStateService : FrontendApplicationStateService ;
31
52
32
- private readonly onChangedEmitter = new Emitter < string [ ] > ( ) ;
33
- private readonly toDispose = new DisposableCollection ( this . onChangedEmitter ) ;
53
+ private readonly onDidChangeEmitter =
54
+ new Emitter < BoardsDataStoreChangeEvent > ( ) ;
55
+ private readonly toDispose = new DisposableCollection (
56
+ this . onDidChangeEmitter
57
+ ) ;
58
+ private _selectedBoardData : BoardsDataStoreChange | undefined ;
34
59
35
60
onStart ( ) : void {
36
- this . toDispose . push (
61
+ this . toDispose . pushAll ( [
62
+ this . boardsServiceProvider . onBoardsConfigDidChange ( async ( event ) => {
63
+ if ( isBoardIdentifierChangeEvent ( event ) ) {
64
+ this . _selectedBoardData = await this . getSelectedBoardData (
65
+ event . selectedBoard ?. fqbn
66
+ ) ;
67
+ }
68
+ } ) ,
37
69
this . notificationCenter . onPlatformDidInstall ( async ( { item } ) => {
38
- const dataDidChangePerFqbn : string [ ] = [ ] ;
70
+ const changes : BoardsDataStoreChange [ ] = [ ] ;
39
71
for ( const fqbn of item . boards
40
72
. map ( ( { fqbn } ) => fqbn )
41
- . filter ( notEmpty )
42
- . filter ( ( fqbn ) => ! ! fqbn ) ) {
73
+ . filter ( notEmpty ) ) {
43
74
const key = this . getStorageKey ( fqbn ) ;
44
- let data = await this . storageService . getData < ConfigOption [ ] > ( key ) ;
45
- if ( ! data || ! data . length ) {
75
+ const storedData =
76
+ await this . storageService . getData < BoardsDataStore . Data > ( key ) ;
77
+ if ( ! storedData ) {
46
78
const details = await this . getBoardDetailsSafe ( fqbn ) ;
47
79
if ( details ) {
48
- data = details . configOptions ;
49
- if ( data . length ) {
50
- await this . storageService . setData ( key , data ) ;
51
- dataDidChangePerFqbn . push ( fqbn ) ;
52
- }
80
+ const data = createDataStoreEntry ( details ) ;
81
+ await this . storageService . setData ( key , data ) ;
82
+ changes . push ( { fqbn, data } ) ;
53
83
}
54
84
}
55
85
}
56
- if ( dataDidChangePerFqbn . length ) {
57
- this . fireChanged ( ...dataDidChangePerFqbn ) ;
86
+ if ( changes . length ) {
87
+ this . fireChanged ( ...changes ) ;
58
88
}
59
- } )
60
- ) ;
89
+ } ) ,
90
+ ] ) ;
91
+ Promise . all ( [
92
+ this . boardsServiceProvider . ready ,
93
+ this . appStateService . reachedState ( 'ready' ) ,
94
+ ] ) . then ( async ( ) => {
95
+ const fqbn = this . boardsServiceProvider . boardsConfig . selectedBoard ?. fqbn ;
96
+ this . _selectedBoardData = await this . getSelectedBoardData ( fqbn ) ;
97
+ } ) ;
98
+ }
99
+
100
+ private async getSelectedBoardData (
101
+ fqbn : string | undefined
102
+ ) : Promise < BoardsDataStoreChange | undefined > {
103
+ if ( ! fqbn ) {
104
+ return undefined ;
105
+ } else {
106
+ const data = await this . getData ( fqbn ) ;
107
+ if ( data === BoardsDataStore . Data . EMPTY ) {
108
+ return undefined ;
109
+ }
110
+ return { fqbn, data } ;
111
+ }
61
112
}
62
113
63
114
onStop ( ) : void {
64
115
this . toDispose . dispose ( ) ;
65
116
}
66
117
67
- get onChanged ( ) : Event < string [ ] > {
68
- return this . onChangedEmitter . event ;
118
+ registerCommands ( registry : CommandRegistry ) : void {
119
+ registry . registerCommand ( USE_INHERITED_DATA , {
120
+ execute : async ( arg : unknown ) => {
121
+ if ( isBoardsDataStoreChange ( arg ) ) {
122
+ await this . setData ( arg ) ;
123
+ this . fireChanged ( arg ) ;
124
+ }
125
+ } ,
126
+ } ) ;
127
+ }
128
+
129
+ tasks ( ) : StartupTask [ ] {
130
+ if ( ! this . _selectedBoardData ) {
131
+ return [ ] ;
132
+ }
133
+ return [
134
+ {
135
+ command : USE_INHERITED_DATA . id ,
136
+ args : [ this . _selectedBoardData ] ,
137
+ } ,
138
+ ] ;
139
+ }
140
+
141
+ get onDidChange ( ) : Event < BoardsDataStoreChangeEvent > {
142
+ return this . onDidChangeEmitter . event ;
69
143
}
70
144
71
145
async appendConfigToFqbn (
@@ -84,22 +158,19 @@ export class BoardsDataStore implements FrontendApplicationContribution {
84
158
}
85
159
86
160
const key = this . getStorageKey ( fqbn ) ;
87
- let data = await this . storageService . getData <
161
+ const storedData = await this . storageService . getData <
88
162
BoardsDataStore . Data | undefined
89
163
> ( key , undefined ) ;
90
- if ( BoardsDataStore . Data . is ( data ) ) {
91
- return data ;
164
+ if ( BoardsDataStore . Data . is ( storedData ) ) {
165
+ return storedData ;
92
166
}
93
167
94
168
const boardDetails = await this . getBoardDetailsSafe ( fqbn ) ;
95
169
if ( ! boardDetails ) {
96
170
return BoardsDataStore . Data . EMPTY ;
97
171
}
98
172
99
- data = {
100
- configOptions : boardDetails . configOptions ,
101
- programmers : boardDetails . programmers ,
102
- } ;
173
+ const data = createDataStoreEntry ( boardDetails ) ;
103
174
await this . storageService . setData ( key , data ) ;
104
175
return data ;
105
176
}
@@ -111,17 +182,15 @@ export class BoardsDataStore implements FrontendApplicationContribution {
111
182
fqbn : string ;
112
183
selectedProgrammer : Programmer ;
113
184
} ) : Promise < boolean > {
114
- const data = deepClone ( await this . getData ( fqbn ) ) ;
115
- const { programmers } = data ;
185
+ const storedData = deepClone ( await this . getData ( fqbn ) ) ;
186
+ const { programmers } = storedData ;
116
187
if ( ! programmers . find ( ( p ) => Programmer . equals ( selectedProgrammer , p ) ) ) {
117
188
return false ;
118
189
}
119
190
120
- await this . setData ( {
121
- fqbn,
122
- data : { ...data , selectedProgrammer } ,
123
- } ) ;
124
- this . fireChanged ( fqbn ) ;
191
+ const data = { ...storedData , selectedProgrammer } ;
192
+ await this . setData ( { fqbn, data } ) ;
193
+ this . fireChanged ( { fqbn, data } ) ;
125
194
return true ;
126
195
}
127
196
@@ -153,17 +222,12 @@ export class BoardsDataStore implements FrontendApplicationContribution {
153
222
return false ;
154
223
}
155
224
await this . setData ( { fqbn, data } ) ;
156
- this . fireChanged ( fqbn ) ;
225
+ this . fireChanged ( { fqbn, data } ) ;
157
226
return true ;
158
227
}
159
228
160
- protected async setData ( {
161
- fqbn,
162
- data,
163
- } : {
164
- fqbn : string ;
165
- data : BoardsDataStore . Data ;
166
- } ) : Promise < void > {
229
+ protected async setData ( change : BoardsDataStoreChange ) : Promise < void > {
230
+ const { fqbn, data } = change ;
167
231
const key = this . getStorageKey ( fqbn ) ;
168
232
return this . storageService . setData ( key , data ) ;
169
233
}
@@ -176,7 +240,7 @@ export class BoardsDataStore implements FrontendApplicationContribution {
176
240
fqbn : string
177
241
) : Promise < BoardDetails | undefined > {
178
242
try {
179
- const details = this . boardsService . getBoardDetails ( { fqbn } ) ;
243
+ const details = await this . boardsService . getBoardDetails ( { fqbn } ) ;
180
244
return details ;
181
245
} catch ( err ) {
182
246
if (
@@ -197,8 +261,8 @@ export class BoardsDataStore implements FrontendApplicationContribution {
197
261
}
198
262
}
199
263
200
- protected fireChanged ( ...fqbn : string [ ] ) : void {
201
- this . onChangedEmitter . fire ( fqbn ) ;
264
+ protected fireChanged ( ...changes : BoardsDataStoreChange [ ] ) : void {
265
+ this . onDidChangeEmitter . fire ( { changes } ) ;
202
266
}
203
267
}
204
268
@@ -224,3 +288,32 @@ export namespace BoardsDataStore {
224
288
}
225
289
}
226
290
}
291
+
292
+ function createDataStoreEntry ( details : BoardDetails ) : BoardsDataStore . Data {
293
+ return {
294
+ configOptions : details . configOptions . slice ( ) ,
295
+ programmers : details . programmers . slice ( ) ,
296
+ } ;
297
+ }
298
+
299
+ export interface BoardsDataStoreChange {
300
+ readonly fqbn : string ;
301
+ readonly data : BoardsDataStore . Data ;
302
+ }
303
+
304
+ function isBoardsDataStoreChange ( arg : unknown ) : arg is BoardsDataStoreChange {
305
+ return (
306
+ typeof arg === 'object' &&
307
+ arg !== null &&
308
+ typeof ( < BoardsDataStoreChange > arg ) . fqbn === 'string' &&
309
+ typeof ( < BoardsDataStoreChange > arg ) . data === 'object' // TODO: better type guard!
310
+ ) ;
311
+ }
312
+
313
+ export interface BoardsDataStoreChangeEvent {
314
+ readonly changes : readonly BoardsDataStoreChange [ ] ;
315
+ }
316
+
317
+ const USE_INHERITED_DATA : Command = {
318
+ id : 'arduino-use-inherited-boards-data' ,
319
+ } ;
0 commit comments