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])