diff --git a/src/ScriptEditor/ui/Editor.tsx b/src/ScriptEditor/ui/Editor.tsx index 412f1d57a..433f8293b 100644 --- a/src/ScriptEditor/ui/Editor.tsx +++ b/src/ScriptEditor/ui/Editor.tsx @@ -1,6 +1,7 @@ +import React, { useEffect, useRef } from "react"; + import * as monaco from "monaco-editor"; -import * as React from "react"; -import { useEffect, useRef } from "react"; + import { useScriptEditorContext } from "./ScriptEditorContext"; interface EditorProps { diff --git a/src/ScriptEditor/ui/OpenScript.ts b/src/ScriptEditor/ui/OpenScript.ts index d137b9b6c..0c86e03b9 100644 --- a/src/ScriptEditor/ui/OpenScript.ts +++ b/src/ScriptEditor/ui/OpenScript.ts @@ -1,19 +1,19 @@ +import type { editor, Position } from "monaco-editor"; + import type { ContentFilePath } from "../../Paths/ContentFile"; -import * as monaco from "monaco-editor"; - -type ITextModel = monaco.editor.ITextModel; +type ITextModel = editor.ITextModel; // Holds all the data for a open script export class OpenScript { path: ContentFilePath; code: string; hostname: string; - lastPosition: monaco.Position; + lastPosition: Position; model: ITextModel; isTxt: boolean; - constructor(path: ContentFilePath, code: string, hostname: string, lastPosition: monaco.Position, model: ITextModel) { + constructor(path: ContentFilePath, code: string, hostname: string, lastPosition: Position, model: ITextModel) { this.path = path; this.code = code; this.hostname = hostname; diff --git a/src/ScriptEditor/ui/Options.ts b/src/ScriptEditor/ui/Options.ts index 5ad72d375..9ea9dbc2c 100644 --- a/src/ScriptEditor/ui/Options.ts +++ b/src/ScriptEditor/ui/Options.ts @@ -1,4 +1,10 @@ +import type { editor } from "monaco-editor"; + export type WordWrapOptions = "on" | "off" | "bounded" | "wordWrapColumn"; + +export type CursorStyle = editor.IEditorOptions["cursorStyle"]; +export type CursorBlinking = editor.IEditorOptions["cursorBlinking"]; + export interface Options { theme: string; insertSpaces: boolean; @@ -9,4 +15,6 @@ export interface Options { fontLigatures: boolean; wordWrap: WordWrapOptions; vim: boolean; + cursorStyle: CursorStyle; + cursorBlinking: CursorBlinking; } diff --git a/src/ScriptEditor/ui/OptionsModal.tsx b/src/ScriptEditor/ui/OptionsModal.tsx index 3f797638c..6eb1843f3 100644 --- a/src/ScriptEditor/ui/OptionsModal.tsx +++ b/src/ScriptEditor/ui/OptionsModal.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { ReactElement } from "react"; import Button from "@mui/material/Button"; import Typography from "@mui/material/Typography"; @@ -11,7 +11,10 @@ import EditIcon from "@mui/icons-material/Edit"; import { useBoolean } from "../../ui/React/hooks"; import { Modal } from "../../ui/React/Modal"; import { ThemeEditorModal } from "./ThemeEditorModal"; -import { Options } from "./Options"; +import { CursorBlinking, CursorStyle, Options } from "./Options"; + +const CURSOR_STYLES: CursorStyle[] = ["line", "block", "underline", "line-thin", "block-outline", "underline-thin"]; +const CURSOR_BLINKING_MODES: CursorBlinking[] = ["blink", "smooth", "phase", "expand", "solid"]; export type OptionsModalProps = { open: boolean; @@ -21,7 +24,7 @@ export type OptionsModalProps = { onThemeChange: () => void; }; -export function OptionsModal(props: OptionsModalProps): React.ReactElement { +export function OptionsModal(props: OptionsModalProps): ReactElement { const [themeEditorOpen, { on: openThemeEditor, off: closeThemeEditor }] = useBoolean(false); const onFontSizeChange = (event: React.ChangeEvent) => { @@ -116,6 +119,34 @@ export function OptionsModal(props: OptionsModalProps): React.ReactElement { checked={props.options.fontLigatures} /> + +
+ Cursor style: + +
+ +
+ Cursor blinking: + +
); } diff --git a/src/ScriptEditor/ui/ScriptEditorContext.tsx b/src/ScriptEditor/ui/ScriptEditorContext.tsx index 872d612c0..d408ce92a 100644 --- a/src/ScriptEditor/ui/ScriptEditorContext.tsx +++ b/src/ScriptEditor/ui/ScriptEditorContext.tsx @@ -79,6 +79,8 @@ export function ScriptEditorContextProvider({ children, vim }: { children: React fontLigatures: Settings.MonacoFontLigatures, wordWrap: Settings.MonacoWordWrap, vim: vim || Settings.MonacoVim, + cursorStyle: Settings.MonacoCursorStyle, + cursorBlinking: Settings.MonacoCursorBlinking, }); function saveOptions(options: Options) { @@ -90,6 +92,8 @@ export function ScriptEditorContextProvider({ children, vim }: { children: React Settings.MonacoFontFamily = options.fontFamily; Settings.MonacoFontSize = options.fontSize; Settings.MonacoFontLigatures = options.fontLigatures; + Settings.MonacoCursorStyle = options.cursorStyle; + Settings.MonacoCursorBlinking = options.cursorBlinking; Settings.MonacoWordWrap = options.wordWrap; Settings.MonacoVim = options.vim; } diff --git a/src/ScriptEditor/ui/ScriptEditorRoot.tsx b/src/ScriptEditor/ui/ScriptEditorRoot.tsx index 9d9e1590d..398e766a6 100644 --- a/src/ScriptEditor/ui/ScriptEditorRoot.tsx +++ b/src/ScriptEditor/ui/ScriptEditorRoot.tsx @@ -1,7 +1,8 @@ import React, { useEffect, useRef } from "react"; -import { Editor } from "./Editor"; import * as monaco from "monaco-editor"; +import { Editor } from "./Editor"; + type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor; import { Router } from "../../ui/GameRoot"; diff --git a/src/ScriptEditor/ui/Toolbar.tsx b/src/ScriptEditor/ui/Toolbar.tsx index 1acb5860f..bd1f9c553 100644 --- a/src/ScriptEditor/ui/Toolbar.tsx +++ b/src/ScriptEditor/ui/Toolbar.tsx @@ -40,8 +40,13 @@ export function Toolbar({ editor, onSave }: IProps) { const { ram, ramEntries, isUpdatingRAM, options, saveOptions } = useScriptEditorContext(); const onOptionChange: OptionsModalProps["onOptionChange"] = (option, value) => { - saveOptions({ ...options, [option]: value }); - editor?.updateOptions(options); + const newOptions = { ...options, [option]: value }; + saveOptions(newOptions); + // delaying editor options update to avoid an issue + // where switching between vim and regular modes causes some settings to be reset + setTimeout(() => { + editor?.updateOptions(newOptions); + }, 100); }; const onThemeChange = () => { diff --git a/src/ScriptEditor/ui/useVimEditor.tsx b/src/ScriptEditor/ui/useVimEditor.tsx index 4012fab47..35525b0ac 100644 --- a/src/ScriptEditor/ui/useVimEditor.tsx +++ b/src/ScriptEditor/ui/useVimEditor.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useRef, useState } from "react"; // @ts-expect-error This library does not have types. import * as MonacoVim from "monaco-vim"; -import * as monaco from "monaco-editor"; -type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor; +import type { editor } from "monaco-editor"; +type IStandaloneCodeEditor = editor.IStandaloneCodeEditor; import Box from "@mui/material/Box"; diff --git a/src/Settings/Settings.ts b/src/Settings/Settings.ts index 15ab27e99..667077c7d 100644 --- a/src/Settings/Settings.ts +++ b/src/Settings/Settings.ts @@ -1,7 +1,7 @@ import { OwnedAugmentationsOrderSetting, PurchaseAugmentationsOrderSetting } from "./SettingEnums"; import { defaultTheme } from "../Themes/Themes"; import { defaultStyles } from "../Themes/Styles"; -import { WordWrapOptions } from "../ScriptEditor/ui/Options"; +import { CursorStyle, CursorBlinking, WordWrapOptions } from "../ScriptEditor/ui/Options"; import { defaultMonacoTheme } from "../ScriptEditor/ui/themes"; /** The current options the player has customized to their play style. */ @@ -96,6 +96,10 @@ export const Settings = { MonacoVim: false, /** Word wrap setting for Script Editor. */ MonacoWordWrap: "off" as WordWrapOptions, + /** Control the cursor style*/ + MonacoCursorStyle: "line" as CursorStyle, + /** Control the cursor animation style */ + MonacoCursorBlinking: "blink" as CursorBlinking, /** Whether to hide trailing zeroes on fractional part of decimal */ hideTrailingDecimalZeros: false, /** Whether to hide thousands separators. */