diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts index c972ac6c0f..cc9162f27c 100644 --- a/apps/remix-ide/src/app/files/fileManager.ts +++ b/apps/remix-ide/src/app/files/fileManager.ts @@ -5,7 +5,6 @@ import JSZip from 'jszip' import { Plugin } from '@remixproject/engine' import * as packageJson from '../../../../../package.json' import {Registry} from '@remix-project/remix-lib' -import { EventEmitter } from 'events' import { fileChangedToastMsg, recursivePasteToastMsg, storageFullMessage } from '@remix-ui/helper' import helper from '../../lib/helper.js' import { RemixAppManager } from '../../remixAppManager' @@ -42,7 +41,6 @@ const createError = (err) => { class FileManager extends Plugin { mode: string openedFiles: any - events: EventEmitter editor: any _components: any appManager: RemixAppManager @@ -56,7 +54,6 @@ class FileManager extends Plugin { super(profile) this.mode = 'browser' this.openedFiles = {} // list all opened files - this.events = new EventEmitter() this.editor = editor this._components = {} this._components.registry = Registry.getInstance() @@ -565,7 +562,6 @@ class FileManager extends Plugin { } // TODO: Only keep `this.emit` (issue#2210) this.emit('fileRenamed', oldName, newName, isFolder) - this.events.emit('fileRenamed', oldName, newName, isFolder) } currentFileProvider() { @@ -583,7 +579,6 @@ class FileManager extends Plugin { async closeAllFiles() { // TODO: Only keep `this.emit` (issue#2210) this.emit('filesAllClosed') - this.events.emit('filesAllClosed') for (const file in this.openedFiles) { await this.closeFile(file) } @@ -595,11 +590,9 @@ class FileManager extends Plugin { this._deps.config.set('currentFile', '') // TODO: Only keep `this.emit` (issue#2210) this.emit('noFileSelected') - this.events.emit('noFileSelected') } // TODO: Only keep `this.emit` (issue#2210) this.emit('fileClosed', name) - this.events.emit('fileClosed', name) } currentPath() { @@ -703,8 +696,9 @@ class FileManager extends Plugin { delete this.openedFiles[path] // TODO: Only keep `this.emit` (issue#2210) this.emit('fileRemoved', path) - this.events.emit('fileRemoved', path) - this.openFile(this._deps.config.get('currentFile')) + if (path === this._deps.config.get('currentFile')) { + this.openFile(this._deps.config.get('currentFile')) + } } async unselectCurrentFile() { @@ -712,13 +706,11 @@ class FileManager extends Plugin { this._deps.config.set('currentFile', '') // TODO: Only keep `this.emit` (issue#2210) this.emit('noFileSelected') - this.events.emit('noFileSelected') } async openFile(file?: string) { if (!file) { this.emit('noFileSelected') - this.events.emit('noFileSelected') } else { file = this.normalize(file) const resolved = this.getPathFromUrl(file) @@ -752,7 +744,6 @@ class FileManager extends Plugin { } // TODO: Only keep `this.emit` (issue#2210) this.emit('currentFileChanged', file) - this.events.emit('currentFileChanged', file) return true } } diff --git a/apps/remixdesktop/src/plugins/fsPlugin.ts b/apps/remixdesktop/src/plugins/fsPlugin.ts index 830ff7aa0b..3818104c90 100644 --- a/apps/remixdesktop/src/plugins/fsPlugin.ts +++ b/apps/remixdesktop/src/plugins/fsPlugin.ts @@ -90,7 +90,7 @@ const clientProfile: Profile = { } class FSPluginClient extends ElectronBasePluginClient { - watcher: chokidar.FSWatcher + watchers: Record = {} workingDir: string = '' trackDownStreamUpdate: Record = {} @@ -148,13 +148,10 @@ class FSPluginClient extends ElectronBasePluginClient { } async rmdir(path: string): Promise { - if (this.watcher) await this.watcher.close() await fs.rm(this.fixPath(path), { recursive: true, }) this.emit('change', 'unlinkDir', path) - await this.watch() - } async unlink(path: string): Promise { @@ -203,59 +200,89 @@ class FSPluginClient extends ElectronBasePluginClient { } async watch(): Promise { - - if (this.watcher) this.watcher.close() try{ - this.watcher = chokidar - .watch(this.workingDir, { + this.on('filePanel' as any, 'expandPathChanged', async (paths: string[]) => { + for (let path of paths) { + if (!this.watchers[path]) { + path = this.fixPath(path) + this.watchers[path] = await this.watcherInit(path) + console.log('added watcher', path) + } + } + paths = paths.map(path => this.fixPath(path)) + for (const watcher in this.watchers) { + if (watcher === this.workingDir) continue + if (!paths.includes(watcher)) { + this.watchers[watcher].close() + delete this.watchers[watcher] + console.log('removed watcher', watcher) + } + } + }) + this.watchers[this.workingDir] = await this.watcherInit(this.workingDir) // root + console.log('added root watcher', this.workingDir) + } catch(e){ + console.log('error watching', e) + } + } + + private async watcherInit (path: string) { + const watcher = chokidar + .watch(path, { ignorePermissionErrors: true, ignoreInitial: true, ignored: [ '**/.git/index.lock', // this file is created and unlinked all the time when git is running on Windows ], - depth: 20 + depth: 1 }) .on('all', async (eventName, path, stats) => { - let pathWithoutPrefix = path.replace(this.workingDir, '') - pathWithoutPrefix = convertPathToPosix(pathWithoutPrefix) - if (pathWithoutPrefix.startsWith('/')) pathWithoutPrefix = pathWithoutPrefix.slice(1) - - if (eventName === 'change') { - // remove workingDir from path - const newContent = await fs.readFile(path, 'utf-8') - - const currentContent = this.trackDownStreamUpdate[pathWithoutPrefix] - - if (currentContent !== newContent) { - try { - this.emit('change', eventName, pathWithoutPrefix) - } catch (e) { - console.log('error emitting change', e) - } - } - } else { - try { - this.emit('change', eventName, pathWithoutPrefix) - } catch (e) { - console.log('error emitting change', e) - } - } + this.watcherExec(eventName, path) }) .on('error', error => { - this.watcher.close() + watcher.close() if(error.message.includes('ENOSPC')) { this.emit('error', 'ENOSPC') } console.log(`Watcher error: ${error}`) }) - }catch(e){ - console.log('error watching', e) + return watcher + } + + private async watcherExec (eventName: string, path: string) { + let pathWithoutPrefix = path.replace(this.workingDir, '') + pathWithoutPrefix = convertPathToPosix(pathWithoutPrefix) + if (pathWithoutPrefix.startsWith('/')) pathWithoutPrefix = pathWithoutPrefix.slice(1) + + if (eventName === 'change') { + // remove workingDir from path + const newContent = await fs.readFile(path, 'utf-8') + + const currentContent = this.trackDownStreamUpdate[pathWithoutPrefix] + + if (currentContent !== newContent) { + try { + console.log('emitting', eventName, pathWithoutPrefix) + this.emit('change', eventName, pathWithoutPrefix) + } catch (e) { + console.log('error emitting change', e) + } + } + } else { + try { + console.log('emitting', eventName, pathWithoutPrefix) + this.emit('change', eventName, pathWithoutPrefix) + } catch (e) { + console.log('error emitting change', e) + } } } async closeWatch(): Promise { - if (this.watcher) this.watcher.close() + for (const watcher in this.watchers) { + this.watchers[watcher].close() + } } async updateRecentFolders(path: string): Promise { diff --git a/libs/remix-ui/run-tab/src/lib/actions/events.ts b/libs/remix-ui/run-tab/src/lib/actions/events.ts index 8377f8920d..bc8833172a 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/events.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/events.ts @@ -104,7 +104,7 @@ export const setupEvents = (plugin: RunTab, dispatch: React.Dispatch) => { } }) - plugin.fileManager.events.on('currentFileChanged', (currentFile: string) => { + plugin.on('fileManager', 'currentFileChanged', (currentFile: string) => { if (/.(.abi)$/.exec(currentFile)) { dispatch(setLoadType('abi')) } else if (/.(.sol)$/.exec(currentFile) || diff --git a/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx b/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx index c743caac68..fc64580349 100644 --- a/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx +++ b/libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx @@ -177,10 +177,10 @@ export const SolidityUnitTesting = (props: Record) => { return tmp ? tmp[1] : version } - testTab.fileManager.events.on('noFileSelected', async () => { + testTab.on('fileManager', 'noFileSelected', async () => { await updateForNewCurrent() }) - testTab.fileManager.events.on('currentFileChanged', async (file: string) => { + testTab.on('fileManager', 'currentFileChanged', async (file: string) => { await updateForNewCurrent(file) }) testTab.on('solidity', 'compilerLoaded', async (version: string, license: string) => { diff --git a/libs/remix-ui/workspace/src/lib/actions/events.ts b/libs/remix-ui/workspace/src/lib/actions/events.ts index dd4dd6c660..932285bddf 100644 --- a/libs/remix-ui/workspace/src/lib/actions/events.ts +++ b/libs/remix-ui/workspace/src/lib/actions/events.ts @@ -220,6 +220,7 @@ const fileRemoved = async (removePath: string) => { const fileRenamed = async (oldPath: string) => { const provider = plugin.fileManager.currentFileProvider() const path = extractParentFromKey(oldPath) || ROOT_PATH + const promise: Promise = new Promise((resolve) => { provider.resolveDirectory(path, (error, fileTree: FileTree) => { if (error) console.error(error) diff --git a/libs/remix-ui/workspace/src/lib/actions/index.ts b/libs/remix-ui/workspace/src/lib/actions/index.ts index a4d25643a9..bcad5bd98a 100644 --- a/libs/remix-ui/workspace/src/lib/actions/index.ts +++ b/libs/remix-ui/workspace/src/lib/actions/index.ts @@ -378,6 +378,7 @@ export const handleClickFile = async (path: string, type: 'file' | 'folder' | 'g } export const handleExpandPath = (paths: string[]) => { + plugin.emit('expandPathChanged', paths) dispatch(setExpandPath(paths)) } diff --git a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts index 3d7476ffdc..628b64d10c 100644 --- a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts @@ -319,7 +319,6 @@ export const browserReducer = (state = browserInitialState, action: Actions) => case 'FILE_ADDED_SUCCESS': { const payload = action.payload - return { ...state, browser: {