WordWrap.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. #! /usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # COPYRIGHT: Openmoko Inc. 2010
  4. # LICENSE: GPL Version 3 or later
  5. # DESCRIPTION: Word wrap a tex strings
  6. # AUTHORS: Sean Moss-Pultz <sean@openmoko.com>
  7. # Christopher Hall <hsw@openmoko.com>
  8. import sys
  9. import os
  10. class WordWrap():
  11. """word wrapping class"""
  12. def __init__(self, char_width_funtion):
  13. self.buffer = []
  14. self.char_width_funtion = char_width_funtion
  15. def append(self, text, face, url):
  16. if type(text) != unicode:
  17. text = unicode(text, 'utf8')
  18. leading_space = text[0] == ' '
  19. trailing_space = text[-1] == ' '
  20. words = text.split()
  21. space_len = self.char_width_funtion(' ', face)
  22. space = (' ', face, url, space_len, [space_len])
  23. if leading_space:
  24. try:
  25. if ' ' == self.buffer[-1][0]:
  26. leading_space = False
  27. except IndexError:
  28. pass
  29. if leading_space:
  30. self.buffer.append(space)
  31. for w in words:
  32. word_len = [self.char_width_funtion(c, face) for c in w]
  33. self.buffer.append((w, face, url, sum(word_len), word_len))
  34. self.buffer.append(space)
  35. if self.buffer != [] and not trailing_space and self.buffer[-1][0] == ' ':
  36. del self.buffer[-1]
  37. def AppendImage(self, width, height, data, url):
  38. self.buffer.append(('@', (width, height, data), url, width, [width]))
  39. def dump(self):
  40. print('B: {0:s}'.format(self.buffer))
  41. def out(self):
  42. try:
  43. if ' ' == self.buffer[-1][0]:
  44. del self.buffer[-1]
  45. except IndexError:
  46. pass
  47. sys.stdout.write('"')
  48. for b in self.buffer:
  49. sys.stdout.write(b[0])
  50. sys.stdout.write('"\n')
  51. def split(self, item, width):
  52. # do not attempt to split a single wide character
  53. # this should not occur, but handle it anyway
  54. if len(item[0]) == 1:
  55. return (item, None)
  56. text = item[0]
  57. lengths = item[4]
  58. i = 0
  59. sum = 0
  60. for w in lengths:
  61. if sum + w > width:
  62. break
  63. sum += w
  64. i += 1
  65. return ((text[:i], item[1], item[2], sum, lengths[:i]),
  66. (text[i:], item[1], item[2], item[3] - sum, lengths[i:]))
  67. def wrap(self, width):
  68. if [] == self.buffer:
  69. return []
  70. while self.buffer[0][0] == ' ':
  71. del self.buffer[0]
  72. if self.buffer == []:
  73. return []
  74. if self.buffer[0][3] > width and len(self.buffer[0][0]) > 1:
  75. (r, self.buffer[0]) = self.split(self.buffer[0], width)
  76. return [r]
  77. result = [self.buffer[0]]
  78. w = result[0][3]
  79. i = 1
  80. for word in self.buffer[1:]:
  81. w += word[3]
  82. if w > width:
  83. break
  84. result.append(word)
  85. i += 1
  86. if i > 0:
  87. del self.buffer[:i]
  88. if result[-1][0] == ' ':
  89. del result[-1]
  90. return result
  91. def have(self):
  92. return self.buffer != []
  93. # some testing
  94. def main():
  95. def make_link(url, x0, x1):
  96. print('\033[1;33mLink: "{0:s}" {1:d} -> {2:d} => {3:d}\033[0m'.format(url, x0, x1, (x1 - x0)))
  97. def cwidth(c, face):
  98. if c == ' ':
  99. return 1
  100. return 2
  101. b = WordWrap(cwidth)
  102. default = '\033[0m'
  103. grey = '\033[1;30m'
  104. pink = '\033[1;31m'
  105. green = '\033[1;32m'
  106. yellow = '\033[1;33m'
  107. blue = '\033[1;34m'
  108. purple = '\033[1;35m'
  109. cyan = '\033[1;36m'
  110. white = '\033[1;37m'
  111. red = '\033[1;38m'
  112. colours = {
  113. 'n': default,
  114. 'b': green,
  115. 'i': blue,
  116. 'bi': purple,
  117. None: red,
  118. }
  119. b.append(' hello world I am some text', 'n', None)
  120. b.append(' this is another bit ', 'n', None)
  121. b.append('that is also add', 'n', 'A Link')
  122. b.append('ed ', 'i', None)
  123. b.append('in ', 'n', None)
  124. b.append(' 1234567890abcdefghijklmnopqrstuvwxyz ', 'bi', None)
  125. b.append(' and another line here is: 1234567890abcdefghijklmnopqrstuvwxyz & more', 'n', None)
  126. b.append(' some bold text ', 'b', None)
  127. b.append(' and ', 'n', None)
  128. b.append(' micro', 'n', 'micro')
  129. b.append('SDHC', 'n', 'SD card')
  130. b.append(' a VeryVeryVery', 'n', None)
  131. b.append('LongLinkWithoutSpacesThatIsCutIntoSeveralLines', 'n', 'nothing')
  132. b.append('VeryVeryVeryNothingNothingNothing', 'n', None)
  133. b.append('The expression list is evaluated once; it should yield an iterable ', 'n', None)
  134. b.append('object. An iterator is created for the result of the ', 'n', None)
  135. b.append('expression_list. The suite is then executed once for each item ', 'n', None)
  136. b.append('provided by the iterator, in the order of ascending indices. Each ', 'n', 'sdfdsf')
  137. b.append('item in turn is assigned to the target list using the standard rules ', 'n', None)
  138. b.append('for assignments, and then the suite is executed. When the items are ', 'n', None)
  139. b.append('exhausted (which is immediately when the sequence is empty), the ', 'n', None)
  140. b.append('suite in the else clause, if present, is executed, and the loop ', 'n', None)
  141. b.append('and yes it is. this ', 'n', None)
  142. b.AppendImage(1, 7, '@@@@', None)
  143. b.AppendImage(101, 7, '@@@@', None)
  144. b.AppendImage(102, 7, '@@@@', None)
  145. b.append(' is an image', 'n', None)
  146. b.dump()
  147. b.out()
  148. print(' " 1 2 3"')
  149. print(' "123456789012345678901234567890"')
  150. while b.have():
  151. url = None
  152. x = 0
  153. url_x0 = 0
  154. l = b.wrap(30)
  155. t = default
  156. for i in l:
  157. if url != i[2]:
  158. if url != None:
  159. make_link(url, url_x0, x)
  160. t += default
  161. url = i[2]
  162. if url != None:
  163. url_x0 = x
  164. t += red
  165. if url == None:
  166. if tuple == type(i[1]):
  167. (width, height, data) = i[1]
  168. t += "[{0:d}.{1:d}:{2:s}]".format(width, height, data)
  169. else:
  170. t += colours[i[1]]
  171. t += i[0]
  172. x += i[3]
  173. if url != None:
  174. make_link(url, url_x0, x)
  175. t += default
  176. print(('Wrap: "{0:s}"' + default).format(t))
  177. # run the program
  178. if __name__ == "__main__":
  179. main()