diff options
author | Nico Weber <thakis@chromium.org> | 2011-12-22 20:21:12 (GMT) |
---|---|---|
committer | Nico Weber <thakis@chromium.org> | 2011-12-22 20:21:12 (GMT) |
commit | ebb6c593468267f1c23ffc2a1a56e8f04fb8fca0 (patch) | |
tree | 1c6445c8adf5ef8131c4b2b9900db1006b7caaf3 /misc | |
parent | ec65275c2613b01115ab4a5c07408e3e53ce7a6e (diff) | |
download | Ninja-ebb6c593468267f1c23ffc2a1a56e8f04fb8fca0.zip Ninja-ebb6c593468267f1c23ffc2a1a56e8f04fb8fca0.tar.gz Ninja-ebb6c593468267f1c23ffc2a1a56e8f04fb8fca0.tar.bz2 |
Let ninja_syntax handle escaped spaces correctly.
Revert the main loop changes made in 2e7ab7514207ea7faad40faedf3fc9d72b3adf7a,
and add just a few lines to the original main loop to make '$ ' escaping work.
Add several new tests, and make the existing tests pass again.
Diffstat (limited to 'misc')
-rw-r--r-- | misc/ninja_syntax.py | 60 | ||||
-rwxr-xr-x | misc/ninja_test.py | 45 |
2 files changed, 75 insertions, 30 deletions
diff --git a/misc/ninja_syntax.py b/misc/ninja_syntax.py index 06fe3cb..263c9bc 100644 --- a/misc/ninja_syntax.py +++ b/misc/ninja_syntax.py @@ -29,7 +29,7 @@ class Writer(object): if value is None: return if isinstance(value, list): - value = ' '.join(value) + value = ' '.join(filter(None, value)) # Filter out empty strings. self._line('%s = %s' % (key, value), indent) def rule(self, name, command, description=None, depfile=None, @@ -78,49 +78,49 @@ class Writer(object): def default(self, paths): self._line('default %s' % ' '.join(self._as_list(paths))) + def _count_dollars_before_index(self, s, i): + """Returns the number of '$' characters right in front of s[i].""" + dollar_count = 0 + dollar_index = i - 1 + while dollar_index > 0 and s[dollar_index] == '$': + dollar_count += 1 + dollar_index -= 1 + return dollar_count + def _line(self, text, indent=0): """Write 'text' word-wrapped at self.width characters.""" leading_space = ' ' * indent while len(text) > self.width: # The text is too wide; wrap if possible. - self.output.write(leading_space) - + # Find the rightmost space that would obey our width constraint and + # that's not an escaped space. available_space = self.width - len(leading_space) - len(' $') + space = available_space + while True: + space = text.rfind(' ', 0, space) + if space < 0 or \ + self._count_dollars_before_index(text, space) % 2 == 0: + break - # Write as much as we can into this line. - done = False - written_stuff = False - while available_space > 0: - space = re.search('((\$\$)+([^$]|^)|[^$]|^) ', text) - if space: - space_idx = space.start() + 1 - else: - # No spaces left. - done = True + if space < 0: + # No such space; just use the first unescaped space we can find. + space = available_space - 1 + while True: + space = text.find(' ', space + 1) + if space < 0 or \ + self._count_dollars_before_index(text, space) % 2 == 0: break + if space < 0: + # Give up on breaking. + break - if space_idx > available_space: - # We're out of space. - if written_stuff: - # See if we can fit it on the next line. - break - # If we haven't written anything yet on this line, don't - # try to wrap. - self.output.write(text[0:space_idx] + ' ') - written_stuff = True - text = text[space_idx+1:] - available_space -= space_idx+1 - - self.output.write('$\n') + self.output.write(leading_space + text[0:space] + ' $\n') + text = text[space+1:] # Subsequent lines are continuations, so indent them. leading_space = ' ' * (indent+2) - if done: - # No more spaces, so bail. - break - self.output.write(leading_space + text + '\n') def _as_list(self, input): diff --git a/misc/ninja_test.py b/misc/ninja_test.py index 481912e..65dbec6 100755 --- a/misc/ninja_test.py +++ b/misc/ninja_test.py @@ -66,5 +66,50 @@ class TestLineWordWrap(unittest.TestCase): ''', self.out.getvalue()) + def test_leading_space(self): + self.n = ninja_syntax.Writer(self.out, width=14) # force wrapping + self.n.variable('foo', ['', '-bar', '-somethinglong'], 0) + self.assertEqual('''\ +foo = -bar $ + -somethinglong +''', + self.out.getvalue()) + + def test_embedded_dollar_dollar(self): + self.n = ninja_syntax.Writer(self.out, width=15) # force wrapping + self.n.variable('foo', ['a$$b', '-somethinglong'], 0) + self.assertEqual('''\ +foo = a$$b $ + -somethinglong +''', + self.out.getvalue()) + + def test_two_embedded_dollar_dollars(self): + self.n = ninja_syntax.Writer(self.out, width=17) # force wrapping + self.n.variable('foo', ['a$$b', '-somethinglong'], 0) + self.assertEqual('''\ +foo = a$$b $ + -somethinglong +''', + self.out.getvalue()) + + def test_leading_dollar_dollar(self): + self.n = ninja_syntax.Writer(self.out, width=14) # force wrapping + self.n.variable('foo', ['$$b', '-somethinglong'], 0) + self.assertEqual('''\ +foo = $$b $ + -somethinglong +''', + self.out.getvalue()) + + def test_trailing_dollar_dollar(self): + self.n = ninja_syntax.Writer(self.out, width=14) # force wrapping + self.n.variable('foo', ['a$$', '-somethinglong'], 0) + self.assertEqual('''\ +foo = a$$ $ + -somethinglong +''', + self.out.getvalue()) + if __name__ == '__main__': unittest.main() |