From 5cb8b448e9485a91ee2d547d7e16e96e8637b381 Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Sat, 30 Dec 2023 20:04:13 -0800 Subject: [PATCH] Rework watchers. --- packages/vscode-extension/package.json | 10 ++--- .../src/graphVisualizerView.ts | 2 + packages/vscode-extension/src/lastRunView.ts | 24 ++++++----- packages/vscode-extension/src/projectsView.ts | 27 ++++++++----- packages/vscode-extension/src/workspace.ts | 40 ++++++++++++++++--- 5 files changed, 70 insertions(+), 33 deletions(-) diff --git a/packages/vscode-extension/package.json b/packages/vscode-extension/package.json index 2e97889..84da64f 100644 --- a/packages/vscode-extension/package.json +++ b/packages/vscode-extension/package.json @@ -76,7 +76,7 @@ }, { "command": "moon.checkProject", - "title": "moon: Run all buildable and testable tasks", + "title": "moon: Run all buildable and testable tasks for a project", "icon": "$(run-all)" }, { @@ -232,22 +232,22 @@ "viewsWelcome": [ { "view": "moonProjects", - "contents": "Unable to find the workspace root. Has moon been installed?\n[Install moon](https://moonrepo.dev/docs/install)\nIf moon was installed in a sub-folder, update the [moon.workspaceRoot](command:moon.openSettings) setting.", + "contents": "Unable to find the workspace root. Has moon been installed? Try opening a file.\n[Install moon](https://moonrepo.dev/docs/install)\nIf moon was installed in a sub-folder, update the [moon.workspaceRoot](command:moon.openSettings) setting.", "when": "!moon.inWorkspaceRoot" }, { "view": "moonProjects", - "contents": "Unable to find moon's binary. Has the [@moonrepo/cli](https://www.npmjs.com/package/@moonrepo/cli) package been installed?\n[Learn more](https://moonrepo.dev/docs/install)\nThe path to moon's binary can be customized with the [moon.binPath](command:moon.openSettings) setting.", + "contents": "Unable to find moon's binary. Has the [@moonrepo/cli](https://www.npmjs.com/package/@moonrepo/cli) package or `moon` global been installed?\n[Learn more](https://moonrepo.dev/docs/install)\nThe path to moon's binary can be customized with the [moon.binPath](command:moon.openSettings) setting.", "when": "moon.inWorkspaceRoot && !moon.hasBinary" }, { "view": "moonProjectsExternal", - "contents": "Unable to find the workspace root. Has moon been installed?\n[Install moon](https://moonrepo.dev/docs/install)\nIf moon was installed in a sub-folder, update the [moon.workspaceRoot](command:moon.openSettings) setting.", + "contents": "Unable to find the workspace root. Has moon been installed? Try opening a file.\n[Install moon](https://moonrepo.dev/docs/install)\nIf moon was installed in a sub-folder, update the [moon.workspaceRoot](command:moon.openSettings) setting.", "when": "!moon.inWorkspaceRoot" }, { "view": "moonProjectsExternal", - "contents": "Unable to find moon's binary. Has the [@moonrepo/cli](https://www.npmjs.com/package/@moonrepo/cli) package been installed?\n[Learn more](https://moonrepo.dev/docs/install)\nThe path to moon's binary can be customized with the [moon.binPath](command:moon.openSettings) setting.", + "contents": "Unable to find moon's binary. Has the [@moonrepo/cli](https://www.npmjs.com/package/@moonrepo/cli) package or `moon` global been installed?\n[Learn more](https://moonrepo.dev/docs/install)\nThe path to moon's binary can be customized with the [moon.binPath](command:moon.openSettings) setting.", "when": "moon.inWorkspaceRoot && !moon.hasBinary" } ] diff --git a/packages/vscode-extension/src/graphVisualizerView.ts b/packages/vscode-extension/src/graphVisualizerView.ts index 92d5dca..3933e5f 100644 --- a/packages/vscode-extension/src/graphVisualizerView.ts +++ b/packages/vscode-extension/src/graphVisualizerView.ts @@ -29,6 +29,8 @@ export class GraphVisualizerView { workspace.onDidChangeWorkspace(() => { void this.renderPanel(); + + return []; }); } diff --git a/packages/vscode-extension/src/lastRunView.ts b/packages/vscode-extension/src/lastRunView.ts index ab6a01e..87e5080 100644 --- a/packages/vscode-extension/src/lastRunView.ts +++ b/packages/vscode-extension/src/lastRunView.ts @@ -5,7 +5,6 @@ import { formatDuration, prepareReportActions } from '@moonrepo/report'; import type { RunReport } from '@moonrepo/types'; import type { Workspace } from './workspace'; -const REPORT_PATH = '.moon/cache/runReport.json'; const SLOW_THRESHOLD_SECS = 120; export class LastRunProvider implements vscode.WebviewViewProvider { @@ -19,16 +18,19 @@ export class LastRunProvider implements vscode.WebviewViewProvider { this.context = context; this.workspace = workspace; - // When the report is changed, refresh view - const watcher = vscode.workspace.createFileSystemWatcher(REPORT_PATH); - watcher.onDidChange(this.renderView, this); - watcher.onDidCreate(this.renderView, this); - watcher.onDidDelete(this.renderView, this); + workspace.onDidChangeWorkspace((folder) => { + // When the report is changed, refresh view + const watcher = vscode.workspace.createFileSystemWatcher( + new vscode.RelativePattern(folder.uri, workspace.getMoonDirPath('cache/runReport.json')), + ); - context.subscriptions.push(watcher); + watcher.onDidChange(this.renderView, this); + watcher.onDidCreate(this.renderView, this); + watcher.onDidDelete(this.renderView, this); - workspace.onDidChangeWorkspace(() => { this.renderView(); + + return [watcher]; }); } @@ -75,11 +77,11 @@ export class LastRunProvider implements vscode.WebviewViewProvider { } renderView() { - if (!this.view || !this.workspace.root) { + if (!this.view?.webview || !this.workspace.root) { return; } - const runReportPath = path.join(this.workspace.root, REPORT_PATH); + const runReportPath = path.join(this.workspace.root, '.moon/cache/runReport.json'); if (fs.existsSync(runReportPath)) { const report = JSON.parse(fs.readFileSync(runReportPath, 'utf8')) as RunReport; @@ -113,7 +115,7 @@ export class LastRunProvider implements vscode.WebviewViewProvider { `); } else { this.view.webview.html = this.renderHtml(` - No run report found. Run a target through the projects view or on the command line. + No run report found. Run a task through the projects view or on the command line. `); } } diff --git a/packages/vscode-extension/src/projectsView.ts b/packages/vscode-extension/src/projectsView.ts index 83ea979..a2d8fd9 100644 --- a/packages/vscode-extension/src/projectsView.ts +++ b/packages/vscode-extension/src/projectsView.ts @@ -205,25 +205,30 @@ export class ProjectsProvider implements vscode.TreeDataProvider { this.onDidChangeTreeDataEmitter = new EventEmitter(); this.onDidChangeTreeData = this.onDidChangeTreeDataEmitter.event; - // When `.moon/*.yml` is changed, refresh projects - const watcher1 = vscode.workspace.createFileSystemWatcher('.moon/**/*.yml'); - watcher1.onDidChange(this.refresh, this); - - // When `moon.yml` is changed, refresh projects - const watcher2 = vscode.workspace.createFileSystemWatcher('**/moon.yml'); - watcher2.onDidChange(this.refresh, this); - context.subscriptions.push( vscode.commands.registerCommand('moon.refreshProjects', this.refresh, this), vscode.commands.registerCommand('moon.runTask', this.runTask, this), vscode.commands.registerCommand('moon.checkProject', this.checkProject, this), vscode.commands.registerCommand('moon.viewProject', this.viewProject, this), - watcher1, - watcher2, ); - workspace.onDidChangeWorkspace(() => { + workspace.onDidChangeWorkspace((folder) => { + // When `.moon/**/*.yml` is changed, refresh projects + const watcher1 = vscode.workspace.createFileSystemWatcher( + new vscode.RelativePattern(folder.uri, workspace.getMoonDirPath('**/*.yml')), + ); + + // When `moon.yml` is changed, refresh projects + const watcher2 = vscode.workspace.createFileSystemWatcher( + new vscode.RelativePattern(folder.uri, '**/moon.yml'), + ); + + watcher1.onDidChange(this.refresh, this); + watcher2.onDidChange(this.refresh, this); + this.refresh(); + + return [watcher1, watcher2]; }); } diff --git a/packages/vscode-extension/src/workspace.ts b/packages/vscode-extension/src/workspace.ts index 9115b6e..34e04c6 100644 --- a/packages/vscode-extension/src/workspace.ts +++ b/packages/vscode-extension/src/workspace.ts @@ -3,6 +3,8 @@ import execa from 'execa'; import vscode from 'vscode'; import { findMoonBin, isRealBin } from './moon'; +export type ChangeWorkspaceListener = (folder: vscode.WorkspaceFolder) => vscode.Disposable[]; + export class Workspace { // Current moon binary path binPath: string | null = null; @@ -16,7 +18,9 @@ export class Workspace { // Current moon workspace root root: string | null = null; - private listeners: (() => void)[] = []; + private disposables: vscode.Disposable[] = []; + + private listeners: ChangeWorkspaceListener[] = []; constructor() { this.logger = vscode.window.createOutputChannel('moon', { log: true }); @@ -35,11 +39,31 @@ export class Workspace { }); } - onDidChangeWorkspace(listener: () => void) { + onDidChangeWorkspace(listener: ChangeWorkspaceListener) { this.listeners.push(listener); } + emitDidChangeWorkspace() { + if (!this.folder) { + return; + } + + // Remove previous watchers + this.disposables.forEach((disposable) => { + disposable.dispose(); + }); + + // Add new watchers + this.listeners.forEach((listener) => { + this.disposables.push(...listener(this.folder!)); + }); + } + async findRoot(openUri: vscode.Uri) { + if (openUri.fsPath === 'moonrepo.moon-console.moon') { + return; + } + if (this.root && openUri.fsPath.startsWith(this.root)) { this.logger.appendLine('Already in a workspace, skipping'); return; @@ -59,9 +83,8 @@ export class Workspace { this.logger.appendLine(`Found workspace folder ${workspaceFolder.uri.fsPath}`); this.logger.appendLine('Attempting to find a moon installation'); - const rootPrefix = vscode.workspace.getConfiguration('moon').get('workspaceRoot', '.'); const files = await vscode.workspace.findFiles( - new vscode.RelativePattern(workspaceFolder.uri, path.join(rootPrefix, '.moon/*.yml')), + new vscode.RelativePattern(workspaceFolder.uri, this.getMoonDirPath('*.yml')), ); if (files.length > 0) { @@ -74,8 +97,7 @@ export class Workspace { this.logger.appendLine(`Found moon binary at ${this.binPath}`); } - // Trigger re-renders - this.listeners.forEach((listener) => void listener()); + this.emitDidChangeWorkspace(); } else { this.logger.appendLine('Did not find a moon installation, disabling'); } @@ -106,6 +128,12 @@ export class Workspace { } } + getMoonDirPath(file: string): string { + const rootPrefix = vscode.workspace.getConfiguration('moon').get('workspaceRoot', '.'); + + return path.join(rootPrefix, '.moon', file); + } + async getMoonVersion(): Promise { try { const result = await this.execMoon(['--version']);