11import { basicSetup } from "codemirror" ;
22import { EditorView , keymap } from "@codemirror/view" ;
33import { EditorState } from "@codemirror/state" ;
4- import { indentWithTab } from "@codemirror/commands"
4+ import { indentWithTab } from "@codemirror/commands"
55import { python } from "@codemirror/lang-python" ;
66import { syntaxHighlighting , indentUnit } from "@codemirror/language" ;
77import { classHighlighter } from "@lezer/highlight" ;
@@ -17,9 +17,10 @@ import { WebWorkflow } from './workflows/web.js';
1717import { isValidBackend , getBackendWorkflow , getWorkflowBackendName } from './workflows/workflow.js' ;
1818import { ButtonValueDialog , MessageModal } from './common/dialogs.js' ;
1919import { isLocal , switchUrl , getUrlParam } from './common/utilities.js' ;
20+ import { Settings } from './common/settings.js' ;
2021import { CONNTYPE } from './constants.js' ;
2122import './layout.js' ; // load for side effects only
22- import { setupPlotterChart } from "./common/plotter.js" ;
23+ import { setupPlotterChart } from "./common/plotter.js" ;
2324import { mainContent , showSerial } from './layout.js' ;
2425
2526// Instantiate workflows
@@ -31,6 +32,7 @@ workflows[CONNTYPE.Web] = new WebWorkflow();
3132let workflow = null ;
3233let unchanged = 0 ;
3334let connectionPromise = null ;
35+ let debugMessageAnsi = null ;
3436
3537const btnRestart = document . querySelector ( '.btn-restart' ) ;
3638const btnHalt = document . querySelector ( '.btn-halt' ) ;
@@ -43,13 +45,15 @@ const btnSave = document.querySelectorAll('.btn-save');
4345const btnSaveAs = document . querySelectorAll ( '.btn-save-as' ) ;
4446const btnSaveRun = document . querySelectorAll ( '.btn-save-run' ) ;
4547const btnInfo = document . querySelector ( '.btn-info' ) ;
48+ const btnSettings = document . querySelector ( '.btn-settings' ) ;
4649const terminalTitle = document . getElementById ( 'terminal-title' ) ;
4750const serialPlotter = document . getElementById ( 'plotter' ) ;
4851
4952const messageDialog = new MessageModal ( "message" ) ;
5053const connectionType = new ButtonValueDialog ( "connection-type" ) ;
54+ const settings = new Settings ( ) ;
5155
52- const editorTheme = EditorView . theme ( { } , { dark : true } ) ;
56+ const editorTheme = EditorView . theme ( { } , { dark : getCssVar ( 'editor-theme-dark' ) . trim ( ) === '1' } ) ;
5357
5458document . addEventListener ( 'DOMContentLoaded' , function ( ) {
5559 document . getElementById ( 'mobile-menu-button' ) . addEventListener ( 'click' , handleMobileToggle ) ;
@@ -168,6 +172,12 @@ btnInfo.addEventListener('click', async function(e) {
168172 }
169173} ) ;
170174
175+ btnSettings . addEventListener ( 'click' , async function ( e ) {
176+ if ( await settings . showDialog ( ) ) {
177+ applySettings ( ) ;
178+ }
179+ } ) ;
180+
171181// Basic functions used for buttons and hotkeys
172182async function openFile ( ) {
173183 if ( await checkConnected ( ) ) {
@@ -420,8 +430,12 @@ async function showMessage(message) {
420430}
421431
422432async function debugLog ( msg ) {
433+ if ( debugMessageAnsi === null ) {
434+ const colorCode = getCssVar ( 'debug-message-color' ) . trim ( ) ;
435+ debugMessageAnsi = `\x1b[38;2;${ parseInt ( colorCode . slice ( 1 , 3 ) , 16 ) } ;${ parseInt ( colorCode . slice ( 3 , 5 ) , 16 ) } ;${ parseInt ( colorCode . slice ( 5 , 7 ) , 16 ) } m` ;
436+ }
423437 state . terminal . writeln ( '' ) ; // get a fresh line without any prior content (a '>>>' prompt might be there without newline)
424- state . terminal . writeln ( `\x1b[93m ${ msg } \x1b[0m` ) ;
438+ state . terminal . writeln ( `${ debugMessageAnsi } ${ msg } \x1b[0m` ) ;
425439}
426440
427441function updateUIConnected ( isConnected ) {
@@ -547,12 +561,16 @@ editor = new EditorView({
547561 parent : document . querySelector ( '#editor' )
548562} ) ;
549563
564+ function getCssVar ( varName ) {
565+ return window . getComputedStyle ( document . body ) . getPropertyValue ( "--" + varName ) ;
566+ }
567+
550568async function setupXterm ( ) {
551569 state . terminal = new Terminal ( {
552570 theme : {
553- background : '#333' ,
554- foreground : '#ddd' ,
555- cursor : '#ddd' ,
571+ background : getCssVar ( 'background-color' ) ,
572+ foreground : getCssVar ( 'terminal-text-color' ) ,
573+ cursor : getCssVar ( 'terminal-text-color' ) ,
556574 }
557575 } ) ;
558576
@@ -585,8 +603,40 @@ function loadParameterizedContent() {
585603 return documentState ;
586604}
587605
606+ function applySettings ( ) {
607+ // ----- Themes -----
608+ const theme = settings . getSetting ( 'theme' ) ;
609+ // Remove all theme-[option] classes from body
610+ document . body . classList . forEach ( ( className ) => {
611+ if ( className . startsWith ( 'theme-' ) ) {
612+ document . body . classList . remove ( className ) ;
613+ }
614+ } ) ;
615+
616+ // Add the selected theme class
617+ document . body . classList . add ( `theme-${ theme } ` ) ;
618+
619+ // Apply to EditorView.theme dark parameter
620+ editor . darkTheme = getCssVar ( 'editor-theme-dark' ) . trim ( ) === '1' ;
621+
622+ // Apply to xterm
623+ state . terminal . options . theme = {
624+ background : getCssVar ( 'background-color' ) ,
625+ foreground : getCssVar ( 'terminal-text-color' ) ,
626+ cursor : getCssVar ( 'terminal-text-color' ) ,
627+ } ;
628+
629+ debugMessageAnsi = null ;
630+
631+ // Note: Debug Message color is applied on next debug message or reload
632+ // I'm not sure how to go through the xterm's existing content and change escape sequences
633+ // Changing the CSS style reverts to the old style on terminal update/redraw
634+
635+ }
636+
588637document . addEventListener ( 'DOMContentLoaded' , async ( event ) => {
589638 await setupXterm ( ) ;
639+ applySettings ( ) ;
590640 btnConnect . forEach ( ( element ) => {
591641 element . addEventListener ( 'click' , async function ( e ) {
592642 e . preventDefault ( ) ;
0 commit comments