home · contact · privacy
Offer removal of redundant empty lines. master
authorChristian Heller <c.heller@plomlompom.de>
Sun, 27 Apr 2025 18:00:38 +0000 (20:00 +0200)
committerChristian Heller <c.heller@plomlompom.de>
Sun, 27 Apr 2025 18:00:38 +0000 (20:00 +0200)
src/ledgplom/http.py
src/ledgplom/ledger.py
src/templates/_macros.tmpl
src/templates/ledger_raw.tmpl
src/templates/ledger_structured.tmpl

index 2eea419af37ea95fb156daa6d51e89b4e70df553..550ad6fdc42b7c0ffc96beddb2910c39bc6f49cb 100644 (file)
@@ -86,6 +86,9 @@ class _Handler(PlomHttpHandler):
 
     def post_ledger_action(self) -> Path:
         """Call .server.ledger.(move|copy|add_empty_new)_booking."""
+        if 'remove_redundant_empty_lines' in self.postvars.as_dict:
+            self.server.ledger.remove_redundant_empty_lines()
+            return Path(self.path)
         if 'add_booking' in self.postvars.as_dict:
             id_ = self.server.ledger.add_empty_block()
         else:
@@ -106,7 +109,8 @@ class _Handler(PlomHttpHandler):
                 Path('/').joinpath(_PAGENAME_EDIT_STRUCTURED
                                    ).joinpath(self.path_toks[2]))
             return
-        ctx = {'unsaved_changes': self.server.ledger.tainted, 'path': self.path}
+        ctx = {'unsaved_changes': self.server.ledger.tainted,
+               'path': self.path}
         if self.pagename == 'balance':
             self.get_balance(ctx)
         elif self.pagename.startswith(_PREFIX_EDIT):
@@ -188,5 +192,7 @@ class _Handler(PlomHttpHandler):
     def get_ledger(self, ctx: dict[str, Any], raw: bool) -> None:
         """Display ledger of all Bookings."""
         ctx['blocks'] = self.server.ledger.blocks
+        ctx['has_redundant_empty_lines'] =\
+            self.server.ledger.has_redundant_empty_lines
         self._send_rendered(
             _PAGENAME_LEDGER_RAW if raw else _PAGENAME_LEDGER_STRUCTURED, ctx)
index 1587fd7fa8af9a321cca2ca2e24b5b951f474001..b7796ffb1c983931fa0a1023055045eb2ca62480 100644 (file)
@@ -134,7 +134,7 @@ class _DatLine:
         """Return as how to be written in .dat file's text content."""
         comment_part = ' ; '.join([''] + [s for s in [self.comment] if s])
         code_part = f'{self.code} ' if self.code else ''
-        return f'{code_part}{comment_part.lstrip()}'
+        return f'{code_part}{comment_part.lstrip()}'.rstrip()
 
     def copy(self) -> Self:
         """Create new instance copying the fields named in .to_copy."""
@@ -344,6 +344,27 @@ class _Gap(_LinesBlock[_GapLine]):
         """Grow self by lines."""
         self._lines += lines
 
+    @property
+    def redundant_empty_lines(self):
+        """If self has more empty lines than necessary."""
+        redundancies = []
+        prev_line = None
+        idx_last_non_empty = -1
+        for idx, line in enumerate(self._lines):
+            if line.comment:
+                idx_last_non_empty = idx
+            elif '' == prev_line and not line.comment:
+                redundancies += [line]
+            prev_line = line
+        redundancies += [line for line in self._lines[idx_last_non_empty + 2:]
+                         if line not in redundancies]
+        return redundancies
+
+    def remove_redundant_empty_lines(self):
+        """From self remove redundant empty lines."""
+        for line in self.redundant_empty_lines:
+            self._lines.remove(line)
+
 
 class _Booking(_LinesBlock[_BookingLine]):
 
@@ -633,6 +654,16 @@ class Ledger:
                 return False
         return True
 
+    @property
+    def has_redundant_empty_lines(self) -> bool:
+        """If any gaps have redunant empty lines."""
+        return bool([b for b in self.blocks if b.gap.redundant_empty_lines])
+
+    def remove_redundant_empty_lines(self) -> None:
+        """From all .blocks remove redundant empty lines."""
+        for gap in [b.gap for b in self.blocks if b.gap.redundant_empty_lines]:
+            gap.remove_redundant_empty_lines()
+
     @property
     def tainted(self) -> bool:
         """If ._dat_lines different to those of last .load()."""
index a9a4b22e21e1107be2a0671587b573674787c71a..dcb3f828d6aac9b450e24d2ffa4403d24953b774 100644 (file)
@@ -70,6 +70,15 @@ td.block_column.critical {
 
 
 
+{% macro ledger_empty_lines_fix(has_redundant_empty_lines) %}
+{% if has_redundant_empty_lines %}
+    Detected redundant empty lines in gaps, <input type="submit" name="remove_redundant_empty_lines" value="fix?" />
+    <hr />
+{% endif %}
+{% endmacro %}
+
+
+
 {% macro ledger_block_columns(mode, block) %}
 <tr></tr><!-- just to keep the background-color alternation in proper order -->
 <tr id="block_{{block.id_}}">
index 76a329855770bb4be20716493f37b3d65bd4e768..87795040388cf4ad8c4dca6797b2374a653fb59f 100644 (file)
@@ -13,6 +13,7 @@ table {
 
 {% block content %}
 <form action="/ledger_raw" method="POST">
+{{macros.ledger_empty_lines_fix(has_redundant_empty_lines)}}
 <table class="alternating">
 {% for block in blocks %}
     {{macros.ledger_block_columns('raw', block)}}
index 12b74003af8af501d2995986924ff95ce9653bc8..efb742e37c6f3ed149be3c9b0f11cc7910b199a3 100644 (file)
@@ -17,6 +17,7 @@ td.amount, td.currency {
 
 {% block content %}
 <form action="/ledger_structured" method="POST">
+{{macros.ledger_empty_lines_fix(has_redundant_empty_lines)}}
 <table class="alternating">
 {% for block in blocks %}
     {{macros.ledger_block_columns('structured', block)}}