Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
7fd1074
Implement external file change detection and refresh logic in text fi…
arneschmid Mar 9, 2026
06d332e
Merge branch 'main' into fix/wrong-target-type-after-renaming-in-csol…
arneschmid Mar 10, 2026
d80cfc3
Add activated state handling in solution load change events
arneschmid Mar 10, 2026
e7df0e5
Add delay to ensure external file change detection in tests
arneschmid Mar 12, 2026
c61e7f2
Rename sendContextData to sendContextDataFromControllerState for clar…
arneschmid Mar 12, 2026
bbec7c3
Improve active target type handling in ManageSolutionController and u…
arneschmid Mar 12, 2026
cc7a556
Refactor ensureActiveTargetTypeNameInKnownTargets access in manage-so…
arneschmid Mar 12, 2026
a786875
Merge branch 'main' of https://github.com/Open-CMSIS-Pack/vscode-cmsi…
arneschmid Mar 12, 2026
1cf936f
Merge branch 'main' into fix/wrong-target-type-after-renaming-in-csol…
arneschmid Mar 13, 2026
43fb823
Merge branch 'main' into fix/wrong-target-type-after-renaming-in-csol…
arneschmid Mar 13, 2026
520bba7
Merge branch 'main' into fix/wrong-target-type-after-renaming-in-csol…
arneschmid Mar 17, 2026
470718d
Merge branch 'main' of https://github.com/Open-CMSIS-Pack/vscode-cmsi…
arneschmid Mar 17, 2026
b8f0696
Merge branch 'main' of https://github.com/Open-CMSIS-Pack/vscode-cmsi…
arneschmid Mar 17, 2026
bbee525
Fix: update test to spy on sendContextDataFromControllerState instead…
arneschmid Mar 17, 2026
bec9bfa
Merge branch 'main' of https://github.com/Open-CMSIS-Pack/vscode-cmsi…
arneschmid Mar 17, 2026
5a29ec2
Merge branch 'main' of https://github.com/Open-CMSIS-Pack/vscode-cmsi…
arneschmid Mar 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/generic/text-file.factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ export const textFileFactory = makeFactory<ITextFile, IErrorList>({
clear: () => jest.fn(),
exists: () => jest.fn(),
unlink: () => jest.fn(),
hasExternalFileChanged: () => jest.fn().mockReturnValue(false),
refreshExternalFileStamp: () => jest.fn(),
}, errorListFactory);
23 changes: 23 additions & 0 deletions src/generic/text-file.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,4 +370,27 @@ describe('TextFile', () => {

testDataHandler.rmDir(unicodeDir);
});

it('primes external stamp on first change check', async () => {
const tf = new TextFile(TEST_FILE);
tf.text = initialContent;
const saveResult = await tf.save();
expect(saveResult).toBe(ETextFileResult.Success);
Comment thread
arneschmid marked this conversation as resolved.
Outdated

expect(tf.hasExternalFileChanged()).toBe(false);
});

it('detects external on-disk updates and then re-baselines', async () => {
const tf = new TextFile(TEST_FILE);
tf.text = initialContent;
const saveResult = await tf.save();
expect(saveResult).toBe(ETextFileResult.Success);

tf.refreshExternalFileStamp();
expect(tf.hasExternalFileChanged()).toBe(false);

fsUtils.writeTextFile(TEST_FILE, changedContent);
expect(tf.hasExternalFileChanged()).toBe(true);
expect(tf.hasExternalFileChanged()).toBe(false);
});
});
58 changes: 58 additions & 0 deletions src/generic/text-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import path from 'node:path';
import * as fs from 'node:fs';
import * as fsUtils from '../utils/fs-utils';
import * as vscodeUtils from '../utils/vscode-utils';
import { ITextParser } from './text-parser';
Expand All @@ -40,6 +41,12 @@ export enum ETextFileResult {
NotExists = 3
}

type ExternalFileStamp = {
path: string;
mtimeMs: number;
size: number;
};

/**
* Represents a text file with parsing, rendering, and error handling capabilities.
* Provides methods and properties for managing file content, file metadata, and associated parsers/renderers.
Expand Down Expand Up @@ -170,6 +177,16 @@ export interface ITextFile extends IErrorList {
/** Clears file content and errors */
clear(): void;

/**
* Refreshes the stored external file stamp baseline.
*/
refreshExternalFileStamp(): void;

/**
* Checks whether the file changed externally since the last stamp refresh/check.
*/
hasExternalFileChanged(): boolean;

/** Copy text and parse it to the object, does not change filename
* @param src source file
*/
Expand All @@ -194,6 +211,7 @@ export class TextFile extends ErrorList implements ITextFile {
protected textRenderer?: ITextRenderer;

private _readOnly = false;
private externalFileStamp?: ExternalFileStamp;

/**
* Constructs a TextFile instance
Expand Down Expand Up @@ -243,6 +261,7 @@ export class TextFile extends ErrorList implements ITextFile {
this._dirty = false;
this.contentString = '';
this.contentObject = undefined;
this.externalFileStamp = undefined;
this.clearErrors();
}

Expand Down Expand Up @@ -285,6 +304,7 @@ export class TextFile extends ErrorList implements ITextFile {
if (value !== this._fileName) {
this._fileName = value;
this._fileDir = path.dirname(value);
this.externalFileStamp = undefined;
}
}

Expand Down Expand Up @@ -360,6 +380,7 @@ export class TextFile extends ErrorList implements ITextFile {
this.fileName = fileName;
}
const result = this.doLoad();
this.refreshExternalFileStamp();
this.showErrorMessage(result);
return result;
}
Expand Down Expand Up @@ -402,10 +423,47 @@ export class TextFile extends ErrorList implements ITextFile {
this._dirty = true; // force saving
}
const result = this.doSave();
this.refreshExternalFileStamp();
this.showErrorMessage(result);
return result;
}

private getCurrentFileStamp(): ExternalFileStamp | undefined {
if (!this.fileName || !fsUtils.fileExists(this.fileName)) {
return undefined;
}
try {
const stat = fs.statSync(this.fileName);
return {
path: this.fileName,
mtimeMs: stat.mtimeMs,
size: stat.size,
};
} catch {
return undefined;
}
}

public refreshExternalFileStamp(): void {
this.externalFileStamp = this.getCurrentFileStamp();
}

public hasExternalFileChanged(): boolean {
const currentStamp = this.getCurrentFileStamp();
if (!this.externalFileStamp) {
this.externalFileStamp = currentStamp;
return false;
}

const changed = !currentStamp
|| currentStamp.path !== this.externalFileStamp.path
|| currentStamp.mtimeMs !== this.externalFileStamp.mtimeMs
|| currentStamp.size !== this.externalFileStamp.size;

this.externalFileStamp = currentStamp;
return changed;
}

/**
* Saves file content to disk
* @returns Save result
Expand Down
2 changes: 2 additions & 0 deletions src/solutions/solution-manager.factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ export const idleSolutionLoadStateFactory = makeFactory<SolutionLoadState>({
solutionPath: () => undefined,
loaded: () => undefined,
converted: () => undefined,
activated: () => undefined,
});

export const activeSolutionLoadStateFactory = makeFactory<SolutionLoadState>({
solutionPath: () => path.join(faker.system.filePath(), `${faker.word.noun()}.csolution.yml`),
loaded: () => undefined,
converted: () => undefined,
activated: () => undefined,
});

const fireOnDidChangeLoadState = (emitter: vscode.EventEmitter<SolutionLoadStateChangeEvent>) => {
Expand Down
Loading
Loading