Merge pull request #1984 from billyvg/feat/add-vim-mode

feat: Add vim mode to script editor
This commit is contained in:
hydroflame 2021-12-20 12:03:05 -05:00 committed by GitHub
commit 25f78f2b30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 200 additions and 61 deletions

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>

@ -2,6 +2,7 @@
import React, { useState, useEffect, useRef, useMemo } from "react"; import React, { useState, useEffect, useRef, useMemo } from "react";
import Editor, { Monaco } from "@monaco-editor/react"; import Editor, { Monaco } 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;
type ITextModel = monaco.editor.ITextModel; type ITextModel = monaco.editor.ITextModel;
import { OptionsModal } from "./OptionsModal"; import { OptionsModal } from "./OptionsModal";
@ -16,7 +17,7 @@ import { TextFile } from "../../TextFile";
import { calculateRamUsage, checkInfiniteLoop } from "../../Script/RamCalculations"; import { calculateRamUsage, checkInfiniteLoop } from "../../Script/RamCalculations";
import { RamCalculationErrorCode } from "../../Script/RamCalculationErrorCodes"; import { RamCalculationErrorCode } from "../../Script/RamCalculationErrorCodes";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'; import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import { NetscriptFunctions } from "../../NetscriptFunctions"; import { NetscriptFunctions } from "../../NetscriptFunctions";
import { WorkerScript } from "../../Netscript/WorkerScript"; import { WorkerScript } from "../../Netscript/WorkerScript";
@ -37,13 +38,13 @@ import { PromptEvent } from "../../ui/React/PromptManager";
import libSource from "!!raw-loader!../NetscriptDefinitions.d.ts"; import libSource from "!!raw-loader!../NetscriptDefinitions.d.ts";
interface IProps { interface IProps {
filename: string; filename: string;
code: string; code: string;
hostname: string; hostname: string;
player: IPlayer; player: IPlayer;
router: IRouter; router: IRouter;
vim?: boolean;
} }
// TODO: try to removve global symbols // TODO: try to removve global symbols
@ -75,7 +76,6 @@ export function SetupTextEditor(): void {
symbols = symbols.filter((symbol: string) => !exclude.includes(symbol)).sort(); symbols = symbols.filter((symbol: string) => !exclude.includes(symbol)).sort();
} }
// Holds all the data for a open script // Holds all the data for a open script
class OpenScript { class OpenScript {
fileName: string; fileName: string;
@ -97,13 +97,20 @@ class OpenScript {
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 monacoRef = useRef<Monaco | null>(null); const monacoRef = useRef<Monaco | null>(null);
const vimStatusRef = useRef<HTMLElement>(null);
const [vimEditor, setVimEditor] = useState<any>(null);
const [editor, setEditor] = useState<IStandaloneCodeEditor | null>(null);
const [openScripts, setOpenScripts] = useState<OpenScript[]>( const [openScripts, setOpenScripts] = useState<OpenScript[]>(
window.localStorage.getItem('scriptEditorOpenScripts') !== null ? JSON.parse(window.localStorage.getItem('scriptEditorOpenScripts')!) : [] window.localStorage.getItem("scriptEditorOpenScripts") !== null
? JSON.parse(window.localStorage.getItem("scriptEditorOpenScripts")!)
: [],
); );
const [currentScript, setCurrentScript] = useState<OpenScript | null>( const [currentScript, setCurrentScript] = useState<OpenScript | null>(
window.localStorage.getItem('scriptEditorCurrentScript') !== null ? JSON.parse(window.localStorage.getItem('scriptEditorCurrentScript')!) : null window.localStorage.getItem("scriptEditorCurrentScript") !== null
? JSON.parse(window.localStorage.getItem("scriptEditorCurrentScript")!)
: null,
); );
const [ram, setRAM] = useState("RAM: ???"); const [ram, setRAM] = useState("RAM: ???");
@ -115,21 +122,28 @@ 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: props.vim || Settings.MonacoVim,
}); });
useEffect(() => { useEffect(() => {
// Save currentScript // Save currentScript
window.localStorage.setItem('scriptEditorCurrentScript', JSON.stringify(currentScript, (key, value) => { window.localStorage.setItem(
if (key == 'model') return undefined; "scriptEditorCurrentScript",
JSON.stringify(currentScript, (key, value) => {
if (key == "model") return undefined;
return value; return value;
})); }),
);
// Save openScripts // Save openScripts
window.localStorage.setItem('scriptEditorOpenScripts', JSON.stringify(openScripts, (key, value) => { window.localStorage.setItem(
if (key == 'model') return undefined; "scriptEditorOpenScripts",
JSON.stringify(openScripts, (key, value) => {
if (key == "model") return undefined;
return value; return value;
})) }),
}, [currentScript, openScripts]) );
}, [currentScript, openScripts]);
useEffect(() => { useEffect(() => {
if (currentScript !== null) { if (currentScript !== null) {
@ -157,6 +171,35 @@ 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]);
// Generates a new model for the script // Generates a new model for the script
function regenerateModel(script: OpenScript): void { function regenerateModel(script: OpenScript): void {
if (monacoRef.current !== null) { if (monacoRef.current !== null) {
@ -253,9 +296,12 @@ export function Root(props: IProps): React.ReactElement {
loadThemes(monaco); loadThemes(monaco);
} }
// When the editor is mounted // When the editor is mounted
function onMount(editor: IStandaloneCodeEditor, monaco: Monaco): void { function onMount(editor: IStandaloneCodeEditor, monaco: Monaco): 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;
monacoRef.current = monaco; monacoRef.current = monaco;
@ -263,10 +309,16 @@ export function Root(props: IProps): React.ReactElement {
if (props.filename) { if (props.filename) {
// Check if file is already opened // Check if file is already opened
const openScriptIndex = openScripts.findIndex(script => script.fileName === props.filename && script.hostname === props.hostname); const openScriptIndex = openScripts.findIndex(
(script) => script.fileName === props.filename && script.hostname === props.hostname,
);
if (openScriptIndex !== -1) { if (openScriptIndex !== -1) {
// Script is already opened // Script is already opened
if (openScripts[openScriptIndex].model === undefined || openScripts[openScriptIndex].model === null || openScripts[openScriptIndex].model.isDisposed()) { if (
openScripts[openScriptIndex].model === undefined ||
openScripts[openScriptIndex].model === null ||
openScripts[openScriptIndex].model.isDisposed()
) {
regenerateModel(openScripts[openScriptIndex]); regenerateModel(openScripts[openScriptIndex]);
} }
@ -277,8 +329,14 @@ export function Root(props: IProps): React.ReactElement {
updateRAM(openScripts[openScriptIndex].code); updateRAM(openScripts[openScriptIndex].code);
} else { } else {
// Open script // Open script
const newScript = new OpenScript(props.filename, props.code, props.hostname, new monacoRef.current.Position(0, 0), monacoRef.current.editor.createModel(props.code, 'javascript')); const newScript = new OpenScript(
setOpenScripts(oldArray => [...oldArray, newScript]); props.filename,
props.code,
props.hostname,
new monacoRef.current.Position(0, 0),
monacoRef.current.editor.createModel(props.code, "javascript"),
);
setOpenScripts((oldArray) => [...oldArray, newScript]);
setCurrentScript({ ...newScript }); setCurrentScript({ ...newScript });
editorRef.current.setModel(newScript.model); editorRef.current.setModel(newScript.model);
updateRAM(newScript.code); updateRAM(newScript.code);
@ -331,9 +389,11 @@ export function Root(props: IProps): React.ReactElement {
if (editorRef.current !== null) { if (editorRef.current !== null) {
const newPos = editorRef.current.getPosition(); const newPos = editorRef.current.getPosition();
if (newPos === null) return; if (newPos === null) return;
setCurrentScript(oldScript => ({ ...oldScript!, code: newCode, lastPosition: newPos! })) setCurrentScript((oldScript) => ({ ...oldScript!, code: newCode, lastPosition: newPos! }));
if (currentScript !== null) { if (currentScript !== null) {
const curIndex = openScripts.findIndex(script => script.fileName === currentScript.fileName && script.hostname === currentScript.hostname); const curIndex = openScripts.findIndex(
(script) => script.fileName === currentScript.fileName && script.hostname === currentScript.hostname,
);
const newArr = [...openScripts]; const newArr = [...openScripts];
const tempScript = currentScript; const tempScript = currentScript;
tempScript.code = newCode; tempScript.code = newCode;
@ -480,7 +540,7 @@ export function Root(props: IProps): React.ReactElement {
function onDragEnd(result: any): void { function onDragEnd(result: any): void {
// Dropped outside of the list // Dropped outside of the list
if (!result.destination) { if (!result.destination) {
result result;
return; return;
} }
@ -492,7 +552,9 @@ export function Root(props: IProps): React.ReactElement {
function onTabClick(index: number): void { function onTabClick(index: number): void {
if (currentScript !== null) { if (currentScript !== null) {
// Save currentScript to openScripts // Save currentScript to openScripts
const curIndex = openScripts.findIndex(script => script.fileName === currentScript.fileName && script.hostname === currentScript.hostname); const curIndex = openScripts.findIndex(
(script) => script.fileName === currentScript.fileName && script.hostname === currentScript.hostname,
);
openScripts[curIndex] = currentScript; openScripts[curIndex] = currentScript;
} }
@ -514,29 +576,36 @@ export function Root(props: IProps): React.ReactElement {
async function onTabClose(index: number): Promise<void> { async function onTabClose(index: number): Promise<void> {
// See if the script on the server is up to date // See if the script on the server is up to date
const closingScript = openScripts[index]; const closingScript = openScripts[index];
const savedOpenScripts: Array<OpenScript> = JSON.parse(window.localStorage.getItem('scriptEditorOpenScripts')!); const savedOpenScripts: Array<OpenScript> = JSON.parse(window.localStorage.getItem("scriptEditorOpenScripts")!);
const savedScriptIndex = savedOpenScripts.findIndex(script => script.fileName === closingScript.fileName && script.hostname === closingScript.hostname); const savedScriptIndex = savedOpenScripts.findIndex(
let savedScriptCode = ''; (script) => script.fileName === closingScript.fileName && script.hostname === closingScript.hostname,
);
let savedScriptCode = "";
if (savedScriptIndex !== -1) { if (savedScriptIndex !== -1) {
savedScriptCode = savedOpenScripts[savedScriptIndex].code; savedScriptCode = savedOpenScripts[savedScriptIndex].code;
} }
const serverScriptIndex = GetServer(closingScript.hostname)?.scripts.findIndex(script => script.filename === closingScript.fileName); const serverScriptIndex = GetServer(closingScript.hostname)?.scripts.findIndex(
if (serverScriptIndex === -1 || savedScriptCode !== GetServer(closingScript.hostname)?.scripts[serverScriptIndex as number].code) { (script) => script.filename === closingScript.fileName,
);
if (
serverScriptIndex === -1 ||
savedScriptCode !== GetServer(closingScript.hostname)?.scripts[serverScriptIndex as number].code
) {
PromptEvent.emit({ PromptEvent.emit({
txt: 'Do you want to save changes to ' + closingScript.fileName + '?', txt: "Do you want to save changes to " + closingScript.fileName + "?",
resolve: (result: boolean) => { resolve: (result: boolean) => {
if (result) { if (result) {
// Save changes // Save changes
closingScript.code = savedScriptCode; closingScript.code = savedScriptCode;
saveScript(closingScript); saveScript(closingScript);
} }
} },
}) });
} }
if (openScripts.length > 1) { if (openScripts.length > 1) {
setOpenScripts(oldScripts => oldScripts.filter((value, i) => i !== index)); setOpenScripts((oldScripts) => oldScripts.filter((value, i) => i !== index));
let indexOffset = -1; let indexOffset = -1;
if (openScripts[index + indexOffset] === undefined) { if (openScripts[index + indexOffset] === undefined) {
@ -546,13 +615,17 @@ export function Root(props: IProps): React.ReactElement {
// Change current script if we closed it // Change current script if we closed it
setCurrentScript(openScripts[index + indexOffset]); setCurrentScript(openScripts[index + indexOffset]);
if (editorRef.current !== null) { if (editorRef.current !== null) {
if (openScripts[index + indexOffset].model === undefined || openScripts[index + indexOffset].model === null || openScripts[index + indexOffset].model.isDisposed()) { if (
openScripts[index + indexOffset].model === undefined ||
openScripts[index + indexOffset].model === null ||
openScripts[index + indexOffset].model.isDisposed()
) {
regenerateModel(openScripts[index + indexOffset]); regenerateModel(openScripts[index + indexOffset]);
} }
editorRef.current.setModel(openScripts[index + indexOffset].model); editorRef.current.setModel(openScripts[index + indexOffset].model);
editorRef.current.setPosition(openScripts[index + indexOffset].lastPosition); editorRef.current.setPosition(openScripts[index + indexOffset].lastPosition);
editorRef.current.revealLineInCenter(openScripts[index + indexOffset].lastPosition.lineNumber) editorRef.current.revealLineInCenter(openScripts[index + indexOffset].lastPosition.lineNumber);
editorRef.current.focus(); editorRef.current.focus();
} }
} else { } else {
@ -562,14 +635,17 @@ export function Root(props: IProps): React.ReactElement {
} }
} }
// 370px 71%, 725px 85.1%, 1085px 90%, 1300px 91.7% // TODO: Make this responsive to window resizes
// fuck around in desmos until you find a function // Toolbars are roughly 108px + vim bar 34px
const p = 11000 / -window.innerHeight + 100; // 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 (
<> <>
<div style={{ display: currentScript !== null ? 'block' : 'none', height: '100%', width: '100%' }}> <div style={{ display: currentScript !== null ? "block" : "none", height: "100%", width: "100%" }}>
<DragDropContext onDragEnd={onDragEnd}> <DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId='tabs' direction='horizontal'> <Droppable droppableId="tabs" direction="horizontal">
{(provided, snapshot) => ( {(provided, snapshot) => (
<Box <Box
maxWidth="1640px" maxWidth="1640px"
@ -579,10 +655,18 @@ export function Root(props: IProps): React.ReactElement {
whiteSpace="nowrap" whiteSpace="nowrap"
ref={provided.innerRef} ref={provided.innerRef}
{...provided.droppableProps} {...provided.droppableProps}
style={{ backgroundColor: snapshot.isDraggingOver ? '#1F2022' : Settings.theme.backgroundprimary, overflowX: 'scroll' }} style={{
backgroundColor: snapshot.isDraggingOver ? "#1F2022" : Settings.theme.backgroundprimary,
overflowX: "scroll",
}}
> >
{openScripts.map(({ fileName, hostname }, index) => ( {openScripts.map(({ fileName, hostname }, index) => (
<Draggable key={fileName + hostname} draggableId={fileName + hostname} index={index} disableInteractiveElementBlocking={true}> <Draggable
key={fileName + hostname}
draggableId={fileName + hostname}
index={index}
disableInteractiveElementBlocking={true}
>
{(provided) => ( {(provided) => (
<div <div
ref={provided.innerRef} ref={provided.innerRef}
@ -590,22 +674,33 @@ export function Root(props: IProps): React.ReactElement {
{...provided.dragHandleProps} {...provided.dragHandleProps}
style={{ style={{
...provided.draggableProps.style, ...provided.draggableProps.style,
marginRight: '5px', marginRight: "5px",
flexShrink: 0 flexShrink: 0,
}} }}
> >
<Button <Button
id={"tabButton" + fileName + hostname} id={"tabButton" + fileName + hostname}
onClick={() => onTabClick(index)} onClick={() => onTabClick(index)}
style={{ background: currentScript?.fileName === openScripts[index].fileName ? Settings.theme.secondarydark : '' }} style={{
background:
currentScript?.fileName === openScripts[index].fileName
? Settings.theme.secondarydark
: "",
}}
> >
{hostname}:~/{fileName} {hostname}:~/{fileName}
</Button> </Button>
<Button <Button
id={"tabCloseButton" + fileName + hostname} id={"tabCloseButton" + fileName + hostname}
onClick={() => onTabClose(index)} onClick={() => onTabClose(index)}
style={{ maxWidth: "20px", minWidth: "20px", background: currentScript?.fileName === openScripts[index].fileName ? Settings.theme.secondarydark : '' }} style={{
maxWidth: "20px",
minWidth: "20px",
background:
currentScript?.fileName === openScripts[index].fileName
? Settings.theme.secondarydark
: "",
}}
> >
x x
</Button> </Button>
@ -618,18 +713,28 @@ export function Root(props: IProps): React.ReactElement {
)} )}
</Droppable> </Droppable>
</DragDropContext> </DragDropContext>
<div style={{ paddingBottom: '5px' }} /> <div style={{ paddingBottom: "5px" }} />
<Editor <Editor
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={''} defaultValue={""}
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 }}>
@ -661,18 +766,31 @@ 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;
}} }}
/> />
</div> </div>
<div style={{ display: currentScript !== null ? 'none' : 'flex', height: '100%', width: '100%', justifyContent: 'center', alignItems: 'center' }}> <div
<p style={{ color: Settings.theme.primary, fontSize: '20px', textAlign: 'center' }}><h1>No open files</h1><h5>Use "nano [File Name]" in the terminal to open files</h5></p> style={{
display: currentScript !== null ? "none" : "flex",
height: "100%",
width: "100%",
justifyContent: "center",
alignItems: "center",
}}
>
<p style={{ color: Settings.theme.primary, fontSize: "20px", textAlign: "center" }}>
<h1>No open files</h1>
<h5>Use "nano [File Name]" in the terminal to open files</h5>
</p>
</div> </div>
</> </>
) );
} }

@ -134,6 +134,8 @@ interface ISettings extends IDefaultSettings {
MonacoInsertSpaces: boolean; MonacoInsertSpaces: boolean;
MonacoFontSize: number; MonacoFontSize: number;
MonacoVim: boolean;
} }
export const defaultSettings: IDefaultSettings = { export const defaultSettings: IDefaultSettings = {
@ -193,6 +195,7 @@ export const Settings: ISettings & ISelfInitializer & ISelfLoading = {
MonacoTheme: "monokai", MonacoTheme: "monokai",
MonacoInsertSpaces: false, MonacoInsertSpaces: false,
MonacoFontSize: 20, MonacoFontSize: 20,
MonacoVim: false,
theme: { ...defaultTheme }, theme: { ...defaultTheme },
init() { init() {

@ -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>