diff --git a/arduino-ide-extension/src/browser/arduino-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-frontend-module.ts index c11aca32..2e7e0d19 100644 --- a/arduino-ide-extension/src/browser/arduino-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-frontend-module.ts @@ -7,6 +7,8 @@ import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar import { WebSocketConnectionProvider } from '@theia/core/lib/browser/messaging/ws-connection-provider'; import { FrontendApplicationContribution, FrontendApplication } 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, ArduinoAdvancedMode } from './arduino-frontend-contribution'; import { ArduinoLanguageGrammarContribution } from './language/arduino-language-grammar-contribution'; @@ -78,8 +80,9 @@ export default new ContainerModule((bind: interfaces.Bind, unbind: interfaces.Un bind(ArduinoToolbarContribution).toSelf().inSingletonScope(); bind(FrontendApplicationContribution).toService(ArduinoToolbarContribution); - // `ino` TextMate grammar + // `ino` TextMate grammar and language client bind(LanguageGrammarDefinitionContribution).to(ArduinoLanguageGrammarContribution).inSingletonScope(); + bind(LanguageClientContribution).to(ArduinoLanguageClientContribution).inSingletonScope(); // Library service bind(LibraryService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, LibraryServicePath)).inSingletonScope(); diff --git a/arduino-ide-extension/src/browser/language/arduino-language-client-contribution.ts b/arduino-ide-extension/src/browser/language/arduino-language-client-contribution.ts new file mode 100644 index 00000000..e3c1cecc --- /dev/null +++ b/arduino-ide-extension/src/browser/language/arduino-language-client-contribution.ts @@ -0,0 +1,18 @@ +import { injectable } from 'inversify'; +import { BaseLanguageClientContribution } from '@theia/languages/lib/browser'; + +@injectable() +export class ArduinoLanguageClientContribution extends BaseLanguageClientContribution { + + readonly id = 'ino' + readonly name = 'Arduino' + + protected get documentSelector(): string[] { + return ['ino']; + } + + protected get globPatterns() { + return ['**/*.ino'] + } + +} diff --git a/arduino-ide-extension/src/node/arduino-backend-module.ts b/arduino-ide-extension/src/node/arduino-backend-module.ts index daeb3878..f69c39f4 100644 --- a/arduino-ide-extension/src/node/arduino-backend-module.ts +++ b/arduino-ide-extension/src/node/arduino-backend-module.ts @@ -2,6 +2,8 @@ import { ContainerModule } from 'inversify'; import { ArduinoDaemon } from './arduino-daemon'; 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 { LibraryService, LibraryServicePath } from '../common/protocol/library-service'; import { BoardsService, BoardsServicePath, BoardsServiceClient } from '../common/protocol/boards-service'; import { LibraryServiceImpl } from './library-service-impl'; @@ -40,6 +42,9 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(ArduinoDaemon).toSelf().inSingletonScope(); bind(BackendApplicationContribution).toService(ArduinoDaemon); + // Language server + bind(LanguageServerContribution).to(ArduinoLanguageServerContribution).inSingletonScope(); + // Library service const libraryServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => { bind(LibraryServiceImpl).toSelf().inSingletonScope(); diff --git a/arduino-ide-extension/src/node/language/arduino-language-server-contribution.ts b/arduino-ide-extension/src/node/language/arduino-language-server-contribution.ts new file mode 100644 index 00000000..802fe8d3 --- /dev/null +++ b/arduino-ide-extension/src/node/language/arduino-language-server-contribution.ts @@ -0,0 +1,48 @@ +import * as which from 'which'; +import * as os from 'os'; +import { join, delimiter } from 'path'; +import { injectable } from 'inversify'; +import { BaseLanguageServerContribution, IConnection } from '@theia/languages/lib/node'; + +@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; + } + + async start(clientConnection: IConnection): Promise { + const clangd = await this.resolveExecutable('clangd') + const languageServer = await this.resolveExecutable('arduino-language-server') + // Add '-log' argument to enable logging to files + const args: string[] = ['-clangd', clangd] + console.log(`Starting language server ${languageServer} ${args.join(' ')}`) + const serverConnection = await this.createProcessStreamConnectionAsync(languageServer, args) + this.forward(clientConnection, serverConnection) + } + + protected resolveExecutable(name: string): Promise { + return new Promise((resolve, reject) => { + const path = `${process.env.PATH}${delimiter}${join(__dirname, '..', '..', '..', 'build')}`; + const suffix = os.platform() === 'win32' ? '.exe' : ''; + which(name + suffix, { path }, (err, execPath) => { + if (err) { + reject(err); + } else { + resolve(execPath); + } + }); + }); + } +}