Skip to content

Commit 0452729

Browse files
committed
configurable monaco themes
1 parent ccba63f commit 0452729

File tree

6 files changed

+72
-62
lines changed

6 files changed

+72
-62
lines changed

ui/frontend/ConfigMenu.tsx

+21-4
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,14 @@ interface ConfigMenuProps {
2121
close: () => void;
2222
}
2323

24+
const MONACO_THEMES = [
25+
'vs', 'vs-dark', 'vscode-dark-plus',
26+
];
27+
2428
const ConfigMenu: React.SFC<ConfigMenuProps> = () => {
2529
const keybinding = useSelector((state: State) => state.configuration.keybinding);
26-
const theme = useSelector((state: State) => state.configuration.theme);
30+
const aceTheme = useSelector((state: State) => state.configuration.aceTheme);
31+
const monacoTheme = useSelector((state: State) => state.configuration.monacoTheme);
2732
const orientation = useSelector((state: State) => state.configuration.orientation);
2833
const editorStyle = useSelector((state: State) => state.configuration.editor);
2934
const pairCharacters = useSelector((state: State) => state.configuration.pairCharacters);
@@ -32,7 +37,8 @@ const ConfigMenu: React.SFC<ConfigMenuProps> = () => {
3237
const processAssembly = useSelector((state: State) => state.configuration.processAssembly);
3338

3439
const dispatch = useDispatch();
35-
const changeTheme = useCallback((t) => dispatch(actions.changeTheme(t)), [dispatch]);
40+
const changeAceTheme = useCallback((t) => dispatch(actions.changeAceTheme(t)), [dispatch]);
41+
const changeMonacoTheme = useCallback((t) => dispatch(actions.changeMonacoTheme(t)), [dispatch]);
3642
const changeKeybinding = useCallback((k) => dispatch(actions.changeKeybinding(k)), [dispatch]);
3743
const changeOrientation = useCallback((o) => dispatch(actions.changeOrientation(o)), [dispatch]);
3844
const changeEditorStyle = useCallback((e) => dispatch(actions.changeEditor(e)), [dispatch]);
@@ -64,8 +70,8 @@ const ConfigMenu: React.SFC<ConfigMenuProps> = () => {
6470

6571
<SelectConfig
6672
name="Theme"
67-
value={theme}
68-
onChange={changeTheme}
73+
value={aceTheme}
74+
onChange={changeAceTheme}
6975
>
7076
{ACE_THEMES.map(t => <option key={t} value={t}>{t}</option>)}
7177
</SelectConfig>
@@ -79,6 +85,17 @@ const ConfigMenu: React.SFC<ConfigMenuProps> = () => {
7985
onChange={changePairCharacters} />
8086
</Fragment>
8187
)}
88+
{editorStyle === Editor.Monaco && (
89+
<Fragment>
90+
<SelectConfig
91+
name="Theme"
92+
value={monacoTheme}
93+
onChange={changeMonacoTheme}
94+
>
95+
{MONACO_THEMES.map(t => <option key={t} value={t}>{t}</option>)}
96+
</SelectConfig>
97+
</Fragment>
98+
)}
8299
</MenuGroup>
83100

84101
<MenuGroup title="UI">

ui/frontend/actions.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ export enum ActionType {
6363
SetPage = 'SET_PAGE',
6464
ChangeEditor = 'CHANGE_EDITOR',
6565
ChangeKeybinding = 'CHANGE_KEYBINDING',
66-
ChangeTheme = 'CHANGE_THEME',
66+
ChangeAceTheme = 'CHANGE_ACE_THEME',
67+
ChangeMonacoTheme = 'CHANGE_MONACO_THEME',
6768
ChangePairCharacters = 'CHANGE_PAIR_CHARACTERS',
6869
ChangeOrientation = 'CHANGE_ORIENTATION',
6970
ChangeAssemblyFlavor = 'CHANGE_ASSEMBLY_FLAVOR',
@@ -138,8 +139,11 @@ export const changeEditor = (editor: Editor) =>
138139
export const changeKeybinding = (keybinding: string) =>
139140
createAction(ActionType.ChangeKeybinding, { keybinding });
140141

141-
export const changeTheme = (theme: string) =>
142-
createAction(ActionType.ChangeTheme, { theme });
142+
export const changeAceTheme = (theme: string) =>
143+
createAction(ActionType.ChangeAceTheme, { theme });
144+
145+
export const changeMonacoTheme = (theme: string) =>
146+
createAction(ActionType.ChangeMonacoTheme, { theme });
143147

144148
export const changePairCharacters = (pairCharacters: PairCharacters) =>
145149
createAction(ActionType.ChangePairCharacters, { pairCharacters });
@@ -822,7 +826,8 @@ export type Action =
822826
| ReturnType<typeof changeOrientation>
823827
| ReturnType<typeof changePrimaryAction>
824828
| ReturnType<typeof changeProcessAssembly>
825-
| ReturnType<typeof changeTheme>
829+
| ReturnType<typeof changeAceTheme>
830+
| ReturnType<typeof changeMonacoTheme>
826831
| ReturnType<typeof requestExecute>
827832
| ReturnType<typeof receiveExecuteSuccess>
828833
| ReturnType<typeof receiveExecuteFailure>

ui/frontend/editor/AceEditor.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ interface PropsFromState {
472472
}
473473

474474
const mapStateToProps = (state: State) => {
475-
const { configuration: { theme, keybinding, pairCharacters } } = state;
475+
const { configuration: { aceTheme: theme, keybinding, pairCharacters } } = state;
476476

477477
return {
478478
theme,

ui/frontend/editor/MonacoEditor.tsx

+17-45
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,12 @@
11
import React from 'react';
22
import { CommonEditorProps, Position } from '../types';
33
import MonacoReact, { Monaco } from "@monaco-editor/react";
4+
import { connect } from 'react-redux';
5+
import State from '../state';
46

57
import styles from './Editor.module.css';
68
import { config, grammar } from './rust_monaco_def';
79

8-
class CodeByteOffsets {
9-
readonly code: string;
10-
readonly lines: string[];
11-
12-
constructor(code: string) {
13-
this.code = code;
14-
this.lines = code.split('\n');
15-
}
16-
17-
public lineToOffsets(line: number) {
18-
const precedingBytes = this.bytesBeforeLine(line);
19-
20-
const highlightedLine = this.lines[line];
21-
const highlightedBytes = highlightedLine.length;
22-
23-
return [precedingBytes, precedingBytes + highlightedBytes];
24-
}
25-
26-
public rangeToOffsets(start: Position, end: Position) {
27-
const startBytes = this.positionToBytes(start);
28-
const endBytes = this.positionToBytes(end);
29-
return [startBytes, endBytes];
30-
}
31-
32-
private positionToBytes(position: Position) {
33-
// Subtract one as this logic is zero-based and the columns are one-based
34-
return this.bytesBeforeLine(position.line) + position.column - 1;
35-
}
36-
37-
private bytesBeforeLine(line: number) {
38-
// Subtract one as this logic is zero-based and the lines are one-based
39-
line -= 1;
40-
41-
const precedingLines = this.lines.slice(0, line);
42-
43-
// Add one to account for the newline we split on and removed
44-
return precedingLines.map(l => l.length + 1).reduce((a, b) => a + b);
45-
}
46-
}
47-
4810
const modeId = 'my-rust';
4911

5012
const initMonaco = (monaco: Monaco) => {
@@ -62,18 +24,28 @@ const initMonaco = (monaco: Monaco) => {
6224
});
6325

6426
monaco.languages.onLanguage(modeId, async () => {
65-
console.log(modeId);
66-
6727
monaco.languages.setLanguageConfiguration(modeId, config);
6828
monaco.languages.setMonarchTokensProvider(modeId, grammar);
6929
});
7030
};
7131

72-
const MonacoEditor: React.SFC<CommonEditorProps> = props => {
32+
interface PropsFromState {
33+
theme: string;
34+
}
35+
36+
const mapStateToProps = (state: State) => {
37+
const { configuration: { monacoTheme: theme, } } = state;
38+
return { theme };
39+
};
40+
41+
42+
type MonacoEditorProps = CommonEditorProps & PropsFromState;
43+
44+
const MonacoEditor: React.SFC<MonacoEditorProps> = props => {
7345
return (
7446
<MonacoReact
7547
language={modeId}
76-
theme="vscode-dark-plus"
48+
theme={props.theme}
7749
loading="Loading the Monaco editor..."
7850
className={styles.advanced}
7951
value={props.code}
@@ -83,4 +55,4 @@ const MonacoEditor: React.SFC<CommonEditorProps> = props => {
8355
);
8456
}
8557

86-
export default MonacoEditor;
58+
export default connect<PropsFromState, undefined, CommonEditorProps>(mapStateToProps)(MonacoEditor);

ui/frontend/local_storage.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55
import State from './state';
66
import storage from './storage';
77

8-
const CURRENT_VERSION = 1;
8+
const CURRENT_VERSION = 2;
99

1010
export function serialize(state: State) {
1111
return JSON.stringify({
1212
version: CURRENT_VERSION,
1313
configuration: {
1414
editor: state.configuration.editor,
1515
keybinding: state.configuration.keybinding,
16-
theme: state.configuration.theme,
16+
aceTheme: state.configuration.aceTheme,
17+
monacoTheme: state.configuration.monacoTheme,
1718
pairCharacters: state.configuration.pairCharacters,
1819
orientation: state.configuration.orientation,
1920
assemblyFlavor: state.configuration.assemblyFlavor,
@@ -29,12 +30,23 @@ export function deserialize(savedState) {
2930
if (!savedState) { return undefined; }
3031
const parsedState = JSON.parse(savedState);
3132
if (!parsedState) { return undefined; }
32-
if (parsedState.version !== CURRENT_VERSION) { return undefined; }
33+
let { version } = parsedState;
34+
delete parsedState.version;
35+
36+
// migrations
37+
if (version === 1) {
38+
if (parsedState.editor === 'advanced') {
39+
parsedState.editor = 'ace';
40+
}
41+
parsedState.aceTheme = parsedState.theme;
42+
parsedState.monacoTheme = 'vscode-dark-plus';
43+
delete parsedState.theme;
44+
version = 2;
45+
}
3346

3447
// This assumes that the keys we serialize with match the keys in the
3548
// live state. If that's no longer true, an additional renaming step
3649
// needs to be added.
37-
delete parsedState.version;
3850
return parsedState;
3951
}
4052

ui/frontend/reducers/configuration.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import {
1717
export interface State {
1818
editor: Editor;
1919
keybinding: string;
20-
theme: string;
20+
aceTheme: string;
21+
monacoTheme: string;
2122
pairCharacters: PairCharacters;
2223
orientation: Orientation;
2324
assemblyFlavor: AssemblyFlavor;
@@ -33,7 +34,8 @@ export interface State {
3334
const DEFAULT: State = {
3435
editor: Editor.Ace,
3536
keybinding: 'ace',
36-
theme: 'github',
37+
aceTheme: 'github',
38+
monacoTheme: 'vscode-dark-plus',
3739
pairCharacters: PairCharacters.Enabled,
3840
orientation: Orientation.Automatic,
3941
assemblyFlavor: AssemblyFlavor.Att,
@@ -52,8 +54,10 @@ export default function configuration(state = DEFAULT, action: Action): State {
5254
return { ...state, editor: action.editor };
5355
case ActionType.ChangeKeybinding:
5456
return { ...state, keybinding: action.keybinding };
55-
case ActionType.ChangeTheme:
56-
return { ...state, theme: action.theme };
57+
case ActionType.ChangeAceTheme:
58+
return { ...state, aceTheme: action.theme };
59+
case ActionType.ChangeMonacoTheme:
60+
return { ...state, monacoTheme: action.theme };
5761
case ActionType.ChangePairCharacters:
5862
return { ...state, pairCharacters: action.pairCharacters };
5963
case ActionType.ChangeOrientation:

0 commit comments

Comments
 (0)