| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 class Code(object): | 5 class Code(object): |
| 6 """A convenience object for constructing code. | 6 """A convenience object for constructing code. |
| 7 | 7 |
| 8 Logically each object should be a block of code. All methods except |Render| | 8 Logically each object should be a block of code. All methods except |Render| |
| 9 and |IsEmpty| return self. | 9 and |IsEmpty| return self. |
| 10 """ | 10 """ |
| 11 def __init__(self, indent_size=2, comment_length=80): | 11 def __init__(self, indent_size=2, comment_length=80): |
| 12 self._code = [] | 12 self._code = [] |
| 13 self._indent_level = 0 | |
| 14 self._indent_size = indent_size | 13 self._indent_size = indent_size |
| 15 self._comment_length = comment_length | 14 self._comment_length = comment_length |
| 15 self._line_prefixes = [] |
| 16 | 16 |
| 17 def Append(self, line='', substitute=True, indent_level=None): | 17 def Append(self, line='', |
| 18 substitute=True, |
| 19 indent_level=None, |
| 20 new_line=True, |
| 21 strip_right=True): |
| 18 """Appends a line of code at the current indent level or just a newline if | 22 """Appends a line of code at the current indent level or just a newline if |
| 19 line is not specified. Trailing whitespace is stripped. | 23 line is not specified. |
| 20 | 24 |
| 21 substitute: indicated whether this line should be affected by | 25 substitute: indicated whether this line should be affected by |
| 22 code.Substitute(). | 26 code.Substitute(). |
| 27 new_line: whether this should be added as a new line, or should be appended |
| 28 to the last line of the code. |
| 29 strip_right: whether or not trailing whitespace should be stripped. |
| 23 """ | 30 """ |
| 24 if indent_level is None: | 31 |
| 25 indent_level = self._indent_level | 32 prefix = indent_level * ' ' if indent_level else ''.join( |
| 26 self._code.append(Line(((' ' * indent_level) + line).rstrip(), | 33 self._line_prefixes) |
| 27 substitute=substitute)) | 34 |
| 35 if strip_right: |
| 36 line = line.rstrip() |
| 37 |
| 38 if not new_line and self._code: |
| 39 self._code[-1].value += line |
| 40 else: |
| 41 self._code.append(Line(prefix + line, substitute=substitute)) |
| 28 return self | 42 return self |
| 29 | 43 |
| 30 def IsEmpty(self): | 44 def IsEmpty(self): |
| 31 """Returns True if the Code object is empty. | 45 """Returns True if the Code object is empty. |
| 32 """ | 46 """ |
| 33 return not bool(self._code) | 47 return not bool(self._code) |
| 34 | 48 |
| 35 def Concat(self, obj): | 49 def Concat(self, obj, new_line=True): |
| 36 """Concatenate another Code object onto this one. Trailing whitespace is | 50 """Concatenate another Code object onto this one. Trailing whitespace is |
| 37 stripped. | 51 stripped. |
| 38 | 52 |
| 39 Appends the code at the current indent level. Will fail if there are any | 53 Appends the code at the current indent level. Will fail if there are any |
| 40 un-interpolated format specifiers eg %s, %(something)s which helps | 54 un-interpolated format specifiers eg %s, %(something)s which helps |
| 41 isolate any strings that haven't been substituted. | 55 isolate any strings that haven't been substituted. |
| 42 """ | 56 """ |
| 43 if not isinstance(obj, Code): | 57 if not isinstance(obj, Code): |
| 44 raise TypeError(type(obj)) | 58 raise TypeError(type(obj)) |
| 45 assert self is not obj | 59 assert self is not obj |
| 60 if not obj._code: |
| 61 return self |
| 62 |
| 46 for line in obj._code: | 63 for line in obj._code: |
| 47 try: | 64 try: |
| 48 # line % () will fail if any substitution tokens are left in line | 65 # line % () will fail if any substitution tokens are left in line |
| 49 if line.substitute: | 66 if line.substitute: |
| 50 line.value %= () | 67 line.value %= () |
| 51 except TypeError: | 68 except TypeError: |
| 52 raise TypeError('Unsubstituted value when concatting\n' + line.value) | 69 raise TypeError('Unsubstituted value when concatting\n' + line.value) |
| 53 except ValueError: | 70 except ValueError: |
| 54 raise ValueError('Stray % character when concatting\n' + line.value) | 71 raise ValueError('Stray % character when concatting\n' + line.value) |
| 72 first_line = obj._code.pop(0) |
| 73 self.Append(first_line.value, first_line.substitute, new_line=new_line) |
| 74 for line in obj._code: |
| 55 self.Append(line.value, line.substitute) | 75 self.Append(line.value, line.substitute) |
| 56 | 76 |
| 57 return self | 77 return self |
| 58 | 78 |
| 59 def Cblock(self, code): | 79 def Cblock(self, code): |
| 60 """Concatenates another Code object |code| onto this one followed by a | 80 """Concatenates another Code object |code| onto this one followed by a |
| 61 blank line, if |code| is non-empty.""" | 81 blank line, if |code| is non-empty.""" |
| 62 if not code.IsEmpty(): | 82 if not code.IsEmpty(): |
| 63 self.Concat(code).Append() | 83 self.Concat(code).Append() |
| 64 return self | 84 return self |
| 65 | 85 |
| 66 def Sblock(self, line=None): | 86 def Sblock(self, line=None, line_prefix=None, new_line=True): |
| 67 """Starts a code block. | 87 """Starts a code block. |
| 68 | 88 |
| 69 Appends a line of code and then increases the indent level. | 89 Appends a line of code and then increases the indent level. If |line_prefix| |
| 90 is present, it will be treated as the extra prefix for the code block. |
| 91 Otherwise, the prefix will be the default indent level. |
| 70 """ | 92 """ |
| 71 if line is not None: | 93 if line is not None: |
| 72 self.Append(line) | 94 self.Append(line, new_line=new_line) |
| 73 self._indent_level += self._indent_size | 95 self._line_prefixes.append(line_prefix or ' ' * self._indent_size) |
| 74 return self | 96 return self |
| 75 | 97 |
| 76 def Eblock(self, line=None): | 98 def Eblock(self, line=None): |
| 77 """Ends a code block by decreasing and then appending a line (or a blank | 99 """Ends a code block by decreasing and then appending a line (or a blank |
| 78 line if not given). | 100 line if not given). |
| 79 """ | 101 """ |
| 80 # TODO(calamity): Decide if type checking is necessary | 102 # TODO(calamity): Decide if type checking is necessary |
| 81 #if not isinstance(line, basestring): | 103 #if not isinstance(line, basestring): |
| 82 # raise TypeError | 104 # raise TypeError |
| 83 self._indent_level -= self._indent_size | 105 self._line_prefixes.pop() |
| 84 if line is not None: | 106 if line is not None: |
| 85 self.Append(line) | 107 self.Append(line) |
| 86 return self | 108 return self |
| 87 | 109 |
| 88 def Comment(self, comment, comment_prefix='// ', wrap_indent=0): | 110 def Comment(self, comment, comment_prefix='// ', |
| 111 wrap_indent=0, new_line=True): |
| 89 """Adds the given string as a comment. | 112 """Adds the given string as a comment. |
| 90 | 113 |
| 91 Will split the comment if it's too long. Use mainly for variable length | 114 Will split the comment if it's too long. Use mainly for variable length |
| 92 comments. Otherwise just use code.Append('// ...') for comments. | 115 comments. Otherwise just use code.Append('// ...') for comments. |
| 93 | 116 |
| 94 Unaffected by code.Substitute(). | 117 Unaffected by code.Substitute(). |
| 95 """ | 118 """ |
| 96 # Helper function to trim a comment to the maximum length, and return one | 119 # Helper function to trim a comment to the maximum length, and return one |
| 97 # line and the remainder of the comment. | 120 # line and the remainder of the comment. |
| 98 def trim_comment(comment, max_len): | 121 def trim_comment(comment, max_len): |
| 99 if len(comment) <= max_len: | 122 if len(comment) <= max_len: |
| 100 return comment, '' | 123 return comment, '' |
| 101 last_space = comment.rfind(' ', 0, max_len + 1) | 124 last_space = comment.rfind(' ', 0, max_len + 1) |
| 102 if last_space != -1: | 125 if last_space != -1: |
| 103 line = comment[0:last_space] | 126 line = comment[0:last_space] |
| 104 comment = comment[last_space + 1:] | 127 comment = comment[last_space + 1:] |
| 105 else: | 128 else: |
| 106 line = comment[0:max_len] | 129 line = comment[0:max_len] |
| 107 comment = comment[max_len:] | 130 comment = comment[max_len:] |
| 108 return line, comment | 131 return line, comment |
| 109 | 132 |
| 110 # First line has the full maximum length. | 133 # First line has the full maximum length. |
| 111 max_len = self._comment_length - self._indent_level - len(comment_prefix) | 134 if not new_line and self._code: |
| 135 max_len = self._comment_length - len(self._code[-1].value) - 1 |
| 136 else: |
| 137 max_len = (self._comment_length - len(''.join(self._line_prefixes)) - |
| 138 len(comment_prefix)) |
| 112 line, comment = trim_comment(comment, max_len) | 139 line, comment = trim_comment(comment, max_len) |
| 113 self.Append(comment_prefix + line, substitute=False) | 140 self.Append(comment_prefix + line, substitute=False, new_line=new_line) |
| 114 | 141 |
| 115 # Any subsequent lines be subject to the wrap indent. | 142 # Any subsequent lines be subject to the wrap indent. |
| 116 max_len = max_len - wrap_indent | 143 max_len = (self._comment_length - len(''.join(self._line_prefixes)) - |
| 144 len(comment_prefix) - wrap_indent) |
| 117 while len(comment): | 145 while len(comment): |
| 118 line, comment = trim_comment(comment, max_len) | 146 line, comment = trim_comment(comment, max_len) |
| 119 self.Append(comment_prefix + (' ' * wrap_indent) + line, substitute=False) | 147 self.Append(comment_prefix + (' ' * wrap_indent) + line, substitute=False) |
| 120 | 148 |
| 121 return self | 149 return self |
| 122 | 150 |
| 123 def Substitute(self, d): | 151 def Substitute(self, d): |
| 124 """Goes through each line and interpolates using the given dict. | 152 """Goes through each line and interpolates using the given dict. |
| 125 | 153 |
| 126 Raises type error if passed something that isn't a dict | 154 Raises type error if passed something that isn't a dict |
| (...skipping 20 matching lines...) Expand all Loading... |
| 147 """ | 175 """ |
| 148 return '\n'.join([l.value for l in self._code]) | 176 return '\n'.join([l.value for l in self._code]) |
| 149 | 177 |
| 150 | 178 |
| 151 class Line(object): | 179 class Line(object): |
| 152 """A line of code. | 180 """A line of code. |
| 153 """ | 181 """ |
| 154 def __init__(self, value, substitute=True): | 182 def __init__(self, value, substitute=True): |
| 155 self.value = value | 183 self.value = value |
| 156 self.substitute = substitute | 184 self.substitute = substitute |
| OLD | NEW |