cmdline.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. # -*- coding: utf-8 -*-
  2. """
  3. pygments.cmdline
  4. ~~~~~~~~~~~~~~~~
  5. Command line interface.
  6. :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
  7. :license: BSD, see LICENSE for details.
  8. """
  9. import sys
  10. import getopt
  11. from textwrap import dedent
  12. from pygments import __version__, highlight
  13. from pygments.util import ClassNotFound, OptionError, docstring_headline
  14. from pygments.lexers import get_all_lexers, get_lexer_by_name, get_lexer_for_filename, \
  15. find_lexer_class, guess_lexer, TextLexer
  16. from pygments.formatters import get_all_formatters, get_formatter_by_name, \
  17. get_formatter_for_filename, find_formatter_class, \
  18. TerminalFormatter # pylint:disable-msg=E0611
  19. from pygments.filters import get_all_filters, find_filter_class
  20. from pygments.styles import get_all_styles, get_style_by_name
  21. USAGE = """\
  22. Usage: %s [-l <lexer> | -g] [-F <filter>[:<options>]] [-f <formatter>]
  23. [-O <options>] [-P <option=value>] [-o <outfile>] [<infile>]
  24. %s -S <style> -f <formatter> [-a <arg>] [-O <options>] [-P <option=value>]
  25. %s -L [<which> ...]
  26. %s -N <filename>
  27. %s -H <type> <name>
  28. %s -h | -V
  29. Highlight the input file and write the result to <outfile>.
  30. If no input file is given, use stdin, if -o is not given, use stdout.
  31. <lexer> is a lexer name (query all lexer names with -L). If -l is not
  32. given, the lexer is guessed from the extension of the input file name
  33. (this obviously doesn't work if the input is stdin). If -g is passed,
  34. attempt to guess the lexer from the file contents, or pass through as
  35. plain text if this fails (this can work for stdin).
  36. Likewise, <formatter> is a formatter name, and will be guessed from
  37. the extension of the output file name. If no output file is given,
  38. the terminal formatter will be used by default.
  39. With the -O option, you can give the lexer and formatter a comma-
  40. separated list of options, e.g. ``-O bg=light,python=cool``.
  41. The -P option adds lexer and formatter options like the -O option, but
  42. you can only give one option per -P. That way, the option value may
  43. contain commas and equals signs, which it can't with -O, e.g.
  44. ``-P "heading=Pygments, the Python highlighter".
  45. With the -F option, you can add filters to the token stream, you can
  46. give options in the same way as for -O after a colon (note: there must
  47. not be spaces around the colon).
  48. The -O, -P and -F options can be given multiple times.
  49. With the -S option, print out style definitions for style <style>
  50. for formatter <formatter>. The argument given by -a is formatter
  51. dependent.
  52. The -L option lists lexers, formatters, styles or filters -- set
  53. `which` to the thing you want to list (e.g. "styles"), or omit it to
  54. list everything.
  55. The -N option guesses and prints out a lexer name based solely on
  56. the given filename. It does not take input or highlight anything.
  57. If no specific lexer can be determined "text" is returned.
  58. The -H option prints detailed help for the object <name> of type <type>,
  59. where <type> is one of "lexer", "formatter" or "filter".
  60. The -h option prints this help.
  61. The -V option prints the package version.
  62. """
  63. def _parse_options(o_strs):
  64. opts = {}
  65. if not o_strs:
  66. return opts
  67. for o_str in o_strs:
  68. if not o_str:
  69. continue
  70. o_args = o_str.split(',')
  71. for o_arg in o_args:
  72. o_arg = o_arg.strip()
  73. try:
  74. o_key, o_val = o_arg.split('=')
  75. o_key = o_key.strip()
  76. o_val = o_val.strip()
  77. except ValueError:
  78. opts[o_arg] = True
  79. else:
  80. opts[o_key] = o_val
  81. return opts
  82. def _parse_filters(f_strs):
  83. filters = []
  84. if not f_strs:
  85. return filters
  86. for f_str in f_strs:
  87. if ':' in f_str:
  88. fname, fopts = f_str.split(':', 1)
  89. filters.append((fname, _parse_options([fopts])))
  90. else:
  91. filters.append((f_str, {}))
  92. return filters
  93. def _print_help(what, name):
  94. try:
  95. if what == 'lexer':
  96. cls = find_lexer_class(name)
  97. print "Help on the %s lexer:" % cls.name
  98. print dedent(cls.__doc__)
  99. elif what == 'formatter':
  100. cls = find_formatter_class(name)
  101. print "Help on the %s formatter:" % cls.name
  102. print dedent(cls.__doc__)
  103. elif what == 'filter':
  104. cls = find_filter_class(name)
  105. print "Help on the %s filter:" % name
  106. print dedent(cls.__doc__)
  107. except AttributeError:
  108. print >>sys.stderr, "%s not found!" % what
  109. def _print_list(what):
  110. if what == 'lexer':
  111. print
  112. print "Lexers:"
  113. print "~~~~~~~"
  114. info = []
  115. for fullname, names, exts, _ in get_all_lexers():
  116. tup = (', '.join(names)+':', fullname,
  117. exts and '(filenames ' + ', '.join(exts) + ')' or '')
  118. info.append(tup)
  119. info.sort()
  120. for i in info:
  121. print ('* %s\n %s %s') % i
  122. elif what == 'formatter':
  123. print
  124. print "Formatters:"
  125. print "~~~~~~~~~~~"
  126. info = []
  127. for cls in get_all_formatters():
  128. doc = docstring_headline(cls)
  129. tup = (', '.join(cls.aliases) + ':', doc, cls.filenames and
  130. '(filenames ' + ', '.join(cls.filenames) + ')' or '')
  131. info.append(tup)
  132. info.sort()
  133. for i in info:
  134. print ('* %s\n %s %s') % i
  135. elif what == 'filter':
  136. print
  137. print "Filters:"
  138. print "~~~~~~~~"
  139. for name in get_all_filters():
  140. cls = find_filter_class(name)
  141. print "* " + name + ':'
  142. print " %s" % docstring_headline(cls)
  143. elif what == 'style':
  144. print
  145. print "Styles:"
  146. print "~~~~~~~"
  147. for name in get_all_styles():
  148. cls = get_style_by_name(name)
  149. print "* " + name + ':'
  150. print " %s" % docstring_headline(cls)
  151. def main(args=sys.argv):
  152. """
  153. Main command line entry point.
  154. """
  155. # pylint: disable-msg=R0911,R0912,R0915
  156. usage = USAGE % ((args[0],) * 6)
  157. try:
  158. popts, args = getopt.getopt(args[1:], "l:f:F:o:O:P:LS:a:N:hVHg")
  159. except getopt.GetoptError, err:
  160. print >>sys.stderr, usage
  161. return 2
  162. opts = {}
  163. O_opts = []
  164. P_opts = []
  165. F_opts = []
  166. for opt, arg in popts:
  167. if opt == '-O':
  168. O_opts.append(arg)
  169. elif opt == '-P':
  170. P_opts.append(arg)
  171. elif opt == '-F':
  172. F_opts.append(arg)
  173. opts[opt] = arg
  174. if not opts and not args:
  175. print usage
  176. return 0
  177. if opts.pop('-h', None) is not None:
  178. print usage
  179. return 0
  180. if opts.pop('-V', None) is not None:
  181. print 'Pygments version %s, (c) 2006-2008 by Georg Brandl.' % __version__
  182. return 0
  183. # handle ``pygmentize -L``
  184. L_opt = opts.pop('-L', None)
  185. if L_opt is not None:
  186. if opts:
  187. print >>sys.stderr, usage
  188. return 2
  189. # print version
  190. main(['', '-V'])
  191. if not args:
  192. args = ['lexer', 'formatter', 'filter', 'style']
  193. for arg in args:
  194. _print_list(arg.rstrip('s'))
  195. return 0
  196. # handle ``pygmentize -H``
  197. H_opt = opts.pop('-H', None)
  198. if H_opt is not None:
  199. if opts or len(args) != 2:
  200. print >>sys.stderr, usage
  201. return 2
  202. what, name = args
  203. if what not in ('lexer', 'formatter', 'filter'):
  204. print >>sys.stderr, usage
  205. return 2
  206. _print_help(what, name)
  207. return 0
  208. # parse -O options
  209. parsed_opts = _parse_options(O_opts)
  210. opts.pop('-O', None)
  211. # parse -P options
  212. for p_opt in P_opts:
  213. try:
  214. name, value = p_opt.split('=', 1)
  215. except ValueError:
  216. parsed_opts[p_opt] = True
  217. else:
  218. parsed_opts[name] = value
  219. opts.pop('-P', None)
  220. # handle ``pygmentize -N``
  221. infn = opts.pop('-N', None)
  222. if infn is not None:
  223. try:
  224. lexer = get_lexer_for_filename(infn, **parsed_opts)
  225. except ClassNotFound, err:
  226. lexer = TextLexer()
  227. except OptionError, err:
  228. print >>sys.stderr, 'Error:', err
  229. return 1
  230. print lexer.aliases[0]
  231. return 0
  232. # handle ``pygmentize -S``
  233. S_opt = opts.pop('-S', None)
  234. a_opt = opts.pop('-a', None)
  235. if S_opt is not None:
  236. f_opt = opts.pop('-f', None)
  237. if not f_opt:
  238. print >>sys.stderr, usage
  239. return 2
  240. if opts or args:
  241. print >>sys.stderr, usage
  242. return 2
  243. try:
  244. parsed_opts['style'] = S_opt
  245. fmter = get_formatter_by_name(f_opt, **parsed_opts)
  246. except ClassNotFound, err:
  247. print >>sys.stderr, err
  248. return 1
  249. arg = a_opt or ''
  250. try:
  251. print fmter.get_style_defs(arg)
  252. except Exception, err:
  253. print >>sys.stderr, 'Error:', err
  254. return 1
  255. return 0
  256. # if no -S is given, -a is not allowed
  257. if a_opt is not None:
  258. print >>sys.stderr, usage
  259. return 2
  260. # parse -F options
  261. F_opts = _parse_filters(F_opts)
  262. opts.pop('-F', None)
  263. # select formatter
  264. outfn = opts.pop('-o', None)
  265. fmter = opts.pop('-f', None)
  266. if fmter:
  267. try:
  268. fmter = get_formatter_by_name(fmter, **parsed_opts)
  269. except (OptionError, ClassNotFound), err:
  270. print >>sys.stderr, 'Error:', err
  271. return 1
  272. if outfn:
  273. if not fmter:
  274. try:
  275. fmter = get_formatter_for_filename(outfn, **parsed_opts)
  276. except (OptionError, ClassNotFound), err:
  277. print >>sys.stderr, 'Error:', err
  278. return 1
  279. try:
  280. outfile = open(outfn, 'wb')
  281. except Exception, err:
  282. print >>sys.stderr, 'Error: cannot open outfile:', err
  283. return 1
  284. else:
  285. if not fmter:
  286. fmter = TerminalFormatter(**parsed_opts)
  287. outfile = sys.stdout
  288. # select lexer
  289. lexer = opts.pop('-l', None)
  290. if lexer:
  291. try:
  292. lexer = get_lexer_by_name(lexer, **parsed_opts)
  293. except (OptionError, ClassNotFound), err:
  294. print >>sys.stderr, 'Error:', err
  295. return 1
  296. if args:
  297. if len(args) > 1:
  298. print >>sys.stderr, usage
  299. return 2
  300. infn = args[0]
  301. try:
  302. code = open(infn, 'rb').read()
  303. except Exception, err:
  304. print >>sys.stderr, 'Error: cannot read infile:', err
  305. return 1
  306. if not lexer:
  307. try:
  308. lexer = get_lexer_for_filename(infn, code, **parsed_opts)
  309. except ClassNotFound, err:
  310. if '-g' in opts:
  311. try:
  312. lexer = guess_lexer(code)
  313. except ClassNotFound:
  314. lexer = TextLexer()
  315. else:
  316. print >>sys.stderr, 'Error:', err
  317. return 1
  318. except OptionError, err:
  319. print >>sys.stderr, 'Error:', err
  320. return 1
  321. else:
  322. if '-g' in opts:
  323. code = sys.stdin.read()
  324. try:
  325. lexer = guess_lexer(code)
  326. except ClassNotFound:
  327. lexer = TextLexer()
  328. elif not lexer:
  329. print >>sys.stderr, 'Error: no lexer name given and reading ' + \
  330. 'from stdin (try using -g or -l <lexer>)'
  331. return 2
  332. else:
  333. code = sys.stdin.read()
  334. # No encoding given? Use latin1 if output file given,
  335. # stdin/stdout encoding otherwise.
  336. # (This is a compromise, I'm not too happy with it...)
  337. if 'encoding' not in parsed_opts and 'outencoding' not in parsed_opts:
  338. if outfn:
  339. # encoding pass-through
  340. fmter.encoding = 'latin1'
  341. else:
  342. if sys.version_info < (3,):
  343. # use terminal encoding; Python 3's terminals already do that
  344. lexer.encoding = getattr(sys.stdin, 'encoding',
  345. None) or 'ascii'
  346. fmter.encoding = getattr(sys.stdout, 'encoding',
  347. None) or 'ascii'
  348. # ... and do it!
  349. try:
  350. # process filters
  351. for fname, fopts in F_opts:
  352. lexer.add_filter(fname, **fopts)
  353. highlight(code, lexer, fmter, outfile)
  354. except Exception, err:
  355. import traceback
  356. info = traceback.format_exception(*sys.exc_info())
  357. msg = info[-1].strip()
  358. if len(info) >= 3:
  359. # extract relevant file and position info
  360. msg += '\n (f%s)' % info[-2].split('\n')[0].strip()[1:]
  361. print >>sys.stderr
  362. print >>sys.stderr, '*** Error while highlighting:'
  363. print >>sys.stderr, msg
  364. return 1
  365. return 0