File indexing completed on 2024-05-05 04:01:50

0001 #!/usr/bin/env python3
0002 """
0003 LICENSE:
0004 SPDX-FileCopyrightText: 2020 Juraj Oravec <jurajoravec@mailo.com>
0005 SPDX-License-Identifier: MIT
0006 
0007 Configuration:
0008 - IncludeCustoms: Try to export all available settings
0009 - prefferStandAloneData: prefferdata set specifically for current datatype
0010 
0011 Usage:
0012 script.py ThemeName themefile.kateschema
0013 """
0014 
0015 from configparser import ConfigParser
0016 import json
0017 import sys
0018 
0019 
0020 settings = {
0021     "prefferStandAloneData": True,
0022     "IncludeCustoms": True
0023 }
0024 
0025 
0026 jsonConfig = {
0027     "_comments": "Created by theme_converter script"
0028 }
0029 editorColors = {
0030     "Color Background": "BackgroundColor",
0031     "Color Code Folding": "CodeFolding",
0032     "Color Current Line Number": "CurrentLineNumber",
0033     "Color Highlighted Bracket": "BracketMatching",
0034     "Color Highlighted Line": "CurrentLine",
0035     "Color Icon Bar": "IconBorder",
0036     "Color Indentation Line": "IndentationLine",
0037     "Color Line Number": "LineNumbers",
0038     "Color MarkType 1": "MarkBookmark",
0039     "Color MarkType 2": "MarkBreakpointActive",
0040     "Color MarkType 3": "MarkBreakpointReached",
0041     "Color MarkType 4": "MarkBreakpointDisabled",
0042     "Color MarkType 5": "MarkExecution",
0043     "Color MarkType 6": "MarkWarning",
0044     "Color MarkType 7": "MarkError",
0045     "Color Modified Lines": "ModifiedLines",
0046     "Color Replace Highlight": "ReplaceHighlight",
0047     "Color Saved Lines": "SavedLines",
0048     "Color Search Highlight": "SearchHighlight",
0049     "Color Selection": "TextSelection",
0050     "Color Separator": "Separator",
0051     "Color Spelling Mistake Line": "SpellChecking",
0052     "Color Tab Marker": "TabMarker",
0053     "Color Template Background": "TemplateBackground",
0054     "Color Template Editable Placeholder": "TemplatePlaceholder",
0055     "Color Template Focused Editable Placeholder": "TemplateFocusedPlaceholder",
0056     "Color Template Not Editable Placeholder": "TemplateReadOnlyPlaceholder",
0057     "Color Word Wrap Marker": "WordWrapMarker"
0058 }
0059 textStyles = {
0060     "Alert": "Alert",
0061     "Annotation": "Annotation",
0062     "Attribute": "Attribute",
0063     "Base-N Integer": "BaseN",
0064     "Built-in": "BuiltIn",
0065     "Character": "Char",
0066     "Comment": "Comment",
0067     "Comment Variable": "CommentVar",
0068     "Constant": "Constant",
0069     "Control Flow": "ControlFlow",
0070     "Data Type": "DataType",
0071     "Decimal/Value": "DecVal",
0072     "Documentation": "Documentation",
0073     "Error": "Error",
0074     "Extension": "Extension",
0075     "Floating Point": "Float",
0076     "Function": "Function",
0077     "Import": "Import",
0078     "Information": "Information",
0079     "Keyword": "Keyword",
0080     "Normal": "Normal",
0081     "Operator": "Operator",
0082     "Others": "Others",
0083     "Preprocessor": "Preprocessor",
0084     "Region Marker": "RegionMarker",
0085     "Special Character": "SpecialChar",
0086     "Special String": "SpecialString",
0087     "String": "String",
0088     "Variable": "Variable",
0089     "Verbatim String": "VerbatimString",
0090     "Warning": "Warning"
0091 }
0092 indexToStyle = {
0093     "0": "Normal",
0094     "1": "Keyword",
0095     "2": "Function",
0096     "3": "Variable",
0097     "4": "ControlFlow",
0098     "5": "Operator",
0099     "6": "BuiltIn",
0100     "7": "Extension",
0101     "8": "Preprocessor",
0102     "9": "Attribute",
0103     "10": "Char",
0104     "11": "SpecialChar",
0105     "12": "String",
0106     "13": "VerbatimString",
0107     "14": "SpecialString",
0108     "15": "Import",
0109     "16": "DataType",
0110     "17": "DecVal",
0111     "18": "BaseN",
0112     "19": "Float",
0113     "20": "Constant",
0114     "21": "Comment",
0115     "22": "Documentation",
0116     "23": "Annotation",
0117     "24": "CommentVar",
0118     "25": "RegionMarker",
0119     "26": "Information",
0120     "27": "Warning",
0121     "28": "Alert",
0122     "29": "Others",
0123     "30": "Error"
0124 }
0125 
0126 NormalizedSections = dict[str, str]
0127 Style = dict[str, str | bool]
0128 CustomStyles = dict[str, Style]
0129 
0130 
0131 def normalizeSections(sections: list[str]) -> NormalizedSections:
0132     return {value.partition(" - ")[0]: value for value in sections}
0133 
0134 
0135 def reEcodeColors(text: str) -> str:
0136     return "#" + text[2:]
0137 
0138 
0139 def reEncodeBool(text: str) -> bool:
0140     return text == "1"
0141 
0142 
0143 def rgb_to_hex(rgb: tuple) -> str:
0144     return '#%02x%02x%02x' % rgb
0145 
0146 
0147 def decodeTextStyle(text: str) -> Style:
0148     style = {}
0149 
0150     field = text.split(",")
0151 
0152     if len(field) == 11:
0153         styleIndex = field.pop(0)
0154         style = jsonConfig["text-styles"].get(indexToStyle[styleIndex], dict()).copy()
0155 
0156     if len(field) != 10 or not any(field[0:8]):
0157         return dict()
0158 
0159     if len(field[0]) == 8:
0160         style["text-color"] = reEcodeColors(field[0])
0161     if len(field[1]) == 8:
0162         style["selected-text-color"] = reEcodeColors(field[1])
0163     if len(field[2]) == 1:
0164         style["bold"] = reEncodeBool(field[2])
0165     if len(field[3]) == 1:
0166         style["italic"] = reEncodeBool(field[3])
0167     if len(field[4]) == 1:
0168         style["strike-through"] = reEncodeBool(field[4])
0169     if len(field[5]) == 1:
0170         style["underline"] = reEncodeBool(field[5])
0171     if len(field[6]) == 8:
0172         style["background-color"] = reEcodeColors(field[6])
0173     if len(field[7]) == 8:
0174         style["selected-text-color"] = reEcodeColors(field[7])
0175     # 8: font family > ignored
0176     # 9: --- > ignored
0177 
0178     return style
0179 
0180 
0181 def decodeColorSettings(text: str) -> str | None:
0182     fieldds = tuple(map(int, text.split(",")))
0183 
0184     if len(fieldds) != 3:
0185         return
0186 
0187     return rgb_to_hex(fieldds)
0188 
0189 
0190 def extractEditorColors(section: dict[str, str]) -> dict[str, str | None]:
0191     return {editorColors[key]: decodeColorSettings(value)
0192             for key, value in section.items()}
0193 
0194 
0195 
0196 def extractTextStyles(section: dict[str, str]) -> dict[str, Style]:
0197     return {textStyles[key]: decodeTextStyle(value)
0198             for key, value in section.items()}
0199 
0200 
0201 def extractCustomStyle(custom_styles: CustomStyles, style: Style, realKey: str):
0202     for key, value in style.items():
0203         style = decodeTextStyle(value)
0204 
0205         # some items have ':' in their name, therefore it is necessary to limit the split
0206         keys = key.split(":", 1)
0207         # invalid or None language
0208         if len(keys) == 1:
0209             continue
0210 
0211         primaryKey, SecondaryKey = keys
0212 
0213         if style:
0214             custom_style = custom_styles.setdefault(primaryKey, dict())
0215             custom_style.setdefault(SecondaryKey, style)
0216 
0217             if settings["prefferStandAloneData"] and realKey == primaryKey:
0218                 custom_style[SecondaryKey] = style
0219 
0220 
0221 def extractCustomStyles(config: ConfigParser, normalizedSections: NormalizedSections) -> CustomStyles:
0222     custom_styles: CustomStyles = {}
0223 
0224     for key, value in normalizedSections.items():
0225         if not key.startswith("Highlighting"):
0226             continue
0227 
0228         realKey = key[len("Highlighting "):]
0229 
0230         extractCustomStyle(custom_styles, config[value], realKey)
0231 
0232     return custom_styles
0233 
0234 
0235 def main(inputFile: str):
0236     config = ConfigParser(delimiters="=")
0237     config.optionxform = str
0238     config.read(inputFile)
0239 
0240     normalizedSections = normalizeSections(config.sections())
0241 
0242     if "Editor Colors" in normalizedSections:
0243         jsonConfig["editor-colors"] = extractEditorColors(config[normalizedSections["Editor Colors"]])
0244     if "Default Item Styles" in normalizedSections:
0245         jsonConfig["text-styles"] = extractTextStyles(config[normalizedSections["Default Item Styles"]])
0246 
0247     if settings["IncludeCustoms"]:
0248         jsonConfig["custom-styles"] = extractCustomStyles(config, normalizedSections)
0249 
0250     print(json.dumps(jsonConfig, indent=4, sort_keys=True))
0251 
0252 
0253 if __name__ == "__main__":
0254     if len(sys.argv) != 3:
0255         print("Usage: " + sys.argv[0] + " ThemeName Filepath.kateschema")
0256         exit()
0257 
0258     jsonConfig["metadata"] = {
0259         "name": str(sys.argv[1]),
0260         "revision": 1
0261     }
0262 
0263     main(sys.argv[2])