StylePatch
Methods
Of (Class method)
Creates a new StylePatch object containing the provided styles. This is the only way to create a Patch object (the new class method is a private method).
Styles is an ordered set of lines. These lines may be separated by semicolons, or be items in a Rexx Array, or both.
Style patches
-- Sample style patch file
-- =======================
--
-- Lines starting with "--" are comments and are ignored
--
-- Patch simple variable elements to display as bold black over 75% yellow
element EL.SIMPLE_VARIABLE #000/#cc0 bold
-- Patch method names to display as black over 75% magenta
name METHOD.NAME #000/#c0c
Style patches have a very simple format: they are arrays of strings consisting of:
- Blank lines, containing only whitespace, which are completely ignored.
- Comments, starting with two dashes
"--"
, which also are completely ignored. - Other lines containing semicolons. In that case, these lines are split at the semicolons, the semicolons are discarded, and the lines are inserted at the beginning of the list.
- Once comment lines starting with
"--"
have been discarded, all dashes"-"
are replaced by blanks" "
. This can be very useful in certain contexts like certain Linux shells, where enclosing arguments between quotes may be cumbersome. - Highlighting patches for element categories:
Element class highlighting
Element
can be abbreviated toE
, and the class name can omit theEL.
prefix, if desired. - Highlighting patches for element category sets:
All set highlighting
All
can be abbreviated toA
, and the set can omit theALL.
prefix, if desired. - Highlighting patched for taken constant names:
Name constantName highlighting
Name
can be abbreviated toN
, and the constantName can omit the.NAME
suffix, if desired. - Highlighting is a blank-separated sequence of
case-insensitive elements, selected between
- Foreground colors, in the format
#rgb
,#rrggbb
, or one of the 147 standard CSS named colors defined here. - Foreground/background color combination, in the format
fg/bg
(with no blanks), wherefg
andbg
are either#rgb
,#rrggbb
, or one of the 147 CSS named colors defined here. - One of the single words
bold
,italic
orunderline
. - The single word
no
, which has to be followed by one ofbold
,italic
orunderline
.
- Foreground colors, in the format
- Element categories, category sets, and subcategories are described in detail here.
::Method methodName
-- In this code fragment, the standard dark mode highlighting style is used.
-- Additionally, local variables are specially highlighted with a bold black
-- font over a yellow background, and the highlighting for method names is
-- modified to have a black foreground over a magenta background.
len = Length("String")
n = Pos("x", value)
Program source
/******************************************************************************/
/* */
/* StylePatch.cls -- Highlighting style patches */
/* ============================================ */
/* */
/* This program is part of the Rexx Parser package */
/* [See https://rexx.epbcn.com/rexx.parser/] */
/* */
/* Copyright (c) 2024-2025 Josep Maria Blasco <josep.maria.blasco@epbcn.com> */
/* */
/* License: Apache License 2.0 (https://www.apache.org/licenses/LICENSE-2.0) */
/* */
/* Version history: */
/* */
/* Date Version Details */
/* -------- ------- --------------------------------------------------------- */
/* 20241206 0.1 First public release */
/* */
/******************************************************************************/
env = .environment
If env~StylePatch == .Nil Then env~StylePatch = .StylePatch
--------------------------------------------------------------------------------
::Class StylePatch Public
-- Make the NEW method private
::Method new Class Private
Use Strict Arg styles
Return self~new:super(styles)
-- Instances should be created by calling the OF class method
::Method Of Class
Use Strict Arg styles
If styles~isA(.String) Then styles = .Array~of( styles )
Else .Validate~classType( "styles", styles, .Array )
clean = .Array~new
Loop style Over styles
style = Strip(style)
If style[1,2] == "--" Then Iterate
Loop line Over style~makeArray(";")
line = Strip(line)
If line[1,2] == "--" Then Iterate
If line == "" Then Iterate
clean~append(line~changeStr("-"," "))
End
End
patch = self~new( clean )
Loop line Over clean
Parse Lower Var line mode rest
Select
When Abbrev("all", mode) Then Call ParseAll
When Abbrev("element",mode) Then Call ParseElement
When Abbrev("name", mode) Then Call ParseName
Otherwise Signal BadMode
End
End
Return patch
ParseElement:
Parse Var rest category highlight
ucategory = Upper(category)
If \ucategory~startsWith("EL."), \ucategory~startsWith("ALL.") Then
ucategory = "EL."ucategory
classes = .environment[ucategory]
If classes == .Nil Then Signal BadClass
patch~add(classes, highlight)
Return
ParseAll:
Parse Var rest category highlight
ucategory = Upper(category)
If \ucategory~startsWith("ALL.") Then
ucategory = "ALL."ucategory
classes = .environment[ucategory]
If classes == .Nil Then Signal BadClassSet
patch~add(classes, highlight)
Return
ParseName:
Parse Var rest name highlight
uName = Upper(name)
If \uName~endsWith(".NAME"), \uName~endsWith(".VALUE") Then
uName = uName".NAME"
classes = .environment[uName]
If classes == .Nil Then Signal BadName
patch~addName(classes, highlight)
Return
BadName:
Raise Syntax 88.900 Additional("Invalid name '"name"'")
BadClass:
Raise Syntax 88.900 Additional("Invalid element category '"category"'")
BadClassSet:
Raise Syntax 88.900 Additional("Invalid element category set '"category"'")
BadMode:
Raise Syntax 88.900 Additional("Invalid option '"line"'")
--------------------------------------------------------------------------------
::Method Init
Expose patch. Tag2Attr. source
Use Strict Arg source
patch. = .Stem~new
Tag2Attr. = ""
patch.!Tag2Attr = Tag2Attr.
self~init:super
::Method getpatch
Expose patch.
Return patch.
::Method AddName
Expose Tag2Attr.
Use Strict Arg name, attributes
constant = .EL.TAKEN_CONSTANT
attr = self~parse( attributes )
Tag2Attr.constant.name = attr
::Method Add
Expose Tag2Attr.
Use Strict Arg classes, attributes
attr = self~parse( attributes )
Do c Over classes~makeArray("")
Tag2Attr.c = attr
End
::Method parse Private
Use Arg attributes
option = ''
If attributes = "" Then Signal BadOption
attr = "."
fg = ""
bg = ""
no = 0
Do option Over attributes~space~makeArray(" ")
option = Lower( option )
If option == "no" Then Do
no = 1
Iterate
End
Select Case option
When "bold" Then
If no Then attr ||= "b"
Else attr ||= "B"
When "italic" Then
If no Then attr ||= "i"
Else attr ||= "I"
When "underline" Then
If no Then attr ||= "u"
Else attr ||= "U"
Otherwise
If no Then Signal BadNo
color = option
If color~contains("/") Then Do
Parse Var color color"/"background
If background[1] \== "#" Then Do
bg = .HTML.Color[background]
If bg == .Nil Then Signal BadBackground
End
Else Do
bg = SubStr(background,2)
If \"3 6"~containsWord( Length(bg) ) Then Signal BadBackground
If \bg~dataType("X") Then Signal BadBackground
bg = Normalize(bg)
End
End
If color[1] \== "#" Then Do
fg = .HTML.Color[color]
If fg == .Nil Then Signal BadColor
End
Else Do
fg = SubStr(color,2)
If \"3 6"~containsWord( Length(fg) ) Then Signal BadColor
If \fg~dataType("X") Then Signal BadColor
fg = Normalize(fg)
End
End
no = 0
End
If no Then Signal BadFinalNo
Return attr fg"/"bg
Normalize:
If Length(Arg(1)) == 6 Then Return Arg(1)
Parse Value Arg(1) With a +1 b +1 c +1
Return Space( a a b b c c , 0 )
BadNo:
Raise Syntax 93.900 Additional("Invalid option 'no "option"'")
BadFinalNo:
Raise Syntax 93.900 Additional("Invalid option 'no'")
BadOption:
Raise Syntax 93.900 Additional("Invalid option '"option"'")
BadColor:
Raise Syntax 93.900 Additional("Invalid color '"color"'")
BadBackground:
Raise Syntax 93.900 Additional("Invalid background color '"background"'")