diff --git a/src/forthlift/forthlift.py b/src/forthlift/forthlift.py index 8611958..c358c38 100755 --- a/src/forthlift/forthlift.py +++ b/src/forthlift/forthlift.py @@ -49,21 +49,22 @@ class consume: class lines(Consume): """Consume line by line.""" def __call__(self, stream): - return stream.readlines() + for line in stream: + yield line class paragraphs(Consume): """Consume paragraph by paragraph (separated by an empty line).""" def __call__(self, stream): - pars = [] current = "" - for item in stream.readlines(): + for item in stream: # Not counting spaces as legit content. if item.strip(): current += item else: - pars.append( current ) + yield current current = "" - return pars + if current.strip(): + yield current class sections(Consume): """Consume section by section. A new section starts when a line matches the `mark` regexp. If `skip` is set to 'skip', the marked line is not consumed.""" @@ -77,19 +78,17 @@ class consume: self.skip = bool(skip) def __call__(self, stream): - sec = [] current = "" - for item in stream.readlines(): + for item in stream: if re.match(self.mark, item[0]): - sec.append( current ) + yield current if self.skip: current = "" else: current = item else: current += item - sec.append( current ) - return sec + yield current class nlines(Consume): """Consume by groups of `nb` lines.""" @@ -97,19 +96,17 @@ class consume: self.nb = int(nb) def __call__(self, stream): - sec = [] count = 0 current = "" - for item in stream.readlines(): + for item in stream: if count >= self.nb: - sec.append( current ) + yield current current = "" count = 0 else: current += item count += 1 - sec.append( current ) - return sec + yield current class format: @@ -120,7 +117,8 @@ class format: class asis(Format): """Do not format anything.""" def __call__(self, items): - return items + for item in items: + yield item class trim(Format): """Split items if their length is longer than `max`, and create new items with the remaining parts.""" @@ -137,57 +135,47 @@ class format: yield item def __call__(self, items): - trimmed = [] for item in items: for separated in self.trim(item): - trimmed.append(separated) - return trimmed + yield separated class eol(Format): """Add an end of line after the item.""" def __call__(self, items): - eoled = [] for item in items: - eoled.append( item + "\n" ) - return eoled + yield item + "\n" class strip(Format): """Remove any space character around the item.""" def __call__(self, items): - stripped = [] for item in items: - stripped.append( item.strip() ) - return stripped + yield item.strip() class skip(Format): """Skip items containing only spaces or being empty.""" def __call__(self, items): - res = [] for item in items: if item.strip(): - res.append( item ) - return res + yield item class glue(Format): """Glue consecutive items together if they are not separated by an empty one.""" def __call__(self, items): - glued = [] current = "" for item in items: if item.strip(): current += item else: - glued.append( current ) + yield current current = "" - return glued + if current.strip(): + yield current class panel(Format): """Surround each item by an ascii-art box. NOTE: only works when lifted on stdout.""" def __call__(self, items): - panel = [] for item in items: - panel.append( Panel.fit(item.strip()) ) - return panel + yield Panel.fit(item.strip()) class counter(Format): """Add a counter at the end of each items, with the current index and the total. If `end` is given, it is added at the very last item. If `sep` is given, it is appended to the item before the counter itself.""" @@ -195,14 +183,16 @@ class format: self.sep = sep self.end = end - def __call__(self, items): + def __call__(self, counted): + items = list(counted) # Consume everything at once. total = len(items) res = [] for i,item in enumerate(items): res.append(f"{item}{self.sep}{i+1}/{total}") if res: res[-1] += self.end - return res + for r in res: + yield r class suffix(Format): """Add the `content` string after each item. If `sep` is given, it is appended to the item before the content and after the item.""" @@ -211,7 +201,8 @@ class format: self.sep = sep def __call__(self, items): - return [i+self.sep+self.content for i in items] + for i in items: + yield i+self.sep+self.content class prefix(Format): """Add the `content` string before each item. If `sep` is given, it is prepended to the item after the content and before the item.""" @@ -220,25 +211,33 @@ class format: self.sep = sep def __call__(self, items): - return [self.content+self.sep+i for i in items] + for i in items: + yield self.content+self.sep+i class lift: class Lift: - def __call__(self, items): + def call(self, items): raise NotImplementedError + def __call__(self, items): + count = 0 + for item in items: + self.call(item) + count += 1 + logger.debug(f"│ │ ├ {count}th item") + logger.debug(f"│ │ └OK {count} items") + class stdout(Lift): """Print the items on the standard output.""" - def __call__(self, items): - for item in items: - if item: - if __debug__: - print(item, end = '', file = sys.stdout, flush = True) - else: - print(item, end = '') + def call(self, item): + if item: + if __debug__: + print(item, end = '', file = sys.stdout, flush = True) else: - logger.debug("Empty item") + print(item, end = '') + else: + logger.debug("Empty item") class Forthlifter: @@ -273,27 +272,24 @@ class Forthlifter: logger.debug(f"│ │ ├ {type(self.consumer).__name__}({type(streamer).__name__})") # Concatenate items += self.consumer(streamer()) - logger.debug(f"│ │ ├ {len(items)} items") - logger.debug(f"│ │ └OK {len(items)} items") + logger.debug(f"│ │ └OK") return items def format(self, items): - logger.debug(f"│ ├ format {len(items)} items") + logger.debug(f"│ ├ format") for formatter in self.formatters: logger.debug(f"│ │ ├ {type(formatter).__name__}") # Replace items = formatter(items) - logger.debug(f"│ │ ├ {len(items)} items") - logger.debug(f"│ │ └OK {len(items)} items") + logger.debug(f"│ │ └OK") return items def lift(self, items): - logger.debug(f"│ ├ lift {len(items)} items") + logger.debug(f"│ ├ lift") for lifter in self.lifters: logger.debug(f"│ │ ├ {type(lifter).__name__}") # Call lifter(items) - logger.debug(f"│ │ └OK {len(items)} items") def __call__(self): logger.debug("├ call")