mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-21 10:16:33 +00:00
ATL-78: Implemented include library.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
56ff86629c
commit
7a37aa2e2f
@ -10,7 +10,7 @@
|
||||
|
||||
(() => {
|
||||
|
||||
const DEFAULT_VERSION = '0.13.0-rc1'; // require('moment')().format('YYYYMMDD');
|
||||
const DEFAULT_VERSION = '0.13.0-rc2'; // require('moment')().format('YYYYMMDD');
|
||||
|
||||
const path = require('path');
|
||||
const shell = require('shelljs');
|
||||
|
@ -122,7 +122,6 @@ import { ExamplesServicePath, ExamplesService } from '../common/protocol/example
|
||||
import { BuiltInExamples, LibraryExamples } from './contributions/examples';
|
||||
import { LibraryServiceProvider } from './library/library-service-provider';
|
||||
import { IncludeLibrary } from './contributions/include-library';
|
||||
import { IncludeLibraryMenuUpdater } from './library/include-library-menu-updater';
|
||||
|
||||
const ElementQueries = require('css-element-queries/src/ElementQueries');
|
||||
|
||||
@ -158,7 +157,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
// Library service
|
||||
bind(LibraryServiceProvider).toSelf().inSingletonScope();
|
||||
bind(LibraryServiceServer).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, LibraryServiceServerPath)).inSingletonScope();
|
||||
bind(FrontendApplicationContribution).to(IncludeLibraryMenuUpdater).inSingletonScope();
|
||||
|
||||
// Library list widget
|
||||
bind(LibraryListWidget).toSelf();
|
||||
|
@ -1,3 +1,4 @@
|
||||
import * as PQueue from 'p-queue';
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { MenuPath, SubMenuOptions } from '@theia/core/lib/common/menu';
|
||||
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
|
@ -1,15 +1,49 @@
|
||||
import { /*inject,*/ injectable } from 'inversify';
|
||||
// import { remote } from 'electron';
|
||||
// import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import * as PQueue from 'p-queue';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
|
||||
import { EditorManager } from '@theia/editor/lib/browser';
|
||||
import { MenuModelRegistry, MenuPath } from '@theia/core/lib/common/menu';
|
||||
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { LibraryPackage, LibraryLocation } from '../../common/protocol';
|
||||
import { MainMenuManager } from '../../common/main-menu-manager';
|
||||
import { LibraryListWidget } from '../library/library-list-widget';
|
||||
import { LibraryServiceProvider } from '../library/library-service-provider';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { SketchContribution, Command, CommandRegistry } from './contribution';
|
||||
import { LibraryPackage } from '../../common/protocol';
|
||||
// import { SaveAsSketch } from './save-as-sketch';
|
||||
// import { EditorManager } from '@theia/editor/lib/browser';
|
||||
// import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
|
||||
|
||||
@injectable()
|
||||
export class IncludeLibrary extends SketchContribution {
|
||||
|
||||
@inject(CommandRegistry)
|
||||
protected readonly commandRegistry: CommandRegistry;
|
||||
|
||||
@inject(MenuModelRegistry)
|
||||
protected readonly menuRegistry: MenuModelRegistry;
|
||||
|
||||
@inject(MainMenuManager)
|
||||
protected readonly mainMenuManager: MainMenuManager;
|
||||
|
||||
@inject(EditorManager)
|
||||
protected readonly editorManager: EditorManager;
|
||||
|
||||
@inject(LibraryServiceProvider)
|
||||
protected readonly libraryServiceProvider: LibraryServiceProvider;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
|
||||
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
|
||||
protected readonly toDispose = new DisposableCollection();
|
||||
|
||||
onStart(): void {
|
||||
this.updateMenuActions();
|
||||
this.boardsServiceClient.onBoardsConfigChanged(() => this.updateMenuActions())
|
||||
this.libraryServiceProvider.onLibraryPackageInstalled(() => this.updateMenuActions());
|
||||
this.libraryServiceProvider.onLibraryPackageUninstalled(() => this.updateMenuActions());
|
||||
}
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(IncludeLibrary.Commands.INCLUDE_LIBRARY, {
|
||||
execute: async arg => {
|
||||
@ -20,9 +54,95 @@ export class IncludeLibrary extends SketchContribution {
|
||||
});
|
||||
}
|
||||
|
||||
protected async updateMenuActions(): Promise<void> {
|
||||
return this.queue.add(async () => {
|
||||
this.toDispose.dispose();
|
||||
this.mainMenuManager.update();
|
||||
const libraries: LibraryPackage[] = []
|
||||
const fqbn = this.boardsServiceClient.boardsConfig.selectedBoard?.fqbn;
|
||||
// Do not show board specific examples, when no board is selected.
|
||||
if (fqbn) {
|
||||
libraries.push(...await this.libraryServiceProvider.list({ fqbn }));
|
||||
}
|
||||
|
||||
// `Include Library` submenu
|
||||
const includeLibMenuPath = [...ArduinoMenus.SKETCH__UTILS_GROUP, '0_include'];
|
||||
this.menuRegistry.registerSubmenu(includeLibMenuPath, 'Include Library', { order: '1' });
|
||||
// `Manage Libraries...` group.
|
||||
this.menuRegistry.registerMenuAction([...includeLibMenuPath, '0_manage'], {
|
||||
commandId: `${LibraryListWidget.WIDGET_ID}:toggle`,
|
||||
label: 'Manage Libraries...'
|
||||
});
|
||||
this.toDispose.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction({ commandId: `${LibraryListWidget.WIDGET_ID}:toggle` })));
|
||||
|
||||
// `Add .ZIP Library...`
|
||||
// TODO: implement it
|
||||
|
||||
// `Arduino libraries`
|
||||
const packageMenuPath = [...includeLibMenuPath, '2_arduino'];
|
||||
const userMenuPath = [...includeLibMenuPath, '3_contributed'];
|
||||
for (const library of libraries) {
|
||||
this.toDispose.push(this.registerLibrary(library, library.location === LibraryLocation.USER ? userMenuPath : packageMenuPath));
|
||||
}
|
||||
|
||||
this.mainMenuManager.update();
|
||||
});
|
||||
}
|
||||
|
||||
protected registerLibrary(library: LibraryPackage, menuPath: MenuPath): Disposable {
|
||||
const commandId = `arduino-include-library--${library.name}:${library.author}`;
|
||||
const command = { id: commandId };
|
||||
const handler = { execute: () => this.commandRegistry.executeCommand(IncludeLibrary.Commands.INCLUDE_LIBRARY.id, library) };
|
||||
const menuAction = { commandId, label: library.name };
|
||||
this.menuRegistry.registerMenuAction(menuPath, menuAction);
|
||||
return new DisposableCollection(
|
||||
this.commandRegistry.registerCommand(command, handler),
|
||||
Disposable.create(() => this.menuRegistry.unregisterMenuAction(menuAction)),
|
||||
);
|
||||
}
|
||||
|
||||
protected async includeLibrary(library: LibraryPackage): Promise<void> {
|
||||
// Always include to the main sketch file unless a c, cpp, or h file is the active one.
|
||||
console.log('INCLUDE', library);
|
||||
const sketch = await this.sketchServiceClient.currentSketch();
|
||||
if (!sketch) {
|
||||
return;
|
||||
}
|
||||
// If the current editor is one of the additional files from the sketch, we use that.
|
||||
// Otherwise, we pick the editor of the main sketch file.
|
||||
let codeEditor: monaco.editor.IStandaloneCodeEditor | undefined;
|
||||
const editor = this.editorManager.currentEditor?.editor;
|
||||
if (editor instanceof MonacoEditor) {
|
||||
if (sketch.additionalFileUris.some(uri => uri === editor.uri.toString())) {
|
||||
codeEditor = editor.getControl();
|
||||
}
|
||||
}
|
||||
|
||||
if (!codeEditor) {
|
||||
const widget = await this.editorManager.open(new URI(sketch.mainFileUri));
|
||||
if (widget.editor instanceof MonacoEditor) {
|
||||
codeEditor = widget.editor.getControl();
|
||||
}
|
||||
}
|
||||
|
||||
if (!codeEditor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const textModel = codeEditor.getModel();
|
||||
if (!textModel) {
|
||||
return;
|
||||
}
|
||||
const cursorState = codeEditor.getSelections() || [];
|
||||
const eol = textModel.getEOL();
|
||||
const includes = library.includes.slice();
|
||||
includes.push(''); // For the trailing new line.
|
||||
const text = includes.map(include => include ? `#include <${include}>` : eol).join(eol);
|
||||
textModel.pushStackElement(); // Start a fresh operation.
|
||||
textModel.pushEditOperations(cursorState, [{
|
||||
range: new monaco.Range(1, 1, 1, 1),
|
||||
text,
|
||||
forceMoveMarkers: true
|
||||
}], () => cursorState);
|
||||
textModel.pushStackElement(); // Make it undoable.
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,94 +0,0 @@
|
||||
import * as PQueue from 'p-queue';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { CommandRegistry } from '@theia/core/lib/common/command';
|
||||
import { MenuModelRegistry, MenuPath } from '@theia/core/lib/common/menu';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser';
|
||||
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { LibraryPackage } from '../../common/protocol';
|
||||
import { IncludeLibrary } from '../contributions/include-library';
|
||||
import { MainMenuManager } from '../../common/main-menu-manager';
|
||||
import { LibraryListWidget } from './library-list-widget';
|
||||
import { LibraryServiceProvider } from './library-service-provider';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
|
||||
@injectable()
|
||||
export class IncludeLibraryMenuUpdater implements FrontendApplicationContribution {
|
||||
|
||||
@inject(CommandRegistry)
|
||||
protected readonly commandRegistry: CommandRegistry;
|
||||
|
||||
@inject(MenuModelRegistry)
|
||||
protected readonly menuRegistry: MenuModelRegistry;
|
||||
|
||||
@inject(MainMenuManager)
|
||||
protected readonly mainMenuManager: MainMenuManager;
|
||||
|
||||
@inject(LibraryServiceProvider)
|
||||
protected readonly libraryServiceProvider: LibraryServiceProvider;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
|
||||
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
|
||||
protected readonly toDispose = new DisposableCollection();
|
||||
|
||||
async onStart(): Promise<void> {
|
||||
this.updateMenuActions();
|
||||
this.boardsServiceClient.onBoardsConfigChanged(() => this.updateMenuActions())
|
||||
this.libraryServiceProvider.onLibraryPackageInstalled(() => this.updateMenuActions());
|
||||
this.libraryServiceProvider.onLibraryPackageUninstalled(() => this.updateMenuActions());
|
||||
}
|
||||
|
||||
protected async updateMenuActions(): Promise<void> {
|
||||
return this.queue.add(async () => {
|
||||
this.toDispose.dispose();
|
||||
this.mainMenuManager.update();
|
||||
const libraries: LibraryPackage[] = []
|
||||
const fqbn = this.boardsServiceClient.boardsConfig.selectedBoard?.fqbn;
|
||||
// Do not show board specific examples, when no board is selected.
|
||||
if (fqbn) {
|
||||
libraries.push(...await this.libraryServiceProvider.list({ fqbn }));
|
||||
}
|
||||
|
||||
// `Include Library` submenu
|
||||
const includeLibMenuPath = [...ArduinoMenus.SKETCH__UTILS_GROUP, '0_include'];
|
||||
this.menuRegistry.registerSubmenu(includeLibMenuPath, 'Include Library', { order: '1' });
|
||||
// `Manage Libraries...` group.
|
||||
this.menuRegistry.registerMenuAction([...includeLibMenuPath, '0_manage'], {
|
||||
commandId: `${LibraryListWidget.WIDGET_ID}:toggle`,
|
||||
label: 'Manage Libraries...'
|
||||
});
|
||||
this.toDispose.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction({ commandId: `${LibraryListWidget.WIDGET_ID}:toggle` })));
|
||||
|
||||
// `Add .ZIP Library...`
|
||||
// TODO: implement it
|
||||
|
||||
// `Arduino libraries`
|
||||
const arduinoLibsMenuPath = [...includeLibMenuPath, '2_arduino'];
|
||||
for (const library of libraries.filter(({ author }) => author.toLowerCase() === 'arduino')) {
|
||||
this.toDispose.push(this.registerLibrary(library, arduinoLibsMenuPath));
|
||||
}
|
||||
|
||||
const contributedLibsMenuPath = [...includeLibMenuPath, '3_contributed'];
|
||||
for (const library of libraries.filter(({ author }) => author.toLowerCase() !== 'arduino')) {
|
||||
this.toDispose.push(this.registerLibrary(library, contributedLibsMenuPath));
|
||||
}
|
||||
|
||||
this.mainMenuManager.update();
|
||||
});
|
||||
}
|
||||
|
||||
protected registerLibrary(library: LibraryPackage, menuPath: MenuPath): Disposable {
|
||||
const commandId = `arduino-include-library--${library.name}:${library.author}`;
|
||||
const command = { id: commandId };
|
||||
const handler = { execute: () => this.commandRegistry.executeCommand(IncludeLibrary.Commands.INCLUDE_LIBRARY.id, library) };
|
||||
const menuAction = { commandId, label: library.name };
|
||||
this.menuRegistry.registerMenuAction(menuPath, menuAction);
|
||||
return new DisposableCollection(
|
||||
this.commandRegistry.registerCommand(command, handler),
|
||||
Disposable.create(() => this.menuRegistry.unregisterMenuAction(menuAction)),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -726,6 +726,11 @@ export class Library extends jspb.Message {
|
||||
setExamplesList(value: Array<string>): Library;
|
||||
addExamples(value: string, index?: number): string;
|
||||
|
||||
clearProvidesIncludesList(): void;
|
||||
getProvidesIncludesList(): Array<string>;
|
||||
setProvidesIncludesList(value: Array<string>): Library;
|
||||
addProvidesIncludes(value: string, index?: number): string;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): Library.AsObject;
|
||||
@ -764,6 +769,7 @@ export namespace Library {
|
||||
location: LibraryLocation,
|
||||
layout: LibraryLayout,
|
||||
examplesList: Array<string>,
|
||||
providesIncludesList: Array<string>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4762,7 +4762,7 @@ proto.cc.arduino.cli.commands.InstalledLibrary.prototype.hasRelease = function()
|
||||
* @private {!Array<number>}
|
||||
* @const
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Library.repeatedFields_ = [8,9,26];
|
||||
proto.cc.arduino.cli.commands.Library.repeatedFields_ = [8,9,26,27];
|
||||
|
||||
|
||||
|
||||
@ -4818,7 +4818,8 @@ proto.cc.arduino.cli.commands.Library.toObject = function(includeInstance, msg)
|
||||
propertiesMap: (f = msg.getPropertiesMap()) ? f.toObject(includeInstance, undefined) : [],
|
||||
location: jspb.Message.getFieldWithDefault(msg, 24, 0),
|
||||
layout: jspb.Message.getFieldWithDefault(msg, 25, 0),
|
||||
examplesList: (f = jspb.Message.getRepeatedField(msg, 26)) == null ? undefined : f
|
||||
examplesList: (f = jspb.Message.getRepeatedField(msg, 26)) == null ? undefined : f,
|
||||
providesIncludesList: (f = jspb.Message.getRepeatedField(msg, 27)) == null ? undefined : f
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@ -4953,6 +4954,10 @@ proto.cc.arduino.cli.commands.Library.deserializeBinaryFromReader = function(msg
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.addExamples(value);
|
||||
break;
|
||||
case 27:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.addProvidesIncludes(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@ -5147,6 +5152,13 @@ proto.cc.arduino.cli.commands.Library.serializeBinaryToWriter = function(message
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getProvidesIncludesList();
|
||||
if (f.length > 0) {
|
||||
writer.writeRepeatedString(
|
||||
27,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -5643,6 +5655,43 @@ proto.cc.arduino.cli.commands.Library.prototype.clearExamplesList = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* repeated string provides_includes = 27;
|
||||
* @return {!Array<string>}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Library.prototype.getProvidesIncludesList = function() {
|
||||
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 27));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Array<string>} value
|
||||
* @return {!proto.cc.arduino.cli.commands.Library} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Library.prototype.setProvidesIncludesList = function(value) {
|
||||
return jspb.Message.setField(this, 27, value || []);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @param {number=} opt_index
|
||||
* @return {!proto.cc.arduino.cli.commands.Library} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Library.prototype.addProvidesIncludes = function(value, opt_index) {
|
||||
return jspb.Message.addToRepeatedField(this, 27, value, opt_index);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the list making it empty but non-null.
|
||||
* @return {!proto.cc.arduino.cli.commands.Library} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.Library.prototype.clearProvidesIncludesList = function() {
|
||||
return this.setProvidesIncludesList([]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
|
@ -11,7 +11,8 @@ import {
|
||||
LibraryInstallReq,
|
||||
LibraryInstallResp,
|
||||
LibraryUninstallReq,
|
||||
LibraryUninstallResp
|
||||
LibraryUninstallResp,
|
||||
Library
|
||||
} from './cli-protocol/commands/lib_pb';
|
||||
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
|
||||
import { Installable } from '../common/protocol/installable';
|
||||
@ -87,7 +88,7 @@ export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
installable: true,
|
||||
installedVersion,
|
||||
}, item.getLatest()!, availableVersions)
|
||||
})
|
||||
});
|
||||
|
||||
return items;
|
||||
}
|
||||
@ -109,9 +110,8 @@ export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
|
||||
const resp = await new Promise<LibraryListResp>((resolve, reject) => client.libraryList(req, ((error, resp) => !!error ? reject(error) : resolve(resp))));
|
||||
return resp.getInstalledLibraryList().map(item => {
|
||||
const release = item.getRelease();
|
||||
const library = item.getLibrary();
|
||||
if (!release || !library) {
|
||||
if (!library) {
|
||||
return undefined;
|
||||
}
|
||||
const installedVersion = library.getVersion();
|
||||
@ -123,11 +123,11 @@ export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
description: library.getSentence(),
|
||||
summary: library.getParagraph(),
|
||||
moreInfoLink: library.getWebsite(),
|
||||
includes: release.getProvidesIncludesList(),
|
||||
includes: library.getProvidesIncludesList(),
|
||||
location: library.getLocation(),
|
||||
installDirUri: FileUri.create(library.getInstallDir()).toString(),
|
||||
exampleUris: library.getExamplesList().map(fsPath => FileUri.create(fsPath).toString())
|
||||
}, release, [library.getVersion()]);
|
||||
}, library, [library.getVersion()]);
|
||||
}).filter(notEmpty);
|
||||
}
|
||||
|
||||
@ -212,7 +212,7 @@ export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
|
||||
}
|
||||
|
||||
function toLibrary(pkg: Partial<LibraryPackage>, release: LibraryRelease, availableVersions: string[]): LibraryPackage {
|
||||
function toLibrary(pkg: Partial<LibraryPackage>, lib: LibraryRelease | Library, availableVersions: string[]): LibraryPackage {
|
||||
return {
|
||||
name: '',
|
||||
label: '',
|
||||
@ -221,11 +221,11 @@ function toLibrary(pkg: Partial<LibraryPackage>, release: LibraryRelease, availa
|
||||
location: 0,
|
||||
...pkg,
|
||||
|
||||
author: release.getAuthor(),
|
||||
author: lib.getAuthor(),
|
||||
availableVersions,
|
||||
includes: release.getProvidesIncludesList(),
|
||||
description: release.getSentence(),
|
||||
moreInfoLink: release.getWebsite(),
|
||||
summary: release.getParagraph()
|
||||
includes: lib.getProvidesIncludesList(),
|
||||
description: lib.getSentence(),
|
||||
moreInfoLink: lib.getWebsite(),
|
||||
summary: lib.getParagraph()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user