Chromium Code Reviews| 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 same_line=False, | |
| 21 white_space=False): | |
|
Dan Beam
2015/03/27 19:05:25
nit: white_space -> preserve_whitespace, strip, rs
Devlin
2015/03/27 20:50:11
Done.
| |
| 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 same_line: whether this should be appended to the last line of the code, | |
| 28 or start a new line. | |
|
Dan Beam
2015/03/27 19:05:25
same_line -> allow_wrapping, dont_wrap, no_wrap im
Devlin
2015/03/27 20:50:11
wrapping doesn't work as well, I think, because it
| |
| 29 white_space: whether or not trailing whitespace should be allowed. | |
|
Dan Beam
2015/03/27 19:05:25
nit: indent off
Devlin
2015/03/27 20:50:11
Done.
| |
| 23 """ | 30 """ |
| 24 if indent_level is None: | 31 |
| 25 indent_level = self._indent_level | 32 prefix = indent_level * ' ' if indent_level else ''.join( |
|
Dan Beam
2015/03/27 19:05:25
think this could be:
(indent_level * ' ').join(
Devlin
2015/03/27 20:50:11
nope, different logic. |indent_level| basically f
| |
| 26 self._code.append(Line(((' ' * indent_level) + line).rstrip(), | 33 self._line_prefixes) |
| 27 substitute=substitute)) | 34 |
| 35 if not white_space: | |
| 36 line = line.rstrip() | |
| 37 | |
| 38 if same_line and len(self._code) > 0: | |
|
Dan Beam
2015/03/27 19:05:25
nit: can this just be
if same_line and self._co
Devlin
2015/03/27 20:50:11
Done.
| |
| 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, same_line=False): |
| 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 len(obj._code) is 0: | |
|
Dan Beam
2015/03/27 19:05:25
nit:
if not obj._code:
Devlin
2015/03/27 20:50:11
Done.
| |
| 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, same_line=same_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, same_line=False): |
| 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, same_line=same_line) |
| 73 self._indent_level += self._indent_size | 95 self._line_prefixes.append( |
| 96 line_prefix if line_prefix else ' ' * self._indent_size) | |
| 74 return self | 97 return self |
| 75 | 98 |
| 76 def Eblock(self, line=None): | 99 def Eblock(self, line=None): |
| 77 """Ends a code block by decreasing and then appending a line (or a blank | 100 """Ends a code block by decreasing and then appending a line (or a blank |
| 78 line if not given). | 101 line if not given). |
| 79 """ | 102 """ |
| 80 # TODO(calamity): Decide if type checking is necessary | 103 # TODO(calamity): Decide if type checking is necessary |
| 81 #if not isinstance(line, basestring): | 104 #if not isinstance(line, basestring): |
| 82 # raise TypeError | 105 # raise TypeError |
| 83 self._indent_level -= self._indent_size | 106 self._line_prefixes.pop() |
| 84 if line is not None: | 107 if line is not None: |
| 85 self.Append(line) | 108 self.Append(line) |
| 86 return self | 109 return self |
| 87 | 110 |
| 88 def Comment(self, comment, comment_prefix='// ', wrap_indent=0): | 111 def Comment(self, comment, comment_prefix='// ', |
| 112 wrap_indent=0, same_line=False): | |
| 89 """Adds the given string as a comment. | 113 """Adds the given string as a comment. |
| 90 | 114 |
| 91 Will split the comment if it's too long. Use mainly for variable length | 115 Will split the comment if it's too long. Use mainly for variable length |
| 92 comments. Otherwise just use code.Append('// ...') for comments. | 116 comments. Otherwise just use code.Append('// ...') for comments. |
| 93 | 117 |
| 94 Unaffected by code.Substitute(). | 118 Unaffected by code.Substitute(). |
| 95 """ | 119 """ |
| 96 # Helper function to trim a comment to the maximum length, and return one | 120 # Helper function to trim a comment to the maximum length, and return one |
| 97 # line and the remainder of the comment. | 121 # line and the remainder of the comment. |
| 98 def trim_comment(comment, max_len): | 122 def trim_comment(comment, max_len): |
| 99 if len(comment) <= max_len: | 123 if len(comment) <= max_len: |
| 100 return comment, '' | 124 return comment, '' |
| 101 last_space = comment.rfind(' ', 0, max_len + 1) | 125 last_space = comment.rfind(' ', 0, max_len + 1) |
| 102 if last_space != -1: | 126 if last_space != -1: |
| 103 line = comment[0:last_space] | 127 line = comment[0:last_space] |
| 104 comment = comment[last_space + 1:] | 128 comment = comment[last_space + 1:] |
| 105 else: | 129 else: |
| 106 line = comment[0:max_len] | 130 line = comment[0:max_len] |
| 107 comment = comment[max_len:] | 131 comment = comment[max_len:] |
| 108 return line, comment | 132 return line, comment |
| 109 | 133 |
| 110 # First line has the full maximum length. | 134 # First line has the full maximum length. |
| 111 max_len = self._comment_length - self._indent_level - len(comment_prefix) | 135 if same_line and len(self._code) > 0: |
| 136 max_len = self._comment_length - len(self._code[-1].value) - 1 | |
| 137 else: | |
| 138 max_len = (self._comment_length - len(''.join(self._line_prefixes)) - | |
| 139 len(comment_prefix)) | |
| 112 line, comment = trim_comment(comment, max_len) | 140 line, comment = trim_comment(comment, max_len) |
| 113 self.Append(comment_prefix + line, substitute=False) | 141 self.Append(comment_prefix + line, substitute=False, same_line=same_line) |
| 114 | 142 |
| 115 # Any subsequent lines be subject to the wrap indent. | 143 # Any subsequent lines be subject to the wrap indent. |
| 116 max_len = max_len - wrap_indent | 144 max_len = (self._comment_length - len(''.join(self._line_prefixes)) - |
| 145 len(comment_prefix) - wrap_indent) | |
| 117 while len(comment): | 146 while len(comment): |
| 118 line, comment = trim_comment(comment, max_len) | 147 line, comment = trim_comment(comment, max_len) |
| 119 self.Append(comment_prefix + (' ' * wrap_indent) + line, substitute=False) | 148 self.Append(comment_prefix + (' ' * wrap_indent) + line, substitute=False) |
| 120 | 149 |
| 121 return self | 150 return self |
| 122 | 151 |
| 123 def Substitute(self, d): | 152 def Substitute(self, d): |
| 124 """Goes through each line and interpolates using the given dict. | 153 """Goes through each line and interpolates using the given dict. |
| 125 | 154 |
| 126 Raises type error if passed something that isn't a dict | 155 Raises type error if passed something that isn't a dict |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 147 """ | 176 """ |
| 148 return '\n'.join([l.value for l in self._code]) | 177 return '\n'.join([l.value for l in self._code]) |
| 149 | 178 |
| 150 | 179 |
| 151 class Line(object): | 180 class Line(object): |
| 152 """A line of code. | 181 """A line of code. |
| 153 """ | 182 """ |
| 154 def __init__(self, value, substitute=True): | 183 def __init__(self, value, substitute=True): |
| 155 self.value = value | 184 self.value = value |
| 156 self.substitute = substitute | 185 self.substitute = substitute |
| OLD | NEW |