Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 40 additions & 7 deletions docs/_plugins/twinbasic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@

require "rouge"

# Register tB-specific token types so the highlighter can distinguish symbols
# the way the twinBASIC IDE's theme system does -- e.g. Boolean / Empty /
# Nothing / Null are each their own slot in tB's Symbol* palette, and the
# line-continuation '_' has its own SymbolContinuationCharacter colour.
module Rouge::Token::Tokens
[
[Literal, :Boolean, 'lb'],
[Literal, :Empty, 'le'],
[Literal, :Nothing, 'ln'],
[Literal, :Null, 'lu'],
[Punctuation, :LineContinuation, 'lc'],
].each do |parent, name, shortname|
parent.token(name, shortname) unless parent.const_defined?(name, false)
end
end

module Rouge
module Lexers
class TwinBasic < RegexLexer
Expand All @@ -17,20 +33,30 @@ def self.keywords
@keywords ||= Set.new %w(
alias byref byval call case class close coclass const
continue declare default delegate dim do each else elseif
empty end endif enum erase error event exit extends
false finally for friend function get global gosub
end endif enum erase error event exit extends
finally for friend function get global gosub
goto handles if implements imports inherits input interface
let lib line lock loop me mid module
namespace new next nothing null of on open option optional
namespace new next of on open option optional
overloads paramarray preserve print private property public
put raiseevent redim resume return select set
shared static step stop structure sub
then throw to true try type unlock until
then throw to try type unlock until
using wend when while width
with withevents write
)
end

def self.keyword_constants
@keyword_constants ||= {
'true' => Literal::Boolean,
'false' => Literal::Boolean,
'empty' => Literal::Empty,
'nothing' => Literal::Nothing,
'null' => Literal::Null,
}
end

def self.keywords_type
@keywords_type ||= Set.new %w(
any boolean byte currency date decimal double integer long
Expand All @@ -54,7 +80,7 @@ def self.builtins
id = /[a-z_]\w*/i

state :whitespace do
rule %r/_[ \t]*\n/, Keyword
rule %r/_[ \t]*\n/, Punctuation::LineContinuation
rule %r/\n/, Text, :bol
rule %r/[^\S\n]+/, Text
rule %r/rem\b.*?$/i, Comment::Single
Expand All @@ -72,12 +98,15 @@ def self.builtins
rule %r(
[#]If\b .*? \bThen
| [#]ElseIf\b .*? \bThen
| [#]Else\b
| [#]End \s+ If
| [#]Const
| [#]Region .*? \n
| [#]End \s+ Region
)xi, Comment::Preproc

rule %r/#\d[^#\n]*#/, Literal::Date

rule %r/\[/, Punctuation, :attribute

rule %r/(\d+\.\d*|\d*\.\d+)(e[+-]?\d+)?[!#@]?/i, Num::Float
Expand All @@ -103,7 +132,9 @@ def self.builtins

rule id do |m|
key = m[0].downcase
if self.class.keywords.include? key
if (kc = self.class.keyword_constants[key])
token kc
elsif self.class.keywords.include? key
token Keyword
elsif self.class.keywords_type.include? key
token Keyword::Type
Expand Down Expand Up @@ -157,7 +188,9 @@ def self.builtins
rule %r/\d+[%&!#@]?/, Num::Integer
rule id do |m|
key = m[0].downcase
if self.class.keywords.include? key
if (kc = self.class.keyword_constants[key])
token kc
elsif self.class.keywords.include? key
token Keyword
elsif self.class.keywords_type.include? key
token Keyword::Type
Expand Down
187 changes: 187 additions & 0 deletions docs/_sass/custom/_twinbasic-dark.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/* twinBASIC Dark theme - Rouge syntax highlighting */
/* Selectors are the Rouge HTML formatter classes emitted by docs/_plugins/twinbasic.rb. */
/* Scoped under .language-tb .highlight so they only repaint tB fenced code blocks. */

.language-tb .highlight {
.c1 { /* SymbolComment — ' comments and REM */
color: #448a63;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.cm { /* SymbolComment — C-style block comments */
color: #448a63;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.cp { /* SymbolConditionalCompilationDirective — #If / #ElseIf / #Else / #End If / #Const / #Region */
color: #ad8c98;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.k { /* SymbolKeyword — Dim, If, End, Sub, ... */
color: #6c8eda;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.kd { /* SymbolKeyword — Option Strict / Explicit / Compare / Base */
color: #6c8eda;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.kt { /* SymbolBuiltInDataType — Boolean, Integer, String, ... */
color: #b1551f;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.lb { /* SymbolLiteralBoolean — True, False */
color: #c495d3;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.lc { /* SymbolContinuationCharacter — '_' line-continuation marker */
color: #808080;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.ld { /* SymbolLiteralDate — #m/d/yyyy [h:mm:ss am/pm]# date-time literals */
color: #c495d3;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.le { /* SymbolLiteralEmpty — Empty */
color: #c495d3;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.ln { /* SymbolLiteralNothing — Nothing */
color: #c495d3;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.lu { /* SymbolLiteralNull — Null */
color: #c495d3;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.mi { /* SymbolLiteralNumeric — integer literals */
color: #aeca89;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.mf { /* SymbolLiteralNumeric — float literals */
color: #aeca89;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.s { /* SymbolLiteralString — string literals */
color: #aeca89;
font-style: oblique;
font-weight: normal;
text-decoration: none;
}

.se { /* SymbolLiteralString — "" escape inside string literals */
color: #aeca89;
font-style: oblique;
font-weight: normal;
text-decoration: none;
}

.o { /* SymbolOperator — +, -, =, <, >, &, ... */
color: #80a1a5;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.ow { /* SymbolNamedOperator — And, Or, Not, Is, Mod, ... */
color: #80a1a5;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.na { /* SymbolAttribute — [Documentation(...)] attribute names */
color: #5c5c53;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.nb { /* SymbolClass — Debug, Err */
color: #e4c685;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.nc { /* SymbolClass — Class / CoClass / Enum / Interface / Type / Structure names */
color: #e4c685;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.nf { /* SymbolFunction — Function / Sub / Property names */
color: #cf9a5d;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.nn { /* SymbolModule — Module / Namespace / Imports targets */
color: #a8a887;
font-style: normal;
font-weight: normal;
text-decoration: none;
}

.nv { /* SymbolVariable — Dim / Const / ReDim variable names */
color: #8b8b52;
font-style: normal;
font-weight: normal;
text-decoration: none;
}
}

/* tB CodePanelBackColor scoped to tB code-block containers (.language-tb). */
/* The .language-tb class lives on the outer .highlighter-rouge div emitted */
/* by kramdown for ```tb``` fenced blocks, so `.language-tb.highlighter-rouge` */
/* (no space) hits the outer container and `.language-tb <descendant>` hits */
/* the nested .highlight / pre / etc. The partial is imported inside */
/* `html.dark-mode { ... }` by just-the-docs-combined.scss, so SCSS nesting */
/* confines these rules to dark mode automatically. */
.language-tb.highlighter-rouge,
.language-tb .highlight,
.language-tb pre.highlight,
.language-tb .highlight pre {
background-color: rgb(33, 33, 33);
}
Loading
Loading