literals_to_xrefs.py 4.7 KB

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