|
| 1 | +import { |
| 2 | + Disposable, |
| 3 | + FileSystem, |
| 4 | + PathChangeListener, |
| 5 | + walkFiles, |
| 6 | +} from "@cursorless/common"; |
| 7 | +import { stat } from "fs/promises"; |
| 8 | +import { max } from "lodash"; |
| 9 | + |
| 10 | +export class VscodeFileSystem implements FileSystem { |
| 11 | + watchDir(path: string, onDidChange: PathChangeListener): Disposable { |
| 12 | + // Just poll for now; we can take advantage of VSCode's sophisticated |
| 13 | + // watcher later. Note that we would need to do a version check, as VSCode |
| 14 | + // file watcher is only available in more recent versions of VSCode. |
| 15 | + return new PollingFileSystemWatcher(path, onDidChange); |
| 16 | + } |
| 17 | +} |
| 18 | + |
| 19 | +const CHECK_INTERVAL_MS = 1000; |
| 20 | + |
| 21 | +class PollingFileSystemWatcher implements Disposable { |
| 22 | + private maxMtimeMs: number = -1; |
| 23 | + private timer: NodeJS.Timer; |
| 24 | + |
| 25 | + constructor( |
| 26 | + private readonly path: string, |
| 27 | + private readonly onDidChange: PathChangeListener, |
| 28 | + ) { |
| 29 | + this.checkForChanges = this.checkForChanges.bind(this); |
| 30 | + this.timer = setInterval(this.checkForChanges, CHECK_INTERVAL_MS); |
| 31 | + } |
| 32 | + |
| 33 | + private async checkForChanges() { |
| 34 | + const paths = await walkFiles(this.path); |
| 35 | + |
| 36 | + const maxMtime = |
| 37 | + max( |
| 38 | + (await Promise.all(paths.map((file) => stat(file)))).map( |
| 39 | + (stat) => stat.mtimeMs, |
| 40 | + ), |
| 41 | + ) ?? 0; |
| 42 | + |
| 43 | + if (maxMtime > this.maxMtimeMs) { |
| 44 | + this.maxMtimeMs = maxMtime; |
| 45 | + this.onDidChange(); |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + dispose() { |
| 50 | + clearInterval(this.timer); |
| 51 | + } |
| 52 | +} |
0 commit comments