mirror of
https://github.com/ninja-build/ninja.git
synced 2026-08-07 00:22:13 +00:00
@@ -8,6 +8,10 @@ use Python.
|
||||
"""
|
||||
|
||||
import textwrap
|
||||
import re
|
||||
|
||||
def escape_spaces(word):
|
||||
return word.replace('$ ','$$ ').replace(' ','$ ')
|
||||
|
||||
class Writer(object):
|
||||
def __init__(self, output, width=78):
|
||||
@@ -43,15 +47,19 @@ class Writer(object):
|
||||
variables=None):
|
||||
outputs = self._as_list(outputs)
|
||||
all_inputs = self._as_list(inputs)[:]
|
||||
out_outputs = map(escape_spaces, outputs)
|
||||
all_inputs = map(escape_spaces, all_inputs)
|
||||
|
||||
if implicit:
|
||||
implicit = map(escape_spaces, self._as_list(implicit))
|
||||
all_inputs.append('|')
|
||||
all_inputs.extend(self._as_list(implicit))
|
||||
all_inputs.extend(implicit)
|
||||
if order_only:
|
||||
order_only = map(escape_spaces, self._as_list(order_only))
|
||||
all_inputs.append('||')
|
||||
all_inputs.extend(self._as_list(order_only))
|
||||
all_inputs.extend(order_only)
|
||||
|
||||
self._line('build %s: %s %s' % (' '.join(outputs),
|
||||
self._line('build %s: %s %s' % (' '.join(out_outputs),
|
||||
rule,
|
||||
' '.join(all_inputs)))
|
||||
|
||||
@@ -76,22 +84,43 @@ class Writer(object):
|
||||
while len(text) > self.width:
|
||||
# The text is too wide; wrap if possible.
|
||||
|
||||
# Find the rightmost space that would obey our width constraint.
|
||||
available_space = self.width - len(leading_space) - len(' $')
|
||||
space = text.rfind(' ', 0, available_space)
|
||||
if space < 0:
|
||||
# No such space; just use the first space we can find.
|
||||
space = text.find(' ', available_space)
|
||||
if space < 0:
|
||||
# Give up on breaking.
|
||||
break
|
||||
self.output.write(leading_space)
|
||||
|
||||
self.output.write(leading_space + text[0:space] + ' $\n')
|
||||
text = text[space+1:]
|
||||
available_space = self.width - len(leading_space) - len(' $')
|
||||
|
||||
# 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
|
||||
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')
|
||||
|
||||
# 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):
|
||||
|
||||
@@ -20,6 +20,7 @@ from StringIO import StringIO
|
||||
import ninja_syntax
|
||||
|
||||
LONGWORD = 'a' * 10
|
||||
LONGWORDWITHSPACES = 'a'*5 + '$ ' + 'a'*5
|
||||
INDENT = ' '
|
||||
|
||||
class TestLineWordWrap(unittest.TestCase):
|
||||
@@ -48,5 +49,22 @@ class TestLineWordWrap(unittest.TestCase):
|
||||
' ' + INDENT + 'y']) + '\n',
|
||||
self.out.getvalue())
|
||||
|
||||
def test_escaped_spaces(self):
|
||||
self.n._line(' '.join(['x', LONGWORDWITHSPACES, 'y']))
|
||||
self.assertEqual(' $\n'.join(['x',
|
||||
INDENT + LONGWORDWITHSPACES,
|
||||
INDENT + 'y']) + '\n',
|
||||
self.out.getvalue())
|
||||
|
||||
def test_fit_many_words(self):
|
||||
self.n = ninja_syntax.Writer(self.out, width=78)
|
||||
self.n._line('command = cd ../../chrome; python ../tools/grit/grit/format/repack.py ../out/Debug/obj/chrome/chrome_dll.gen/repack/theme_resources_large.pak ../out/Debug/gen/chrome/theme_resources_large.pak', 1)
|
||||
self.assertEqual('''\
|
||||
command = cd ../../chrome; python ../tools/grit/grit/format/repack.py $
|
||||
../out/Debug/obj/chrome/chrome_dll.gen/repack/theme_resources_large.pak $
|
||||
../out/Debug/gen/chrome/theme_resources_large.pak
|
||||
''',
|
||||
self.out.getvalue())
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -58,6 +58,9 @@ bool EvalString::Parse(const string& input, string* err, size_t* err_index) {
|
||||
} else if (start < input.size() && input[start] == '$') {
|
||||
parsed_.push_back(make_pair("$", RAW));
|
||||
end = start + 1;
|
||||
} else if (start < input.size() && input[start] == ' ') {
|
||||
parsed_.push_back(make_pair(" ", RAW));
|
||||
end = start + 1;
|
||||
} else {
|
||||
for (end = start; end < input.size(); ++end) {
|
||||
char c = input[end];
|
||||
|
||||
@@ -217,6 +217,9 @@ Token::Type Tokenizer::PeekToken() {
|
||||
|
||||
if (IsIdentChar(*cur_)) {
|
||||
while (cur_ < end_ && IsIdentChar(*cur_)) {
|
||||
if (*cur_ == '$' && cur_ + 1 < end_ && cur_[1] == ' ') {
|
||||
++cur_;
|
||||
}
|
||||
++cur_;
|
||||
}
|
||||
token_.end_ = cur_;
|
||||
|
||||
@@ -149,6 +149,19 @@ TEST_F(ParserTest, Dollars) {
|
||||
EXPECT_EQ("$dollarbar$baz$blah", state.edges_[0]->EvaluateCommand());
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, EscapeSpaces) {
|
||||
ASSERT_NO_FATAL_FAILURE(AssertParse(
|
||||
"rule has$ spaces\n"
|
||||
" command = something\n"
|
||||
"build foo$ bar: has$ spaces $$one two$$$ three\n"
|
||||
));
|
||||
EXPECT_TRUE(state.LookupNode("foo bar"));
|
||||
EXPECT_EQ(state.edges_[0]->outputs_[0]->file_->path_, "foo bar");
|
||||
EXPECT_EQ(state.edges_[0]->inputs_[0]->file_->path_, "$one");
|
||||
EXPECT_EQ(state.edges_[0]->inputs_[1]->file_->path_, "two$ three");
|
||||
EXPECT_EQ(state.edges_[0]->EvaluateCommand(), "something");
|
||||
}
|
||||
|
||||
TEST_F(ParserTest, CanonicalizeFile) {
|
||||
ASSERT_NO_FATAL_FAILURE(AssertParse(
|
||||
"rule cat\n"
|
||||
|
||||
Reference in New Issue
Block a user