This commit is contained in:
Olivier Gagnon 2022-03-10 22:34:54 -05:00
parent 9b12da4eb7
commit 9c3c83dcd5

@ -32,8 +32,8 @@ import Typography from "@mui/material/Typography";
import Link from "@mui/material/Link"; import Link from "@mui/material/Link";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import SettingsIcon from "@mui/icons-material/Settings"; import SettingsIcon from "@mui/icons-material/Settings";
import SyncIcon from '@mui/icons-material/Sync'; import SyncIcon from "@mui/icons-material/Sync";
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from "@mui/icons-material/Close";
import Table from "@mui/material/Table"; import Table from "@mui/material/Table";
import TableCell from "@mui/material/TableCell"; import TableCell from "@mui/material/TableCell";
import TableRow from "@mui/material/TableRow"; import TableRow from "@mui/material/TableRow";
@ -133,13 +133,12 @@ export function Root(props: IProps): React.ReactElement {
// Prevent Crash if script is open on deleted server // Prevent Crash if script is open on deleted server
openScripts = openScripts.filter((script) => { openScripts = openScripts.filter((script) => {
return GetServer(script.hostname) !== null; return GetServer(script.hostname) !== null;
}) });
if (currentScript && (GetServer(currentScript.hostname) === null)) { if (currentScript && GetServer(currentScript.hostname) === null) {
currentScript = openScripts[0]; currentScript = openScripts[0];
if (currentScript === undefined) currentScript = null; if (currentScript === undefined) currentScript = null;
} }
const [dimensions, setDimensions] = useState({ const [dimensions, setDimensions] = useState({
height: window.innerHeight, height: window.innerHeight,
width: window.innerWidth, width: window.innerWidth,
@ -208,7 +207,7 @@ export function Root(props: IProps): React.ReactElement {
// Setup "go to next tab" and "go to previous tab". This is a little more involved // Setup "go to next tab" and "go to previous tab". This is a little more involved
// since these aren't Ex commands (they run in normal mode, not after typing `:`) // since these aren't Ex commands (they run in normal mode, not after typing `:`)
MonacoVim.VimMode.Vim.defineAction("nextTabs", function (_cm: any, args: {repeat?: number}, _vim: any) { MonacoVim.VimMode.Vim.defineAction("nextTabs", function (_cm: any, args: { repeat?: number }) {
const nTabs = args.repeat ?? 1; const nTabs = args.repeat ?? 1;
// Go to the next tab (to the right). Wraps around when at the rightmost tab // Go to the next tab (to the right). Wraps around when at the rightmost tab
const currIndex = currentTabIndex(); const currIndex = currentTabIndex();
@ -217,23 +216,23 @@ export function Root(props: IProps): React.ReactElement {
onTabClick(nextIndex); onTabClick(nextIndex);
} }
}); });
MonacoVim.VimMode.Vim.defineAction("prevTabs", function (_cm: any, args: {repeat?: number}, _vim: any) { MonacoVim.VimMode.Vim.defineAction("prevTabs", function (_cm: any, args: { repeat?: number }) {
const nTabs = args.repeat ?? 1; const nTabs = args.repeat ?? 1;
// Go to the previous tab (to the left). Wraps around when at the leftmost tab // Go to the previous tab (to the left). Wraps around when at the leftmost tab
const currIndex = currentTabIndex(); const currIndex = currentTabIndex();
if (currIndex !== undefined) { if (currIndex !== undefined) {
let nextIndex = (currIndex - nTabs); let nextIndex = currIndex - nTabs;
while (nextIndex < 0) { while (nextIndex < 0) {
nextIndex += openScripts.length; nextIndex += openScripts.length;
} }
onTabClick(nextIndex); onTabClick(nextIndex);
} }
}); });
MonacoVim.VimMode.Vim.mapCommand("gt", "action", "nextTabs", {}, {context: "normal"}); MonacoVim.VimMode.Vim.mapCommand("gt", "action", "nextTabs", {}, { context: "normal" });
MonacoVim.VimMode.Vim.mapCommand("gT", "action", "prevTabs", {}, {context: "normal"}); MonacoVim.VimMode.Vim.mapCommand("gT", "action", "prevTabs", {}, { context: "normal" });
editor.focus(); editor.focus();
}); });
} catch { } } catch {}
} else if (!options.vim) { } else if (!options.vim) {
// Whem vim mode is disabled // Whem vim mode is disabled
vimEditor?.dispose(); vimEditor?.dispose();
@ -342,13 +341,18 @@ export function Root(props: IProps): React.ReactElement {
.loader(); .loader();
// replaced the bare tokens with regexes surrounded by \b, e.g. \b{token}\b which matches a word-break on either side // replaced the bare tokens with regexes surrounded by \b, e.g. \b{token}\b which matches a word-break on either side
// this prevents the highlighter from highlighting pieces of variables that start with a reserved token name // this prevents the highlighter from highlighting pieces of variables that start with a reserved token name
l.language.tokenizer.root.unshift([new RegExp('\\bns\\b'), { token: "ns" }]); l.language.tokenizer.root.unshift([new RegExp("\\bns\\b"), { token: "ns" }]);
for (const symbol of symbols) l.language.tokenizer.root.unshift([new RegExp(`\\b${symbol}\\b`), { token: "netscriptfunction" }]); for (const symbol of symbols)
l.language.tokenizer.root.unshift([new RegExp(`\\b${symbol}\\b`), { token: "netscriptfunction" }]);
const otherKeywords = ["let", "const", "var", "function"]; const otherKeywords = ["let", "const", "var", "function"];
const otherKeyvars = ["true", "false", "null", "undefined"]; const otherKeyvars = ["true", "false", "null", "undefined"];
otherKeywords.forEach((k) => l.language.tokenizer.root.unshift([new RegExp(`\\b${k}\\b`), { token: "otherkeywords" }])); otherKeywords.forEach((k) =>
otherKeyvars.forEach((k) => l.language.tokenizer.root.unshift([new RegExp(`\\b${k}\\b`), { token: "otherkeyvars" }])); l.language.tokenizer.root.unshift([new RegExp(`\\b${k}\\b`), { token: "otherkeywords" }]),
l.language.tokenizer.root.unshift([new RegExp('\\bthis\\b'), { token: "this" }]); );
otherKeyvars.forEach((k) =>
l.language.tokenizer.root.unshift([new RegExp(`\\b${k}\\b`), { token: "otherkeyvars" }]),
);
l.language.tokenizer.root.unshift([new RegExp("\\bthis\\b"), { token: "this" }]);
})(); })();
const source = (libSource + "").replace(/export /g, ""); const source = (libSource + "").replace(/export /g, "");
@ -474,7 +478,7 @@ export function Root(props: IProps): React.ReactElement {
} }
try { try {
infLoop(newCode); infLoop(newCode);
} catch (err) { } } catch (err) {}
} }
function saveScript(scriptToSave: OpenScript): void { function saveScript(scriptToSave: OpenScript): void {
@ -633,12 +637,12 @@ export function Root(props: IProps): React.ReactElement {
function currentTabIndex(): number | undefined { function currentTabIndex(): number | undefined {
if (currentScript !== null) { if (currentScript !== null) {
return openScripts.findIndex( return openScripts.findIndex(
(script) => (script) =>
currentScript !== null && currentScript !== null &&
script.fileName === currentScript.fileName && script.fileName === currentScript.fileName &&
script.hostname === currentScript.hostname, script.hostname === currentScript.hostname,
); );
} }
return undefined; return undefined;
} }
@ -737,15 +741,17 @@ export function Root(props: IProps): React.ReactElement {
if (openScript.code !== serverScriptCode) { if (openScript.code !== serverScriptCode) {
PromptEvent.emit({ PromptEvent.emit({
txt: "Do you want to overwrite the current editor content with the contents of " + txt:
openScript.fileName + " on the server? This cannot be undone.", "Do you want to overwrite the current editor content with the contents of " +
openScript.fileName +
" on the server? This cannot be undone.",
resolve: (result: boolean) => { resolve: (result: boolean) => {
if (result) { if (result) {
// Save changes // Save changes
openScript.code = serverScriptCode; openScript.code = serverScriptCode;
// Switch to target tab // Switch to target tab
onTabClick(index) onTabClick(index);
if (editorRef.current !== null && openScript !== null) { if (editorRef.current !== null && openScript !== null) {
if (openScript.model === undefined || openScript.model.isDisposed()) { if (openScript.model === undefined || openScript.model.isDisposed()) {
@ -789,11 +795,11 @@ export function Root(props: IProps): React.ReactElement {
// 44px bottom tool bar + 16px margin // 44px bottom tool bar + 16px margin
// + vim bar 34px // + vim bar 34px
const editorHeight = dimensions.height - (130 + (options.vim ? 34 : 0)); const editorHeight = dimensions.height - (130 + (options.vim ? 34 : 0));
const tabsMaxWidth = 1640 const tabsMaxWidth = 1640;
const tabMargin = 5 const tabMargin = 5;
const tabMaxWidth = openScripts.length ? (tabsMaxWidth / openScripts.length) - tabMargin : 0 const tabMaxWidth = openScripts.length ? tabsMaxWidth / openScripts.length - tabMargin : 0;
const tabIconWidth = 25 const tabIconWidth = 25;
const tabTextWidth = tabMaxWidth - (tabIconWidth * 2) const tabTextWidth = tabMaxWidth - tabIconWidth * 2;
return ( return (
<> <>
<div style={{ display: currentScript !== null ? "block" : "none", height: "100%", width: "100%" }}> <div style={{ display: currentScript !== null ? "block" : "none", height: "100%", width: "100%" }}>
@ -819,20 +825,22 @@ export function Root(props: IProps): React.ReactElement {
const iconButtonStyle = { const iconButtonStyle = {
maxWidth: `${tabIconWidth}px`, maxWidth: `${tabIconWidth}px`,
minWidth: `${tabIconWidth}px`, minWidth: `${tabIconWidth}px`,
minHeight: '38.5px', minHeight: "38.5px",
maxHeight: '38.5px', maxHeight: "38.5px",
...(currentScript?.fileName === openScripts[index].fileName ? { ...(currentScript?.fileName === openScripts[index].fileName
background: Settings.theme.button, ? {
borderColor: Settings.theme.button, background: Settings.theme.button,
color: Settings.theme.primary borderColor: Settings.theme.button,
} : { color: Settings.theme.primary,
background: Settings.theme.backgroundsecondary, }
borderColor: Settings.theme.backgroundsecondary, : {
color: Settings.theme.secondary background: Settings.theme.backgroundsecondary,
}) borderColor: Settings.theme.backgroundsecondary,
color: Settings.theme.secondary,
}),
}; };
const scriptTabText = `${hostname}:~/${fileName} ${dirty(index)}` const scriptTabText = `${hostname}:~/${fileName} ${dirty(index)}`;
return ( return (
<Draggable <Draggable
key={fileName + hostname} key={fileName + hostname}
@ -850,47 +858,49 @@ export function Root(props: IProps): React.ReactElement {
maxWidth: `${tabMaxWidth}px`, maxWidth: `${tabMaxWidth}px`,
marginRight: `${tabMargin}px`, marginRight: `${tabMargin}px`,
flexShrink: 0, flexShrink: 0,
border: '1px solid ' + Settings.theme.well, border: "1px solid " + Settings.theme.well,
}} }}
> >
<Tooltip title={scriptTabText}> <Tooltip title={scriptTabText}>
<Button <Button
onClick={() => onTabClick(index)} onClick={() => onTabClick(index)}
onMouseDown={e => { onMouseDown={(e) => {
e.preventDefault(); e.preventDefault();
if (e.button === 1) onTabClose(index); if (e.button === 1) onTabClose(index);
}} }}
style={{ style={{
maxWidth: `${tabTextWidth}px`, maxWidth: `${tabTextWidth}px`,
overflow: "hidden", overflow: "hidden",
...(currentScript?.fileName === openScripts[index].fileName ? { ...(currentScript?.fileName === openScripts[index].fileName
background: Settings.theme.button, ? {
borderColor: Settings.theme.button, background: Settings.theme.button,
color: Settings.theme.primary borderColor: Settings.theme.button,
} : { color: Settings.theme.primary,
background: Settings.theme.backgroundsecondary, }
borderColor: Settings.theme.backgroundsecondary, : {
color: Settings.theme.secondary background: Settings.theme.backgroundsecondary,
}) borderColor: Settings.theme.backgroundsecondary,
color: Settings.theme.secondary,
}),
}} }}
> >
<span style={{ overflow: 'hidden', direction: 'rtl', textOverflow: "ellipsis" }}> <span style={{ overflow: "hidden", direction: "rtl", textOverflow: "ellipsis" }}>
{scriptTabText} {scriptTabText}
</span> </span>
</Button> </Button>
</Tooltip> </Tooltip>
<Tooltip title="Overwrite editor content with saved file content"> <Tooltip title="Overwrite editor content with saved file content">
<Button onClick={() => onTabUpdate(index)} style={iconButtonStyle} > <Button onClick={() => onTabUpdate(index)} style={iconButtonStyle}>
<SyncIcon fontSize='small' /> <SyncIcon fontSize="small" />
</Button> </Button>
</Tooltip> </Tooltip>
<Button onClick={() => onTabClose(index)} style={iconButtonStyle}> <Button onClick={() => onTabClose(index)} style={iconButtonStyle}>
<CloseIcon fontSize='small' /> <CloseIcon fontSize="small" />
</Button> </Button>
</div> </div>
)} )}
</Draggable> </Draggable>
) );
})} })}
{provided.placeholder} {provided.placeholder}
</Box> </Box>
@ -920,13 +930,23 @@ export function Root(props: IProps): React.ReactElement {
></Box> ></Box>
<Box display="flex" flexDirection="row" sx={{ m: 1 }} alignItems="center"> <Box display="flex" flexDirection="row" sx={{ m: 1 }} alignItems="center">
<Button startIcon={<SettingsIcon />} onClick={() => setOptionsOpen(true)} sx={{ mr: 1 }}>Options</Button> <Button startIcon={<SettingsIcon />} onClick={() => setOptionsOpen(true)} sx={{ mr: 1 }}>
Options
</Button>
<Button onClick={beautify}>Beautify</Button> <Button onClick={beautify}>Beautify</Button>
<Button color={updatingRam ? "secondary" : "primary"} sx={{ mx: 1 }} onClick={() => { setRamInfoOpen(true) }}> <Button
color={updatingRam ? "secondary" : "primary"}
sx={{ mx: 1 }}
onClick={() => {
setRamInfoOpen(true);
}}
>
{ram} {ram}
</Button> </Button>
<Button onClick={save}>Save (Ctrl/Cmd + s)</Button> <Button onClick={save}>Save (Ctrl/Cmd + s)</Button>
<Button sx={{ mx: 1 }} onClick={props.router.toTerminal}>Terminal (Ctrl/Cmd + b)</Button> <Button sx={{ mx: 1 }} onClick={props.router.toTerminal}>
Terminal (Ctrl/Cmd + b)
</Button>
<Typography> <Typography>
{" "} {" "}
Documentation:{" "} Documentation:{" "}
@ -965,7 +985,9 @@ export function Root(props: IProps): React.ReactElement {
<React.Fragment key={n + r}> <React.Fragment key={n + r}>
<TableRow> <TableRow>
<TableCell sx={{ color: Settings.theme.primary }}>{n}</TableCell> <TableCell sx={{ color: Settings.theme.primary }}>{n}</TableCell>
<TableCell align="right" sx={{ color: Settings.theme.primary }}>{r}</TableCell> <TableCell align="right" sx={{ color: Settings.theme.primary }}>
{r}
</TableCell>
</TableRow> </TableRow>
</React.Fragment> </React.Fragment>
))} ))}