summaryrefslogtreecommitdiffstats
path: root/misc
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2011-12-22 20:21:12 (GMT)
committerNico Weber <thakis@chromium.org>2011-12-22 20:21:12 (GMT)
commitebb6c593468267f1c23ffc2a1a56e8f04fb8fca0 (patch)
tree1c6445c8adf5ef8131c4b2b9900db1006b7caaf3 /misc
parentec65275c2613b01115ab4a5c07408e3e53ce7a6e (diff)
downloadNinja-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.py60
-rwxr-xr-xmisc/ninja_test.py45
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()