#!/usr/bin/python import yaml, codecs, sys, os.path, optparse class Style: def __init__(self, header=None, footer=None, tokens=None, events=None, replaces=None): self.header = header self.footer = footer self.replaces = replaces self.substitutions = {} for domain, Class in [(tokens, 'Token'), (events, 'Event')]: if not domain: continue for key in domain: name = ''.join([part.capitalize() for part in key.split('-')]) cls = getattr(yaml, '%s%s' % (name, Class)) value = domain[key] if not value: continue start = value.get('start') end = value.get('end') if start: self.substitutions[cls, -1] = start if end: self.substitutions[cls, +1] = end def __setstate__(self, state): self.__init__(**state) yaml.add_path_resolver(u'tag:yaml.org,2002:python/object:__main__.Style', [None], dict) yaml.add_path_resolver(u'tag:yaml.org,2002:pairs', [None, u'replaces'], list) class YAMLHighlight: def __init__(self, options): config = yaml.full_load(file(options.config, 'rb').read()) self.style = config[options.style] if options.input: self.input = file(options.input, 'rb') else: self.input = sys.stdin if options.output: self.output = file(options.output, 'wb') else: self.output = sys.stdout def highlight(self): input = self.input.read() if input.startswith(codecs.BOM_UTF16_LE): input = unicode(input, 'utf-16-le') elif input.startswith(codecs.BOM_UTF16_BE): input = unicode(input, 'utf-16-be') else: input = unicode(input, 'utf-8') substitutions = self.style.substitutions tokens = yaml.scan(input) events = yaml.parse(input) markers = [] number = 0 for token in tokens: number += 1 if token.start_mark.index != token.end_mark.index: cls = token.__class__ if (cls, -1) in substitutions: markers.append([token.start_mark.index, +2, number, substitutions[cls, -1]]) if (cls, +1) in substitutions: markers.append([token.end_mark.index, -2, number, substitutions[cls, +1]]) number = 0 for event in events: number += 1 cls = event.__class__ if (cls, -1) in substitutions: markers.append([event.start_mark.index, +1, number, substitutions[cls, -1]]) if (cls, +1) in substitutions: markers.append([event.end_mark.index, -1, number, substitutions[cls, +1]]) markers.sort() markers.reverse() chunks = [] position = len(input) for index, weight1, weight2, substitution in markers: if index < position: chunk = input[index:position] for substring, replacement in self.style.replaces: chunk = chunk.replace(substring, replacement) chunks.append(chunk) position = index chunks.append(substitution) chunks.reverse() result = u''.join(chunks) if self.style.header: self.output.write(self.style.header) self.output.write(result.encode('utf-8')) if self.style.footer: self.output.write(self.style.footer) if __name__ == '__main__': parser = optparse.OptionParser() parser.add_option('-s', '--style', dest='style', default='ascii', help="specify the highlighting style", metavar='STYLE') parser.add_option('-c', '--config', dest='config', default=os.path.join(os.path.dirname(sys.argv[0]), 'yaml_hl.cfg'), help="set an alternative configuration file", metavar='CONFIG') parser.add_option('-i', '--input', dest='input', default=None, help="set the input file (default: stdin)", metavar='FILE') parser.add_option('-o', '--output', dest='output', default=None, help="set the output file (default: stdout)", metavar='FILE') (options, args) = parser.parse_args() hl = YAMLHighlight(options) hl.highlight()