mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-29 11:03:48 +01:00
feat: Add vim mode to script editor
This adds an option to turn on vim mode using the `monaco-vim` library.
This commit is contained in:
parent
3436873373
commit
fb5d374279
7
dist/ext/monaco-vim.js
vendored
Normal file
7
dist/ext/monaco-vim.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -17,12 +17,13 @@
|
|||||||
<link rel="stylesheet" data-name="vs/editor/editor.main" href="dist/ext/monaco-editor/min/vs/editor/editor.main.css"/>
|
<link rel="stylesheet" data-name="vs/editor/editor.main" href="dist/ext/monaco-editor/min/vs/editor/editor.main.css"/>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var require = { paths: { vs: "dist/ext/monaco-editor/min/vs" } };
|
var require = { paths: { vs: "dist/ext/monaco-editor/min/vs", "monaco-vim": "dist/ext/monaco-vim" } };
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="dist/ext/monaco-editor/min/vs/loader.js"></script>
|
<script src="dist/ext/monaco-editor/min/vs/loader.js"></script>
|
||||||
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.nls.js"></script>
|
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.nls.js"></script>
|
||||||
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.js"></script>
|
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.js"></script>
|
||||||
|
<script src="dist/ext/monaco-vim.js"></script>
|
||||||
|
|
||||||
<!-- Google Analytics -->
|
<!-- Google Analytics -->
|
||||||
<script>
|
<script>
|
||||||
|
@ -2,4 +2,5 @@ export interface Options {
|
|||||||
theme: string;
|
theme: string;
|
||||||
insertSpaces: boolean;
|
insertSpaces: boolean;
|
||||||
fontSize: number;
|
fontSize: number;
|
||||||
|
vim: boolean;
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,14 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
|||||||
const [theme, setTheme] = useState(props.options.theme);
|
const [theme, setTheme] = useState(props.options.theme);
|
||||||
const [insertSpaces, setInsertSpaces] = useState(props.options.insertSpaces);
|
const [insertSpaces, setInsertSpaces] = useState(props.options.insertSpaces);
|
||||||
const [fontSize, setFontSize] = useState(props.options.fontSize);
|
const [fontSize, setFontSize] = useState(props.options.fontSize);
|
||||||
|
const [vim, setVim] = useState(props.options.vim);
|
||||||
|
|
||||||
function save(): void {
|
function save(): void {
|
||||||
props.save({
|
props.save({
|
||||||
theme: theme,
|
theme,
|
||||||
insertSpaces: insertSpaces,
|
insertSpaces,
|
||||||
fontSize: fontSize,
|
fontSize,
|
||||||
|
vim,
|
||||||
});
|
});
|
||||||
props.onClose();
|
props.onClose();
|
||||||
}
|
}
|
||||||
@ -54,6 +56,12 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
|||||||
<Typography>Use whitespace over tabs: </Typography>
|
<Typography>Use whitespace over tabs: </Typography>
|
||||||
<Switch onChange={(event) => setInsertSpaces(event.target.checked)} checked={insertSpaces} />
|
<Switch onChange={(event) => setInsertSpaces(event.target.checked)} checked={insertSpaces} />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
<Box display="flex" flexDirection="row" alignItems="center">
|
||||||
|
<Typography>Enable vim mode: </Typography>
|
||||||
|
<Switch onChange={(event) => setVim(event.target.checked)} checked={vim} />
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box display="flex" flexDirection="row" alignItems="center">
|
<Box display="flex" flexDirection="row" alignItems="center">
|
||||||
<TextField type="number" label="Font size" value={fontSize} onChange={onFontChange} />
|
<TextField type="number" label="Font size" value={fontSize} onChange={onFontChange} />
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect, useRef, useMemo } from "react";
|
import React, { useState, useEffect, useRef, useMemo } from "react";
|
||||||
import Editor from "@monaco-editor/react";
|
import Editor from "@monaco-editor/react";
|
||||||
import * as monaco from "monaco-editor";
|
import * as monaco from "monaco-editor";
|
||||||
|
|
||||||
type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor;
|
type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor;
|
||||||
import { OptionsModal } from "./OptionsModal";
|
import { OptionsModal } from "./OptionsModal";
|
||||||
import { Options } from "./Options";
|
import { Options } from "./Options";
|
||||||
@ -86,9 +87,13 @@ let lastFilename = "";
|
|||||||
let lastCode = "";
|
let lastCode = "";
|
||||||
let hostname = "";
|
let hostname = "";
|
||||||
let lastPosition: monaco.Position | null = null;
|
let lastPosition: monaco.Position | null = null;
|
||||||
|
// let vimEditor: any | null = null;
|
||||||
|
|
||||||
export function Root(props: IProps): React.ReactElement {
|
export function Root(props: IProps): React.ReactElement {
|
||||||
const editorRef = useRef<IStandaloneCodeEditor | null>(null);
|
const editorRef = useRef<IStandaloneCodeEditor | null>(null);
|
||||||
|
const vimStatusRef = useRef<HTMLElement>(null);
|
||||||
|
const [vimEditor, setVimEditor] = useState<any>(null);
|
||||||
|
const [editor, setEditor] = useState<IStandaloneCodeEditor|null>(null);
|
||||||
const [filename, setFilename] = useState(props.filename ? props.filename : lastFilename);
|
const [filename, setFilename] = useState(props.filename ? props.filename : lastFilename);
|
||||||
const [code, setCode] = useState<string>(props.filename ? props.code : lastCode);
|
const [code, setCode] = useState<string>(props.filename ? props.code : lastCode);
|
||||||
const [decorations, setDecorations] = useState<string[]>([]);
|
const [decorations, setDecorations] = useState<string[]>([]);
|
||||||
@ -103,6 +108,7 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
theme: Settings.MonacoTheme,
|
theme: Settings.MonacoTheme,
|
||||||
insertSpaces: Settings.MonacoInsertSpaces,
|
insertSpaces: Settings.MonacoInsertSpaces,
|
||||||
fontSize: Settings.MonacoFontSize,
|
fontSize: Settings.MonacoFontSize,
|
||||||
|
vim: Settings.MonacoVim,
|
||||||
});
|
});
|
||||||
|
|
||||||
const debouncedSetRAM = useMemo(
|
const debouncedSetRAM = useMemo(
|
||||||
@ -314,7 +320,39 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
return () => document.removeEventListener("keydown", maybeSave);
|
return () => document.removeEventListener("keydown", maybeSave);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// setup monaco-vim
|
||||||
|
if (options.vim && editor && !vimEditor) {
|
||||||
|
try {
|
||||||
|
// This library is not typed
|
||||||
|
// @ts-expect-error
|
||||||
|
window.require(["monaco-vim"], function (MonacoVim: any) {
|
||||||
|
setVimEditor(MonacoVim.initVimMode(editor, vimStatusRef.current));
|
||||||
|
MonacoVim.VimMode.Vim.defineEx('write', 'w', function() {
|
||||||
|
// your own implementation on what you want to do when :w is pressed
|
||||||
|
save();
|
||||||
|
});
|
||||||
|
MonacoVim.VimMode.Vim.defineEx('quit', 'q', function() {
|
||||||
|
save();
|
||||||
|
});
|
||||||
|
editor.focus();
|
||||||
|
});
|
||||||
|
} catch {}
|
||||||
|
} else if (!options.vim) {
|
||||||
|
// Whem vim mode is disabled
|
||||||
|
vimEditor?.dispose();
|
||||||
|
setVimEditor(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
vimEditor?.dispose();
|
||||||
|
}
|
||||||
|
}, [ options, editorRef, editor, vimEditor])
|
||||||
|
|
||||||
function onMount(editor: IStandaloneCodeEditor): void {
|
function onMount(editor: IStandaloneCodeEditor): void {
|
||||||
|
// Required when switching between site navigation (e.g. from Script Editor -> Terminal and back)
|
||||||
|
// the `useEffect()` for vim mode is called before editor is mounted.
|
||||||
|
setEditor(editor);
|
||||||
editorRef.current = editor;
|
editorRef.current = editor;
|
||||||
if (editorRef.current === null) return;
|
if (editorRef.current === null) return;
|
||||||
const position = CursorPositions.getCursor(filename);
|
const position = CursorPositions.getCursor(filename);
|
||||||
@ -328,6 +366,7 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
lineNumber: lastPosition.lineNumber,
|
lineNumber: lastPosition.lineNumber,
|
||||||
column: lastPosition.column + 1,
|
column: lastPosition.column + 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
editorRef.current.focus();
|
editorRef.current.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,9 +407,13 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
monaco.languages.typescript.typescriptDefaults.addExtraLib(source, "netscript.d.ts");
|
monaco.languages.typescript.typescriptDefaults.addExtraLib(source, "netscript.d.ts");
|
||||||
loadThemes(monaco);
|
loadThemes(monaco);
|
||||||
}
|
}
|
||||||
// 370px 71%, 725px 85.1%, 1085px 90%, 1300px 91.7%
|
|
||||||
// fuck around in desmos until you find a function
|
// TODO: Make this responsive to window resizes
|
||||||
const p = 11000 / -window.innerHeight + 100;
|
// Toolbars are roughly 108px + vim bar 34px
|
||||||
|
// Get percentage of space that toolbars represent and the rest should be the
|
||||||
|
// editor
|
||||||
|
const editorHeight = 100 - (((108 + (options.vim ? 34 : 0)) / window.innerHeight) * 100);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box display="flex" flexDirection="row" alignItems="center">
|
<Box display="flex" flexDirection="row" alignItems="center">
|
||||||
@ -393,13 +436,16 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
beforeMount={beforeMount}
|
beforeMount={beforeMount}
|
||||||
onMount={onMount}
|
onMount={onMount}
|
||||||
loading={<Typography>Loading script editor!</Typography>}
|
loading={<Typography>Loading script editor!</Typography>}
|
||||||
height={p + "%"}
|
height={`${editorHeight}%`}
|
||||||
defaultLanguage="javascript"
|
defaultLanguage="javascript"
|
||||||
defaultValue={code}
|
defaultValue={code}
|
||||||
onChange={updateCode}
|
onChange={updateCode}
|
||||||
theme={options.theme}
|
theme={options.theme}
|
||||||
options={{ ...options, glyphMargin: true }}
|
options={{ ...options, glyphMargin: true }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Box ref={vimStatusRef} className="monaco-editor" display="flex" flexDirection="row" sx={{ p: 1 }} alignItems="center"></Box>
|
||||||
|
|
||||||
<Box display="flex" flexDirection="row" sx={{ m: 1 }} alignItems="center">
|
<Box display="flex" flexDirection="row" sx={{ m: 1 }} alignItems="center">
|
||||||
<Button onClick={beautify}>Beautify</Button>
|
<Button onClick={beautify}>Beautify</Button>
|
||||||
<Typography color={updatingRam ? "secondary" : "primary"} sx={{ mx: 1 }}>
|
<Typography color={updatingRam ? "secondary" : "primary"} sx={{ mx: 1 }}>
|
||||||
@ -425,12 +471,14 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
theme: Settings.MonacoTheme,
|
theme: Settings.MonacoTheme,
|
||||||
insertSpaces: Settings.MonacoInsertSpaces,
|
insertSpaces: Settings.MonacoInsertSpaces,
|
||||||
fontSize: Settings.MonacoFontSize,
|
fontSize: Settings.MonacoFontSize,
|
||||||
|
vim: Settings.MonacoVim,
|
||||||
}}
|
}}
|
||||||
save={(options: Options) => {
|
save={(options: Options) => {
|
||||||
setOptions(options);
|
setOptions(options);
|
||||||
Settings.MonacoTheme = options.theme;
|
Settings.MonacoTheme = options.theme;
|
||||||
Settings.MonacoInsertSpaces = options.insertSpaces;
|
Settings.MonacoInsertSpaces = options.insertSpaces;
|
||||||
Settings.MonacoFontSize = options.fontSize;
|
Settings.MonacoFontSize = options.fontSize;
|
||||||
|
Settings.MonacoVim = options.vim;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -163,6 +163,8 @@ interface ISettings extends IDefaultSettings {
|
|||||||
MonacoInsertSpaces: boolean;
|
MonacoInsertSpaces: boolean;
|
||||||
|
|
||||||
MonacoFontSize: number;
|
MonacoFontSize: number;
|
||||||
|
|
||||||
|
MonacoVim: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultSettings: IDefaultSettings = {
|
export const defaultSettings: IDefaultSettings = {
|
||||||
@ -254,6 +256,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
|
|||||||
MonacoTheme: "monokai",
|
MonacoTheme: "monokai",
|
||||||
MonacoInsertSpaces: false,
|
MonacoInsertSpaces: false,
|
||||||
MonacoFontSize: 20,
|
MonacoFontSize: 20,
|
||||||
|
MonacoVim: false,
|
||||||
|
|
||||||
theme: {
|
theme: {
|
||||||
primarylight: defaultSettings.theme.primarylight,
|
primarylight: defaultSettings.theme.primarylight,
|
||||||
|
@ -21,12 +21,13 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var require = { paths: { vs: "dist/ext/monaco-editor/min/vs" } };
|
var require = { paths: { vs: "dist/ext/monaco-editor/min/vs", "monaco-vim": "dist/ext/monaco-vim" } };
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="dist/ext/monaco-editor/min/vs/loader.js"></script>
|
<script src="dist/ext/monaco-editor/min/vs/loader.js"></script>
|
||||||
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.nls.js"></script>
|
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.nls.js"></script>
|
||||||
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.js"></script>
|
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.js"></script>
|
||||||
|
<script src="dist/ext/monaco-vim.js"></script>
|
||||||
|
|
||||||
<!-- Google Analytics -->
|
<!-- Google Analytics -->
|
||||||
<script>
|
<script>
|
||||||
|
Loading…
Reference in New Issue
Block a user