11import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application' ;
2+ import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state' ;
23import { StorageService } from '@theia/core/lib/browser/storage-service' ;
4+ import type {
5+ Command ,
6+ CommandContribution ,
7+ CommandRegistry ,
8+ } from '@theia/core/lib/common/command' ;
39import { DisposableCollection } from '@theia/core/lib/common/disposable' ;
410import { Emitter , Event } from '@theia/core/lib/common/event' ;
511import { ILogger } from '@theia/core/lib/common/logger' ;
@@ -10,12 +16,23 @@ import {
1016 BoardsService ,
1117 ConfigOption ,
1218 Programmer ,
19+ isBoardIdentifierChangeEvent ,
1320} from '../../common/protocol' ;
1421import { notEmpty } from '../../common/utils' ;
22+ import type {
23+ StartupTask ,
24+ StartupTaskProvider ,
25+ } from '../../electron-common/startup-task' ;
1526import { NotificationCenter } from '../notification-center' ;
27+ import { BoardsServiceProvider } from './boards-service-provider' ;
1628
1729@injectable ( )
18- export class BoardsDataStore implements FrontendApplicationContribution {
30+ export class BoardsDataStore
31+ implements
32+ FrontendApplicationContribution ,
33+ StartupTaskProvider ,
34+ CommandContribution
35+ {
1936 @inject ( ILogger )
2037 @named ( 'store' )
2138 private readonly logger : ILogger ;
@@ -28,44 +45,107 @@ export class BoardsDataStore implements FrontendApplicationContribution {
2845 // 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
2946 @inject ( StorageService )
3047 private readonly storageService : StorageService ;
48+ @inject ( BoardsServiceProvider )
49+ private readonly boardsServiceProvider : BoardsServiceProvider ;
50+ @inject ( FrontendApplicationStateService )
51+ private readonly appStateService : FrontendApplicationStateService ;
3152
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 ;
3459
3560 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+ } ) ,
3767 this . notificationCenter . onPlatformDidInstall ( async ( { item } ) => {
38- const dataDidChangePerFqbn : string [ ] = [ ] ;
68+ const changes : BoardsDataStoreChange [ ] = [ ] ;
3969 for ( const fqbn of item . boards
4070 . map ( ( { fqbn } ) => fqbn )
41- . filter ( notEmpty )
42- . filter ( ( fqbn ) => ! ! fqbn ) ) {
71+ . filter ( notEmpty ) ) {
4372 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 ) {
4676 const details = await this . getBoardDetailsSafe ( fqbn ) ;
4777 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 } ) ;
5381 }
5482 }
5583 }
56- if ( dataDidChangePerFqbn . length ) {
57- this . fireChanged ( ...dataDidChangePerFqbn ) ;
84+ if ( changes . length ) {
85+ this . fireChanged ( ...changes ) ;
5886 }
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+ )
6097 ) ;
6198 }
6299
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+
63120 onStop ( ) : void {
64121 this . toDispose . dispose ( ) ;
65122 }
66123
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 ;
69149 }
70150
71151 async appendConfigToFqbn (
@@ -84,22 +164,19 @@ export class BoardsDataStore implements FrontendApplicationContribution {
84164 }
85165
86166 const key = this . getStorageKey ( fqbn ) ;
87- let data = await this . storageService . getData <
167+ const storedData = await this . storageService . getData <
88168 BoardsDataStore . Data | undefined
89169 > ( key , undefined ) ;
90- if ( BoardsDataStore . Data . is ( data ) ) {
91- return data ;
170+ if ( BoardsDataStore . Data . is ( storedData ) ) {
171+ return storedData ;
92172 }
93173
94174 const boardDetails = await this . getBoardDetailsSafe ( fqbn ) ;
95175 if ( ! boardDetails ) {
96176 return BoardsDataStore . Data . EMPTY ;
97177 }
98178
99- data = {
100- configOptions : boardDetails . configOptions ,
101- programmers : boardDetails . programmers ,
102- } ;
179+ const data = createDataStoreEntry ( boardDetails ) ;
103180 await this . storageService . setData ( key , data ) ;
104181 return data ;
105182 }
@@ -111,17 +188,15 @@ export class BoardsDataStore implements FrontendApplicationContribution {
111188 fqbn : string ;
112189 selectedProgrammer : Programmer ;
113190 } ) : 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 ;
116193 if ( ! programmers . find ( ( p ) => Programmer . equals ( selectedProgrammer , p ) ) ) {
117194 return false ;
118195 }
119196
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 } ) ;
125200 return true ;
126201 }
127202
@@ -153,17 +228,12 @@ export class BoardsDataStore implements FrontendApplicationContribution {
153228 return false ;
154229 }
155230 await this . setData ( { fqbn, data } ) ;
156- this . fireChanged ( fqbn ) ;
231+ this . fireChanged ( { fqbn, data } ) ;
157232 return true ;
158233 }
159234
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 ;
167237 const key = this . getStorageKey ( fqbn ) ;
168238 return this . storageService . setData ( key , data ) ;
169239 }
@@ -176,7 +246,7 @@ export class BoardsDataStore implements FrontendApplicationContribution {
176246 fqbn : string
177247 ) : Promise < BoardDetails | undefined > {
178248 try {
179- const details = this . boardsService . getBoardDetails ( { fqbn } ) ;
249+ const details = await this . boardsService . getBoardDetails ( { fqbn } ) ;
180250 return details ;
181251 } catch ( err ) {
182252 if (
@@ -197,8 +267,8 @@ export class BoardsDataStore implements FrontendApplicationContribution {
197267 }
198268 }
199269
200- protected fireChanged ( ...fqbn : string [ ] ) : void {
201- this . onChangedEmitter . fire ( fqbn ) ;
270+ protected fireChanged ( ...changes : BoardsDataStoreChange [ ] ) : void {
271+ this . onDidChangeEmitter . fire ( { changes } ) ;
202272 }
203273}
204274
@@ -224,3 +294,32 @@ export namespace BoardsDataStore {
224294 }
225295 }
226296}
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