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,107 @@ 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 ( ( event ) => {
63
+ if ( isBoardIdentifierChangeEvent ( event ) ) {
64
+ this . updateSelectedBoardData ( event . selectedBoard ?. fqbn ) ;
65
+ }
66
+ } ) ,
37
67
this . notificationCenter . onPlatformDidInstall ( async ( { item } ) => {
38
- const dataDidChangePerFqbn : string [ ] = [ ] ;
68
+ const changes : BoardsDataStoreChange [ ] = [ ] ;
39
69
for ( const fqbn of item . boards
40
70
. map ( ( { fqbn } ) => fqbn )
41
- . filter ( notEmpty )
42
- . filter ( ( fqbn ) => ! ! fqbn ) ) {
71
+ . filter ( notEmpty ) ) {
43
72
const key = this . getStorageKey ( fqbn ) ;
44
- let data = await this . storageService . getData < ConfigOption [ ] > ( key ) ;
45
- if ( ! data || ! data . length ) {
73
+ const storedData =
74
+ await this . storageService . getData < BoardsDataStore . Data > ( key ) ;
75
+ if ( ! storedData && BoardsDataStore . Data . EMPTY !== storedData ) {
46
76
const details = await this . getBoardDetailsSafe ( fqbn ) ;
47
77
if ( details ) {
48
- data = details . configOptions ;
49
- if ( data . length ) {
50
- await this . storageService . setData ( key , data ) ;
51
- dataDidChangePerFqbn . push ( fqbn ) ;
52
- }
78
+ const data = createDataStoreEntry ( details ) ;
79
+ await this . storageService . setData ( key , data ) ;
80
+ changes . push ( { fqbn, data } ) ;
53
81
}
54
82
}
55
83
}
56
- if ( dataDidChangePerFqbn . length ) {
57
- this . fireChanged ( ...dataDidChangePerFqbn ) ;
84
+ if ( changes . length ) {
85
+ this . fireChanged ( ...changes ) ;
58
86
}
59
- } )
87
+ } ) ,
88
+ ] ) ;
89
+
90
+ Promise . all ( [
91
+ this . boardsServiceProvider . ready ,
92
+ this . appStateService . reachedState ( 'ready' ) ,
93
+ ] ) . then ( ( ) =>
94
+ this . updateSelectedBoardData (
95
+ this . boardsServiceProvider . boardsConfig . selectedBoard ?. fqbn
96
+ )
60
97
) ;
61
98
}
62
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
+ }
112
+ }
113
+
114
+ private async updateSelectedBoardData (
115
+ fqbn : string | undefined
116
+ ) : Promise < void > {
117
+ this . _selectedBoardData = await this . getSelectedBoardData ( fqbn ) ;
118
+ }
119
+
63
120
onStop ( ) : void {
64
121
this . toDispose . dispose ( ) ;
65
122
}
66
123
67
- get onChanged ( ) : Event < string [ ] > {
68
- return this . onChangedEmitter . event ;
124
+ registerCommands ( registry : CommandRegistry ) : void {
125
+ registry . registerCommand ( USE_INHERITED_DATA , {
126
+ execute : async ( arg : unknown ) => {
127
+ if ( isBoardsDataStoreChange ( arg ) ) {
128
+ await this . setData ( arg ) ;
129
+ this . fireChanged ( arg ) ;
130
+ }
131
+ } ,
132
+ } ) ;
133
+ }
134
+
135
+ tasks ( ) : StartupTask [ ] {
136
+ if ( ! this . _selectedBoardData ) {
137
+ return [ ] ;
138
+ }
139
+ return [
140
+ {
141
+ command : USE_INHERITED_DATA . id ,
142
+ args : [ this . _selectedBoardData ] ,
143
+ } ,
144
+ ] ;
145
+ }
146
+
147
+ get onDidChange ( ) : Event < BoardsDataStoreChangeEvent > {
148
+ return this . onDidChangeEmitter . event ;
69
149
}
70
150
71
151
async appendConfigToFqbn (
@@ -84,22 +164,19 @@ export class BoardsDataStore implements FrontendApplicationContribution {
84
164
}
85
165
86
166
const key = this . getStorageKey ( fqbn ) ;
87
- let data = await this . storageService . getData <
167
+ const storedData = await this . storageService . getData <
88
168
BoardsDataStore . Data | undefined
89
169
> ( key , undefined ) ;
90
- if ( BoardsDataStore . Data . is ( data ) ) {
91
- return data ;
170
+ if ( BoardsDataStore . Data . is ( storedData ) ) {
171
+ return storedData ;
92
172
}
93
173
94
174
const boardDetails = await this . getBoardDetailsSafe ( fqbn ) ;
95
175
if ( ! boardDetails ) {
96
176
return BoardsDataStore . Data . EMPTY ;
97
177
}
98
178
99
- data = {
100
- configOptions : boardDetails . configOptions ,
101
- programmers : boardDetails . programmers ,
102
- } ;
179
+ const data = createDataStoreEntry ( boardDetails ) ;
103
180
await this . storageService . setData ( key , data ) ;
104
181
return data ;
105
182
}
@@ -111,17 +188,15 @@ export class BoardsDataStore implements FrontendApplicationContribution {
111
188
fqbn : string ;
112
189
selectedProgrammer : Programmer ;
113
190
} ) : Promise < boolean > {
114
- const data = deepClone ( await this . getData ( fqbn ) ) ;
115
- const { programmers } = data ;
191
+ const storedData = deepClone ( await this . getData ( fqbn ) ) ;
192
+ const { programmers } = storedData ;
116
193
if ( ! programmers . find ( ( p ) => Programmer . equals ( selectedProgrammer , p ) ) ) {
117
194
return false ;
118
195
}
119
196
120
- await this . setData ( {
121
- fqbn,
122
- data : { ...data , selectedProgrammer } ,
123
- } ) ;
124
- this . fireChanged ( fqbn ) ;
197
+ const data = { ...storedData , selectedProgrammer } ;
198
+ await this . setData ( { fqbn, data } ) ;
199
+ this . fireChanged ( { fqbn, data } ) ;
125
200
return true ;
126
201
}
127
202
@@ -153,17 +228,12 @@ export class BoardsDataStore implements FrontendApplicationContribution {
153
228
return false ;
154
229
}
155
230
await this . setData ( { fqbn, data } ) ;
156
- this . fireChanged ( fqbn ) ;
231
+ this . fireChanged ( { fqbn, data } ) ;
157
232
return true ;
158
233
}
159
234
160
- protected async setData ( {
161
- fqbn,
162
- data,
163
- } : {
164
- fqbn : string ;
165
- data : BoardsDataStore . Data ;
166
- } ) : Promise < void > {
235
+ protected async setData ( change : BoardsDataStoreChange ) : Promise < void > {
236
+ const { fqbn, data } = change ;
167
237
const key = this . getStorageKey ( fqbn ) ;
168
238
return this . storageService . setData ( key , data ) ;
169
239
}
@@ -176,7 +246,7 @@ export class BoardsDataStore implements FrontendApplicationContribution {
176
246
fqbn : string
177
247
) : Promise < BoardDetails | undefined > {
178
248
try {
179
- const details = this . boardsService . getBoardDetails ( { fqbn } ) ;
249
+ const details = await this . boardsService . getBoardDetails ( { fqbn } ) ;
180
250
return details ;
181
251
} catch ( err ) {
182
252
if (
@@ -197,8 +267,8 @@ export class BoardsDataStore implements FrontendApplicationContribution {
197
267
}
198
268
}
199
269
200
- protected fireChanged ( ...fqbn : string [ ] ) : void {
201
- this . onChangedEmitter . fire ( fqbn ) ;
270
+ protected fireChanged ( ...changes : BoardsDataStoreChange [ ] ) : void {
271
+ this . onDidChangeEmitter . fire ( { changes } ) ;
202
272
}
203
273
}
204
274
@@ -224,3 +294,32 @@ export namespace BoardsDataStore {
224
294
}
225
295
}
226
296
}
297
+
298
+ function createDataStoreEntry ( details : BoardDetails ) : BoardsDataStore . Data {
299
+ return {
300
+ configOptions : details . configOptions . slice ( ) ,
301
+ programmers : details . programmers . slice ( ) ,
302
+ } ;
303
+ }
304
+
305
+ export interface BoardsDataStoreChange {
306
+ readonly fqbn : string ;
307
+ readonly data : BoardsDataStore . Data ;
308
+ }
309
+
310
+ function isBoardsDataStoreChange ( arg : unknown ) : arg is BoardsDataStoreChange {
311
+ return (
312
+ typeof arg === 'object' &&
313
+ arg !== null &&
314
+ typeof ( < BoardsDataStoreChange > arg ) . fqbn === 'string' &&
315
+ BoardsDataStore . Data . is ( ( < BoardsDataStoreChange > arg ) . data )
316
+ ) ;
317
+ }
318
+
319
+ export interface BoardsDataStoreChangeEvent {
320
+ readonly changes : readonly BoardsDataStoreChange [ ] ;
321
+ }
322
+
323
+ const USE_INHERITED_DATA : Command = {
324
+ id : 'arduino-use-inherited-boards-data' ,
325
+ } ;
0 commit comments