Merge branch 'filesystem_events' of https://github.com/ethereum/remix-project into flattentree

flattentree
filip mertens 11 months ago
parent e81f05549a
commit 646f965e92
  1. 71
      apps/remixdesktop/src/plugins/fsPlugin.ts
  2. 4
      libs/remix-ui/workspace/src/lib/components/file-recursive-tree.tsx

@ -1,22 +1,22 @@
import { ElectronBasePlugin, ElectronBasePluginClient } from "@remixproject/plugin-electron" import {ElectronBasePlugin, ElectronBasePluginClient} from '@remixproject/plugin-electron'
import fs from 'fs/promises' import fs from 'fs/promises'
import { Profile } from "@remixproject/plugin-utils"; import {Profile} from '@remixproject/plugin-utils'
import chokidar from 'chokidar' import chokidar from 'chokidar'
import { dialog, shell } from "electron"; import {dialog, shell} from 'electron'
import { createWindow, isPackaged } from "../main"; import {createWindow, isPackaged} from '../main'
import { writeConfig } from "../utils/config"; import {writeConfig} from '../utils/config'
import { Path } from 'path-scurry' import {Path} from 'path-scurry'
import {rgPath} from '@vscode/ripgrep' import {rgPath} from '@vscode/ripgrep'
import byline from 'byline'; import byline from 'byline'
import path from "path"; import path from 'path'
import { spawn } from "child_process"; import {spawn} from 'child_process'
import { customAction } from "@remixproject/plugin-api"; import {customAction} from '@remixproject/plugin-api'
const profile: Profile = { const profile: Profile = {
displayName: 'fs', displayName: 'fs',
name: 'fs', name: 'fs',
description: 'fs' description: 'fs',
} }
const convertPathToPosix = (pathName: string): string => { const convertPathToPosix = (pathName: string): string => {
@ -27,7 +27,6 @@ const getBaseName = (pathName: string): string => {
return path.basename(pathName) return path.basename(pathName)
} }
export class FSPlugin extends ElectronBasePlugin { export class FSPlugin extends ElectronBasePlugin {
clients: FSPluginClient[] = [] clients: FSPluginClient[] = []
constructor() { constructor() {
@ -37,8 +36,8 @@ export class FSPlugin extends ElectronBasePlugin {
async onActivation(): Promise<void> { async onActivation(): Promise<void> {
const config = await this.call('electronconfig' as any, 'readConfig') const config = await this.call('electronconfig' as any, 'readConfig')
const openedFolders = config && config.openedFolders || [] const openedFolders = (config && config.openedFolders) || []
this.call('electronconfig', 'writeConfig', { 'openedFolders': openedFolders }) this.call('electronconfig', 'writeConfig', {openedFolders: openedFolders})
const foldersToDelete: string[] = [] const foldersToDelete: string[] = []
if (openedFolders && openedFolders.length) { if (openedFolders && openedFolders.length) {
for (const folder of openedFolders) { for (const folder of openedFolders) {
@ -54,9 +53,9 @@ export class FSPlugin extends ElectronBasePlugin {
} }
if (foldersToDelete.length) { if (foldersToDelete.length) {
const newFolders = openedFolders.filter((f: string) => !foldersToDelete.includes(f)) const newFolders = openedFolders.filter((f: string) => !foldersToDelete.includes(f))
this.call('electronconfig', 'writeConfig', { 'recentFolders': newFolders }) this.call('electronconfig', 'writeConfig', {recentFolders: newFolders})
} }
}else{ } else {
createWindow() createWindow()
} }
} }
@ -74,25 +73,25 @@ export class FSPlugin extends ElectronBasePlugin {
} }
openFolder(webContentsId: any): void { openFolder(webContentsId: any): void {
const client = this.clients.find(c => c.webContentsId === webContentsId) const client = this.clients.find((c) => c.webContentsId === webContentsId)
if (client) { if (client) {
client.openFolder() client.openFolder()
} }
} }
} }
const clientProfile: Profile = { const clientProfile: Profile = {
name: 'fs', name: 'fs',
displayName: 'fs', displayName: 'fs',
description: 'fs', description: 'fs',
methods: ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'lstat', 'exists', 'currentPath', 'watch', 'closeWatch', 'setWorkingDir', 'openFolder', 'openFolderInSameWindow', 'getRecentFolders', 'removeRecentFolder', 'openWindow', 'selectFolder', 'revealInExplorer', 'openInVSCode', 'openInVSCode'] methods: ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'lstat', 'exists', 'currentPath', 'watch', 'closeWatch', 'setWorkingDir', 'openFolder', 'openFolderInSameWindow', 'getRecentFolders', 'removeRecentFolder', 'openWindow', 'selectFolder', 'revealInExplorer', 'openInVSCode', 'openInVSCode'],
} }
class FSPluginClient extends ElectronBasePluginClient { class FSPluginClient extends ElectronBasePluginClient {
watchers: Record<string, chokidar.FSWatcher> = {} watchers: Record<string, chokidar.FSWatcher> = {}
workingDir: string = '' workingDir: string = ''
trackDownStreamUpdate: Record<string, string> = {} trackDownStreamUpdate: Record<string, string> = {}
expandedPaths: string[] = ['.']
constructor(webContentsId: number, profile: Profile) { constructor(webContentsId: number, profile: Profile) {
super(webContentsId, profile) super(webContentsId, profile)
@ -200,8 +199,9 @@ class FSPluginClient extends ElectronBasePluginClient {
} }
async watch(): Promise<void> { async watch(): Promise<void> {
try{ try {
this.on('filePanel' as any, 'expandPathChanged', async (paths: string[]) => { this.on('filePanel' as any, 'expandPathChanged', async (paths: string[]) => {
this.expandedPaths = ['.', ...paths] // add root
for (let path of paths) { for (let path of paths) {
if (!this.watchers[path]) { if (!this.watchers[path]) {
path = this.fixPath(path) path = this.fixPath(path)
@ -209,7 +209,7 @@ class FSPluginClient extends ElectronBasePluginClient {
console.log('added watcher', path) console.log('added watcher', path)
} }
} }
paths = paths.map(path => this.fixPath(path)) paths = paths.map((path) => this.fixPath(path))
for (const watcher in this.watchers) { for (const watcher in this.watchers) {
if (watcher === this.workingDir) continue if (watcher === this.workingDir) continue
if (!paths.includes(watcher)) { if (!paths.includes(watcher)) {
@ -221,12 +221,12 @@ class FSPluginClient extends ElectronBasePluginClient {
}) })
this.watchers[this.workingDir] = await this.watcherInit(this.workingDir) // root this.watchers[this.workingDir] = await this.watcherInit(this.workingDir) // root
console.log('added root watcher', this.workingDir) console.log('added root watcher', this.workingDir)
} catch(e){ } catch (e) {
console.log('error watching', e) console.log('error watching', e)
} }
} }
private async watcherInit (path: string) { private async watcherInit(path: string) {
const watcher = chokidar const watcher = chokidar
.watch(path, { .watch(path, {
ignorePermissionErrors: true, ignorePermissionErrors: true,
@ -234,15 +234,14 @@ class FSPluginClient extends ElectronBasePluginClient {
ignored: [ ignored: [
'**/.git/index.lock', // this file is created and unlinked all the time when git is running on Windows '**/.git/index.lock', // this file is created and unlinked all the time when git is running on Windows
], ],
depth: 1 depth: 0,
}) })
.on('all', async (eventName, path, stats) => { .on('all', async (eventName, path, stats) => {
this.watcherExec(eventName, path) this.watcherExec(eventName, path)
}) })
.on('error', error => { .on('error', (error) => {
watcher.close() watcher.close()
if(error.message.includes('ENOSPC')) { if (error.message.includes('ENOSPC')) {
this.emit('error', 'ENOSPC') this.emit('error', 'ENOSPC')
} }
console.log(`Watcher error: ${error}`) console.log(`Watcher error: ${error}`)
@ -250,20 +249,24 @@ class FSPluginClient extends ElectronBasePluginClient {
return watcher return watcher
} }
private async watcherExec (eventName: string, path: string) { private async watcherExec(eventName: string, eventPath: string) {
let pathWithoutPrefix = path.replace(this.workingDir, '') let pathWithoutPrefix = eventPath.replace(this.workingDir, '')
pathWithoutPrefix = convertPathToPosix(pathWithoutPrefix) pathWithoutPrefix = convertPathToPosix(pathWithoutPrefix)
if (pathWithoutPrefix.startsWith('/')) pathWithoutPrefix = pathWithoutPrefix.slice(1) if (pathWithoutPrefix.startsWith('/')) pathWithoutPrefix = pathWithoutPrefix.slice(1)
if (eventName === 'change') { if (eventName === 'change') {
// remove workingDir from path // remove workingDir from path
const newContent = await fs.readFile(path, 'utf-8') const newContent = await fs.readFile(eventPath, 'utf-8')
const currentContent = this.trackDownStreamUpdate[pathWithoutPrefix] const currentContent = this.trackDownStreamUpdate[pathWithoutPrefix]
if (currentContent !== newContent) { if (currentContent !== newContent) {
try { try {
console.log('emitting', eventName, pathWithoutPrefix) const dirname = path.dirname(pathWithoutPrefix)
if (this.expandedPaths.includes(dirname) || this.expandedPaths.includes(pathWithoutPrefix)) {
console.log('emitting', eventName, pathWithoutPrefix, this.expandedPaths)
this.emit('change', eventName, pathWithoutPrefix)
}
this.emit('change', eventName, pathWithoutPrefix) this.emit('change', eventName, pathWithoutPrefix)
} catch (e) { } catch (e) {
console.log('error emitting change', e) console.log('error emitting change', e)
@ -271,8 +274,12 @@ class FSPluginClient extends ElectronBasePluginClient {
} }
} else { } else {
try { try {
console.log('emitting', eventName, pathWithoutPrefix) const dirname = path.dirname(pathWithoutPrefix)
console.log('check emitting', eventName, pathWithoutPrefix, this.expandedPaths, dirname)
if (this.expandedPaths.includes(dirname) || this.expandedPaths.includes(pathWithoutPrefix)) {
console.log('emitting', eventName, pathWithoutPrefix, this.expandedPaths)
this.emit('change', eventName, pathWithoutPrefix) this.emit('change', eventName, pathWithoutPrefix)
}
} catch (e) { } catch (e) {
console.log('error emitting change', e) console.log('error emitting change', e)
} }

@ -149,9 +149,9 @@ export const RecursiveTree = (props: RecursiveTreeProps) => {
} }
}> }>
<Popover.Content className='py-1'> <Popover.Body>
{mouseOverTarget && mouseOverTarget.path} {mouseOverTarget && mouseOverTarget.path}
</Popover.Content> </Popover.Body>
</Popover> </Popover>
} }

Loading…
Cancel
Save