mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-09 12:26:34 +00:00
another approach
Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
parent
a04527d3b8
commit
750486a8f0
@ -19,10 +19,11 @@ import {
|
|||||||
SketchContribution,
|
SketchContribution,
|
||||||
CommandRegistry,
|
CommandRegistry,
|
||||||
MenuModelRegistry,
|
MenuModelRegistry,
|
||||||
|
URI,
|
||||||
} from './contribution';
|
} from './contribution';
|
||||||
import { NotificationCenter } from '../notification-center';
|
import { NotificationCenter } from '../notification-center';
|
||||||
import { Board, SketchRef, SketchContainer } from '../../common/protocol';
|
import { Board, SketchRef, SketchContainer } from '../../common/protocol';
|
||||||
import { nls } from '@theia/core/lib/common';
|
import { nls } from '@theia/core/lib/common/nls';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export abstract class Examples extends SketchContribution {
|
export abstract class Examples extends SketchContribution {
|
||||||
@ -150,10 +151,13 @@ export abstract class Examples extends SketchContribution {
|
|||||||
return {
|
return {
|
||||||
execute: async () => {
|
execute: async () => {
|
||||||
const sketch = await this.sketchService.cloneExample(uri);
|
const sketch = await this.sketchService.cloneExample(uri);
|
||||||
return this.commandService.executeCommand(
|
return this.commandService
|
||||||
OpenSketch.Commands.OPEN_SKETCH.id,
|
.executeCommand(OpenSketch.Commands.OPEN_SKETCH.id, sketch)
|
||||||
sketch
|
.then((result) => {
|
||||||
);
|
const name = new URI(uri).path.base;
|
||||||
|
this.sketchService.markAsRecentlyOpened({ name, sourceUri: uri }); // no await
|
||||||
|
return result;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import { MainMenuManager } from '../../common/main-menu-manager';
|
|||||||
import { OpenSketch } from './open-sketch';
|
import { OpenSketch } from './open-sketch';
|
||||||
import { NotificationCenter } from '../notification-center';
|
import { NotificationCenter } from '../notification-center';
|
||||||
import { nls } from '@theia/core/lib/common';
|
import { nls } from '@theia/core/lib/common';
|
||||||
|
import { ExampleRef } from '../../common/protocol';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class OpenRecentSketch extends SketchContribution {
|
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.register(sketches);
|
||||||
this.mainMenuManager.update();
|
this.mainMenuManager.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected register(sketches: Sketch[]): void {
|
protected register(sketches: (Sketch | ExampleRef)[]): void {
|
||||||
const order = 0;
|
const order = 0;
|
||||||
for (const sketch of sketches) {
|
for (const sketch of sketches) {
|
||||||
const { uri } = sketch;
|
const uri = Sketch.is(sketch) ? sketch.uri : sketch.sourceUri;
|
||||||
const toDispose = this.toDisposeBeforeRegister.get(uri);
|
const toDispose = this.toDisposeBeforeRegister.get(uri);
|
||||||
if (toDispose) {
|
if (toDispose) {
|
||||||
toDispose.dispose();
|
toDispose.dispose();
|
||||||
}
|
}
|
||||||
const command = { id: `arduino-open-recent--${uri}` };
|
const command = { id: `arduino-open-recent--${uri}` };
|
||||||
const handler = {
|
const handler = {
|
||||||
execute: () =>
|
execute: async () => {
|
||||||
|
const toOpen = Sketch.is(sketch)
|
||||||
|
? sketch
|
||||||
|
: await this.sketchService.cloneExample(sketch.sourceUri);
|
||||||
this.commandRegistry.executeCommand(
|
this.commandRegistry.executeCommand(
|
||||||
OpenSketch.Commands.OPEN_SKETCH.id,
|
OpenSketch.Commands.OPEN_SKETCH.id,
|
||||||
sketch
|
toOpen
|
||||||
),
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
this.commandRegistry.registerCommand(command, handler);
|
this.commandRegistry.registerCommand(command, handler);
|
||||||
this.menuRegistry.registerMenuAction(
|
this.menuRegistry.registerMenuAction(
|
||||||
@ -86,7 +91,7 @@ export class OpenRecentSketch extends SketchContribution {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.toDisposeBeforeRegister.set(
|
this.toDisposeBeforeRegister.set(
|
||||||
sketch.uri,
|
uri,
|
||||||
new DisposableCollection(
|
new DisposableCollection(
|
||||||
Disposable.create(() =>
|
Disposable.create(() =>
|
||||||
this.commandRegistry.unregisterCommand(command)
|
this.commandRegistry.unregisterCommand(command)
|
||||||
|
@ -5,6 +5,7 @@ import type {
|
|||||||
Config,
|
Config,
|
||||||
ProgressMessage,
|
ProgressMessage,
|
||||||
Sketch,
|
Sketch,
|
||||||
|
ExampleRef,
|
||||||
} from '../protocol';
|
} from '../protocol';
|
||||||
import type { LibraryPackage } from './library-service';
|
import type { LibraryPackage } from './library-service';
|
||||||
|
|
||||||
@ -27,7 +28,9 @@ export interface NotificationServiceClient {
|
|||||||
notifyLibraryDidInstall(event: { item: LibraryPackage }): void;
|
notifyLibraryDidInstall(event: { item: LibraryPackage }): void;
|
||||||
notifyLibraryDidUninstall(event: { item: LibraryPackage }): void;
|
notifyLibraryDidUninstall(event: { item: LibraryPackage }): void;
|
||||||
notifyAttachedBoardsDidChange(event: AttachedBoardsChangeEvent): void;
|
notifyAttachedBoardsDidChange(event: AttachedBoardsChangeEvent): void;
|
||||||
notifyRecentSketchesDidChange(event: { sketches: Sketch[] }): void;
|
notifyRecentSketchesDidChange(event: {
|
||||||
|
sketches: (Sketch | ExampleRef)[];
|
||||||
|
}): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NotificationServicePath = '/services/notification-service';
|
export const NotificationServicePath = '/services/notification-service';
|
||||||
|
@ -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.
|
* 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.
|
* 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.
|
* Archives the sketch, resolves to the archive URI.
|
||||||
@ -102,6 +102,27 @@ export interface SketchesService {
|
|||||||
deleteSketch(sketch: Sketch): Promise<void>;
|
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 {
|
export interface SketchRef {
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
readonly uri: string; // `LocationPath`
|
readonly uri: string; // `LocationPath`
|
||||||
|
@ -183,10 +183,7 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
|||||||
);
|
);
|
||||||
for (const workspace of workspaces) {
|
for (const workspace of workspaces) {
|
||||||
if (await this.isValidSketchPath(workspace.file)) {
|
if (await this.isValidSketchPath(workspace.file)) {
|
||||||
if (
|
if (this.isTempSketch.is(workspace.file)) {
|
||||||
this.isTempSketch.is(workspace.file) &&
|
|
||||||
!this.isTempSketch.isExample(workspace.file)
|
|
||||||
) {
|
|
||||||
console.info(
|
console.info(
|
||||||
`Skipped opening sketch. The sketch was detected as temporary. Workspace path: ${workspace.file}.`
|
`Skipped opening sketch. The sketch was detected as temporary. Workspace path: ${workspace.file}.`
|
||||||
);
|
);
|
||||||
@ -430,7 +427,7 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
|||||||
// Do not try to reopen the sketch if it was temp.
|
// Do not try to reopen the sketch if it was temp.
|
||||||
// Unfortunately, IDE2 has two different logic of restoring recent sketches: the Theia default `recentworkspace.json` and there is the `recent-sketches.json`.
|
// Unfortunately, IDE2 has two different logic of restoring recent sketches: the Theia default `recentworkspace.json` and there is the `recent-sketches.json`.
|
||||||
const file = workspaceUri.fsPath;
|
const file = workspaceUri.fsPath;
|
||||||
if (this.isTempSketch.is(file) && !this.isTempSketch.isExample(file)) {
|
if (this.isTempSketch.is(file)) {
|
||||||
console.info(
|
console.info(
|
||||||
`Ignored marking workspace as a closed sketch. The sketch was detected as temporary. Workspace URI: ${workspaceUri.toString()}.`
|
`Ignored marking workspace as a closed sketch. The sketch was detected as temporary. Workspace URI: ${workspaceUri.toString()}.`
|
||||||
);
|
);
|
||||||
|
@ -3,11 +3,9 @@ import * as tempDir from 'temp-dir';
|
|||||||
import { isWindows, isOSX } from '@theia/core/lib/common/os';
|
import { isWindows, isOSX } from '@theia/core/lib/common/os';
|
||||||
import { injectable } from '@theia/core/shared/inversify';
|
import { injectable } from '@theia/core/shared/inversify';
|
||||||
import { firstToLowerCase } from '../common/utils';
|
import { firstToLowerCase } from '../common/utils';
|
||||||
import { join } from 'path';
|
|
||||||
|
|
||||||
const Win32DriveRegex = /^[a-zA-Z]:\\/;
|
const Win32DriveRegex = /^[a-zA-Z]:\\/;
|
||||||
export const TempSketchPrefix = '.arduinoIDE-unsaved';
|
export const TempSketchPrefix = '.arduinoIDE-unsaved';
|
||||||
export const ExampleTempSketchPrefix = `${TempSketchPrefix}-example`;
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class IsTempSketch {
|
export class IsTempSketch {
|
||||||
@ -35,16 +33,6 @@ export class IsTempSketch {
|
|||||||
console.debug(`isTempSketch: ${result}. Input was ${normalizedSketchPath}`);
|
console.debug(`isTempSketch: ${result}. Input was ${normalizedSketchPath}`);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
isExample(sketchPath: string): boolean {
|
|
||||||
const normalizedSketchPath = maybeNormalizeDrive(sketchPath);
|
|
||||||
const result =
|
|
||||||
normalizedSketchPath.startsWith(this.tempDirRealpath) &&
|
|
||||||
normalizedSketchPath.includes(
|
|
||||||
join(this.tempDirRealpath, ExampleTempSketchPrefix)
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,6 +8,7 @@ import type {
|
|||||||
Config,
|
Config,
|
||||||
Sketch,
|
Sketch,
|
||||||
ProgressMessage,
|
ProgressMessage,
|
||||||
|
ExampleRef,
|
||||||
} from '../common/protocol';
|
} from '../common/protocol';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
@ -76,7 +77,9 @@ export class NotificationServiceServerImpl
|
|||||||
this.clients.forEach((client) => client.notifyConfigDidChange(event));
|
this.clients.forEach((client) => client.notifyConfigDidChange(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyRecentSketchesDidChange(event: { sketches: Sketch[] }): void {
|
notifyRecentSketchesDidChange(event: {
|
||||||
|
sketches: (Sketch | ExampleRef)[];
|
||||||
|
}): void {
|
||||||
this.clients.forEach((client) =>
|
this.clients.forEach((client) =>
|
||||||
client.notifyRecentSketchesDidChange(event)
|
client.notifyRecentSketchesDidChange(event)
|
||||||
);
|
);
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
SketchRef,
|
SketchRef,
|
||||||
SketchContainer,
|
SketchContainer,
|
||||||
SketchesError,
|
SketchesError,
|
||||||
|
ExampleRef,
|
||||||
} from '../common/protocol/sketches-service';
|
} from '../common/protocol/sketches-service';
|
||||||
import { NotificationServiceServerImpl } from './notification-service-server';
|
import { NotificationServiceServerImpl } from './notification-service-server';
|
||||||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||||
@ -29,7 +30,6 @@ import * as glob from 'glob';
|
|||||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||||
import { ServiceError } from './service-error';
|
import { ServiceError } from './service-error';
|
||||||
import {
|
import {
|
||||||
ExampleTempSketchPrefix,
|
|
||||||
IsTempSketch,
|
IsTempSketch,
|
||||||
maybeNormalizeDrive,
|
maybeNormalizeDrive,
|
||||||
TempSketchPrefix,
|
TempSketchPrefix,
|
||||||
@ -258,9 +258,7 @@ export class SketchesServiceImpl
|
|||||||
.then((uri) => path.join(FileUri.fsPath(uri), 'recent-sketches.json'));
|
.then((uri) => path.join(FileUri.fsPath(uri), 'recent-sketches.json'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async loadRecentSketches(
|
private async loadRecentSketches(fsPath: string): Promise<RecentSketches> {
|
||||||
fsPath: string
|
|
||||||
): Promise<Record<string, number>> {
|
|
||||||
let data: Record<string, number> = {};
|
let data: Record<string, number> = {};
|
||||||
try {
|
try {
|
||||||
const raw = await promisify(fs.readFile)(fsPath, {
|
const raw = await promisify(fs.readFile)(fsPath, {
|
||||||
@ -271,32 +269,39 @@ export class SketchesServiceImpl
|
|||||||
return data;
|
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;
|
let sketch: Sketch | undefined = undefined;
|
||||||
try {
|
try {
|
||||||
sketch = await this.loadSketch(uri);
|
sketch = await this.loadSketch(uri);
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (await this.isTemp(sketch)) {
|
||||||
(await this.isTemp(sketch)) &&
|
|
||||||
!this.isTempSketch.isExample(FileUri.fsPath(sketch.uri))
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fsPath = await this.recentSketchesFsPath;
|
const fsPath = await this.recentSketchesFsPath;
|
||||||
const data = await this.loadRecentSketches(fsPath);
|
const data = await this.loadRecentSketches(fsPath);
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
data[sketch.uri] = now;
|
data[sketch.uri] = isExample ? { type: 'example', mtimeMs: now } : now;
|
||||||
|
|
||||||
let toDeleteUri: string | undefined = undefined;
|
let toDeleteUri: string | undefined = undefined;
|
||||||
if (Object.keys(data).length > 10) {
|
if (Object.keys(data).length > 10) {
|
||||||
let min = Number.MAX_SAFE_INTEGER;
|
let min = Number.MAX_SAFE_INTEGER;
|
||||||
for (const uri of Object.keys(data)) {
|
for (const uri of Object.keys(data)) {
|
||||||
if (min > data[uri]) {
|
const value = data[uri];
|
||||||
min = data[uri];
|
if (typeof value === 'number') {
|
||||||
toDeleteUri = uri;
|
if (min > value) {
|
||||||
|
min = value;
|
||||||
|
toDeleteUri = uri;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (min > value.mtimeMs) {
|
||||||
|
min = value.mtimeMs;
|
||||||
|
toDeleteUri = uri;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,13 +316,13 @@ export class SketchesServiceImpl
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async recentlyOpenedSketches(): Promise<Sketch[]> {
|
async recentlyOpenedSketches(): Promise<(Sketch | ExampleRef)[]> {
|
||||||
const configDirUri = await this.envVariableServer.getConfigDirUri();
|
const configDirUri = await this.envVariableServer.getConfigDirUri();
|
||||||
const fsPath = path.join(
|
const fsPath = path.join(
|
||||||
FileUri.fsPath(configDirUri),
|
FileUri.fsPath(configDirUri),
|
||||||
'recent-sketches.json'
|
'recent-sketches.json'
|
||||||
);
|
);
|
||||||
let data: Record<string, number> = {};
|
let data: RecentSketches = {};
|
||||||
try {
|
try {
|
||||||
const raw = await promisify(fs.readFile)(fsPath, {
|
const raw = await promisify(fs.readFile)(fsPath, {
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
@ -325,14 +330,25 @@ export class SketchesServiceImpl
|
|||||||
data = JSON.parse(raw);
|
data = JSON.parse(raw);
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
const sketches: SketchWithDetails[] = [];
|
const sketches: (Sketch | ExampleRef)[] = [];
|
||||||
for (const uri of Object.keys(data).sort(
|
for (const uri of Object.keys(data).sort((left, right) => {
|
||||||
(left, right) => data[right] - data[left]
|
const leftValue = data[left];
|
||||||
)) {
|
const rightValue = data[right];
|
||||||
try {
|
const leftMtimeMs =
|
||||||
const sketch = await this.loadSketch(uri);
|
typeof leftValue === 'number' ? leftValue : leftValue.mtimeMs;
|
||||||
sketches.push(sketch);
|
const rightMtimeMs =
|
||||||
} catch {}
|
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;
|
return sketches;
|
||||||
@ -340,7 +356,7 @@ export class SketchesServiceImpl
|
|||||||
|
|
||||||
async cloneExample(uri: string): Promise<Sketch> {
|
async cloneExample(uri: string): Promise<Sketch> {
|
||||||
const sketch = await this.loadSketch(uri);
|
const sketch = await this.loadSketch(uri);
|
||||||
const parentPath = await this.createTempFolder(false);
|
const parentPath = await this.createTempFolder();
|
||||||
const destinationUri = FileUri.create(
|
const destinationUri = FileUri.create(
|
||||||
path.join(parentPath, sketch.name)
|
path.join(parentPath, sketch.name)
|
||||||
).toString();
|
).toString();
|
||||||
@ -421,24 +437,21 @@ 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.
|
* 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`
|
* `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(isTemp = true): Promise<string> {
|
private createTempFolder(prefix: string = TempSketchPrefix): Promise<string> {
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
temp.mkdir(
|
temp.mkdir({ prefix }, (createError, dirPath) => {
|
||||||
{ prefix: isTemp ? TempSketchPrefix : ExampleTempSketchPrefix },
|
if (createError) {
|
||||||
(createError, dirPath) => {
|
reject(createError);
|
||||||
if (createError) {
|
return;
|
||||||
reject(createError);
|
}
|
||||||
|
fs.realpath.native(dirPath, (resolveError, resolvedDirPath) => {
|
||||||
|
if (resolveError) {
|
||||||
|
reject(resolveError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fs.realpath.native(dirPath, (resolveError, resolvedDirPath) => {
|
resolve(resolvedDirPath);
|
||||||
if (resolveError) {
|
});
|
||||||
reject(resolveError);
|
});
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(resolvedDirPath);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -641,3 +654,8 @@ function sketchIndexToLetters(num: number): string {
|
|||||||
} while (pow > 0);
|
} while (pow > 0);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RecentSketches = Record<
|
||||||
|
string,
|
||||||
|
number | { type: 'example'; mtimeMs: number }
|
||||||
|
>;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user