From 8beade0867f48254a3cc82a2e7881427f93c9ac2 Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Fri, 26 Aug 2022 12:14:49 +0200 Subject: [PATCH] Fixed sketch content changes when renaming a file. Signed-off-by: Akos Kitta --- .../protocol/sketches-service-client-impl.ts | 17 ++++- .../src/common/protocol/sketches-service.ts | 68 +++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/arduino-ide-extension/src/common/protocol/sketches-service-client-impl.ts b/arduino-ide-extension/src/common/protocol/sketches-service-client-impl.ts index 63141ca9..34da46bf 100644 --- a/arduino-ide-extension/src/common/protocol/sketches-service-client-impl.ts +++ b/arduino-ide-extension/src/common/protocol/sketches-service-client-impl.ts @@ -93,7 +93,17 @@ export class SketchesServiceClientImpl CurrentSketch.isValid(this._currentSketch) && new URI(this._currentSketch.uri).isEqualOrParent(resource) ) { - if (type === FileChangeType.UPDATED) { + // https://github.com/arduino/arduino-ide/pull/1351#pullrequestreview-1086666656 + // On a sketch file rename, the FS watcher will contain two changes: + // - Deletion of the original file, + // - Update of the new file, + // Hence, `UPDATE` events must be processed but only and if only there is a `DELETED` change in the same event. + // Otherwise, IDE2 would ask CLI to reload the sketch content on every save event in IDE2. + if ( + type === FileChangeType.UPDATED && + event.changes.length === 1 + ) { + // If the event contains only one `UPDATE` change, it cannot be a rename. return; } @@ -112,8 +122,9 @@ export class SketchesServiceClientImpl return; } - // TODO: check if current is the same as reloaded? - this.useCurrentSketch(reloadedSketch, true); + if (!Sketch.sameAs(this._currentSketch, reloadedSketch)) { + this.useCurrentSketch(reloadedSketch, true); + } return; } // We track main sketch files changes only. // TODO: check sketch folder changes. One can rename the folder without renaming the `.ino` file. diff --git a/arduino-ide-extension/src/common/protocol/sketches-service.ts b/arduino-ide-extension/src/common/protocol/sketches-service.ts index e34aa275..719ecaac 100644 --- a/arduino-ide-extension/src/common/protocol/sketches-service.ts +++ b/arduino-ide-extension/src/common/protocol/sketches-service.ts @@ -162,6 +162,74 @@ export namespace Sketch { const { mainFileUri, otherSketchFileUris, additionalFileUris } = sketch; return [mainFileUri, ...otherSketchFileUris, ...additionalFileUris]; } + const primitiveProps: Array = ['name', 'uri', 'mainFileUri']; + const arrayProps: Array = [ + 'additionalFileUris', + 'otherSketchFileUris', + 'rootFolderFileUris', + ]; + export function sameAs(left: Sketch, right: Sketch): boolean { + for (const prop of primitiveProps) { + const leftValue = left[prop]; + const rightValue = right[prop]; + assertIsNotArray(leftValue, prop, left); + assertIsNotArray(rightValue, prop, right); + if (leftValue !== rightValue) { + return false; + } + } + for (const prop of arrayProps) { + const leftValue = left[prop]; + const rightValue = right[prop]; + assertIsArray(leftValue, prop, left); + assertIsArray(rightValue, prop, right); + if (leftValue.length !== rightValue.length) { + return false; + } + } + for (const prop of arrayProps) { + const leftValue = left[prop]; + const rightValue = right[prop]; + assertIsArray(leftValue, prop, left); + assertIsArray(rightValue, prop, right); + if ( + toSortedString(leftValue as string[]) !== + toSortedString(rightValue as string[]) + ) { + return false; + } + } + return true; + } + function toSortedString(array: string[]): string { + return array.slice().sort().join(','); + } + function assertIsNotArray( + toTest: unknown, + prop: keyof Sketch, + object: Sketch + ): void { + if (Array.isArray(toTest)) { + throw new Error( + `Expected a non-array type. Got: ${toTest}. Property was: ${prop}. Object was: ${JSON.stringify( + object + )}` + ); + } + } + function assertIsArray( + toTest: unknown, + prop: keyof Sketch, + object: Sketch + ): void { + if (!Array.isArray(toTest)) { + throw new Error( + `Expected an array type. Got: ${toTest}. Property was: ${prop}. Object was: ${JSON.stringify( + object + )}` + ); + } + } } export interface SketchContainer {