rdesktop2
bunsenstraat 1 year ago
parent f34a4e394e
commit dffa78e3dc
  1. 13
      apps/remixdesktop/src/plugins/xtermPlugin.ts
  2. 80
      apps/remixdesktop/src/utils/findExecutable.ts
  3. 8
      libs/remix-ui/xterm/src/lib/components/remix-ui-xterminals.tsx

@ -7,6 +7,7 @@ import * as pty from "node-pty"
import process from 'node:process'; import process from 'node:process';
import { userInfo } from 'node:os'; import { userInfo } from 'node:os';
import { findExecutable } from "../utils/findExecutable";
export const detectDefaultShell = () => { export const detectDefaultShell = () => {
const { env } = process; const { env } = process;
@ -86,12 +87,18 @@ class XtermPluginClient extends ElectronBasePluginClient {
} }
async getShells(): Promise<string[]> { async getShells(): Promise<string[]> {
if(os.platform() === 'win32') {
const bash = await findExecutable('bash')
if(bash) {
return [bash, 'powershell.exe', 'cmd.exe']
}
return ['powershell.exe', 'cmd.exe']
}
return [defaultShell] return [defaultShell]
} }
async createTerminal(path?: string): Promise<number> { async createTerminal(path?: string, shell?: string): Promise<number> {
const shell = defaultShell;
// filter undefined out of the env // filter undefined out of the env
@ -103,7 +110,7 @@ class XtermPluginClient extends ElectronBasePluginClient {
}, {} as Record<string, string>); }, {} as Record<string, string>);
const ptyProcess = pty.spawn(shell, [], { const ptyProcess = pty.spawn(shell || defaultShell, [], {
name: 'xterm-color', name: 'xterm-color',
cols: 80, cols: 80,
rows: 20, rows: 20,

@ -0,0 +1,80 @@
import path from "path";
import process from "process";
import { Stats } from "fs";
import fs from 'fs/promises'
export async function findExecutable(command: string, cwd?: string, paths?: string[]): Promise<string> {
// If we have an absolute path then we take it.
if (path.isAbsolute(command)) {
return command;
}
if (cwd === undefined) {
cwd = process.cwd();
}
const dir = path.dirname(command);
if (dir !== '.') {
// We have a directory and the directory is relative (see above). Make the path absolute
// to the current working directory.
return path.join(cwd, command);
}
if (paths === undefined && typeof process.env['PATH'] === 'string') {
paths = (process && process.env['PATH'] && process.env['PATH'].split(path.delimiter)) || [];
}
// No PATH environment. Make path absolute to the cwd.
if (paths === undefined || paths.length === 0) {
return path.join(cwd, command);
}
async function fileExists(path: string): Promise<boolean> {
try {
if (await fs.stat(path)) {
let statValue: Stats | undefined;
try {
statValue = await fs.stat(path);
} catch (e: any) {
if (e.message.startsWith('EACCES')) {
// it might be symlink
statValue = await fs.lstat(path);
}
}
return statValue ? !statValue.isDirectory() : false;
}
} catch (e) {
}
return false;
}
// We have a simple file name. We get the path variable from the env
// and try to find the executable on the path.
for (const pathEntry of paths) {
// The path entry is absolute.
let fullPath: string;
if (path.isAbsolute(pathEntry)) {
fullPath = path.join(pathEntry, command);
} else {
fullPath = path.join(cwd, pathEntry, command);
}
if (await fileExists(fullPath)) {
return fullPath;
}
let withExtension = fullPath + '.com';
if (await fileExists(withExtension)) {
return withExtension;
}
withExtension = fullPath + '.exe';
if (await fileExists(withExtension)) {
return withExtension;
}
}
return path.join(cwd, command);
}

@ -92,8 +92,8 @@ export const RemixUiXterminals = (props: RemixUiXterminalsProps) => {
plugin.call('xterm', 'keystroke', data, pid) plugin.call('xterm', 'keystroke', data, pid)
} }
const createTerminal = async () => { const createTerminal = async (shell?: string) => {
const pid = await plugin.call('xterm', 'createTerminal', workingDir) const pid = await plugin.call('xterm', 'createTerminal', workingDir, shell)
setShowOutput(false) setShowOutput(false)
setTerminals(prevState => { setTerminals(prevState => {
// set all to hidden // set all to hidden
@ -161,14 +161,14 @@ export const RemixUiXterminals = (props: RemixUiXterminalsProps) => {
<div className={`xterm-panel-header-right ${showOutput ? 'd-none' : ''}`}> <div className={`xterm-panel-header-right ${showOutput ? 'd-none' : ''}`}>
<Dropdown as={ButtonGroup}> <Dropdown as={ButtonGroup}>
<button className="btn btn-sm btn-secondary" onClick={createTerminal}><span className="far fa-plus border-0 p-0 m-0"></span></button> <button className="btn btn-sm btn-secondary" onClick={async() => createTerminal()}><span className="far fa-plus border-0 p-0 m-0"></span></button>
<Dropdown.Toggle split variant="secondary" id="dropdown-split-basic" /> <Dropdown.Toggle split variant="secondary" id="dropdown-split-basic" />
<Dropdown.Menu className='custom-dropdown-items remixui_menuwidth'> <Dropdown.Menu className='custom-dropdown-items remixui_menuwidth'>
{shells.map((shell, index) => { {shells.map((shell, index) => {
return (<Dropdown.Item key={index} onClick={createTerminal}>{shell}</Dropdown.Item>) return (<Dropdown.Item key={index} onClick={async() => await createTerminal(shell)}>{shell}</Dropdown.Item>)
})} })}
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> </Dropdown>

Loading…
Cancel
Save