Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linear-time Ninja line wrapping #150

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 18 additions & 41 deletions lib/ninja_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,50 +118,27 @@ def subninja(self, path):
def default(self, paths):
self._line('default %s' % ' '.join(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(leading_space) + len(text) > self.width:
# The text is too wide; wrap if possible.

# 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

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

self.output.write(leading_space + text[0:space] + ' $\n')
text = text[space+1:]

# Subsequent lines are continuations, so indent them.
leading_space = ' ' * (indent+2)

self.output.write(leading_space + text + '\n')
in_escape = False
most_recent_space_index = None
written_up_to = 0
for i, c in enumerate(text):
if c == '$':
in_escape = not in_escape
if not in_escape and c == ' ':
most_recent_space_index = i
if (len(leading_space) + i - written_up_to > self.width and
most_recent_space_index is not None):
self.output.write(leading_space +
text[written_up_to:most_recent_space_index] +
' $\n')
# Subsequent lines are continuations, so indent them.
leading_space = ' ' * (indent + 2)
written_up_to = most_recent_space_index + 1
most_recent_space_index = None
self.output.write(leading_space + text[written_up_to:] + '\n')

def close(self):
self.output.close()
Expand Down