mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-19 15:54:09 +02:00
merge base
This commit is contained in:
+69
-10
@@ -2386,6 +2386,30 @@ export interface Singularity {
|
||||
* purchased. Throws an error if the specified program/exploit does not exist
|
||||
*/
|
||||
getDarkwebProgramCost(programName: string): number;
|
||||
|
||||
/**
|
||||
* b1t_flum3 into a different BN.
|
||||
* @remarks
|
||||
* RAM cost: 16 GB * 16/4/1
|
||||
*
|
||||
* @param nextBN - BN number to jump to
|
||||
* @param callbackScript - Name of the script to launch in the next BN.
|
||||
*/
|
||||
b1tflum3(nextBN: number, callbackScript?: string): void;
|
||||
|
||||
/**
|
||||
* Destroy the w0r1d_d43m0n and move on to the next BN.
|
||||
* @remarks
|
||||
* RAM cost: 32 GB * 16/4/1
|
||||
*
|
||||
* You must have the special augment installed and the required hacking level
|
||||
* OR
|
||||
* Completed the final black op.
|
||||
*
|
||||
* @param nextBN - BN number to jump to
|
||||
* @param callbackScript - Name of the script to launch in the next BN.
|
||||
*/
|
||||
destroyW0r1dD43m0n(nextBN: number, callbackScript?: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3234,7 +3258,7 @@ export interface CodingContract {
|
||||
* Attempts to solve the Coding Contract with the provided solution.
|
||||
*
|
||||
* @param answer - Solution for the contract.
|
||||
* @param fn - Filename of the contract.
|
||||
* @param filename - Filename of the contract.
|
||||
* @param host - Host of the server containing the contract. Optional. Defaults to current server if not provided.
|
||||
* @param opts - Optional parameters for configuring function behavior.
|
||||
* @returns True if the solution was correct, false otherwise. If the returnReward option is configured, then the function will instead return a string. If the contract is successfully solved, the string will contain a description of the contract’s reward. Otherwise, it will be an empty string.
|
||||
@@ -3249,7 +3273,7 @@ export interface CodingContract {
|
||||
* Returns a name describing the type of problem posed by the Coding Contract.
|
||||
* (e.g. Find Largest Prime Factor, Total Ways to Sum, etc.)
|
||||
*
|
||||
* @param fn - Filename of the contract.
|
||||
* @param filename - Filename of the contract.
|
||||
* @param host - Host of the server containing the contract. Optional. Defaults to current server if not provided.
|
||||
* @returns Name describing the type of problem posed by the Coding Contract.
|
||||
*/
|
||||
@@ -3262,7 +3286,7 @@ export interface CodingContract {
|
||||
*
|
||||
* Get the full text description for the problem posed by the Coding Contract.
|
||||
*
|
||||
* @param fn - Filename of the contract.
|
||||
* @param filename - Filename of the contract.
|
||||
* @param host - Host of the server containing the contract. Optional. Defaults to current server if not provided.
|
||||
* @returns Contract’s text description.
|
||||
*/
|
||||
@@ -3290,7 +3314,7 @@ export interface CodingContract {
|
||||
*
|
||||
* Get the number of tries remaining on the contract before it self-destructs.
|
||||
*
|
||||
* @param fn - Filename of the contract.
|
||||
* @param filename - Filename of the contract.
|
||||
* @param host - Host of the server containing the contract. Optional. Defaults to current server if not provided.
|
||||
* @returns How many attempts are remaining for the contract;
|
||||
*/
|
||||
@@ -3784,6 +3808,18 @@ export interface Grafting {
|
||||
*/
|
||||
getAugmentationGraftTime(augName: string): number;
|
||||
|
||||
/**
|
||||
* Retrieves a list of Augmentations that can be grafted.
|
||||
* @remarks
|
||||
* RAM cost: 5 GB
|
||||
*
|
||||
* Note that this function returns a list of currently graftable Augmentations,
|
||||
* based off of the Augmentations that you already own.
|
||||
*
|
||||
* @returns An array of graftable Augmentations.
|
||||
*/
|
||||
getGraftableAugmentations(): string[];
|
||||
|
||||
/**
|
||||
* Begins grafting the named aug. You must be in New Tokyo to use this.
|
||||
* @remarks
|
||||
@@ -4693,9 +4729,11 @@ export interface NS {
|
||||
* Returns the security increase that would occur if a grow with this many threads happened.
|
||||
*
|
||||
* @param threads - Amount of threads that will be used.
|
||||
* @param hostname - Optional. Hostname of the target server. The number of threads is limited to the number needed to hack the servers maximum amount of money.
|
||||
* @param cores - Optional. The number of cores of the server that would run grow.
|
||||
* @returns The security increase.
|
||||
*/
|
||||
growthAnalyzeSecurity(threads: number): number;
|
||||
growthAnalyzeSecurity(threads: number, hostname?: string, cores?: number): number;
|
||||
|
||||
/**
|
||||
* Suspends the script for n milliseconds.
|
||||
@@ -5129,8 +5167,7 @@ export interface NS {
|
||||
* PID stands for Process ID. The PID is a unique identifier for each script.
|
||||
* The PID will always be a positive integer.
|
||||
*
|
||||
* Running this function with a numThreads argument of 0 will return 0 without running the script.
|
||||
* However, running this function with a negative numThreads argument will cause a runtime error.
|
||||
* Running this function with 0 or a negative numThreads argument will cause a runtime error.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
@@ -6781,8 +6818,9 @@ export interface WarehouseAPI {
|
||||
* Upgrade warehouse
|
||||
* @param divisionName - Name of the division
|
||||
* @param cityName - Name of the city
|
||||
* @param amt - amount of upgrades defaults to 1
|
||||
*/
|
||||
upgradeWarehouse(divisionName: string, cityName: string): void;
|
||||
upgradeWarehouse(divisionName: string, cityName: string, amt?: number): void;
|
||||
/**
|
||||
* Create a new product
|
||||
* @param divisionName - Name of the division
|
||||
@@ -6798,6 +6836,22 @@ export interface WarehouseAPI {
|
||||
designInvest: number,
|
||||
marketingInvest: number,
|
||||
): void;
|
||||
/**
|
||||
* Limit Material Production.
|
||||
* @param divisionName - Name of the division
|
||||
* @param cityName - Name of the city
|
||||
* @param materialName - Name of the material
|
||||
* @param qty - Amount to limit to
|
||||
*/
|
||||
limitMaterialProduction(divisionName: string, cityName: string, materialName: string, qty: number): void;
|
||||
/**
|
||||
* Limit Product Production.
|
||||
* @param divisionName - Name of the division
|
||||
* @param cityName - Name of the city
|
||||
* @param productName - Name of the product
|
||||
* @param qty - Amount to limit to
|
||||
*/
|
||||
limitProductProduction(divisionName: string, cityName: string, productName: string, qty: number): void;
|
||||
/**
|
||||
* Gets the cost to purchase a warehouse
|
||||
* @returns cost
|
||||
@@ -6805,9 +6859,12 @@ export interface WarehouseAPI {
|
||||
getPurchaseWarehouseCost(): number;
|
||||
/**
|
||||
* Gets the cost to upgrade a warehouse to the next level
|
||||
* @param divisionName - Name of the division
|
||||
* @param cityName - Name of the city
|
||||
* @param amt - amount of upgrades defaults to 1
|
||||
* @returns cost to upgrade
|
||||
*/
|
||||
getUpgradeWarehouseCost(adivisionName: any, acityName: any): number;
|
||||
getUpgradeWarehouseCost(adivisionName: any, acityName: any, amt?: number): number;
|
||||
/**
|
||||
* Check if you have a warehouse in city
|
||||
* @returns true if warehouse is present, false if not
|
||||
@@ -7051,8 +7108,10 @@ interface Material {
|
||||
cmp: number | undefined;
|
||||
/** Amount of material produced */
|
||||
prod: number;
|
||||
/** Amount of material sold */
|
||||
/** Amount of material sold */
|
||||
sell: number;
|
||||
/** cost to buy material */
|
||||
cost: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,10 @@ import Select from "@mui/material/Select";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import SaveIcon from "@mui/icons-material/Save";
|
||||
|
||||
import { ThemeEditorModal } from "./ThemeEditorModal";
|
||||
|
||||
interface IProps {
|
||||
options: Options;
|
||||
@@ -23,6 +27,7 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
const [fontSize, setFontSize] = useState(props.options.fontSize);
|
||||
const [wordWrap, setWordWrap] = useState(props.options.wordWrap);
|
||||
const [vim, setVim] = useState(props.options.vim);
|
||||
const [themeEditorOpen, setThemeEditorOpen] = useState(false);
|
||||
|
||||
function save(): void {
|
||||
props.save({
|
||||
@@ -43,6 +48,7 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<ThemeEditorModal open={themeEditorOpen} onClose={() => setThemeEditorOpen(false)} />
|
||||
<Box display="flex" flexDirection="row" alignItems="center">
|
||||
<Typography>Theme: </Typography>
|
||||
<Select onChange={(event) => setTheme(event.target.value)} value={theme}>
|
||||
@@ -53,7 +59,11 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
<MenuItem value="light">light</MenuItem>
|
||||
<MenuItem value="dracula">dracula</MenuItem>
|
||||
<MenuItem value="one-dark">one-dark</MenuItem>
|
||||
<MenuItem value="customTheme">Custom theme</MenuItem>
|
||||
</Select>
|
||||
<Button onClick={() => setThemeEditorOpen(true)} sx={{ mx: 1 }} startIcon={<EditIcon />}>
|
||||
Edit custom theme
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Box display="flex" flexDirection="row" alignItems="center">
|
||||
@@ -80,7 +90,9 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
<TextField type="number" label="Font size" value={fontSize} onChange={onFontChange} />
|
||||
</Box>
|
||||
<br />
|
||||
<Button onClick={save}>Save</Button>
|
||||
<Button onClick={save} startIcon={<SaveIcon />}>
|
||||
Save
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import { Settings } from "../../Settings/Settings";
|
||||
import { iTutorialNextStep, ITutorial, iTutorialSteps } from "../../InteractiveTutorial";
|
||||
import { debounce } from "lodash";
|
||||
import { saveObject } from "../../SaveObject";
|
||||
import { loadThemes } from "./themes";
|
||||
import { loadThemes, makeTheme, sanitizeTheme } from "./themes";
|
||||
import { GetServer } from "../../Server/AllServers";
|
||||
|
||||
import Button from "@mui/material/Button";
|
||||
@@ -362,6 +362,8 @@ export function Root(props: IProps): React.ReactElement {
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(source, "netscript.d.ts");
|
||||
monaco.languages.typescript.typescriptDefaults.addExtraLib(source, "netscript.d.ts");
|
||||
loadThemes(monaco);
|
||||
sanitizeTheme(Settings.EditorTheme);
|
||||
monaco.editor.defineTheme("customTheme", makeTheme(Settings.EditorTheme));
|
||||
}
|
||||
|
||||
// When the editor is mounted
|
||||
@@ -993,7 +995,11 @@ export function Root(props: IProps): React.ReactElement {
|
||||
</Box>
|
||||
<OptionsModal
|
||||
open={optionsOpen}
|
||||
onClose={() => setOptionsOpen(false)}
|
||||
onClose={() => {
|
||||
sanitizeTheme(Settings.EditorTheme);
|
||||
monacoRef.current?.editor.defineTheme("customTheme", makeTheme(Settings.EditorTheme));
|
||||
setOptionsOpen(false);
|
||||
}}
|
||||
options={{
|
||||
theme: Settings.MonacoTheme,
|
||||
insertSpaces: Settings.MonacoInsertSpaces,
|
||||
@@ -1002,6 +1008,8 @@ export function Root(props: IProps): React.ReactElement {
|
||||
vim: Settings.MonacoVim,
|
||||
}}
|
||||
save={(options: Options) => {
|
||||
sanitizeTheme(Settings.EditorTheme);
|
||||
monacoRef.current?.editor.defineTheme("customTheme", makeTheme(Settings.EditorTheme));
|
||||
setOptions(options);
|
||||
Settings.MonacoTheme = options.theme;
|
||||
Settings.MonacoInsertSpaces = options.insertSpaces;
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
import { History, Reply, Save } from "@mui/icons-material";
|
||||
import { Box, Button, Paper, TextField, Tooltip, Typography } from "@mui/material";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import _ from "lodash";
|
||||
import { Color, ColorPicker } from "material-ui-color";
|
||||
import React, { useState } from "react";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { OptionSwitch } from "../../ui/React/OptionSwitch";
|
||||
import { defaultMonacoTheme, IScriptEditorTheme } from "./themes";
|
||||
|
||||
interface IProps {
|
||||
onClose: () => void;
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
interface IColorEditorProps {
|
||||
label: string;
|
||||
themePath: string;
|
||||
color: string | undefined;
|
||||
onColorChange: (name: string, value: string) => void;
|
||||
defaultColor: string;
|
||||
}
|
||||
|
||||
// Slightly tweaked version of the same function found in game options
|
||||
function ColorEditor({ label, themePath, onColorChange, color, defaultColor }: IColorEditorProps): React.ReactElement {
|
||||
if (color === undefined) {
|
||||
console.error(`color ${themePath} was undefined, reverting to default`);
|
||||
color = defaultColor;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title={label}>
|
||||
<span>
|
||||
<TextField
|
||||
label={themePath}
|
||||
value={"#" + color}
|
||||
sx={{ display: "block", my: 1 }}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<>
|
||||
<ColorPicker
|
||||
hideTextfield
|
||||
deferred
|
||||
value={"#" + color}
|
||||
onChange={(newColor: Color) => onColorChange(themePath, newColor.hex)}
|
||||
disableAlpha
|
||||
/>
|
||||
</>
|
||||
),
|
||||
endAdornment: (
|
||||
<>
|
||||
<IconButton onClick={() => onColorChange(themePath, defaultColor)}>
|
||||
<Reply color="primary" />
|
||||
</IconButton>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function ThemeEditorModal(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
function rerender(): void {
|
||||
setRerender((o) => !o);
|
||||
}
|
||||
|
||||
// Need to deep copy the object since it has nested attributes
|
||||
const [themeCopy, setThemeCopy] = useState<IScriptEditorTheme>(JSON.parse(JSON.stringify(Settings.EditorTheme)));
|
||||
|
||||
function onColorChange(name: string, value: string): void {
|
||||
setThemeCopy(_.set(themeCopy, name, value));
|
||||
rerender();
|
||||
}
|
||||
|
||||
function onThemeChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
try {
|
||||
const importedTheme = JSON.parse(event.target.value);
|
||||
if (typeof importedTheme !== "object") return;
|
||||
setThemeCopy(importedTheme);
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={props.open}
|
||||
onClose={() => {
|
||||
setThemeCopy(Settings.EditorTheme);
|
||||
props.onClose();
|
||||
}}
|
||||
>
|
||||
<Typography variant="h4">Customize Editor theme</Typography>
|
||||
<Typography>Hover over input boxes for more information</Typography>
|
||||
<Paper sx={{ p: 1, my: 1 }}>
|
||||
<OptionSwitch
|
||||
checked={themeCopy.base === "vs"}
|
||||
onChange={(val) => {
|
||||
setThemeCopy(_.set(themeCopy, "base", val ? "vs" : "vs-dark"));
|
||||
rerender();
|
||||
}}
|
||||
text="Use light theme as base"
|
||||
tooltip={
|
||||
<>
|
||||
If enabled, the <code>vs</code> light theme will be used as the theme base, otherwise,{" "}
|
||||
<code>vs-dark</code> will be used.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "fit-content", gap: 1 }}>
|
||||
<Box>
|
||||
<Typography variant="h6">UI</Typography>
|
||||
<ColorEditor
|
||||
label="Background color"
|
||||
themePath="common.bg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.common.bg}
|
||||
defaultColor={defaultMonacoTheme.common.bg}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Current line and minimap background color"
|
||||
themePath="ui.line"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.line}
|
||||
defaultColor={defaultMonacoTheme.ui.line}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Base text color"
|
||||
themePath="common.fg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.common.fg}
|
||||
defaultColor={defaultMonacoTheme.common.fg}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Popup background color"
|
||||
themePath="ui.panel.bg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.panel.bg}
|
||||
defaultColor={defaultMonacoTheme.ui.panel.bg}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Background color for selected item in popup"
|
||||
themePath="ui.panel.selected"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.panel.selected}
|
||||
defaultColor={defaultMonacoTheme.ui.panel.selected}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Popup border color"
|
||||
themePath="ui.panel.border"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.panel.border}
|
||||
defaultColor={defaultMonacoTheme.ui.panel.border}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Background color of highlighted text"
|
||||
themePath="ui.selection.bg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.selection.bg}
|
||||
defaultColor={defaultMonacoTheme.ui.selection.bg}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography variant="h6">Syntax</Typography>
|
||||
<ColorEditor
|
||||
label="Numbers, function names, and other key vars"
|
||||
themePath="common.accent"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.common.accent}
|
||||
defaultColor={defaultMonacoTheme.common.accent}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Keywords"
|
||||
themePath="syntax.keyword"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.keyword}
|
||||
defaultColor={defaultMonacoTheme.syntax.keyword}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Strings"
|
||||
themePath="syntax.string"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.string}
|
||||
defaultColor={defaultMonacoTheme.syntax.string}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Regexp literals as well as escapes within strings"
|
||||
themePath="syntax.regexp"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.regexp}
|
||||
defaultColor={defaultMonacoTheme.syntax.regexp}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Constants"
|
||||
themePath="syntax.constant"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.constant}
|
||||
defaultColor={defaultMonacoTheme.syntax.constant}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Entities"
|
||||
themePath="syntax.entity"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.entity}
|
||||
defaultColor={defaultMonacoTheme.syntax.entity}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="'this', 'ns', types, and tags"
|
||||
themePath="syntax.tag"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.tag}
|
||||
defaultColor={defaultMonacoTheme.syntax.tag}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Netscript functions and constructors"
|
||||
themePath="syntax.markup"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.markup}
|
||||
defaultColor={defaultMonacoTheme.syntax.markup}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Errors"
|
||||
themePath="syntax.error"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.error}
|
||||
defaultColor={defaultMonacoTheme.syntax.error}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Comments"
|
||||
themePath="syntax.comment"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.comment}
|
||||
defaultColor={defaultMonacoTheme.syntax.comment}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Paper>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<TextField
|
||||
multiline
|
||||
fullWidth
|
||||
maxRows={10}
|
||||
label={"import / export theme"}
|
||||
value={JSON.stringify(themeCopy, undefined, 2)}
|
||||
onChange={onThemeChange}
|
||||
/>
|
||||
<Box sx={{ mt: 1 }}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
Settings.EditorTheme = { ...themeCopy };
|
||||
props.onClose();
|
||||
}}
|
||||
startIcon={<Save />}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setThemeCopy(defaultMonacoTheme);
|
||||
rerender();
|
||||
}}
|
||||
startIcon={<History />}
|
||||
>
|
||||
Reset to default
|
||||
</Button>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -1,3 +1,216 @@
|
||||
export interface IScriptEditorTheme {
|
||||
[key: string]: any;
|
||||
base: string;
|
||||
inherit: boolean;
|
||||
common: {
|
||||
[key: string]: string;
|
||||
accent: string;
|
||||
bg: string;
|
||||
fg: string;
|
||||
};
|
||||
syntax: {
|
||||
[key: string]: string;
|
||||
tag: string;
|
||||
entity: string;
|
||||
string: string;
|
||||
regexp: string;
|
||||
markup: string;
|
||||
keyword: string;
|
||||
comment: string;
|
||||
constant: string;
|
||||
error: string;
|
||||
};
|
||||
ui: {
|
||||
[key: string]: any;
|
||||
line: string;
|
||||
panel: {
|
||||
[key: string]: string;
|
||||
bg: string;
|
||||
selected: string;
|
||||
border: string;
|
||||
};
|
||||
selection: {
|
||||
[key: string]: string;
|
||||
bg: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const defaultMonacoTheme: IScriptEditorTheme = {
|
||||
base: "vs-dark",
|
||||
inherit: true,
|
||||
common: {
|
||||
accent: "B5CEA8",
|
||||
bg: "1E1E1E",
|
||||
fg: "D4D4D4",
|
||||
},
|
||||
syntax: {
|
||||
tag: "569CD6",
|
||||
entity: "569CD6",
|
||||
string: "CE9178",
|
||||
regexp: "646695",
|
||||
markup: "569CD6",
|
||||
keyword: "569CD6",
|
||||
comment: "6A9955",
|
||||
constant: "569CD6",
|
||||
error: "F44747",
|
||||
},
|
||||
ui: {
|
||||
line: "1E1E1E",
|
||||
panel: {
|
||||
bg: "252526",
|
||||
selected: "252526",
|
||||
border: "1E1E1E",
|
||||
},
|
||||
selection: {
|
||||
bg: "ADD6FF26",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Regex used for token color validation
|
||||
// https://github.com/microsoft/vscode/blob/973684056e67153952f495fce93bf50d0ec0b892/src/vs/editor/common/languages/supports/tokenization.ts#L153
|
||||
const colorRegExp = /^#?([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$/;
|
||||
|
||||
// Recursively sanitize the theme data to prevent errors
|
||||
// Invalid data will be replaced with FF0000 (bright red)
|
||||
export const sanitizeTheme = (theme: IScriptEditorTheme): void => {
|
||||
for (const [k, v] of Object.entries(theme)) {
|
||||
switch (k) {
|
||||
case "base":
|
||||
if (!["vs-dark", "vs"].includes(theme.base)) theme.base = "vs-dark";
|
||||
continue;
|
||||
case "inherit":
|
||||
if (typeof theme.inherit !== "boolean") theme.inherit = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const repairBlock = (block: { [key: string]: any }): void => {
|
||||
for (const [k, v] of Object.entries(block)) {
|
||||
if (typeof v === "object") {
|
||||
repairBlock(v as { [key: string]: string });
|
||||
} else if (!v.match(colorRegExp)) block[k] = "FF0000";
|
||||
}
|
||||
};
|
||||
repairBlock(v);
|
||||
}
|
||||
};
|
||||
|
||||
export function makeTheme(theme: IScriptEditorTheme): any {
|
||||
const themeRules = [
|
||||
{
|
||||
token: "",
|
||||
background: theme.ui.line,
|
||||
foreground: theme.common.fg,
|
||||
},
|
||||
{
|
||||
token: "identifier",
|
||||
foreground: theme.common.accent,
|
||||
},
|
||||
{
|
||||
token: "keyword",
|
||||
foreground: theme.syntax.keyword,
|
||||
},
|
||||
{
|
||||
token: "string",
|
||||
foreground: theme.syntax.string,
|
||||
},
|
||||
{
|
||||
token: "string.escape",
|
||||
foreground: theme.syntax.regexp,
|
||||
},
|
||||
{
|
||||
token: "comment",
|
||||
foreground: theme.syntax.comment,
|
||||
},
|
||||
{
|
||||
token: "constant",
|
||||
foreground: theme.syntax.constant,
|
||||
},
|
||||
{
|
||||
token: "entity",
|
||||
foreground: theme.syntax.entity,
|
||||
},
|
||||
{
|
||||
token: "type",
|
||||
foreground: theme.syntax.tag,
|
||||
},
|
||||
{
|
||||
token: "tag",
|
||||
foreground: theme.syntax.tag,
|
||||
},
|
||||
{
|
||||
token: "regexp",
|
||||
foreground: theme.syntax.regexp,
|
||||
},
|
||||
{
|
||||
token: "attribute",
|
||||
foreground: theme.syntax.tag,
|
||||
},
|
||||
{
|
||||
token: "constructor",
|
||||
foreground: theme.syntax.markup,
|
||||
},
|
||||
{
|
||||
token: "invalid",
|
||||
foreground: theme.syntax.error,
|
||||
},
|
||||
{
|
||||
token: "number",
|
||||
foreground: theme.common.accent,
|
||||
},
|
||||
{
|
||||
token: "delimiter",
|
||||
foreground: theme.common.fg,
|
||||
},
|
||||
// Custom tokens
|
||||
{
|
||||
token: "ns",
|
||||
foreground: theme.syntax.tag,
|
||||
},
|
||||
{
|
||||
token: "netscriptfunction",
|
||||
foreground: theme.syntax.markup,
|
||||
},
|
||||
{
|
||||
token: "otherkeywords",
|
||||
foreground: theme.syntax.keyword,
|
||||
},
|
||||
{
|
||||
token: "otherkeyvars",
|
||||
foreground: theme.common.accent,
|
||||
},
|
||||
{
|
||||
token: "this",
|
||||
foreground: theme.syntax.tag,
|
||||
},
|
||||
];
|
||||
|
||||
const themeColors = Object.fromEntries(
|
||||
[
|
||||
["editor.background", theme.common.bg],
|
||||
["editor.foreground", theme.common.fg],
|
||||
["editor.lineHighlightBackground", theme.ui.line],
|
||||
["editor.selectionBackground", theme.ui.selection.bg],
|
||||
|
||||
["editorSuggestWidget.background", theme.ui.panel.bg],
|
||||
["editorSuggestWidget.border", theme.ui.panel.border],
|
||||
["editorSuggestWidget.selectedBackground", theme.ui.panel.selected],
|
||||
|
||||
["editorHoverWidget.background", theme.ui.panel.bg],
|
||||
["editorHoverWidget.border", theme.ui.panel.border],
|
||||
|
||||
["editorWidget.background", theme.ui.panel.bg],
|
||||
["editorWidget.border", theme.ui.panel.border],
|
||||
|
||||
["input.background", theme.ui.panel.bg],
|
||||
["input.border", theme.ui.panel.border],
|
||||
].map(([k, v]) => [k, "#" + v]),
|
||||
);
|
||||
|
||||
return { base: theme.base, inherit: theme.inherit, rules: themeRules, colors: themeColors };
|
||||
}
|
||||
|
||||
export async function loadThemes(monaco: { editor: any }): Promise<void> {
|
||||
monaco.editor.defineTheme("monokai", {
|
||||
base: "vs-dark",
|
||||
@@ -261,6 +474,7 @@ export async function loadThemes(monaco: { editor: any }): Promise<void> {
|
||||
foreground: "FFB86C",
|
||||
fontStyle: "italic",
|
||||
},
|
||||
|
||||
{
|
||||
token: "netscriptfunction",
|
||||
foreground: "FF79C6",
|
||||
|
||||
Reference in New Issue
Block a user