@@ -148,11 +148,43 @@ def close(self):
148148
149149Command = namedtuple ('Command' , 'negated cmd args lineno' )
150150
151- LINE_PATTERN = re .compile (r'(?<=(?<!\S)@)(?P<negated>!?)(?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)(?P<args>.*)$' )
151+ # returns a generator out of the file object, which
152+ # - removes `\\` then `\n` then a shared prefix with the previous line then optional whitespace;
153+ # - keeps a line number (starting from 0) of the first line being concatenated.
154+ def concat_multi_lines (f ):
155+ lastline = None # set to the last line when the last line has a backslash
156+ firstlineno = None
157+ catenated = ''
158+ for lineno , line in enumerate (f ):
159+ line = line .rstrip ('\r \n ' )
160+
161+ # strip the common prefix from the current line if needed
162+ if lastline is not None :
163+ maxprefix = 0
164+ for i in xrange (min (len (line ), len (lastline ))):
165+ if line [i ] != lastline [i ]: break
166+ maxprefix += 1
167+ line = line [maxprefix :].lstrip ()
168+
169+ firstlineno = firstlineno or lineno
170+ if line .endswith ('\\ ' ):
171+ lastline = line [:- 1 ]
172+ catenated += line [:- 1 ]
173+ else :
174+ yield firstlineno , catenated + line
175+ lastline = None
176+ firstlineno = None
177+ catenated = ''
178+
179+ LINE_PATTERN = re .compile (r'''
180+ (?<=(?<!\S)@)(?P<negated>!?)
181+ (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
182+ (?P<args>.*)$
183+ ''' , re .X )
152184def get_commands (template ):
153185 with open (template , 'rUb' ) as f :
154- for lineno , line in enumerate (f ):
155- m = LINE_PATTERN .search (line . rstrip ( ' \r \n ' ) )
186+ for lineno , line in concat_multi_lines (f ):
187+ m = LINE_PATTERN .search (line )
156188 if not m : continue
157189
158190 negated = (m .group ('negated' ) == '!' )
0 commit comments