1
1
import * as React from 'react' ;
2
+ import * as dateFormat from 'dateformat' ;
3
+ import { remote } from 'electron' ;
2
4
import { injectable , inject , postConstruct } from 'inversify' ;
3
5
import URI from '@theia/core/lib/common/uri' ;
4
6
import { EditorWidget } from '@theia/editor/lib/browser/editor-widget' ;
@@ -8,8 +10,8 @@ import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/li
8
10
import { BoardsService , BoardsServiceClient , CoreService , Sketch , SketchesService , ToolOutputServiceClient } from '../common/protocol' ;
9
11
import { ArduinoCommands } from './arduino-commands' ;
10
12
import { BoardsServiceClientImpl } from './boards/boards-service-client-impl' ;
11
- import { WorkspaceRootUriAwareCommandHandler , WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands' ;
12
- import { SelectionService , MenuContribution , MenuModelRegistry , MAIN_MENU_BAR , MenuPath } from '@theia/core' ;
13
+ import { WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands' ;
14
+ import { SelectionService , MenuContribution , MenuModelRegistry , MAIN_MENU_BAR , MenuPath , notEmpty } from '@theia/core' ;
13
15
import { ArduinoToolbar } from './toolbar/arduino-toolbar' ;
14
16
import { EditorManager , EditorMainMenu } from '@theia/editor/lib/browser' ;
15
17
import {
@@ -44,6 +46,7 @@ import { ArduinoDaemon } from '../common/protocol/arduino-daemon';
44
46
import { ConfigService } from '../common/protocol/config-service' ;
45
47
import { BoardsConfigStore } from './boards/boards-config-store' ;
46
48
import { MainMenuManager } from './menu/main-menu-manager' ;
49
+ import { FileSystemExt } from '../common/protocol/filesystem-ext' ;
47
50
48
51
export namespace ArduinoMenus {
49
52
export const SKETCH = [ ...MAIN_MENU_BAR , '3_sketch' ] ;
@@ -152,6 +155,9 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
152
155
@inject ( MainMenuManager )
153
156
protected readonly mainMenuManager : MainMenuManager ;
154
157
158
+ @inject ( FileSystemExt )
159
+ protected readonly fileSystemExt : FileSystemExt ;
160
+
155
161
protected application : FrontendApplication ;
156
162
protected wsSketchCount : number = 0 ; // TODO: this does not belong here, does it?
157
163
@@ -194,24 +200,32 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
194
200
registry . registerItem ( {
195
201
id : ArduinoCommands . VERIFY . id ,
196
202
command : ArduinoCommands . VERIFY_TOOLBAR . id ,
197
- tooltip : 'Verify'
203
+ tooltip : 'Verify' ,
204
+ priority : 1
198
205
} ) ;
199
206
registry . registerItem ( {
200
207
id : ArduinoCommands . UPLOAD . id ,
201
208
command : ArduinoCommands . UPLOAD_TOOLBAR . id ,
202
- tooltip : 'Upload'
209
+ tooltip : 'Upload' ,
210
+ priority : 2
211
+ } ) ;
212
+ registry . registerItem ( {
213
+ id : ArduinoCommands . NEW_SKETCH . id ,
214
+ command : ArduinoCommands . NEW_SKETCH_TOOLBAR . id ,
215
+ tooltip : 'New' ,
216
+ priority : 4 // Note: priority 3 was reserved by debug.
203
217
} ) ;
204
218
registry . registerItem ( {
205
219
id : ArduinoCommands . SHOW_OPEN_CONTEXT_MENU . id ,
206
220
command : ArduinoCommands . SHOW_OPEN_CONTEXT_MENU . id ,
207
221
tooltip : 'Open' ,
208
- priority : 2
222
+ priority : 5
209
223
} ) ;
210
224
registry . registerItem ( {
211
225
id : ArduinoCommands . SAVE_SKETCH . id ,
212
226
command : ArduinoCommands . SAVE_SKETCH . id ,
213
227
tooltip : 'Save' ,
214
- priority : 2
228
+ priority : 6
215
229
} ) ;
216
230
registry . registerItem ( {
217
231
id : BoardsToolBarItem . TOOLBAR_ID ,
@@ -220,14 +234,13 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
220
234
commands = { this . commandRegistry }
221
235
boardsServiceClient = { this . boardsServiceClientImpl } /> ,
222
236
isVisible : widget => ArduinoToolbar . is ( widget ) && widget . side === 'left' ,
223
- priority : 2
237
+ priority : 6
224
238
} ) ;
225
239
registry . registerItem ( {
226
240
id : 'toggle-serial-monitor' ,
227
241
command : MonitorViewContribution . TOGGLE_SERIAL_MONITOR_TOOLBAR ,
228
- tooltip : 'Toggle Serial Monitor'
242
+ tooltip : 'Serial Monitor'
229
243
} ) ;
230
-
231
244
registry . registerItem ( {
232
245
id : ArduinoCommands . TOGGLE_ADVANCED_MODE . id ,
233
246
command : ArduinoCommands . TOGGLE_ADVANCED_MODE_TOOLBAR . id ,
@@ -335,21 +348,65 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
335
348
}
336
349
} ) ;
337
350
338
- registry . registerCommand ( ArduinoCommands . NEW_SKETCH , new WorkspaceRootUriAwareCommandHandler ( this . workspaceService , this . selectionService , {
339
- execute : async uri => {
340
- try {
341
- // hack: sometimes we don't get the workspace root, but the currently active file: correct for that
342
- if ( uri . path . ext !== "" ) {
343
- uri = uri . withPath ( uri . path . dir . dir ) ;
344
- }
351
+ registry . registerCommand ( ArduinoCommands . SAVE_SKETCH_AS , {
352
+ execute : async ( { execOnlyIfTemp } : { execOnlyIfTemp : boolean } = { execOnlyIfTemp : false } ) => {
353
+ const sketches = ( await Promise . all ( this . workspaceService . tryGetRoots ( ) . map ( ( { uri } ) => this . sketchService . getSketchFolder ( uri ) ) ) ) . filter ( notEmpty ) ;
354
+ if ( ! sketches . length ) {
355
+ return ;
356
+ }
357
+ if ( sketches . length > 1 ) {
358
+ console . log ( `Multiple sketch folders were found in the workspace. Falling back to the first one. Sketch folders: ${ JSON . stringify ( sketches ) } ` ) ;
359
+ }
360
+ const sketch = sketches [ 0 ] ;
361
+ const isTemp = await this . sketchService . isTemp ( sketch ) ;
362
+ if ( ! isTemp && ! ! execOnlyIfTemp ) {
363
+ return ;
364
+ }
345
365
346
- const sketch = await this . sketchService . createNewSketch ( uri . toString ( ) ) ;
366
+ // If target does not exist, propose a `directories.user`/${sketch.name} path
367
+ // If target exists, propose `directories.user`/${sketch.name}_copy_${yyyymmddHHMMss}
368
+ const sketchDirUri = new URI ( ( await this . configService . getConfiguration ( ) ) . sketchDirUri ) ;
369
+ const exists = await this . fileSystem . exists ( sketchDirUri . resolve ( sketch . name ) . toString ( ) ) ;
370
+ const defaultUri = exists
371
+ ? sketchDirUri . resolve ( sketchDirUri . resolve ( `${ sketch . name } _copy_${ dateFormat ( new Date ( ) , 'yyyymmddHHMMss' ) } ` ) . toString ( ) )
372
+ : sketchDirUri . resolve ( sketch . name ) ;
373
+ const defaultPath = await this . fileSystem . getFsPath ( defaultUri . toString ( ) ) ! ;
374
+ const fsPath = await new Promise < string | undefined > ( resolve => {
375
+ remote . dialog . showSaveDialog ( {
376
+ title : 'Save sketch folder as...' ,
377
+ defaultPath
378
+ } , ( filename ) => resolve ( filename ) ) ;
379
+ } ) ;
380
+ if ( ! fsPath ) { // Canceled
381
+ return ;
382
+ }
383
+ const destinationUri = await this . fileSystemExt . getUri ( fsPath ) ;
384
+ if ( ! destinationUri ) {
385
+ return ;
386
+ }
387
+ const workspaceUri = await this . sketchService . copy ( sketch , { destinationUri } ) ;
388
+ if ( workspaceUri ) {
389
+ this . workspaceService . open ( new URI ( workspaceUri ) ) ;
390
+ }
391
+ }
392
+ } ) ;
393
+
394
+ registry . registerCommand ( ArduinoCommands . NEW_SKETCH , {
395
+ execute : async ( ) => {
396
+ try {
397
+ const sketch = await this . sketchService . createNewSketch ( ) ;
347
398
this . workspaceService . open ( new URI ( sketch . uri ) ) ;
348
399
} catch ( e ) {
349
400
await this . messageService . error ( e . toString ( ) ) ;
350
401
}
351
402
}
352
- } ) ) ;
403
+ } ) ;
404
+ registry . registerCommand ( ArduinoCommands . NEW_SKETCH_TOOLBAR , {
405
+ isVisible : widget => ArduinoToolbar . is ( widget ) && widget . side === 'left' ,
406
+ execute : async ( ) => {
407
+ return registry . executeCommand ( ArduinoCommands . NEW_SKETCH . id ) ;
408
+ }
409
+ } ) ;
353
410
354
411
registry . registerCommand ( ArduinoCommands . OPEN_BOARDS_DIALOG , {
355
412
execute : async ( ) => {
@@ -481,7 +538,6 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
481
538
registry . getMenu ( MAIN_MENU_BAR ) . removeNode ( this . getMenuId ( TerminalMenus . TERMINAL ) ) ;
482
539
registry . getMenu ( MAIN_MENU_BAR ) . removeNode ( this . getMenuId ( CommonMenus . VIEW ) ) ;
483
540
}
484
-
485
541
registry . registerSubmenu ( ArduinoMenus . SKETCH , 'Sketch' ) ;
486
542
registry . registerMenuAction ( ArduinoMenus . SKETCH , {
487
543
commandId : ArduinoCommands . TOGGLE_COMPILE_FOR_DEBUG . id ,
@@ -517,6 +573,11 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
517
573
registry . registerMenuAction ( [ ...CommonMenus . FILE_SETTINGS_SUBMENU , '3_settings_cli' ] , {
518
574
commandId : ArduinoCommands . OPEN_CLI_CONFIG . id
519
575
} ) ;
576
+
577
+ registry . registerMenuAction ( CommonMenus . FILE_SAVE , {
578
+ commandId : ArduinoCommands . SAVE_SKETCH_AS . id ,
579
+ label : 'Save As...'
580
+ } ) ;
520
581
}
521
582
522
583
protected getMenuId ( menuPath : string [ ] ) : string {
@@ -526,13 +587,22 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
526
587
}
527
588
528
589
registerKeybindings ( keybindings : KeybindingRegistry ) : void {
590
+ keybindings . unregisterKeybinding ( 'ctrlcmd+n' ) ; // Unregister the keybinding for `New File`, will be used by `New Sketch`. (eclipse-theia/theia#8170)
529
591
keybindings . registerKeybinding ( {
530
592
command : ArduinoCommands . VERIFY . id ,
531
- keybinding : 'ctrlcmd+alt+v '
593
+ keybinding : 'CtrlCmd+Alt+V '
532
594
} ) ;
533
595
keybindings . registerKeybinding ( {
534
596
command : ArduinoCommands . UPLOAD . id ,
535
- keybinding : 'ctrlcmd+alt+u'
597
+ keybinding : 'CtrlCmd+Alt+U'
598
+ } ) ;
599
+ keybindings . registerKeybinding ( {
600
+ command : ArduinoCommands . NEW_SKETCH . id ,
601
+ keybinding : 'CtrlCmd+N'
602
+ } ) ;
603
+ keybindings . registerKeybinding ( {
604
+ command : ArduinoCommands . SAVE_SKETCH_AS . id ,
605
+ keybinding : 'CtrlCmd+Shift+S'
536
606
} ) ;
537
607
}
538
608
0 commit comments