diff --git a/arduino-ide-extension/src/browser/contributions/contribution.ts b/arduino-ide-extension/src/browser/contributions/contribution.ts index e5d85a85..06d3335a 100644 --- a/arduino-ide-extension/src/browser/contributions/contribution.ts +++ b/arduino-ide-extension/src/browser/contributions/contribution.ts @@ -1,9 +1,11 @@ import { inject, injectable, interfaces } from 'inversify'; import URI from '@theia/core/lib/common/uri'; import { ILogger } from '@theia/core/lib/common/logger'; +import { Saveable } from '@theia/core/lib/browser/saveable'; import { FileService } from '@theia/filesystem/lib/browser/file-service'; import { MaybePromise } from '@theia/core/lib/common/types'; import { LabelProvider } from '@theia/core/lib/browser/label-provider'; +import { EditorManager } from '@theia/editor/lib/browser/editor-manager'; import { MessageService } from '@theia/core/lib/common/message-service'; import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service'; import { open, OpenerService } from '@theia/core/lib/browser/opener-service'; @@ -85,6 +87,23 @@ export abstract class SketchContribution extends Contribution { @inject(ArduinoPreferences) protected readonly preferences: ArduinoPreferences; + @inject(EditorManager) + protected readonly editorManager: EditorManager; + + protected async sourceOverride(): Promise> { + const override: Record = {}; + const sketch = await this.sketchServiceClient.currentSketch(); + if (sketch) { + for (const editor of this.editorManager.all) { + const uri = editor.editor.uri; + if (Saveable.isDirty(editor) && Sketch.isInSketch(uri, sketch)) { + override[uri.toString()] = editor.editor.document.getText(); + } + } + } + return override; + } + } export namespace Contribution { diff --git a/arduino-ide-extension/src/browser/contributions/upload-sketch.ts b/arduino-ide-extension/src/browser/contributions/upload-sketch.ts index d8cb8c31..fdd85f94 100644 --- a/arduino-ide-extension/src/browser/contributions/upload-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/upload-sketch.ts @@ -73,8 +73,8 @@ export class UploadSketch extends SketchContribution { } async uploadSketch(usingProgrammer: boolean = false): Promise { - const uri = await this.sketchServiceClient.currentSketchFile(); - if (!uri) { + const sketch = await this.sketchServiceClient.currentSketch(); + if (!sketch) { return; } let shouldAutoConnect = false; @@ -88,15 +88,16 @@ export class UploadSketch extends SketchContribution { } try { const { boardsConfig } = this.boardsServiceClientImpl; - const [fqbn, { selectedProgrammer }, verify, verbose] = await Promise.all([ + const [fqbn, { selectedProgrammer }, verify, verbose, sourceOverride] = await Promise.all([ this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard?.fqbn), this.boardsDataStore.getData(boardsConfig.selectedBoard?.fqbn), this.preferences.get('arduino.upload.verify'), - this.preferences.get('arduino.upload.verbose') + this.preferences.get('arduino.upload.verbose'), + this.sourceOverride() ]); let options: CoreService.Upload.Options | undefined = undefined; - const sketchUri = uri; + const sketchUri = sketch.uri; const optimizeForDebug = this.editorMode.compileForDebug; const { selectedPort } = boardsConfig; const port = selectedPort?.address; @@ -110,7 +111,8 @@ export class UploadSketch extends SketchContribution { programmer, port, verbose, - verify + verify, + sourceOverride }; } else { options = { @@ -119,7 +121,8 @@ export class UploadSketch extends SketchContribution { optimizeForDebug, port, verbose, - verify + verify, + sourceOverride }; } this.outputChannelManager.getChannel('Arduino').clear(); diff --git a/arduino-ide-extension/src/browser/contributions/verify-sketch.ts b/arduino-ide-extension/src/browser/contributions/verify-sketch.ts index 01bc2a1c..e1906741 100644 --- a/arduino-ide-extension/src/browser/contributions/verify-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/verify-sketch.ts @@ -69,21 +69,25 @@ export class VerifySketch extends SketchContribution { } async verifySketch(exportBinaries: boolean = false): Promise { - const uri = await this.sketchServiceClient.currentSketchFile(); - if (!uri) { + const sketch = await this.sketchServiceClient.currentSketch(); + if (!sketch) { return; } try { const { boardsConfig } = this.boardsServiceClientImpl; - const fqbn = await this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard?.fqbn); + const [fqbn, sourceOverride] = await Promise.all([ + this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard?.fqbn), + this.sourceOverride() + ]); const verbose = this.preferences.get('arduino.compile.verbose'); this.outputChannelManager.getChannel('Arduino').clear(); await this.coreService.compile({ - sketchUri: uri, + sketchUri: sketch.uri, fqbn, optimizeForDebug: this.editorMode.compileForDebug, verbose, - exportBinaries + exportBinaries, + sourceOverride }); this.messageService.info('Done compiling.', { timeout: 1000 }); } catch (e) { diff --git a/arduino-ide-extension/src/common/protocol/core-service.ts b/arduino-ide-extension/src/common/protocol/core-service.ts index 19edf661..2d169a0c 100644 --- a/arduino-ide-extension/src/common/protocol/core-service.ts +++ b/arduino-ide-extension/src/common/protocol/core-service.ts @@ -13,10 +13,14 @@ export namespace CoreService { export namespace Compile { export interface Options { + /** + * `file` URI to the sketch folder. + */ readonly sketchUri: string; readonly fqbn?: string | undefined; readonly optimizeForDebug: boolean; readonly verbose: boolean; + readonly sourceOverride: Record; } } diff --git a/arduino-ide-extension/src/node/core-service-impl.ts b/arduino-ide-extension/src/node/core-service-impl.ts index a2024c69..7c455f3d 100644 --- a/arduino-ide-extension/src/node/core-service-impl.ts +++ b/arduino-ide-extension/src/node/core-service-impl.ts @@ -1,6 +1,7 @@ import { FileUri } from '@theia/core/lib/node/file-uri'; import { inject, injectable } from 'inversify'; -import { dirname } from 'path'; +import { relative } from 'path'; +import * as jspb from 'google-protobuf'; import { CoreService } from '../common/protocol/core-service'; import { CompileReq, CompileResp } from './cli-protocol/commands/compile_pb'; import { CoreClientProvider } from './core-client-provider'; @@ -24,17 +25,15 @@ export class CoreServiceImpl implements CoreService { protected readonly notificationService: NotificationServiceServer; async compile(options: CoreService.Compile.Options & { exportBinaries: boolean }): Promise { - this.outputService.append({ chunk: 'Compile...\n' + JSON.stringify(options, null, 2) + '\n--------------------------\n' }); const { sketchUri, fqbn } = options; - const sketchFilePath = FileUri.fsPath(sketchUri); - const sketchpath = dirname(sketchFilePath); + const sketchPath = FileUri.fsPath(sketchUri); const coreClient = await this.coreClient(); const { client, instance } = coreClient; const compilerReq = new CompileReq(); compilerReq.setInstance(instance); - compilerReq.setSketchpath(sketchpath); + compilerReq.setSketchpath(sketchPath); if (fqbn) { compilerReq.setFqbn(fqbn); } @@ -43,6 +42,7 @@ export class CoreServiceImpl implements CoreService { compilerReq.setVerbose(options.verbose); compilerReq.setQuiet(false); compilerReq.setExportBinaries(options.exportBinaries); + this.mergeSourceOverrides(compilerReq, options); const result = client.compile(compilerReq); try { @@ -76,18 +76,15 @@ export class CoreServiceImpl implements CoreService { task: string = 'upload'): Promise { await this.compile(Object.assign(options, { exportBinaries: false })); - const chunk = firstToUpperCase(task) + '...\n'; - this.outputService.append({ chunk: chunk + JSON.stringify(options, null, 2) + '\n--------------------------\n' }); const { sketchUri, fqbn, port, programmer } = options; - const sketchFilePath = FileUri.fsPath(sketchUri); - const sketchpath = dirname(sketchFilePath); + const sketchPath = FileUri.fsPath(sketchUri); const coreClient = await this.coreClient(); const { client, instance } = coreClient; const req = requestProvider(); req.setInstance(instance); - req.setSketchPath(sketchpath); + req.setSketchPath(sketchPath); if (fqbn) { req.setFqbn(fqbn); } @@ -169,4 +166,15 @@ export class CoreServiceImpl implements CoreService { return coreClient; } + private mergeSourceOverrides(req: { getSourceOverrideMap(): jspb.Map }, options: CoreService.Compile.Options): void { + const sketchPath = FileUri.fsPath(options.sketchUri); + for (const uri of Object.keys(options.sourceOverride)) { + const content = options.sourceOverride[uri]; + if (content) { + const relativePath = relative(sketchPath, FileUri.fsPath(uri)); + req.getSourceOverrideMap().set(relativePath, content); + } + } + } + }