Compare commits

...

3 Commits

Author SHA1 Message Date
Akos Kitta
750486a8f0 another approach
Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
2022-09-15 19:12:31 +02:00
Francesco Spissu
a04527d3b8 different prefix for temp example sketch 2022-09-15 19:12:31 +02:00
Francesco Spissu
33ec67109b mark as recently opened only sketches that not includes sketch_ in the name 2022-09-15 19:12:31 +02:00
6 changed files with 97 additions and 36 deletions

View File

@@ -19,10 +19,11 @@ import {
SketchContribution,
CommandRegistry,
MenuModelRegistry,
URI,
} from './contribution';
import { NotificationCenter } from '../notification-center';
import { Board, SketchRef, SketchContainer } from '../../common/protocol';
import { nls } from '@theia/core/lib/common';
import { nls } from '@theia/core/lib/common/nls';
@injectable()
export abstract class Examples extends SketchContribution {
@@ -150,10 +151,13 @@ export abstract class Examples extends SketchContribution {
return {
execute: async () => {
const sketch = await this.sketchService.cloneExample(uri);
return this.commandService.executeCommand(
OpenSketch.Commands.OPEN_SKETCH.id,
sketch
);
return this.commandService
.executeCommand(OpenSketch.Commands.OPEN_SKETCH.id, sketch)
.then((result) => {
const name = new URI(uri).path.base;
this.sketchService.markAsRecentlyOpened({ name, sourceUri: uri }); // no await
return result;
});
},
};
}

View File

@@ -15,6 +15,7 @@ import { MainMenuManager } from '../../common/main-menu-manager';
import { OpenSketch } from './open-sketch';
import { NotificationCenter } from '../notification-center';
import { nls } from '@theia/core/lib/common';
import { ExampleRef } from '../../common/protocol';
@injectable()
export class OpenRecentSketch extends SketchContribution {
@@ -55,26 +56,30 @@ export class OpenRecentSketch extends SketchContribution {
);
}
private refreshMenu(sketches: Sketch[]): void {
private refreshMenu(sketches: (Sketch | ExampleRef)[]): void {
this.register(sketches);
this.mainMenuManager.update();
}
protected register(sketches: Sketch[]): void {
protected register(sketches: (Sketch | ExampleRef)[]): void {
const order = 0;
for (const sketch of sketches) {
const { uri } = sketch;
const uri = Sketch.is(sketch) ? sketch.uri : sketch.sourceUri;
const toDispose = this.toDisposeBeforeRegister.get(uri);
if (toDispose) {
toDispose.dispose();
}
const command = { id: `arduino-open-recent--${uri}` };
const handler = {
execute: () =>
execute: async () => {
const toOpen = Sketch.is(sketch)
? sketch
: await this.sketchService.cloneExample(sketch.sourceUri);
this.commandRegistry.executeCommand(
OpenSketch.Commands.OPEN_SKETCH.id,
sketch
),
toOpen
);
},
};
this.commandRegistry.registerCommand(command, handler);
this.menuRegistry.registerMenuAction(
@@ -86,7 +91,7 @@ export class OpenRecentSketch extends SketchContribution {
}
);
this.toDisposeBeforeRegister.set(
sketch.uri,
uri,
new DisposableCollection(
Disposable.create(() =>
this.commandRegistry.unregisterCommand(command)

View File

@@ -5,6 +5,7 @@ import type {
Config,
ProgressMessage,
Sketch,
ExampleRef,
} from '../protocol';
import type { LibraryPackage } from './library-service';
@@ -27,7 +28,9 @@ export interface NotificationServiceClient {
notifyLibraryDidInstall(event: { item: LibraryPackage }): void;
notifyLibraryDidUninstall(event: { item: LibraryPackage }): void;
notifyAttachedBoardsDidChange(event: AttachedBoardsChangeEvent): void;
notifyRecentSketchesDidChange(event: { sketches: Sketch[] }): void;
notifyRecentSketchesDidChange(event: {
sketches: (Sketch | ExampleRef)[];
}): void;
}
export const NotificationServicePath = '/services/notification-service';

View File

@@ -78,12 +78,12 @@ export interface SketchesService {
/**
* Marks the sketch with the given URI as recently opened. It does nothing if the sketch is temp or not valid.
*/
markAsRecentlyOpened(uri: string): Promise<void>;
markAsRecentlyOpened(uriOrRef: string | ExampleRef): Promise<void>;
/**
* Resolves to an array of sketches in inverse chronological order. The newest is the first.
*/
recentlyOpenedSketches(): Promise<Sketch[]>;
recentlyOpenedSketches(): Promise<(Sketch | ExampleRef)[]>;
/**
* Archives the sketch, resolves to the archive URI.
@@ -102,6 +102,27 @@ export interface SketchesService {
deleteSketch(sketch: Sketch): Promise<void>;
}
export interface ExampleRef {
/**
* Name of the example.
*/
readonly name: string;
/**
* This is the location where the example is. IDE2 will clone the sketch from this location.
*/
readonly sourceUri: string;
}
export namespace ExampleRef {
export function is(arg: unknown): arg is ExampleRef {
return (
(arg as ExampleRef).name !== undefined &&
typeof (arg as ExampleRef).name === 'string' &&
(arg as ExampleRef).sourceUri !== undefined &&
typeof (arg as ExampleRef).sourceUri === 'string'
);
}
}
export interface SketchRef {
readonly name: string;
readonly uri: string; // `LocationPath`

View File

@@ -8,6 +8,7 @@ import type {
Config,
Sketch,
ProgressMessage,
ExampleRef,
} from '../common/protocol';
@injectable()
@@ -76,7 +77,9 @@ export class NotificationServiceServerImpl
this.clients.forEach((client) => client.notifyConfigDidChange(event));
}
notifyRecentSketchesDidChange(event: { sketches: Sketch[] }): void {
notifyRecentSketchesDidChange(event: {
sketches: (Sketch | ExampleRef)[];
}): void {
this.clients.forEach((client) =>
client.notifyRecentSketchesDidChange(event)
);

View File

@@ -16,6 +16,7 @@ import {
SketchRef,
SketchContainer,
SketchesError,
ExampleRef,
} from '../common/protocol/sketches-service';
import { NotificationServiceServerImpl } from './notification-service-server';
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
@@ -257,9 +258,7 @@ export class SketchesServiceImpl
.then((uri) => path.join(FileUri.fsPath(uri), 'recent-sketches.json'));
}
private async loadRecentSketches(
fsPath: string
): Promise<Record<string, number>> {
private async loadRecentSketches(fsPath: string): Promise<RecentSketches> {
let data: Record<string, number> = {};
try {
const raw = await promisify(fs.readFile)(fsPath, {
@@ -270,7 +269,9 @@ export class SketchesServiceImpl
return data;
}
async markAsRecentlyOpened(uri: string): Promise<void> {
async markAsRecentlyOpened(uriOrRef: string | ExampleRef): Promise<void> {
const isExample = typeof uriOrRef !== 'string';
const uri = isExample ? uriOrRef.sourceUri : uriOrRef;
let sketch: Sketch | undefined = undefined;
try {
sketch = await this.loadSketch(uri);
@@ -284,16 +285,24 @@ export class SketchesServiceImpl
const fsPath = await this.recentSketchesFsPath;
const data = await this.loadRecentSketches(fsPath);
const now = Date.now();
data[sketch.uri] = now;
data[sketch.uri] = isExample ? { type: 'example', mtimeMs: now } : now;
let toDeleteUri: string | undefined = undefined;
if (Object.keys(data).length > 10) {
let min = Number.MAX_SAFE_INTEGER;
for (const uri of Object.keys(data)) {
if (min > data[uri]) {
min = data[uri];
const value = data[uri];
if (typeof value === 'number') {
if (min > value) {
min = value;
toDeleteUri = uri;
}
} else {
if (min > value.mtimeMs) {
min = value.mtimeMs;
toDeleteUri = uri;
}
}
}
}
@@ -307,13 +316,13 @@ export class SketchesServiceImpl
);
}
async recentlyOpenedSketches(): Promise<Sketch[]> {
async recentlyOpenedSketches(): Promise<(Sketch | ExampleRef)[]> {
const configDirUri = await this.envVariableServer.getConfigDirUri();
const fsPath = path.join(
FileUri.fsPath(configDirUri),
'recent-sketches.json'
);
let data: Record<string, number> = {};
let data: RecentSketches = {};
try {
const raw = await promisify(fs.readFile)(fsPath, {
encoding: 'utf8',
@@ -321,14 +330,25 @@ export class SketchesServiceImpl
data = JSON.parse(raw);
} catch {}
const sketches: SketchWithDetails[] = [];
for (const uri of Object.keys(data).sort(
(left, right) => data[right] - data[left]
)) {
const sketches: (Sketch | ExampleRef)[] = [];
for (const uri of Object.keys(data).sort((left, right) => {
const leftValue = data[left];
const rightValue = data[right];
const leftMtimeMs =
typeof leftValue === 'number' ? leftValue : leftValue.mtimeMs;
const rightMtimeMs =
typeof rightValue === 'number' ? rightValue : rightValue.mtimeMs;
return leftMtimeMs - rightMtimeMs;
})) {
const value = data[uri];
if (typeof value === 'number') {
try {
const sketch = await this.loadSketch(uri);
sketches.push(sketch);
} catch {}
} else {
sketches.push({ name: new URI(uri).path.base, sourceUri: uri });
}
}
return sketches;
@@ -417,9 +437,9 @@ void loop() {
* For example, on Windows, instead of getting an [8.3 filename](https://en.wikipedia.org/wiki/8.3_filename), callers will get a fully resolved path.
* `C:\\Users\\KITTAA~1\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2022615-21100-iahybb.yyvh\\sketch_jul15a` will be `C:\\Users\\kittaakos\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2022615-21100-iahybb.yyvh\\sketch_jul15a`
*/
private createTempFolder(): Promise<string> {
private createTempFolder(prefix: string = TempSketchPrefix): Promise<string> {
return new Promise<string>((resolve, reject) => {
temp.mkdir({ prefix: TempSketchPrefix }, (createError, dirPath) => {
temp.mkdir({ prefix }, (createError, dirPath) => {
if (createError) {
reject(createError);
return;
@@ -634,3 +654,8 @@ function sketchIndexToLetters(num: number): string {
} while (pow > 0);
return out;
}
type RecentSketches = Record<
string,
number | { type: 'example'; mtimeMs: number }
>;