parent
24039ebb43
commit
6c25d81166
@ -1,8 +1,14 @@ |
|||||||
import * as ReactDOM from 'react-dom'; |
import * as ReactDOM from 'react-dom'; |
||||||
import { RemixUiXterminals } from './remix/ui/remix-ui-xterminals'; |
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'; |
import { createRoot } from 'react-dom/client'; |
||||||
const container = document.getElementById('app'); |
const container = document.getElementById('app'); |
||||||
const root = createRoot(container); // createRoot(container!) if you use TypeScript
|
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 { Engine, PluginManager } from '@remixproject/engine'; |
||||||
import { ipcMain } from 'electron'; |
import { BrowserWindow, ipcMain } from 'electron'; |
||||||
import { FSPlugin } from './fsPlugin'; |
import { FSPlugin } from './fsPlugin'; |
||||||
import { GitPlugin } from './gitPlugin'; |
import { GitPlugin } from './gitPlugin'; |
||||||
import { app } from 'electron'; |
import { app } from 'electron'; |
||||||
import { XtermPlugin } from './xtermPlugin'; |
import { XtermPlugin } from './xtermPlugin'; |
||||||
|
|
||||||
|
|
||||||
const engine = new Engine() |
const engine = new Engine() |
||||||
const appManager = new PluginManager() |
const appManager = new PluginManager() |
||||||
const fsPlugin = new FSPlugin() |
const fsPlugin = new FSPlugin() |
||||||
const gitPlugin = new GitPlugin() |
const gitPlugin = new GitPlugin() |
||||||
const xtermPlugin = new XtermPlugin() |
const xtermPlugin = new XtermPlugin() |
||||||
|
|
||||||
engine.register(appManager) |
engine.register(appManager) |
||||||
engine.register(fsPlugin) |
engine.register(fsPlugin) |
||||||
engine.register(gitPlugin) |
engine.register(gitPlugin) |
||||||
engine.register(xtermPlugin)
|
engine.register(xtermPlugin)
|
||||||
|
|
||||||
ipcMain.handle('manager:activatePlugin', async (event, arg) => { |
appManager.activatePlugin('fs') |
||||||
console.log('manager:activatePlugin', arg) |
appManager.activatePlugin('git') |
||||||
if(await appManager.isActive(arg)){ |
appManager.activatePlugin('xterm') |
||||||
return true |
|
||||||
} |
ipcMain.handle('manager:activatePlugin', async (event, plugin) => { |
||||||
return await appManager.activatePlugin(arg) |
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 () => { |
app.on('before-quit', async () => { |
||||||
|
console.log('before-quit') |
||||||
await appManager.call('fs', 'closeWatch') |
await appManager.call('fs', 'closeWatch') |
||||||
app.quit() |
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'; |
import { ElectronPlugin } from './lib/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 |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
return path |
||||||
|
} |
||||||
|
|
||||||
export class fsPlugin extends ElectronPlugin { |
export class fsPlugin extends ElectronPlugin { |
||||||
|
public fs: any |
||||||
|
|
||||||
constructor(){ |
constructor() { |
||||||
super({ |
super({ |
||||||
displayName: 'fs', |
displayName: 'fs', |
||||||
name: 'fs', |
name: 'fs', |
||||||
description: '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