1
- import { /*inject,*/ injectable } from 'inversify' ;
2
- // import { remote } from 'electron';
3
- // import { ArduinoMenus } from '../menu/arduino-menus';
1
+ import * as PQueue from 'p-queue' ;
2
+ import { inject , injectable } from 'inversify' ;
3
+ import URI from '@theia/core/lib/common/uri' ;
4
+ import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor' ;
5
+ import { EditorManager } from '@theia/editor/lib/browser' ;
6
+ import { MenuModelRegistry , MenuPath } from '@theia/core/lib/common/menu' ;
7
+ import { Disposable , DisposableCollection } from '@theia/core/lib/common/disposable' ;
8
+ import { ArduinoMenus } from '../menu/arduino-menus' ;
9
+ import { LibraryPackage , LibraryLocation } from '../../common/protocol' ;
10
+ import { MainMenuManager } from '../../common/main-menu-manager' ;
11
+ import { LibraryListWidget } from '../library/library-list-widget' ;
12
+ import { LibraryServiceProvider } from '../library/library-service-provider' ;
13
+ import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl' ;
4
14
import { SketchContribution , Command , CommandRegistry } from './contribution' ;
5
- import { LibraryPackage } from '../../common/protocol' ;
6
- // import { SaveAsSketch } from './save-as-sketch';
7
- // import { EditorManager } from '@theia/editor/lib/browser';
8
- // import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
9
15
10
16
@injectable ( )
11
17
export class IncludeLibrary extends SketchContribution {
12
18
19
+ @inject ( CommandRegistry )
20
+ protected readonly commandRegistry : CommandRegistry ;
21
+
22
+ @inject ( MenuModelRegistry )
23
+ protected readonly menuRegistry : MenuModelRegistry ;
24
+
25
+ @inject ( MainMenuManager )
26
+ protected readonly mainMenuManager : MainMenuManager ;
27
+
28
+ @inject ( EditorManager )
29
+ protected readonly editorManager : EditorManager ;
30
+
31
+ @inject ( LibraryServiceProvider )
32
+ protected readonly libraryServiceProvider : LibraryServiceProvider ;
33
+
34
+ @inject ( BoardsServiceClientImpl )
35
+ protected readonly boardsServiceClient : BoardsServiceClientImpl ;
36
+
37
+ protected readonly queue = new PQueue ( { autoStart : true , concurrency : 1 } ) ;
38
+ protected readonly toDispose = new DisposableCollection ( ) ;
39
+
40
+ onStart ( ) : void {
41
+ this . updateMenuActions ( ) ;
42
+ this . boardsServiceClient . onBoardsConfigChanged ( ( ) => this . updateMenuActions ( ) )
43
+ this . libraryServiceProvider . onLibraryPackageInstalled ( ( ) => this . updateMenuActions ( ) ) ;
44
+ this . libraryServiceProvider . onLibraryPackageUninstalled ( ( ) => this . updateMenuActions ( ) ) ;
45
+ }
46
+
13
47
registerCommands ( registry : CommandRegistry ) : void {
14
48
registry . registerCommand ( IncludeLibrary . Commands . INCLUDE_LIBRARY , {
15
49
execute : async arg => {
@@ -20,9 +54,95 @@ export class IncludeLibrary extends SketchContribution {
20
54
} ) ;
21
55
}
22
56
57
+ protected async updateMenuActions ( ) : Promise < void > {
58
+ return this . queue . add ( async ( ) => {
59
+ this . toDispose . dispose ( ) ;
60
+ this . mainMenuManager . update ( ) ;
61
+ const libraries : LibraryPackage [ ] = [ ]
62
+ const fqbn = this . boardsServiceClient . boardsConfig . selectedBoard ?. fqbn ;
63
+ // Do not show board specific examples, when no board is selected.
64
+ if ( fqbn ) {
65
+ libraries . push ( ...await this . libraryServiceProvider . list ( { fqbn } ) ) ;
66
+ }
67
+
68
+ // `Include Library` submenu
69
+ const includeLibMenuPath = [ ...ArduinoMenus . SKETCH__UTILS_GROUP , '0_include' ] ;
70
+ this . menuRegistry . registerSubmenu ( includeLibMenuPath , 'Include Library' , { order : '1' } ) ;
71
+ // `Manage Libraries...` group.
72
+ this . menuRegistry . registerMenuAction ( [ ...includeLibMenuPath , '0_manage' ] , {
73
+ commandId : `${ LibraryListWidget . WIDGET_ID } :toggle` ,
74
+ label : 'Manage Libraries...'
75
+ } ) ;
76
+ this . toDispose . push ( Disposable . create ( ( ) => this . menuRegistry . unregisterMenuAction ( { commandId : `${ LibraryListWidget . WIDGET_ID } :toggle` } ) ) ) ;
77
+
78
+ // `Add .ZIP Library...`
79
+ // TODO: implement it
80
+
81
+ // `Arduino libraries`
82
+ const packageMenuPath = [ ...includeLibMenuPath , '2_arduino' ] ;
83
+ const userMenuPath = [ ...includeLibMenuPath , '3_contributed' ] ;
84
+ for ( const library of libraries ) {
85
+ this . toDispose . push ( this . registerLibrary ( library , library . location === LibraryLocation . USER ? userMenuPath : packageMenuPath ) ) ;
86
+ }
87
+
88
+ this . mainMenuManager . update ( ) ;
89
+ } ) ;
90
+ }
91
+
92
+ protected registerLibrary ( library : LibraryPackage , menuPath : MenuPath ) : Disposable {
93
+ const commandId = `arduino-include-library--${ library . name } :${ library . author } ` ;
94
+ const command = { id : commandId } ;
95
+ const handler = { execute : ( ) => this . commandRegistry . executeCommand ( IncludeLibrary . Commands . INCLUDE_LIBRARY . id , library ) } ;
96
+ const menuAction = { commandId, label : library . name } ;
97
+ this . menuRegistry . registerMenuAction ( menuPath , menuAction ) ;
98
+ return new DisposableCollection (
99
+ this . commandRegistry . registerCommand ( command , handler ) ,
100
+ Disposable . create ( ( ) => this . menuRegistry . unregisterMenuAction ( menuAction ) ) ,
101
+ ) ;
102
+ }
103
+
23
104
protected async includeLibrary ( library : LibraryPackage ) : Promise < void > {
24
- // Always include to the main sketch file unless a c, cpp, or h file is the active one.
25
- console . log ( 'INCLUDE' , library ) ;
105
+ const sketch = await this . sketchServiceClient . currentSketch ( ) ;
106
+ if ( ! sketch ) {
107
+ return ;
108
+ }
109
+ // If the current editor is one of the additional files from the sketch, we use that.
110
+ // Otherwise, we pick the editor of the main sketch file.
111
+ let codeEditor : monaco . editor . IStandaloneCodeEditor | undefined ;
112
+ const editor = this . editorManager . currentEditor ?. editor ;
113
+ if ( editor instanceof MonacoEditor ) {
114
+ if ( sketch . additionalFileUris . some ( uri => uri === editor . uri . toString ( ) ) ) {
115
+ codeEditor = editor . getControl ( ) ;
116
+ }
117
+ }
118
+
119
+ if ( ! codeEditor ) {
120
+ const widget = await this . editorManager . open ( new URI ( sketch . mainFileUri ) ) ;
121
+ if ( widget . editor instanceof MonacoEditor ) {
122
+ codeEditor = widget . editor . getControl ( ) ;
123
+ }
124
+ }
125
+
126
+ if ( ! codeEditor ) {
127
+ return ;
128
+ }
129
+
130
+ const textModel = codeEditor . getModel ( ) ;
131
+ if ( ! textModel ) {
132
+ return ;
133
+ }
134
+ const cursorState = codeEditor . getSelections ( ) || [ ] ;
135
+ const eol = textModel . getEOL ( ) ;
136
+ const includes = library . includes . slice ( ) ;
137
+ includes . push ( '' ) ; // For the trailing new line.
138
+ const text = includes . map ( include => include ? `#include <${ include } >` : eol ) . join ( eol ) ;
139
+ textModel . pushStackElement ( ) ; // Start a fresh operation.
140
+ textModel . pushEditOperations ( cursorState , [ {
141
+ range : new monaco . Range ( 1 , 1 , 1 , 1 ) ,
142
+ text,
143
+ forceMoveMarkers : true
144
+ } ] , ( ) => cursorState ) ;
145
+ textModel . pushStackElement ( ) ; // Make it undoable.
26
146
}
27
147
28
148
}
0 commit comments