| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- import sys
- from subprocess import Popen, PIPE
- import re
- from collections import namedtuple
- from itertools import chain
- import argparse
- from vim_pandoc.utils import ensure_string
- PandocOption = namedtuple('PandocOption', ['names', 'arg', 'optional_arg'])
- class PandocInfo(object):
- def __init__(self, pandoc='pandoc'):
- if type(pandoc) == bytes:
- pandoc = pandoc.decode()
- self.pandoc = pandoc
- self.update()
- def __raw_output(self, cmd, pattern=None):
- data = ensure_string(Popen([self.pandoc, cmd], stdout=PIPE).communicate()[0])
- if pattern:
- return re.search(pattern, data, re.DOTALL)
- else:
- return data
- def update(self):
- self.version = self.get_version()
- self.options = self.get_options()
- self.extensions = self.get_extensions()
- self.input_formats = self.get_input_formats()
- self.output_formats = self.get_output_formats()
- def get_version(self):
- versionPattern = 'pandoc(\.exe)? (?P<version>\d+\.\d+)'
- return self.__raw_output('--version', pattern=versionPattern).group('version')
- def get_options(self):
- # first line describes pandoc usage
- data = self.__raw_output('--help').splitlines()[1:]
- data = [l.strip() for l in data]
- # options from --trace onwards are not meaningful for us
- try:
- cutoff = data.index('--trace')
- except ValueError:
- cutoff = -1
- data = data[:cutoff]
- options = []
- for line in data:
- # TODO: simplify if possible
- if re.search(',', line): # multiple variant options
- if re.search('(?<![a-z])(?<!-)-(?!-)', line):
- if re.search('\[', line):
- optional = True
- else:
- optional = False
- opts = re.findall("-+([a-zA-Z-]+)[\[ =]", line)
- if opts:
- options.append(PandocOption(opts, True, optional))
- else:
- opts = re.findall('--([a-z-]+)', line)
- if opts:
- options.append(PandocOption(opts, False, False))
- else:
- if re.search('=', line): # take arguments
- if re.search('\[=', line): # arguments are optional
- optional = re.findall('--([a-z-]+)\[=', line)
- if optional:
- options.append(PandocOption(optional, True, True))
- else:
- optarg_opts = re.findall('-+([a-zA-Z-]+)[ =][A-Za-z]+', line)
- if optarg_opts:
- options.append(PandocOption(optarg_opts, True, False))
- else: # flags
- flag_opts = re.findall('-+([a-z-]+(?![=]))', line)
- if flag_opts:
- options.append(PandocOption(flag_opts, False, False))
- return options
- def get_options_list(self):
- return list(chain.from_iterable([v.names for v in self.options]))
- def get_extensions(self):
- data = self.__raw_output('--list-extensions')
- data = re.sub('(^ |^)[\+-]', '', data, flags=re.MULTILINE)
- return data.splitlines()
- def get_input_formats(self):
- data = self.__raw_output('--list-input-formats')
- return data.splitlines()
- def get_output_formats(self):
- data = self.__raw_output('--list-output-formats')
- return data.splitlines()
- def is_valid_output_format(self, identifier):
- if not identifier.startswith("markdown") and identifier in self.output_formats:
- return True
- elif identifier.startswith("markdown"):
- return re.match(identifier+"(([+-]("+"|".join(self.extensions)+"))+)?$", identifier)
- def build_argument_parser(self):
- def wrap_flag(flag):
- if len(flag) == 1:
- return "-" + flag
- else:
- return "--" + flag
- parser = argparse.ArgumentParser()
- parser.add_argument('output_format')
- for opt in self.options:
- flags = [wrap_flag(f) for f in opt.names]
- extra = {}
- extra['action'] = 'store_true' if not opt.arg else 'store'
- # some options can be given several times
- repeatable_options = ['bibliography', 'css', 'defaults', 'metadata-file', 'syntax-definition']
- if any(map(lambda x: x.isupper() and x != 'T' or x in repeatable_options, opt.names)):
- extra['action'] = 'append'
- if opt.arg:
- extra['nargs'] = '?' if opt.optional_arg else 1
- parser.add_argument(*flags, **extra)
- return parser
|