parent
24039ebb43
commit
6c25d81166
@ -1,8 +1,14 @@ |
||||
import * as ReactDOM from 'react-dom'; |
||||
import { RemixUiXterminals } from './remix/ui/remix-ui-xterminals'; |
||||
import { xterm } from './renderer'; |
||||
import { RemixUIFileDialog } from './remix/ui/remix-ui-filedialog'; |
||||
import { xterm, filePanel } from './renderer'; |
||||
|
||||
import { createRoot } from 'react-dom/client'; |
||||
const container = document.getElementById('app'); |
||||
const root = createRoot(container); // createRoot(container!) if you use TypeScript
|
||||
root.render(<RemixUiXterminals plugin={xterm} />) |
||||
root.render( |
||||
<> |
||||
<RemixUiXterminals plugin={xterm} /> |
||||
<RemixUIFileDialog plugin={filePanel} /> |
||||
</> |
||||
) |
@ -1,29 +1,39 @@ |
||||
import { Engine, PluginManager } from '@remixproject/engine'; |
||||
import { ipcMain } from 'electron'; |
||||
import { BrowserWindow, ipcMain } from 'electron'; |
||||
import { FSPlugin } from './fsPlugin'; |
||||
import { GitPlugin } from './gitPlugin'; |
||||
import { app } from 'electron'; |
||||
import { XtermPlugin } from './xtermPlugin'; |
||||
|
||||
|
||||
const engine = new Engine() |
||||
const appManager = new PluginManager() |
||||
const fsPlugin = new FSPlugin() |
||||
const gitPlugin = new GitPlugin() |
||||
const xtermPlugin = new XtermPlugin() |
||||
|
||||
engine.register(appManager) |
||||
engine.register(fsPlugin) |
||||
engine.register(gitPlugin) |
||||
engine.register(xtermPlugin) |
||||
|
||||
ipcMain.handle('manager:activatePlugin', async (event, arg) => { |
||||
console.log('manager:activatePlugin', arg) |
||||
if(await appManager.isActive(arg)){ |
||||
return true |
||||
} |
||||
return await appManager.activatePlugin(arg) |
||||
engine.register(xtermPlugin)
|
||||
|
||||
appManager.activatePlugin('fs') |
||||
appManager.activatePlugin('git') |
||||
appManager.activatePlugin('xterm') |
||||
|
||||
ipcMain.handle('manager:activatePlugin', async (event, plugin) => { |
||||
console.log('manager:activatePlugin', plugin, event.sender.id) |
||||
appManager.call(plugin, 'createClient', event.sender.id) |
||||
}) |
||||
|
||||
ipcMain.handle('getWebContentsID', (event, message) => { |
||||
return event.sender.id |
||||
}) |
||||
|
||||
|
||||
app.on('before-quit', async () => { |
||||
console.log('before-quit') |
||||
await appManager.call('fs', 'closeWatch') |
||||
app.quit() |
||||
}) |
||||
}) |
||||
|
||||
|
@ -0,0 +1,43 @@ |
||||
import { Plugin } from "@remixproject/engine"; |
||||
import { PluginClient } from "@remixproject/plugin"; |
||||
import { Profile } from "@remixproject/plugin-utils"; |
||||
import { BrowserWindow } from "electron"; |
||||
import { createElectronClient } from "./electronPluginClient"; |
||||
|
||||
export interface ElectronBasePluginInterface { |
||||
createClient(windowId: number): Promise<void>; |
||||
closeClient(windowId: number): Promise<void>; |
||||
} |
||||
|
||||
export abstract class ElectronBasePlugin extends Plugin implements ElectronBasePluginInterface { |
||||
clients: ElectronBasePluginClient[] = []; |
||||
constructor(profile: Profile) { |
||||
super(profile); |
||||
this.methods = ['createClient', 'closeClient']; |
||||
} |
||||
|
||||
async createClient(windowId: number): Promise<void> { |
||||
console.log('createClient method not implemented'); |
||||
} |
||||
async closeClient(windowId: number): Promise<void> { |
||||
console.log('closeClient method not implemented'); |
||||
} |
||||
} |
||||
|
||||
export class ElectronBasePluginClient extends PluginClient { |
||||
window: Electron.BrowserWindow; |
||||
webContentsId: number; |
||||
constructor(webcontentsid: number, profile: Profile, methods: string[] = []) { |
||||
super(); |
||||
console.log('ElectronBasePluginClient', profile); |
||||
this.methods = profile.methods; |
||||
this.webContentsId = webcontentsid; |
||||
BrowserWindow.getAllWindows().forEach((window) => { |
||||
if (window.webContents.id === webcontentsid) { |
||||
this.window = window; |
||||
} |
||||
}); |
||||
createElectronClient(this, profile, this.window); |
||||
} |
||||
} |
||||
|
@ -0,0 +1,18 @@ |
||||
import {app, Menu, BrowserWindow} from 'electron'; |
||||
import { createWindow } from '../../'; |
||||
|
||||
const commands: Record<string, (focusedWindow?: BrowserWindow) => void> = { |
||||
'window:new': () => { |
||||
// If window is created on the same tick, it will consume event too
|
||||
setTimeout(createWindow, 0); |
||||
}, |
||||
|
||||
}; |
||||
|
||||
|
||||
export const execCommand = (command: string, focusedWindow?: BrowserWindow) => { |
||||
const fn = commands[command]; |
||||
if (fn) { |
||||
fn(focusedWindow); |
||||
} |
||||
}; |
@ -0,0 +1,36 @@ |
||||
import {BrowserWindow, MenuItemConstructorOptions} from 'electron'; |
||||
|
||||
export default ( |
||||
commandKeys: Record<string, string>, |
||||
execCommand: (command: string, focusedWindow?: BrowserWindow) => void |
||||
): MenuItemConstructorOptions => { |
||||
const isMac = process.platform === 'darwin'; |
||||
|
||||
return { |
||||
label: isMac ? 'Shell' : 'File', |
||||
submenu: [ |
||||
{ |
||||
label: 'New Window', |
||||
accelerator: commandKeys['window:new'], |
||||
click(item, focusedWindow) { |
||||
execCommand('window:new', focusedWindow); |
||||
} |
||||
}, |
||||
{ |
||||
type: 'separator' |
||||
}, |
||||
{ |
||||
label: 'Close', |
||||
accelerator: commandKeys['pane:close'], |
||||
click(item, focusedWindow) { |
||||
execCommand('pane:close', focusedWindow); |
||||
} |
||||
}, |
||||
{ |
||||
label: isMac ? 'Close Window' : 'Quit', |
||||
role: 'close', |
||||
accelerator: commandKeys['window:close'] |
||||
} |
||||
] |
||||
}; |
||||
}; |
@ -1,14 +1,97 @@ |
||||
import { ElectronPlugin } from './lib/electronPlugin'; |
||||
|
||||
export class fsPlugin extends ElectronPlugin { |
||||
let workingDir = '/Volumes/bunsen/code/rmproject2/remix-project/apps/remix-ide/contracts/' |
||||
|
||||
const fixPath = (path: string) => { |
||||
/* |
||||
// if it starts with /, it's an absolute path remove it
|
||||
if (path.startsWith('/')) { |
||||
path = path.slice(1) |
||||
} |
||||
|
||||
path = workingDir + path |
||||
*/ |
||||
|
||||
|
||||
constructor(){ |
||||
return path |
||||
} |
||||
|
||||
export class fsPlugin extends ElectronPlugin { |
||||
public fs: any |
||||
|
||||
constructor() { |
||||
super({ |
||||
displayName: 'fs', |
||||
name: 'fs', |
||||
description: 'fs', |
||||
}) |
||||
this.methods = ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'exists'] |
||||
this.methods = ['readdir', 'readFile', 'writeFile', 'mkdir', 'rmdir', 'unlink', 'rename', 'stat', 'exists', 'setWorkingDir'] |
||||
|
||||
|
||||
this.fs = { |
||||
|
||||
exists: async (path: string) => { |
||||
path = fixPath(path) |
||||
const exists = await this.call('fs', 'exists', path) |
||||
return exists |
||||
}, |
||||
rmdir: async (path: string) => { |
||||
path = fixPath(path) |
||||
return await this.call('fs', 'rmdir', path) |
||||
|
||||
}, |
||||
readdir: async (path: string) => { |
||||
path = fixPath(path) |
||||
console.log('readdir', path) |
||||
const files = await this.call('fs', 'readdir', path) |
||||
return files |
||||
}, |
||||
unlink: async (path: string) => { |
||||
path = fixPath(path) |
||||
return await this.call('fs', 'unlink', path) |
||||
}, |
||||
mkdir: async (path: string) => { |
||||
path = fixPath(path) |
||||
return await this.call('fs', 'mkdir', path) |
||||
}, |
||||
readFile: async (path: string) => { |
||||
path = fixPath(path) |
||||
return await this.call('fs', 'readFile', path) |
||||
} |
||||
, |
||||
rename: async (from: string, to: string) => { |
||||
return await this.call('fs', 'rename', from, to) |
||||
}, |
||||
writeFile: async (path: string, content: string) => { |
||||
path = fixPath(path) |
||||
return await this.call('fs', 'writeFile', path, content) |
||||
} |
||||
, |
||||
stat: async (path: string) => { |
||||
path = fixPath(path) |
||||
const stat = await this.call('fs', 'stat', path) |
||||
stat.isDirectory = () => stat.isDirectoryValue |
||||
stat.isFile = () => !stat.isDirectoryValue |
||||
//console.log('stat', path, stat)
|
||||
return stat |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
async onActivation() { |
||||
console.log('fsPluginClient onload', this.fs); |
||||
(window as any).remixFileSystem = this.fs |
||||
|
||||
this.on('fs', 'workingDirChanged', (path: string) => { |
||||
console.log('change working dir', path) |
||||
workingDir = path |
||||
}) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,40 @@ |
||||
import { Plugin } from "@remixproject/engine" |
||||
import { useEffect, useState } from "react" |
||||
import { ElectronPlugin } from "../lib/electronPlugin" |
||||
|
||||
interface RemixUIFileDialogInterface { |
||||
plugin: Plugin |
||||
} |
||||
|
||||
export const RemixUIFileDialog = (props: RemixUIFileDialogInterface) => { |
||||
const { plugin } = props |
||||
const [files, setFiles] = useState<string[]>([]) |
||||
const [workingDir, setWorkingDir] = useState<string>('') |
||||
|
||||
useEffect(() => { |
||||
plugin.on('fs', 'workingDirChanged', async (path: string) => { |
||||
console.log('workingDirChanged') |
||||
setWorkingDir(path) |
||||
await readdir() |
||||
}) |
||||
}, []) |
||||
|
||||
const readdir = async () => { |
||||
const files = await plugin.call('fs', 'readdir', '/') |
||||
console.log('files', files) |
||||
setFiles(files) |
||||
} |
||||
|
||||
return ( |
||||
<> |
||||
<h1>RemixUIFileDialog</h1> |
||||
<button onClick={() => plugin.call('fs', 'setWorkingDir')}>open</button> |
||||
<button onClick={async () => await readdir()}>read</button> |
||||
<hr></hr> |
||||
{workingDir} |
||||
<hr></hr> |
||||
|
||||
{files.map(file => <div key={file}>{file}</div>)} |
||||
</> |
||||
) |
||||
} |
Loading…
Reference in new issue