Skip to content

Instantly share code, notes, and snippets.

@infosec-intern
Created June 27, 2021 16:47
Show Gist options
  • Save infosec-intern/efb5af0a5cc94f5ffce87abd58c17032 to your computer and use it in GitHub Desktop.
Save infosec-intern/efb5af0a5cc94f5ffce87abd58c17032 to your computer and use it in GitHub Desktop.
Python script to convert an XML-based TextMate bundle to JSON format
#!/usr/bin/env python3
''' Convert an XML-based TextMate bundle to JSON format '''
import argparse
import json
import xml.etree.ElementTree as ET
parser = argparse.ArgumentParser(description='Convert XML TM bundle to JSON TM bundle')
parser.add_argument('input', type=argparse.FileType('r'))
parser.add_argument('-o', '--output', type=argparse.FileType('w'))
args = parser.parse_args()
tree = ET.parse(args.input)
root = tree.getroot()
json_bundle = {
'fileTypes': [],
'name': None,
'scopeName': None,
'patterns': [],
'smartTypingPairs': [],
'highlightPairs': []
}
# first find all the top-level keys for our JSON document
bundle = root.find('./dict')
for i in range(0, len(bundle)):
element = bundle[i]
if element.tag == 'key' and element.text == 'fileTypes':
# next element is an array of <string> filetypes
json_bundle['fileTypes'] = list(map(lambda x: x.text, bundle[i+1]))
elif element.tag == 'key' and element.text == 'array':
pass
elif element.tag == 'key' and element.text == 'name':
# next element is a <string> with the correct name
json_bundle['name'] = bundle[i+1].text
elif element.tag == 'key' and element.text == 'scopeName':
# next element is a <string> with the correct name
json_bundle['scopeName'] = bundle[i+1].text
elif element.tag == 'key' and element.text == 'smartTypingPairs':
# next element is an <array> of <array>s of <string> characters
json_bundle['smartTypingPairs'] = list(map(lambda x: [x[0].text, x[1].text], bundle[i+1]))
elif element.tag == 'key' and element.text == 'highlightPairs':
# next element is an <array> of <array>s of <string> characters
json_bundle['highlightPairs'] = list(map(lambda x: [x[0].text, x[1].text], bundle[i+1]))
elif element.tag == 'key' and element.text == 'patterns':
# next element is an <array> of <dict>s of <string> elements
# NOTE: this is incomplete. For example, sub-patterns are skipped
patterns = bundle[i+1]
CURR_KEY = None
for pattern_dict in patterns.iterfind('./dict'):
pattern = {}
for element in pattern_dict.iter():
if element.tag == 'key':
CURR_KEY = element.text
elif element.tag == 'string':
pattern[CURR_KEY] = element.text
CURR_KEY = None
json_bundle['patterns'].append(pattern)
if args.output:
json.dump(json_bundle, args.output, indent=2)
else:
print(json.dumps(json_bundle, indent=2))
@infosec-intern
Copy link
Author

Specific to the VSCode implementation of TextMate bundles: https://code.visualstudio.com/api/language-extensions/syntax-highlight-guide

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment