GH-432: Made compile/verify work on dirty editors

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
Akos Kitta 2021-02-11 17:53:24 +01:00 committed by Akos Kitta
parent ec1abcc989
commit f1c80041fe
5 changed files with 60 additions and 22 deletions

View File

@ -1,9 +1,11 @@
import { inject, injectable, interfaces } from 'inversify'; import { inject, injectable, interfaces } from 'inversify';
import URI from '@theia/core/lib/common/uri'; import URI from '@theia/core/lib/common/uri';
import { ILogger } from '@theia/core/lib/common/logger'; 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 { FileService } from '@theia/filesystem/lib/browser/file-service';
import { MaybePromise } from '@theia/core/lib/common/types'; import { MaybePromise } from '@theia/core/lib/common/types';
import { LabelProvider } from '@theia/core/lib/browser/label-provider'; 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 { MessageService } from '@theia/core/lib/common/message-service';
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service'; import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
import { open, OpenerService } from '@theia/core/lib/browser/opener-service'; import { open, OpenerService } from '@theia/core/lib/browser/opener-service';
@ -85,6 +87,23 @@ export abstract class SketchContribution extends Contribution {
@inject(ArduinoPreferences) @inject(ArduinoPreferences)
protected readonly preferences: ArduinoPreferences; protected readonly preferences: ArduinoPreferences;
@inject(EditorManager)
protected readonly editorManager: EditorManager;
protected async sourceOverride(): Promise<Record<string, string>> {
const override: Record<string, string> = {};
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 { export namespace Contribution {

View File

@ -73,8 +73,8 @@ export class UploadSketch extends SketchContribution {
} }
async uploadSketch(usingProgrammer: boolean = false): Promise<void> { async uploadSketch(usingProgrammer: boolean = false): Promise<void> {
const uri = await this.sketchServiceClient.currentSketchFile(); const sketch = await this.sketchServiceClient.currentSketch();
if (!uri) { if (!sketch) {
return; return;
} }
let shouldAutoConnect = false; let shouldAutoConnect = false;
@ -88,15 +88,16 @@ export class UploadSketch extends SketchContribution {
} }
try { try {
const { boardsConfig } = this.boardsServiceClientImpl; 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.appendConfigToFqbn(boardsConfig.selectedBoard?.fqbn),
this.boardsDataStore.getData(boardsConfig.selectedBoard?.fqbn), this.boardsDataStore.getData(boardsConfig.selectedBoard?.fqbn),
this.preferences.get('arduino.upload.verify'), 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; let options: CoreService.Upload.Options | undefined = undefined;
const sketchUri = uri; const sketchUri = sketch.uri;
const optimizeForDebug = this.editorMode.compileForDebug; const optimizeForDebug = this.editorMode.compileForDebug;
const { selectedPort } = boardsConfig; const { selectedPort } = boardsConfig;
const port = selectedPort?.address; const port = selectedPort?.address;
@ -110,7 +111,8 @@ export class UploadSketch extends SketchContribution {
programmer, programmer,
port, port,
verbose, verbose,
verify verify,
sourceOverride
}; };
} else { } else {
options = { options = {
@ -119,7 +121,8 @@ export class UploadSketch extends SketchContribution {
optimizeForDebug, optimizeForDebug,
port, port,
verbose, verbose,
verify verify,
sourceOverride
}; };
} }
this.outputChannelManager.getChannel('Arduino').clear(); this.outputChannelManager.getChannel('Arduino').clear();

View File

@ -69,21 +69,25 @@ export class VerifySketch extends SketchContribution {
} }
async verifySketch(exportBinaries: boolean = false): Promise<void> { async verifySketch(exportBinaries: boolean = false): Promise<void> {
const uri = await this.sketchServiceClient.currentSketchFile(); const sketch = await this.sketchServiceClient.currentSketch();
if (!uri) { if (!sketch) {
return; return;
} }
try { try {
const { boardsConfig } = this.boardsServiceClientImpl; 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'); const verbose = this.preferences.get('arduino.compile.verbose');
this.outputChannelManager.getChannel('Arduino').clear(); this.outputChannelManager.getChannel('Arduino').clear();
await this.coreService.compile({ await this.coreService.compile({
sketchUri: uri, sketchUri: sketch.uri,
fqbn, fqbn,
optimizeForDebug: this.editorMode.compileForDebug, optimizeForDebug: this.editorMode.compileForDebug,
verbose, verbose,
exportBinaries exportBinaries,
sourceOverride
}); });
this.messageService.info('Done compiling.', { timeout: 1000 }); this.messageService.info('Done compiling.', { timeout: 1000 });
} catch (e) { } catch (e) {

View File

@ -13,10 +13,14 @@ export namespace CoreService {
export namespace Compile { export namespace Compile {
export interface Options { export interface Options {
/**
* `file` URI to the sketch folder.
*/
readonly sketchUri: string; readonly sketchUri: string;
readonly fqbn?: string | undefined; readonly fqbn?: string | undefined;
readonly optimizeForDebug: boolean; readonly optimizeForDebug: boolean;
readonly verbose: boolean; readonly verbose: boolean;
readonly sourceOverride: Record<string, string>;
} }
} }

View File

@ -1,6 +1,7 @@
import { FileUri } from '@theia/core/lib/node/file-uri'; import { FileUri } from '@theia/core/lib/node/file-uri';
import { inject, injectable } from 'inversify'; 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 { CoreService } from '../common/protocol/core-service';
import { CompileReq, CompileResp } from './cli-protocol/commands/compile_pb'; import { CompileReq, CompileResp } from './cli-protocol/commands/compile_pb';
import { CoreClientProvider } from './core-client-provider'; import { CoreClientProvider } from './core-client-provider';
@ -24,17 +25,15 @@ export class CoreServiceImpl implements CoreService {
protected readonly notificationService: NotificationServiceServer; protected readonly notificationService: NotificationServiceServer;
async compile(options: CoreService.Compile.Options & { exportBinaries: boolean }): Promise<void> { async compile(options: CoreService.Compile.Options & { exportBinaries: boolean }): Promise<void> {
this.outputService.append({ chunk: 'Compile...\n' + JSON.stringify(options, null, 2) + '\n--------------------------\n' });
const { sketchUri, fqbn } = options; const { sketchUri, fqbn } = options;
const sketchFilePath = FileUri.fsPath(sketchUri); const sketchPath = FileUri.fsPath(sketchUri);
const sketchpath = dirname(sketchFilePath);
const coreClient = await this.coreClient(); const coreClient = await this.coreClient();
const { client, instance } = coreClient; const { client, instance } = coreClient;
const compilerReq = new CompileReq(); const compilerReq = new CompileReq();
compilerReq.setInstance(instance); compilerReq.setInstance(instance);
compilerReq.setSketchpath(sketchpath); compilerReq.setSketchpath(sketchPath);
if (fqbn) { if (fqbn) {
compilerReq.setFqbn(fqbn); compilerReq.setFqbn(fqbn);
} }
@ -43,6 +42,7 @@ export class CoreServiceImpl implements CoreService {
compilerReq.setVerbose(options.verbose); compilerReq.setVerbose(options.verbose);
compilerReq.setQuiet(false); compilerReq.setQuiet(false);
compilerReq.setExportBinaries(options.exportBinaries); compilerReq.setExportBinaries(options.exportBinaries);
this.mergeSourceOverrides(compilerReq, options);
const result = client.compile(compilerReq); const result = client.compile(compilerReq);
try { try {
@ -76,18 +76,15 @@ export class CoreServiceImpl implements CoreService {
task: string = 'upload'): Promise<void> { task: string = 'upload'): Promise<void> {
await this.compile(Object.assign(options, { exportBinaries: false })); 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 { sketchUri, fqbn, port, programmer } = options;
const sketchFilePath = FileUri.fsPath(sketchUri); const sketchPath = FileUri.fsPath(sketchUri);
const sketchpath = dirname(sketchFilePath);
const coreClient = await this.coreClient(); const coreClient = await this.coreClient();
const { client, instance } = coreClient; const { client, instance } = coreClient;
const req = requestProvider(); const req = requestProvider();
req.setInstance(instance); req.setInstance(instance);
req.setSketchPath(sketchpath); req.setSketchPath(sketchPath);
if (fqbn) { if (fqbn) {
req.setFqbn(fqbn); req.setFqbn(fqbn);
} }
@ -169,4 +166,15 @@ export class CoreServiceImpl implements CoreService {
return coreClient; return coreClient;
} }
private mergeSourceOverrides(req: { getSourceOverrideMap(): jspb.Map<string, string> }, 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);
}
}
}
} }