ATL-222: Moved the language feature to a VS Code extension.

Updated to next Theia: 1.6.0-next.b43a1623.

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
Akos Kitta 2020-09-08 13:15:55 +02:00 committed by Akos Kitta
parent fbebfc7cca
commit f26dae185b
30 changed files with 1368 additions and 3575 deletions

View File

@ -32,10 +32,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Install Node.js 10.x
- name: Install Node.js 12.x
uses: actions/setup-node@v1
with:
node-version: '10.x'
node-version: '12.14.1'
registry-url: 'https://registry.npmjs.org'
- name: Install Python 2.7

11
.vscode/tasks.json vendored
View File

@ -3,6 +3,17 @@
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Arduino Pro IDE - Rebuild Electron App",
"type": "shell",
"command": "yarn rebuild:browser && yarn rebuild:electron",
"group": "build",
"presentation": {
"reveal": "always",
"panel": "new",
"clear": false
}
},
{
"label": "Arduino Pro IDE - Start Browser App",
"type": "shell",

View File

@ -1,5 +1,5 @@
import { injectable, inject } from 'inversify';
import { MenuModelRegistry, Path, MessageService, Command, CommandRegistry } from '@theia/core';
import { MenuModelRegistry, MessageService, Command, CommandRegistry } from '@theia/core';
import { KeybindingRegistry } from '@theia/core/lib/browser';
import { TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import { DebugFrontendApplicationContribution, DebugCommands } from '@theia/debug/lib/browser/debug-frontend-application-contribution';
@ -62,8 +62,8 @@ export class ArduinoDebugFrontendApplicationContribution extends DebugFrontendAp
if (current.configuration.type === 'arduino') {
const wsStat = this.workspaceService.workspace;
let sketchFileURI: URI | undefined;
if (wsStat && await this.sketchesService.isSketchFolder(wsStat.uri)) {
const wsPath = new Path(wsStat.uri);
if (wsStat && await this.sketchesService.isSketchFolder(wsStat.resource.toString())) {
const wsPath = wsStat.resource.path;
const sketchFilePath = wsPath.join(wsPath.name + '.ino').toString();
sketchFileURI = new URI(sketchFilePath);
} else if (this.editorManager.currentEditor) {

View File

@ -30,6 +30,7 @@ export class ArduinoGDBBackend extends GDBBackend {
'--interpreter', 'mi2',
sketchDir
];
console.log('Starting debugger:', command, JSON.stringify(args));
const proc = spawn(command, args);
this.proc = proc;
this.out = proc.stdin;

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,6 @@
"@theia/editor": "next",
"@theia/filesystem": "next",
"@theia/git": "next",
"@theia/languages": "next",
"@theia/markers": "next",
"@theia/monaco": "next",
"@theia/navigator": "next",

View File

@ -1,4 +1,4 @@
import { MAIN_MENU_BAR, MenuContribution, MenuModelRegistry, SelectionService } from '@theia/core';
import { MAIN_MENU_BAR, MenuContribution, MenuModelRegistry, SelectionService, ILogger } from '@theia/core';
import {
ContextMenuRenderer,
FrontendApplication, FrontendApplicationContribution,
@ -13,7 +13,6 @@ import { MessageService } from '@theia/core/lib/common/message-service';
import URI from '@theia/core/lib/common/uri';
import { EditorMainMenu, EditorManager } from '@theia/editor/lib/browser';
import { FileDialogService } from '@theia/filesystem/lib/browser/file-dialog';
import { FileSystem } from '@theia/filesystem/lib/common';
import { ProblemContribution } from '@theia/markers/lib/browser/problem/problem-contribution';
import { MonacoMenus } from '@theia/monaco/lib/browser/monaco-menu';
import { FileNavigatorContribution } from '@theia/navigator/lib/browser/navigator-contribution';
@ -25,7 +24,7 @@ import { TerminalMenus } from '@theia/terminal/lib/browser/terminal-frontend-con
import { inject, injectable, postConstruct } from 'inversify';
import * as React from 'react';
import { MainMenuManager } from '../common/main-menu-manager';
import { BoardsService, BoardsServiceClient, CoreService, Port, SketchesService, ToolOutputServiceClient } from '../common/protocol';
import { BoardsService, BoardsServiceClient, CoreService, Port, SketchesService, ToolOutputServiceClient, ExecutableService } from '../common/protocol';
import { ArduinoDaemon } from '../common/protocol/arduino-daemon';
import { ConfigService } from '../common/protocol/config-service';
import { FileSystemExt } from '../common/protocol/filesystem-ext';
@ -41,11 +40,18 @@ import { MonitorConnection } from './monitor/monitor-connection';
import { MonitorViewContribution } from './monitor/monitor-view-contribution';
import { WorkspaceService } from './theia/workspace/workspace-service';
import { ArduinoToolbar } from './toolbar/arduino-toolbar';
import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
const debounce = require('lodash.debounce');
@injectable()
export class ArduinoFrontendContribution implements FrontendApplicationContribution,
TabBarToolbarContribution, CommandContribution, MenuContribution, ColorContribution {
@inject(ILogger)
protected logger: ILogger;
@inject(MessageService)
protected readonly messageService: MessageService;
@ -77,8 +83,8 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
@inject(FileDialogService)
protected readonly fileDialogService: FileDialogService;
@inject(FileSystem)
protected readonly fileSystem: FileSystem;
@inject(FileService)
protected readonly fileSystem: FileService;
@inject(SketchesService)
protected readonly sketchService: SketchesService;
@ -140,6 +146,12 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
@inject(FileSystemExt)
protected readonly fileSystemExt: FileSystemExt;
@inject(HostedPluginSupport)
protected hostedPluginSupport: HostedPluginSupport;
@inject(ExecutableService)
protected executableService: ExecutableService;
@postConstruct()
protected async init(): Promise<void> {
if (!window.navigator.onLine) {
@ -177,6 +189,35 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
viewContribution.initializeLayout(app);
}
}
this.boardsServiceClientImpl.onBoardsConfigChanged(async ({ selectedBoard }) => {
if (selectedBoard) {
const { name, fqbn } = selectedBoard;
if (fqbn) {
await this.hostedPluginSupport.didStart;
this.startLanguageServer(fqbn, name);
}
}
});
}
protected startLanguageServer = debounce((fqbn: string, name: string | undefined) => this.doStartLanguageServer(fqbn, name));
protected async doStartLanguageServer(fqbn: string, name: string | undefined): Promise<void> {
this.logger.info(`Starting language server: ${fqbn}`);
const { clangdUri, cliUri, lsUri } = await this.executableService.list();
const [clangdPath, cliPath, lsPath] = await Promise.all([
this.fileSystem.fsPath(new URI(clangdUri)),
this.fileSystem.fsPath(new URI(cliUri)),
this.fileSystem.fsPath(new URI(lsUri)),
]);
this.commandRegistry.executeCommand('arduino.languageserver.start', {
lsPath,
cliPath,
clangdPath,
board: {
fqbn,
name: name ? `"${name}"` : undefined
}
});
}
registerToolbarItems(registry: TabBarToolbarRegistry): void {
@ -208,7 +249,7 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
isToggled: () => this.editorMode.compileForDebug
});
registry.registerCommand(ArduinoCommands.OPEN_SKETCH_FILES, {
execute: async (uri: string) => {
execute: async (uri: URI) => {
this.openSketchFiles(uri);
}
});
@ -256,9 +297,9 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
});
}
protected async openSketchFiles(uri: string): Promise<void> {
protected async openSketchFiles(uri: URI): Promise<void> {
try {
const sketch = await this.sketchService.loadSketch(uri);
const sketch = await this.sketchService.loadSketch(uri.toString());
const { mainFileUri, otherSketchFileUris, additionalFileUris } = sketch;
for (const uri of [mainFileUri, ...otherSketchFileUris, ...additionalFileUris]) {
await this.ensureOpened(uri);

View File

@ -6,12 +6,8 @@ import { bindViewContribution } from '@theia/core/lib/browser/shell/view-contrib
import { TabBarToolbarContribution, TabBarToolbarFactory } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import { WebSocketConnectionProvider } from '@theia/core/lib/browser/messaging/ws-connection-provider';
import { FrontendApplicationContribution, FrontendApplication as TheiaFrontendApplication } from '@theia/core/lib/browser/frontend-application'
import { LanguageGrammarDefinitionContribution } from '@theia/monaco/lib/browser/textmate';
import { LanguageClientContribution } from '@theia/languages/lib/browser';
import { ArduinoLanguageClientContribution } from './language/arduino-language-client-contribution';
import { LibraryListWidget } from './library/library-list-widget';
import { ArduinoFrontendContribution } from './arduino-frontend-contribution';
import { ArduinoLanguageGrammarContribution } from './language/arduino-language-grammar-contribution';
import { LibraryServiceServer, LibraryServiceServerPath } from '../common/protocol/library-service';
import { BoardsService, BoardsServicePath, BoardsServiceClient } from '../common/protocol/boards-service';
import { SketchesService, SketchesServicePath } from '../common/protocol/sketches-service';
@ -125,6 +121,9 @@ import { IncludeLibrary } from './contributions/include-library';
import { OutputChannelManager as TheiaOutputChannelManager } from '@theia/output/lib/common/output-channel';
import { OutputChannelManager } from './theia/output/output-channel';
import { OutputChannelRegistryMainImpl as TheiaOutputChannelRegistryMainImpl, OutputChannelRegistryMainImpl } from './theia/plugin-ext/output-channel-registry-main';
import { ExecutableService, ExecutableServicePath } from '../common/protocol';
import { MonacoTextModelService as TheiaMonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
import { MonacoTextModelService } from './theia/monaco/monaco-text-model-service';
const ElementQueries = require('css-element-queries/src/ElementQueries');
@ -150,10 +149,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(ArduinoToolbarContribution).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(ArduinoToolbarContribution);
// `ino` TextMate grammar and language client
bind(LanguageGrammarDefinitionContribution).to(ArduinoLanguageGrammarContribution).inSingletonScope();
bind(LanguageClientContribution).to(ArduinoLanguageClientContribution).inSingletonScope();
// Renderer for both the library and the core widgets.
bind(ListItemRenderer).toSelf().inSingletonScope();
@ -317,6 +312,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
rebind(TheiaOutputChannelManager).toService(OutputChannelManager);
bind(OutputChannelRegistryMainImpl).toSelf().inTransientScope();
rebind(TheiaOutputChannelRegistryMainImpl).toService(OutputChannelRegistryMainImpl);
bind(MonacoTextModelService).toSelf().inSingletonScope();
rebind(TheiaMonacoTextModelService).toService(MonacoTextModelService);
// Show a disconnected status bar, when the daemon is not available
bind(ApplicationConnectionStatusContribution).toSelf().inSingletonScope();
@ -360,9 +357,12 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
// File-system extension
bind(FileSystemExt).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, FileSystemExtPath)).inSingletonScope();
// Examples service
// Examples service@
bind(ExamplesService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, ExamplesServicePath)).inSingletonScope();
// Executable URIs known by the backend
bind(ExecutableService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, ExecutableServicePath)).inSingletonScope();
Contribution.configure(bind, NewSketch);
Contribution.configure(bind, OpenSketch);
Contribution.configure(bind, CloseSketch);

View File

@ -1,40 +0,0 @@
import { injectable, inject, postConstruct } from 'inversify';
import { BaseLanguageClientContribution } from '@theia/languages/lib/browser';
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
import { BoardsConfig } from '../boards/boards-config';
@injectable()
export class ArduinoLanguageClientContribution extends BaseLanguageClientContribution {
readonly id = 'ino';
readonly name = 'Arduino';
protected get documentSelector(): string[] {
return ['ino'];
}
protected get globPatterns() {
return ['**/*.ino'];
}
@inject(BoardsServiceClientImpl)
protected readonly boardsServiceClient: BoardsServiceClientImpl;
protected boardConfig?: BoardsConfig.Config;
@postConstruct()
protected init() {
this.boardsServiceClient.onBoardsConfigChanged(this.selectBoard.bind(this));
}
selectBoard(config: BoardsConfig.Config): void {
this.boardConfig = config;
// Force a restart to send the new board config to the language server
this.restart();
}
protected getStartParameters(): BoardsConfig.Config | undefined {
return this.boardConfig;
}
}

View File

@ -1,63 +0,0 @@
import { injectable } from 'inversify';
import { LanguageGrammarDefinitionContribution, TextmateRegistry } from '@theia/monaco/lib/browser/textmate';
@injectable()
export class ArduinoLanguageGrammarContribution implements LanguageGrammarDefinitionContribution {
static INO_LANGUAGE_ID = 'ino';
registerTextmateLanguage(registry: TextmateRegistry) {
monaco.languages.register({
id: ArduinoLanguageGrammarContribution.INO_LANGUAGE_ID,
extensions: ['.ino'],
aliases: ['INO', 'Ino', 'ino'],
});
monaco.languages.setLanguageConfiguration(ArduinoLanguageGrammarContribution.INO_LANGUAGE_ID, this.configuration);
const inoGrammar = require('../../../data/ino.tmLanguage.json');
registry.registerTextmateGrammarScope('source.ino', {
async getGrammarDefinition() {
return {
format: 'json',
content: inoGrammar
};
}
});
registry.mapLanguageIdToTextmateGrammar(ArduinoLanguageGrammarContribution.INO_LANGUAGE_ID, 'source.ino');
}
private readonly configuration: monaco.languages.LanguageConfiguration = {
comments: {
lineComment: '//',
blockComment: ['/*', '*/'],
},
brackets: [
['{', '}'],
['[', ']'],
['(', ')']
],
autoClosingPairs: [
{ open: '[', close: ']' },
{ open: '{', close: '}' },
{ open: '(', close: ')' },
{ open: '\'', close: '\'', notIn: ['string', 'comment'] },
{ open: '"', close: '"', notIn: ['string'] },
{ open: '/*', close: ' */', notIn: ['string'] }
],
surroundingPairs: [
{ open: '{', close: '}' },
{ open: '[', close: ']' },
{ open: '(', close: ')' },
{ open: '"', close: '"' },
{ open: '\'', close: '\'' },
],
folding: {
markers: {
start: new RegExp('^\\s*#pragma\\s+region\\b'),
end: new RegExp('^\\s*#pragma\\s+endregion\\b')
}
}
};
}

View File

@ -1,5 +1,5 @@
import { injectable, inject } from 'inversify';
import { FileSystem } from '@theia/filesystem/lib/common/filesystem';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { CommandService } from '@theia/core/lib/common/command';
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
import { FrontendApplication as TheiaFrontendApplication } from '@theia/core/lib/browser/frontend-application';
@ -8,8 +8,8 @@ import { ArduinoCommands } from '../../arduino-commands';
@injectable()
export class FrontendApplication extends TheiaFrontendApplication {
@inject(FileSystem)
protected readonly fileSystem: FileSystem;
@inject(FileService)
protected readonly fileService: FileService;
@inject(WorkspaceService)
protected readonly workspaceService: WorkspaceService;
@ -21,9 +21,9 @@ export class FrontendApplication extends TheiaFrontendApplication {
await super.initializeLayout();
const roots = await this.workspaceService.roots;
for (const root of roots) {
const exists = await this.fileSystem.exists(root.uri);
const exists = await this.fileService.exists(root.resource);
if (exists) {
await this.commandService.executeCommand(ArduinoCommands.OPEN_SKETCH_FILES.id, root.uri);
await this.commandService.executeCommand(ArduinoCommands.OPEN_SKETCH_FILES.id, root.resource);
}
}
}

View File

@ -1,11 +1,11 @@
import { inject, injectable, postConstruct } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { Title, Widget } from '@phosphor/widgets';
import { ILogger } from '@theia/core';
import { ILogger } from '@theia/core/lib/common/logger';
import { EditorWidget } from '@theia/editor/lib/browser';
import { WidgetDecoration } from '@theia/core/lib/browser/widget-decoration';
import { TabBarDecoratorService as TheiaTabBarDecoratorService } from '@theia/core/lib/browser/shell/tab-bar-decorator';
import { ConfigService } from '../../../common/protocol/config-service';
import { EditorWidget } from '@theia/editor/lib/browser';
@injectable()
export class TabBarDecoratorService extends TheiaTabBarDecoratorService {
@ -20,7 +20,6 @@ export class TabBarDecoratorService extends TheiaTabBarDecoratorService {
@postConstruct()
protected init(): void {
super.init();
this.configService.getConfiguration()
.then(({ dataDirUri }) => this.dataDirUri = new URI(dataDirUri))
.catch(err => this.logger.error(`Failed to determine the data directory: ${err}`));

View File

@ -0,0 +1,29 @@
import { injectable } from 'inversify';
import { Resource } from '@theia/core/lib/common/resource';
import { MaybePromise } from '@theia/core/lib/common/types';
import { Log, Loggable } from '@theia/core/lib/common/logger';
import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
import { MonacoTextModelService as TheiaMonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
@injectable()
export class MonacoTextModelService extends TheiaMonacoTextModelService {
protected createModel(resource: Resource): MaybePromise<MonacoEditorModel> {
const factory = this.factories.getContributions().find(({ scheme }) => resource.uri.scheme === scheme);
return factory ? factory.createModel(resource) : new SilentMonacoEditorModel(resource, this.m2p, this.p2m, this.logger);
}
}
// https://github.com/eclipse-theia/theia/pull/8491
export class SilentMonacoEditorModel extends MonacoEditorModel {
protected trace(loggable: Loggable): void {
if (this.logger) {
this.logger.trace((log: Log) =>
loggable((message, ...params) => log(message, ...params, this.resource.uri.toString(true)))
);
}
}
}

View File

@ -1,7 +1,7 @@
import { inject, injectable } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { open } from '@theia/core/lib/browser/opener-service';
import { FileStat } from '@theia/filesystem/lib/common';
import { FileStat } from '@theia/filesystem/lib/common/files';
import { CommandRegistry, CommandService } from '@theia/core/lib/common/command';
import { WorkspaceCommandContribution as TheiaWorkspaceCommandContribution, WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands';
import { Sketch } from '../../../common/protocol';
@ -40,7 +40,7 @@ export class WorkspaceCommandContribution extends TheiaWorkspaceCommandContribut
return;
}
const parentUri = new URI(parent.uri);
const parentUri = parent.resource;
const dialog = new WorkspaceInputDialog({
title: 'Name for new file',
parentUri,
@ -51,7 +51,7 @@ export class WorkspaceCommandContribution extends TheiaWorkspaceCommandContribut
const nameWithExt = this.maybeAppendInoExt(name);
if (nameWithExt) {
const fileUri = parentUri.resolve(nameWithExt);
await this.fileSystem.createFile(fileUri.toString());
await this.fileService.createFile(fileUri);
this.fireCreateNewFile({ parent: parentUri, uri: fileUri });
open(this.openerService, fileUri);
}
@ -132,7 +132,7 @@ export class WorkspaceCommandContribution extends TheiaWorkspaceCommandContribut
if (newNameWithExt) {
const oldUri = uri;
const newUri = uri.parent.resolve(newNameWithExt);
this.fileSystem.move(oldUri.toString(), newUri.toString());
this.fileService.move(oldUri, newUri);
}
}

View File

@ -25,7 +25,7 @@ export class WorkspaceDeleteHandler extends TheiaWorkspaceDeleteHandler {
});
if (response === 1) { // OK
await Promise.all([...sketch.additionalFileUris, ...sketch.otherSketchFileUris, sketch.mainFileUri].map(uri => this.closeWithoutSaving(new URI(uri))));
await this.fileSystem.delete(sketch.uri);
await this.fileService.delete(new URI(sketch.uri));
window.close();
}
return;

View File

@ -74,7 +74,7 @@ export class WorkspaceService extends TheiaWorkspaceService {
}
private async isValid(uri: string): Promise<boolean> {
const exists = await this.fileSystem.exists(uri);
const exists = await this.fileService.exists(new URI(uri));
if (!exists) {
return false;
}
@ -104,8 +104,7 @@ export class WorkspaceService extends TheiaWorkspaceService {
protected get workspaceTitle(): string | undefined {
if (this.workspace) {
const uri = new URI(this.workspace.uri);
return this.labelProvider.getName(uri);
return this.labelProvider.getName(this.workspace.resource);
}
}

View File

@ -0,0 +1,5 @@
export const ExecutableServicePath = '/services/executable-service';
export const ExecutableService = Symbol('ExecutableService');
export interface ExecutableService {
list(): Promise<{ clangdUri: string, cliUri: string, lsUri: string }>;
}

View File

@ -10,3 +10,5 @@ export * from './monitor-service';
export * from './searchable';
export * from './sketches-service';
export * from './tool-output-service';
export * from './examples-service';
export * from './executable-service';

View File

@ -1,6 +1,7 @@
import { inject, injectable } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { notEmpty } from '@theia/core/lib/common/objects';
import { FileSystem } from '@theia/filesystem/lib/common';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { MessageService } from '@theia/core/lib/common/message-service';
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
import { Sketch, SketchesService } from '../../common/protocol';
@ -8,8 +9,8 @@ import { Sketch, SketchesService } from '../../common/protocol';
@injectable()
export class SketchesServiceClientImpl {
@inject(FileSystem)
protected readonly fileSystem: FileSystem;
@inject(FileService)
protected readonly fileService: FileService;
@inject(MessageService)
protected readonly messageService: MessageService;
@ -21,7 +22,7 @@ export class SketchesServiceClientImpl {
protected readonly workspaceService: WorkspaceService;
async currentSketch(): Promise<Sketch | undefined> {
const sketches = (await Promise.all(this.workspaceService.tryGetRoots().map(({ uri }) => this.sketchService.getSketchFolder(uri)))).filter(notEmpty);
const sketches = (await Promise.all(this.workspaceService.tryGetRoots().map(({ resource }) => this.sketchService.getSketchFolder(resource.toString())))).filter(notEmpty);
if (!sketches.length) {
return undefined;
}
@ -35,7 +36,7 @@ export class SketchesServiceClientImpl {
const sketch = await this.currentSketch();
if (sketch) {
const uri = sketch.mainFileUri;
const exists = await this.fileSystem.exists(uri);
const exists = await this.fileService.exists(new URI(uri));
if (!exists) {
this.messageService.warn(`Could not find sketch file: ${uri}`);
return undefined;

View File

@ -5,8 +5,6 @@ import { ContainerModule } from 'inversify';
import { ArduinoDaemonImpl } from './arduino-daemon-impl';
import { ILogger } from '@theia/core/lib/common/logger';
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
import { LanguageServerContribution } from '@theia/languages/lib/node';
import { ArduinoLanguageServerContribution } from './language/arduino-language-server-contribution';
import { LibraryServiceServerPath, LibraryServiceServer, LibraryServiceClient } from '../common/protocol/library-service';
import { BoardsService, BoardsServicePath, BoardsServiceClient } from '../common/protocol/boards-service';
import { LibraryServiceServerImpl } from './library-service-server-impl';
@ -37,6 +35,8 @@ import { NodeFileSystemExt } from './node-filesystem-ext';
import { FileSystemExt, FileSystemExtPath } from '../common/protocol/filesystem-ext';
import { ExamplesServiceImpl } from './examples-service-impl';
import { ExamplesService, ExamplesServicePath } from '../common/protocol/examples-service';
import { ExecutableService, ExecutableServicePath } from '../common/protocol/executable-service';
import { ExecutableServiceImpl } from './executable-service-impl';
export default new ContainerModule((bind, unbind, isBound, rebind) => {
rebind(EnvVariablesServer).to(ArduinoEnvVariablesServer).inSingletonScope();
@ -73,9 +73,10 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(ExamplesService).toService(ExamplesServiceImpl);
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(ExamplesServicePath, () => context.container.get(ExamplesService))).inSingletonScope();
// Language server
bind(ArduinoLanguageServerContribution).toSelf().inSingletonScope();
bind(LanguageServerContribution).toService(ArduinoLanguageServerContribution);
// Exposes the executable paths/URIs to the frontend
bind(ExecutableServiceImpl).toSelf().inSingletonScope();
bind(ExecutableService).toService(ExecutableServiceImpl);
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(ExecutableServicePath, () => context.container.get(ExecutableService))).inSingletonScope();
// Library service
bind(LibraryServiceServerImpl).toSelf().inSingletonScope();

View File

@ -1,5 +1,5 @@
import { inject, injectable, postConstruct } from 'inversify';
import { FileSystem } from '@theia/filesystem/lib/common/filesystem';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { CoreService, CoreServiceClient } from '../common/protocol/core-service';
import { CompileReq, CompileResp } from './cli-protocol/commands/compile_pb';
import { BoardsService } from '../common/protocol/boards-service';
@ -14,8 +14,6 @@ export class CoreServiceImpl implements CoreService {
@inject(CoreClientProvider)
protected readonly coreClientProvider: CoreClientProvider;
@inject(FileSystem)
protected readonly fileSystem: FileSystem;
@inject(BoardsService)
protected readonly boardsService: BoardsService;
@ -37,10 +35,7 @@ export class CoreServiceImpl implements CoreService {
async compile(options: CoreService.Compile.Options): Promise<void> {
this.toolOutputService.append({ tool: 'compile', chunk: 'Compiling...\n' + JSON.stringify(options, null, 2) + '\n--------------------------\n' });
const { sketchUri, fqbn } = options;
const sketchFilePath = await this.fileSystem.getFsPath(sketchUri);
if (!sketchFilePath) {
throw new Error(`Cannot resolve filesystem path for URI: ${sketchUri}.`);
}
const sketchFilePath = FileUri.fsPath(sketchUri);
const sketchpath = path.dirname(sketchFilePath);
const coreClient = await this.coreClientProvider.client();
@ -83,10 +78,7 @@ export class CoreServiceImpl implements CoreService {
await this.compile(options);
this.toolOutputService.append({ tool: 'upload', chunk: 'Uploading...\n' + JSON.stringify(options, null, 2) + '\n--------------------------\n' });
const { sketchUri, fqbn } = options;
const sketchFilePath = await this.fileSystem.getFsPath(sketchUri);
if (!sketchFilePath) {
throw new Error(`Cannot resolve filesystem path for URI: ${sketchUri}.`);
}
const sketchFilePath = FileUri.fsPath(sketchUri);
const sketchpath = path.dirname(sketchFilePath);
const coreClient = await this.coreClientProvider.client();

View File

@ -0,0 +1,31 @@
import * as os from 'os';
import { injectable, inject } from 'inversify';
import { ILogger } from '@theia/core/lib/common/logger';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { getExecPath } from './exec-util';
import { ExecutableService } from '../common/protocol/executable-service';
@injectable()
export class ExecutableServiceImpl implements ExecutableService {
@inject(ILogger)
protected logger: ILogger;
async list(): Promise<{ clangdUri: string, cliUri: string, lsUri: string }> {
const [ls, clangd, cli] = await Promise.all([
getExecPath('arduino-language-server', this.onError.bind(this)),
getExecPath('clangd', this.onError.bind(this), '--version', os.platform() !== 'win32'),
getExecPath('arduino-cli', this.onError.bind(this))
]);
return {
clangdUri: FileUri.create(clangd).toString(),
cliUri: FileUri.create(cli).toString(),
lsUri: FileUri.create(ls).toString()
};
}
protected onError(error: Error): void {
this.logger.error(error);
}
}

View File

@ -1,55 +0,0 @@
import * as os from 'os';
import { injectable, inject } from 'inversify';
import { ILogger } from '@theia/core';
import { BaseLanguageServerContribution, IConnection, LanguageServerStartOptions } from '@theia/languages/lib/node';
import { Board } from '../../common/protocol/boards-service';
import { getExecPath } from '../exec-util';
@injectable()
export class ArduinoLanguageServerContribution extends BaseLanguageServerContribution {
readonly description = {
id: 'ino',
name: 'Arduino',
documentSelector: ['ino'],
fileEvents: ['**/*.ino']
}
get id() {
return this.description.id;
}
get name() {
return this.description.name;
}
@inject(ILogger)
protected logger: ILogger;
async start(clientConnection: IConnection, options: LanguageServerStartOptions): Promise<void> {
const [languageServer, clangd, cli] = await Promise.all([
getExecPath('arduino-language-server', this.onError.bind(this)),
getExecPath('clangd', this.onError.bind(this), '--version', os.platform() !== 'win32'),
getExecPath('arduino-cli', this.onError.bind(this))
]);
// Add '-log' argument to enable logging to files
const args: string[] = ['-clangd', clangd, '-cli', cli];
if (options.parameters && options.parameters.selectedBoard) {
const board = options.parameters.selectedBoard as Board;
if (board.fqbn) {
args.push('-fqbn', board.fqbn);
}
if (board.name) {
args.push('-board-name', `"${board.name}"`);
}
}
console.log(`Starting language server ${languageServer} ${args.join(' ')}`);
const serverConnection = await this.createProcessStreamConnectionAsync(languageServer, args);
this.forward(clientConnection, serverConnection);
}
protected onError(error: Error): void {
this.logger.error(error);
}
}

View File

@ -9,7 +9,6 @@
"@theia/editor": "next",
"@theia/file-search": "next",
"@theia/filesystem": "next",
"@theia/languages": "next",
"@theia/messages": "next",
"@theia/monaco": "next",
"@theia/navigator": "next",

View File

@ -8,13 +8,13 @@ Building the Pro IDE on Linux `armv7l` (aka `armhf`) and `aarch64` (aka `arm64`)
```
Restart your shell then:
```
nvm install 10.15.3
nvm use 10.15.3
nvm install 12.14.1
nvm use 12.14.1
```
Verify:
```
node -v
v10.15.3
v12.14.1
```
2. Install [Yarn](https://classic.yarnpkg.com/en/docs/install/#debian-stable):

View File

@ -11,7 +11,6 @@
"@theia/electron": "next",
"@theia/file-search": "next",
"@theia/filesystem": "next",
"@theia/languages": "next",
"@theia/messages": "next",
"@theia/monaco": "next",
"@theia/navigator": "next",

View File

@ -25,7 +25,7 @@
"patch": "ncp ./patch/electron-main.js ./src-gen/frontend/electron-main.js && ncp ./patch/main.js ./src-gen/backend/main.js"
},
"engines": {
"node": ">=10.11.0 <13"
"node": ">=12.14.1 <13"
},
"repository": {
"type": "git",
@ -127,6 +127,7 @@
},
"theiaPluginsDir": "plugins",
"theiaPlugins": {
"vscode-builtin-cpp": "http://open-vsx.org/api/vscode/cpp/1.44.2/file/vscode.cpp-1.44.2.vsix"
"vscode-builtin-cpp": "http://open-vsx.org/api/vscode/cpp/1.44.2/file/vscode.cpp-1.44.2.vsix",
"vscode-arduino-language-server": "https://downloads.arduino.cc/vscode-arduino-language-server/nightly/vscode-arduino-language-server-0.0.1.vsix"
}
}

View File

@ -31,7 +31,7 @@
"yargs": "^12.0.5"
},
"engines": {
"node": ">=10.11.0 <13"
"node": ">=12.14.1 <13"
},
"mocha": {
"reporter": "spec",

View File

@ -7,7 +7,7 @@
"license": "MIT",
"private": true,
"engines": {
"node": ">=10.11.0 <13"
"node": ">=12.14.1 <13"
},
"devDependencies": {
"@theia/cli": "next",
@ -34,6 +34,7 @@
],
"theiaPluginsDir": "plugins",
"theiaPlugins": {
"vscode-builtin-cpp": "http://open-vsx.org/api/vscode/cpp/1.44.2/file/vscode.cpp-1.44.2.vsix"
"vscode-builtin-cpp": "http://open-vsx.org/api/vscode/cpp/1.44.2/file/vscode.cpp-1.44.2.vsix",
"vscode-arduino-language-server": "https://downloads.arduino.cc/vscode-arduino-language-server/nightly/vscode-arduino-language-server-0.0.1.vsix"
}
}

2162
yarn.lock

File diff suppressed because it is too large Load Diff