literals_to_xrefs.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. """
  2. Runs through a reST file looking for old-style literals, and helps replace them
  3. with new-style references.
  4. """
  5. from __future__ import absolute_import, unicode_literals
  6. import re
  7. import sys
  8. import shelve
  9. try:
  10. input = input
  11. except NameError:
  12. input = raw_input # noqa
  13. refre = re.compile(r'``([^`\s]+?)``')
  14. ROLES = (
  15. 'attr',
  16. 'class',
  17. 'djadmin',
  18. 'data',
  19. 'exc',
  20. 'file',
  21. 'func',
  22. 'lookup',
  23. 'meth',
  24. 'mod',
  25. 'djadminopt',
  26. 'ref',
  27. 'setting',
  28. 'term',
  29. 'tfilter',
  30. 'ttag',
  31. # special
  32. 'skip',
  33. )
  34. ALWAYS_SKIP = [
  35. 'NULL',
  36. 'True',
  37. 'False',
  38. ]
  39. def fixliterals(fname):
  40. data = open(fname).read()
  41. last = 0
  42. new = []
  43. storage = shelve.open('/tmp/literals_to_xref.shelve')
  44. lastvalues = storage.get('lastvalues', {})
  45. for m in refre.finditer(data):
  46. new.append(data[last:m.start()])
  47. last = m.end()
  48. line_start = data.rfind('\n', 0, m.start())
  49. line_end = data.find('\n', m.end())
  50. prev_start = data.rfind('\n', 0, line_start)
  51. next_end = data.find('\n', line_end + 1)
  52. # Skip always-skip stuff
  53. if m.group(1) in ALWAYS_SKIP:
  54. new.append(m.group(0))
  55. continue
  56. # skip when the next line is a title
  57. next_line = data[m.end():next_end].strip()
  58. if next_line[0] in '!-/:-@[-`{-~' and \
  59. all(c == next_line[0] for c in next_line):
  60. new.append(m.group(0))
  61. continue
  62. sys.stdout.write('\n' + '-' * 80 + '\n')
  63. sys.stdout.write(data[prev_start + 1:m.start()])
  64. sys.stdout.write(colorize(m.group(0), fg='red'))
  65. sys.stdout.write(data[m.end():next_end])
  66. sys.stdout.write('\n\n')
  67. replace_type = None
  68. while replace_type is None:
  69. replace_type = input(
  70. colorize('Replace role: ', fg='yellow')).strip().lower()
  71. if replace_type and replace_type not in ROLES:
  72. replace_type = None
  73. if replace_type == '':
  74. new.append(m.group(0))
  75. continue
  76. if replace_type == 'skip':
  77. new.append(m.group(0))
  78. ALWAYS_SKIP.append(m.group(1))
  79. continue
  80. default = lastvalues.get(m.group(1), m.group(1))
  81. if default.endswith('()') and \
  82. replace_type in ('class', 'func', 'meth'):
  83. default = default[:-2]
  84. replace_value = input(
  85. colorize('Text <target> [', fg='yellow') +
  86. default + colorize(']: ', fg='yellow'),
  87. ).strip()
  88. if not replace_value:
  89. replace_value = default
  90. new.append(':%s:`%s`' % (replace_type, replace_value))
  91. lastvalues[m.group(1)] = replace_value
  92. new.append(data[last:])
  93. open(fname, 'w').write(''.join(new))
  94. storage['lastvalues'] = lastvalues
  95. storage.close()
  96. def colorize(text='', opts=(), **kwargs):
  97. """
  98. Returns your text, enclosed in ANSI graphics codes.
  99. Depends on the keyword arguments 'fg' and 'bg', and the contents of
  100. the opts tuple/list.
  101. Returns the RESET code if no parameters are given.
  102. Valid colors:
  103. 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
  104. Valid options:
  105. 'bold'
  106. 'underscore'
  107. 'blink'
  108. 'reverse'
  109. 'conceal'
  110. 'noreset' - string will not be auto-terminated with the RESET code
  111. Examples:
  112. colorize('hello', fg='red', bg='blue', opts=('blink',))
  113. colorize()
  114. colorize('goodbye', opts=('underscore',))
  115. print colorize('first line', fg='red', opts=('noreset',))
  116. print 'this should be red too'
  117. print colorize('and so should this')
  118. print 'this should not be red'
  119. """
  120. color_names = ('black', 'red', 'green', 'yellow',
  121. 'blue', 'magenta', 'cyan', 'white')
  122. foreground = {color_names[x]: '3%s' % x for x in range(8)}
  123. background = {color_names[x]: '4%s' % x for x in range(8)}
  124. RESET = '0'
  125. opt_dict = {'bold': '1',
  126. 'underscore': '4',
  127. 'blink': '5',
  128. 'reverse': '7',
  129. 'conceal': '8'}
  130. text = str(text)
  131. code_list = []
  132. if text == '' and len(opts) == 1 and opts[0] == 'reset':
  133. return '\x1b[%sm' % RESET
  134. for k, v in kwargs.items():
  135. if k == 'fg':
  136. code_list.append(foreground[v])
  137. elif k == 'bg':
  138. code_list.append(background[v])
  139. for o in opts:
  140. if o in opt_dict:
  141. code_list.append(opt_dict[o])
  142. if 'noreset' not in opts:
  143. text = text + '\x1b[%sm' % RESET
  144. return ('\x1b[%sm' % ';'.join(code_list)) + text
  145. if __name__ == '__main__':
  146. try:
  147. fixliterals(sys.argv[1])
  148. except (KeyboardInterrupt, SystemExit):
  149. print