IncludeCPP 3.3.20__py3-none-any.whl → 3.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- includecpp/__init__.py +4 -3
- includecpp/cli/commands.py +400 -21
- includecpp/core/cppy_converter.py +143 -18
- includecpp/core/cssl/__init__.py +40 -0
- includecpp/core/cssl/cssl_builtins.py +1693 -0
- includecpp/core/cssl/cssl_events.py +621 -0
- includecpp/core/cssl/cssl_modules.py +2803 -0
- includecpp/core/cssl/cssl_parser.py +1493 -0
- includecpp/core/cssl/cssl_runtime.py +1549 -0
- includecpp/core/cssl/cssl_syntax.py +488 -0
- includecpp/core/cssl/cssl_types.py +390 -0
- includecpp/core/cssl_bridge.py +132 -0
- includecpp/core/project_ui.py +684 -34
- includecpp/generator/parser.cpp +81 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.2.dist-info}/METADATA +48 -4
- includecpp-3.4.2.dist-info/RECORD +40 -0
- includecpp-3.3.20.dist-info/RECORD +0 -31
- {includecpp-3.3.20.dist-info → includecpp-3.4.2.dist-info}/WHEEL +0 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.2.dist-info}/entry_points.txt +0 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.2.dist-info}/licenses/LICENSE +0 -0
- {includecpp-3.3.20.dist-info → includecpp-3.4.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CSSL Syntax Highlighting
|
|
3
|
+
|
|
4
|
+
Provides syntax highlighting for CSSL (CSO Service Script Language) code.
|
|
5
|
+
Can be used with:
|
|
6
|
+
- PyQt5/6 QSyntaxHighlighter
|
|
7
|
+
- VSCode/TextMate grammar export
|
|
8
|
+
- Terminal ANSI colors
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from typing import Dict, List, Tuple, Optional
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from enum import Enum, auto
|
|
14
|
+
import re
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TokenCategory(Enum):
|
|
18
|
+
"""Categories for syntax highlighting"""
|
|
19
|
+
KEYWORD = auto() # service-init, struct, define, if, while, etc.
|
|
20
|
+
BUILTIN = auto() # print, len, typeof, etc.
|
|
21
|
+
OPERATOR = auto() # <==, ==>, ->, <-, +, -, etc.
|
|
22
|
+
STRING = auto() # "string" or 'string'
|
|
23
|
+
STRING_INTERP = auto() # <variable> in strings - NEW
|
|
24
|
+
NUMBER = auto() # 123, 45.67
|
|
25
|
+
COMMENT = auto() # # comment or // comment
|
|
26
|
+
MODULE_REF = auto() # @Module, @VSRAM, @Desktop
|
|
27
|
+
SELF_REF = auto() # s@StructName, s@Backend.Loop
|
|
28
|
+
IDENTIFIER = auto() # variable names
|
|
29
|
+
PROPERTY = auto() # service-name:, service-version:
|
|
30
|
+
BOOLEAN = auto() # True, False, true, false
|
|
31
|
+
NULL = auto() # null, None
|
|
32
|
+
PACKAGE_KW = auto() # package, package-includes - NEW
|
|
33
|
+
TYPE_LITERAL = auto() # list, dict - NEW
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class HighlightRule:
|
|
38
|
+
"""Rule for syntax highlighting"""
|
|
39
|
+
pattern: str
|
|
40
|
+
category: TokenCategory
|
|
41
|
+
group: int = 0 # Regex group to highlight
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# CSSL Keywords
|
|
45
|
+
KEYWORDS = {
|
|
46
|
+
'service-init', 'service-run', 'service-include',
|
|
47
|
+
'struct', 'define', 'main',
|
|
48
|
+
'if', 'else', 'elif', 'while', 'for', 'foreach', 'in', 'range',
|
|
49
|
+
'switch', 'case', 'default', 'break', 'continue', 'return',
|
|
50
|
+
'try', 'catch', 'finally', 'throw',
|
|
51
|
+
'and', 'or', 'not',
|
|
52
|
+
'start', 'stop', 'wait_for', 'on_event', 'emit_event',
|
|
53
|
+
'await',
|
|
54
|
+
# NEW: Extended keywords
|
|
55
|
+
'package', 'package-includes', 'exec', 'as', 'global'
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# NEW: Package-related keywords for special highlighting
|
|
59
|
+
PACKAGE_KEYWORDS = {'package', 'package-includes'}
|
|
60
|
+
|
|
61
|
+
# NEW: Type literals
|
|
62
|
+
TYPE_LITERALS = {'list', 'dict'}
|
|
63
|
+
|
|
64
|
+
# CSSL Built-in Functions
|
|
65
|
+
BUILTINS = {
|
|
66
|
+
# Output
|
|
67
|
+
'print', 'println', 'debug', 'error', 'warn', 'log',
|
|
68
|
+
# Type conversion
|
|
69
|
+
'int', 'float', 'str', 'bool', 'list', 'dict',
|
|
70
|
+
# Type checking
|
|
71
|
+
'typeof', 'isinstance', 'isint', 'isfloat', 'isstr', 'isbool', 'islist', 'isdict', 'isnull',
|
|
72
|
+
# String
|
|
73
|
+
'len', 'upper', 'lower', 'trim', 'split', 'join', 'replace', 'contains', 'startswith', 'endswith',
|
|
74
|
+
'substr', 'format', 'reverse', 'repeat',
|
|
75
|
+
# List
|
|
76
|
+
'append', 'extend', 'insert', 'remove', 'pop', 'index', 'count', 'sort', 'sorted', 'filter', 'map',
|
|
77
|
+
# Dict
|
|
78
|
+
'keys', 'values', 'items', 'get', 'set', 'has', 'merge', 'delete',
|
|
79
|
+
# Math
|
|
80
|
+
'abs', 'round', 'floor', 'ceil', 'min', 'max', 'sum', 'pow', 'sqrt', 'sin', 'cos', 'tan', 'log10',
|
|
81
|
+
'random', 'randint', 'randrange', 'choice', 'shuffle', 'sample',
|
|
82
|
+
# Time
|
|
83
|
+
'now', 'timestamp', 'sleep', 'date', 'time', 'datetime', 'strftime', 'strptime',
|
|
84
|
+
# File I/O
|
|
85
|
+
'read_file', 'write_file', 'append_file', 'file_exists', 'delete_file',
|
|
86
|
+
'mkdir', 'rmdir', 'listdir', 'getcwd', 'chdir',
|
|
87
|
+
# System
|
|
88
|
+
'exit', 'getenv', 'setenv', 'exec', 'system', 'platform', 'argv',
|
|
89
|
+
# JSON
|
|
90
|
+
'json_encode', 'json_decode', 'json_load', 'json_dump',
|
|
91
|
+
# Regex
|
|
92
|
+
'regex_match', 'regex_search', 'regex_replace', 'regex_split', 'regex_findall',
|
|
93
|
+
# Hash
|
|
94
|
+
'md5', 'sha1', 'sha256', 'sha512', 'hash',
|
|
95
|
+
# Other
|
|
96
|
+
'copy', 'deepcopy', 'assert', 'range', 'enumerate', 'zip', 'any', 'all',
|
|
97
|
+
'include', 'cso_root', 'createcmd', 'wait_for_booted', 'emit', 'on_event'
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class CSSLSyntaxRules:
|
|
102
|
+
"""Collection of syntax highlighting rules for CSSL"""
|
|
103
|
+
|
|
104
|
+
@staticmethod
|
|
105
|
+
def get_rules() -> List[HighlightRule]:
|
|
106
|
+
"""Get all highlighting rules in priority order"""
|
|
107
|
+
rules = []
|
|
108
|
+
|
|
109
|
+
# Comments (highest priority - should match first)
|
|
110
|
+
# NEW: Both # and // style comments
|
|
111
|
+
rules.append(HighlightRule(
|
|
112
|
+
pattern=r'#[^\n]*',
|
|
113
|
+
category=TokenCategory.COMMENT
|
|
114
|
+
))
|
|
115
|
+
rules.append(HighlightRule(
|
|
116
|
+
pattern=r'//[^\n]*',
|
|
117
|
+
category=TokenCategory.COMMENT
|
|
118
|
+
))
|
|
119
|
+
|
|
120
|
+
# Strings
|
|
121
|
+
rules.append(HighlightRule(
|
|
122
|
+
pattern=r'"(?:[^"\\]|\\.)*"',
|
|
123
|
+
category=TokenCategory.STRING
|
|
124
|
+
))
|
|
125
|
+
rules.append(HighlightRule(
|
|
126
|
+
pattern=r"'(?:[^'\\]|\\.)*'",
|
|
127
|
+
category=TokenCategory.STRING
|
|
128
|
+
))
|
|
129
|
+
|
|
130
|
+
# NEW: String interpolation <variable> in strings
|
|
131
|
+
rules.append(HighlightRule(
|
|
132
|
+
pattern=r'<[A-Za-z_][A-Za-z0-9_]*>',
|
|
133
|
+
category=TokenCategory.STRING_INTERP
|
|
134
|
+
))
|
|
135
|
+
|
|
136
|
+
# NEW: Package keywords (special highlighting)
|
|
137
|
+
rules.append(HighlightRule(
|
|
138
|
+
pattern=r'\b(package|package-includes)\b',
|
|
139
|
+
category=TokenCategory.PACKAGE_KW
|
|
140
|
+
))
|
|
141
|
+
|
|
142
|
+
# NEW: Type literals (list, dict)
|
|
143
|
+
rules.append(HighlightRule(
|
|
144
|
+
pattern=r'\b(list|dict)\b(?!\s*\()',
|
|
145
|
+
category=TokenCategory.TYPE_LITERAL
|
|
146
|
+
))
|
|
147
|
+
|
|
148
|
+
# Self-references (s@Name, s@Backend.Loop)
|
|
149
|
+
rules.append(HighlightRule(
|
|
150
|
+
pattern=r's@[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*',
|
|
151
|
+
category=TokenCategory.SELF_REF
|
|
152
|
+
))
|
|
153
|
+
|
|
154
|
+
# Module references (@Module, @VSRAM.Read)
|
|
155
|
+
rules.append(HighlightRule(
|
|
156
|
+
pattern=r'@[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*',
|
|
157
|
+
category=TokenCategory.MODULE_REF
|
|
158
|
+
))
|
|
159
|
+
|
|
160
|
+
# Properties (key: value in service-init)
|
|
161
|
+
rules.append(HighlightRule(
|
|
162
|
+
pattern=r'\b(service-name|service-version|service-author|service-description|execution|executation)\s*:',
|
|
163
|
+
category=TokenCategory.PROPERTY,
|
|
164
|
+
group=1
|
|
165
|
+
))
|
|
166
|
+
|
|
167
|
+
# Keywords
|
|
168
|
+
keyword_pattern = r'\b(' + '|'.join(re.escape(k) for k in KEYWORDS) + r')\b'
|
|
169
|
+
rules.append(HighlightRule(
|
|
170
|
+
pattern=keyword_pattern,
|
|
171
|
+
category=TokenCategory.KEYWORD
|
|
172
|
+
))
|
|
173
|
+
|
|
174
|
+
# Builtins
|
|
175
|
+
builtin_pattern = r'\b(' + '|'.join(re.escape(b) for b in BUILTINS) + r')\s*\('
|
|
176
|
+
rules.append(HighlightRule(
|
|
177
|
+
pattern=builtin_pattern,
|
|
178
|
+
category=TokenCategory.BUILTIN,
|
|
179
|
+
group=1
|
|
180
|
+
))
|
|
181
|
+
|
|
182
|
+
# Boolean literals
|
|
183
|
+
rules.append(HighlightRule(
|
|
184
|
+
pattern=r'\b(True|False|true|false)\b',
|
|
185
|
+
category=TokenCategory.BOOLEAN
|
|
186
|
+
))
|
|
187
|
+
|
|
188
|
+
# Null literals
|
|
189
|
+
rules.append(HighlightRule(
|
|
190
|
+
pattern=r'\b(null|None|none)\b',
|
|
191
|
+
category=TokenCategory.NULL
|
|
192
|
+
))
|
|
193
|
+
|
|
194
|
+
# Numbers
|
|
195
|
+
rules.append(HighlightRule(
|
|
196
|
+
pattern=r'\b\d+\.?\d*\b',
|
|
197
|
+
category=TokenCategory.NUMBER
|
|
198
|
+
))
|
|
199
|
+
|
|
200
|
+
# Special operators
|
|
201
|
+
rules.append(HighlightRule(
|
|
202
|
+
pattern=r'<==|==>|->|<-',
|
|
203
|
+
category=TokenCategory.OPERATOR
|
|
204
|
+
))
|
|
205
|
+
|
|
206
|
+
# Comparison operators
|
|
207
|
+
rules.append(HighlightRule(
|
|
208
|
+
pattern=r'==|!=|<=|>=|<|>',
|
|
209
|
+
category=TokenCategory.OPERATOR
|
|
210
|
+
))
|
|
211
|
+
|
|
212
|
+
return rules
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# Default color schemes
|
|
216
|
+
class ColorScheme:
|
|
217
|
+
"""Color scheme for syntax highlighting"""
|
|
218
|
+
|
|
219
|
+
# CSO Theme (Orange accent, dark background)
|
|
220
|
+
CSO_THEME = {
|
|
221
|
+
TokenCategory.KEYWORD: '#508cff', # Blue
|
|
222
|
+
TokenCategory.BUILTIN: '#ff8c00', # Orange
|
|
223
|
+
TokenCategory.OPERATOR: '#c8c8d2', # Light gray
|
|
224
|
+
TokenCategory.STRING: '#50c878', # Green
|
|
225
|
+
TokenCategory.STRING_INTERP: '#f1fa8c',# Yellow for interpolation - NEW
|
|
226
|
+
TokenCategory.NUMBER: '#f0c040', # Yellow
|
|
227
|
+
TokenCategory.COMMENT: '#707080', # Gray
|
|
228
|
+
TokenCategory.MODULE_REF: '#ff8c00', # Orange
|
|
229
|
+
TokenCategory.SELF_REF: '#60c8dc', # Cyan
|
|
230
|
+
TokenCategory.IDENTIFIER: '#f0f0f5', # White
|
|
231
|
+
TokenCategory.PROPERTY: '#c8a8ff', # Purple
|
|
232
|
+
TokenCategory.BOOLEAN: '#ff8c00', # Orange
|
|
233
|
+
TokenCategory.NULL: '#ff6464', # Red
|
|
234
|
+
TokenCategory.PACKAGE_KW: '#bd93f9', # Purple for package - NEW
|
|
235
|
+
TokenCategory.TYPE_LITERAL: '#8be9fd', # Cyan for type literals - NEW
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
# Light theme variant
|
|
239
|
+
LIGHT_THEME = {
|
|
240
|
+
TokenCategory.KEYWORD: '#0000ff', # Blue
|
|
241
|
+
TokenCategory.BUILTIN: '#c65d00', # Dark orange
|
|
242
|
+
TokenCategory.OPERATOR: '#444444', # Dark gray
|
|
243
|
+
TokenCategory.STRING: '#008000', # Green
|
|
244
|
+
TokenCategory.STRING_INTERP: '#b8860b',# DarkGoldenrod for interpolation - NEW
|
|
245
|
+
TokenCategory.NUMBER: '#a06000', # Brown
|
|
246
|
+
TokenCategory.COMMENT: '#808080', # Gray
|
|
247
|
+
TokenCategory.MODULE_REF: '#c65d00', # Dark orange
|
|
248
|
+
TokenCategory.SELF_REF: '#008b8b', # Dark cyan
|
|
249
|
+
TokenCategory.IDENTIFIER: '#000000', # Black
|
|
250
|
+
TokenCategory.PROPERTY: '#800080', # Purple
|
|
251
|
+
TokenCategory.BOOLEAN: '#c65d00', # Dark orange
|
|
252
|
+
TokenCategory.NULL: '#ff0000', # Red
|
|
253
|
+
TokenCategory.PACKAGE_KW: '#8b008b', # DarkMagenta for package - NEW
|
|
254
|
+
TokenCategory.TYPE_LITERAL: '#008b8b', # Dark cyan for type literals - NEW
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def highlight_cssl(source: str, scheme: Dict[TokenCategory, str] = None) -> List[Tuple[int, int, str, TokenCategory]]:
|
|
259
|
+
"""
|
|
260
|
+
Highlight CSSL source code.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
source: CSSL source code
|
|
264
|
+
scheme: Color scheme dict (defaults to CSO_THEME)
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
List of (start, end, color, category) tuples
|
|
268
|
+
"""
|
|
269
|
+
if scheme is None:
|
|
270
|
+
scheme = ColorScheme.CSO_THEME
|
|
271
|
+
|
|
272
|
+
highlights = []
|
|
273
|
+
rules = CSSLSyntaxRules.get_rules()
|
|
274
|
+
|
|
275
|
+
# Track which positions are already highlighted (for priority)
|
|
276
|
+
highlighted_positions = set()
|
|
277
|
+
|
|
278
|
+
for rule in rules:
|
|
279
|
+
try:
|
|
280
|
+
pattern = re.compile(rule.pattern)
|
|
281
|
+
for match in pattern.finditer(source):
|
|
282
|
+
if rule.group > 0 and rule.group <= len(match.groups()):
|
|
283
|
+
start = match.start(rule.group)
|
|
284
|
+
end = match.end(rule.group)
|
|
285
|
+
else:
|
|
286
|
+
start = match.start()
|
|
287
|
+
end = match.end()
|
|
288
|
+
|
|
289
|
+
# Check if position already highlighted
|
|
290
|
+
pos_range = range(start, end)
|
|
291
|
+
if any(p in highlighted_positions for p in pos_range):
|
|
292
|
+
continue
|
|
293
|
+
|
|
294
|
+
# Add highlight
|
|
295
|
+
color = scheme.get(rule.category, '#ffffff')
|
|
296
|
+
highlights.append((start, end, color, rule.category))
|
|
297
|
+
|
|
298
|
+
# Mark positions as highlighted
|
|
299
|
+
highlighted_positions.update(pos_range)
|
|
300
|
+
|
|
301
|
+
except re.error:
|
|
302
|
+
continue
|
|
303
|
+
|
|
304
|
+
# Sort by start position
|
|
305
|
+
highlights.sort(key=lambda h: h[0])
|
|
306
|
+
|
|
307
|
+
return highlights
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def highlight_cssl_ansi(source: str) -> str:
|
|
311
|
+
"""
|
|
312
|
+
Highlight CSSL source with ANSI terminal colors.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
source: CSSL source code
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
Source with ANSI color codes
|
|
319
|
+
"""
|
|
320
|
+
# ANSI color codes
|
|
321
|
+
ANSI_COLORS = {
|
|
322
|
+
TokenCategory.KEYWORD: '\033[94m', # Blue
|
|
323
|
+
TokenCategory.BUILTIN: '\033[33m', # Yellow/Orange
|
|
324
|
+
TokenCategory.OPERATOR: '\033[37m', # White
|
|
325
|
+
TokenCategory.STRING: '\033[92m', # Green
|
|
326
|
+
TokenCategory.STRING_INTERP: '\033[93m',# Yellow for interpolation - NEW
|
|
327
|
+
TokenCategory.NUMBER: '\033[93m', # Yellow
|
|
328
|
+
TokenCategory.COMMENT: '\033[90m', # Gray
|
|
329
|
+
TokenCategory.MODULE_REF: '\033[33m', # Yellow/Orange
|
|
330
|
+
TokenCategory.SELF_REF: '\033[96m', # Cyan
|
|
331
|
+
TokenCategory.IDENTIFIER: '\033[0m', # Default
|
|
332
|
+
TokenCategory.PROPERTY: '\033[95m', # Magenta
|
|
333
|
+
TokenCategory.BOOLEAN: '\033[33m', # Yellow/Orange
|
|
334
|
+
TokenCategory.NULL: '\033[91m', # Red
|
|
335
|
+
TokenCategory.PACKAGE_KW: '\033[95m', # Magenta for package - NEW
|
|
336
|
+
TokenCategory.TYPE_LITERAL: '\033[96m', # Cyan for type literals - NEW
|
|
337
|
+
}
|
|
338
|
+
RESET = '\033[0m'
|
|
339
|
+
|
|
340
|
+
highlights = highlight_cssl(source, ColorScheme.CSO_THEME)
|
|
341
|
+
|
|
342
|
+
# Build highlighted string
|
|
343
|
+
result = []
|
|
344
|
+
last_end = 0
|
|
345
|
+
|
|
346
|
+
for start, end, color, category in highlights:
|
|
347
|
+
# Add unhighlighted text before this highlight
|
|
348
|
+
if start > last_end:
|
|
349
|
+
result.append(source[last_end:start])
|
|
350
|
+
|
|
351
|
+
# Add highlighted text
|
|
352
|
+
ansi_color = ANSI_COLORS.get(category, '')
|
|
353
|
+
result.append(f"{ansi_color}{source[start:end]}{RESET}")
|
|
354
|
+
last_end = end
|
|
355
|
+
|
|
356
|
+
# Add remaining text
|
|
357
|
+
if last_end < len(source):
|
|
358
|
+
result.append(source[last_end:])
|
|
359
|
+
|
|
360
|
+
return ''.join(result)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
# PyQt5/6 Syntax Highlighter
|
|
364
|
+
def get_pyqt_highlighter():
|
|
365
|
+
"""
|
|
366
|
+
Get a QSyntaxHighlighter class for CSSL.
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
CSSLHighlighter class (requires PyQt5 or PyQt6)
|
|
370
|
+
"""
|
|
371
|
+
try:
|
|
372
|
+
from PyQt5.QtGui import QSyntaxHighlighter, QTextCharFormat, QColor, QFont
|
|
373
|
+
from PyQt5.QtCore import QRegularExpression
|
|
374
|
+
except ImportError:
|
|
375
|
+
try:
|
|
376
|
+
from PyQt6.QtGui import QSyntaxHighlighter, QTextCharFormat, QColor, QFont
|
|
377
|
+
from PyQt6.QtCore import QRegularExpression
|
|
378
|
+
except ImportError:
|
|
379
|
+
return None
|
|
380
|
+
|
|
381
|
+
class CSSLHighlighter(QSyntaxHighlighter):
|
|
382
|
+
"""Syntax highlighter for CSSL code in Qt editors"""
|
|
383
|
+
|
|
384
|
+
def __init__(self, parent=None):
|
|
385
|
+
super().__init__(parent)
|
|
386
|
+
self._rules = []
|
|
387
|
+
self._setup_rules()
|
|
388
|
+
|
|
389
|
+
def _setup_rules(self):
|
|
390
|
+
"""Setup highlighting rules"""
|
|
391
|
+
scheme = ColorScheme.CSO_THEME
|
|
392
|
+
|
|
393
|
+
for rule in CSSLSyntaxRules.get_rules():
|
|
394
|
+
fmt = QTextCharFormat()
|
|
395
|
+
color = QColor(scheme.get(rule.category, '#ffffff'))
|
|
396
|
+
fmt.setForeground(color)
|
|
397
|
+
|
|
398
|
+
# Bold for keywords and builtins
|
|
399
|
+
if rule.category in (TokenCategory.KEYWORD, TokenCategory.BUILTIN):
|
|
400
|
+
fmt.setFontWeight(QFont.Bold)
|
|
401
|
+
|
|
402
|
+
# Italic for comments
|
|
403
|
+
if rule.category == TokenCategory.COMMENT:
|
|
404
|
+
fmt.setFontItalic(True)
|
|
405
|
+
|
|
406
|
+
self._rules.append((QRegularExpression(rule.pattern), fmt, rule.group))
|
|
407
|
+
|
|
408
|
+
def highlightBlock(self, text):
|
|
409
|
+
"""Apply highlighting to a block of text"""
|
|
410
|
+
for pattern, fmt, group in self._rules:
|
|
411
|
+
match_iterator = pattern.globalMatch(text)
|
|
412
|
+
while match_iterator.hasNext():
|
|
413
|
+
match = match_iterator.next()
|
|
414
|
+
if group > 0 and group <= match.lastCapturedIndex():
|
|
415
|
+
start = match.capturedStart(group)
|
|
416
|
+
length = match.capturedLength(group)
|
|
417
|
+
else:
|
|
418
|
+
start = match.capturedStart()
|
|
419
|
+
length = match.capturedLength()
|
|
420
|
+
self.setFormat(start, length, fmt)
|
|
421
|
+
|
|
422
|
+
return CSSLHighlighter
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
# Export for external editors (TextMate/VSCode grammar format)
|
|
426
|
+
def export_textmate_grammar() -> dict:
|
|
427
|
+
"""
|
|
428
|
+
Export CSSL syntax as TextMate grammar for VSCode.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
Dictionary suitable for JSON export as .tmLanguage.json
|
|
432
|
+
"""
|
|
433
|
+
return {
|
|
434
|
+
"scopeName": "source.cssl",
|
|
435
|
+
"name": "CSSL",
|
|
436
|
+
"fileTypes": ["cssl", "service"],
|
|
437
|
+
"patterns": [
|
|
438
|
+
{
|
|
439
|
+
"name": "comment.line.cssl",
|
|
440
|
+
"match": "#.*$"
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
"name": "string.quoted.double.cssl",
|
|
444
|
+
"match": '"(?:[^"\\\\]|\\\\.)*"'
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"name": "string.quoted.single.cssl",
|
|
448
|
+
"match": "'(?:[^'\\\\]|\\\\.)*'"
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
"name": "variable.other.self-reference.cssl",
|
|
452
|
+
"match": "s@[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*"
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
"name": "variable.other.module-reference.cssl",
|
|
456
|
+
"match": "@[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*"
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"name": "keyword.control.cssl",
|
|
460
|
+
"match": "\\b(service-init|service-run|service-include|struct|define|if|else|elif|while|for|foreach|in|switch|case|default|break|continue|return|try|catch|await)\\b"
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
"name": "keyword.operator.cssl",
|
|
464
|
+
"match": "\\b(and|or|not)\\b"
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
"name": "constant.language.cssl",
|
|
468
|
+
"match": "\\b(True|False|true|false|null|None)\\b"
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"name": "constant.numeric.cssl",
|
|
472
|
+
"match": "\\b\\d+\\.?\\d*\\b"
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
"name": "keyword.operator.assignment.cssl",
|
|
476
|
+
"match": "<==|==>|->|<-"
|
|
477
|
+
}
|
|
478
|
+
]
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
# Export public API
|
|
483
|
+
__all__ = [
|
|
484
|
+
'TokenCategory', 'HighlightRule', 'CSSLSyntaxRules', 'ColorScheme',
|
|
485
|
+
'highlight_cssl', 'highlight_cssl_ansi', 'get_pyqt_highlighter',
|
|
486
|
+
'export_textmate_grammar', 'KEYWORDS', 'BUILTINS',
|
|
487
|
+
'PACKAGE_KEYWORDS', 'TYPE_LITERALS' # NEW
|
|
488
|
+
]
|