From: Christian Heller Date: Mon, 2 Feb 2026 03:33:42 +0000 (+0100) Subject: Record/preserve BookingLine indentations via edit form. X-Git-Url: https://plomlompom.com/repos/booking/static/%7B%7Bdb.prefix%7D%7D/foo.html?a=commitdiff_plain;h=e21c37e5aa029ce8db7acd0639ec9876425fb865;p=ledgplom Record/preserve BookingLine indentations via edit form. --- diff --git a/src/ledgplom/http.py b/src/ledgplom/http.py index a5a62fe..0c8d437 100644 --- a/src/ledgplom/http.py +++ b/src/ledgplom/http.py @@ -5,7 +5,7 @@ from typing import Any # plomlib from plomlib.web import PlomHttpHandler, PlomHttpServer, PlomQueryMap # ourselves -from ledgplom.ledger import DEFAULT_INDENT, Ledger +from ledgplom.ledger import Ledger _PATH_TEMPLATES = Path('templates') @@ -72,10 +72,11 @@ class _Handler(PlomHttpHandler): inputs = {key: self.postvars.first(f'line_{lineno}_{key}') for key in input_names} if 0 == lineno: - code = f'{inputs["date"]} {inputs["target"]}' + code = inputs["date"] + ' ' + inputs["target"] else: - code = f'{DEFAULT_INDENT}{inputs["account"]} ' +\ - f'{inputs["amount"]} {inputs["currency"]}' + code = (' ' * int(inputs["len_indent"]) + + inputs["account"] + ' ' * 2 + + inputs["amount"] + ' ' + inputs["currency"]) new_lines += [f'{code} ; {inputs["comment"]}'] new_lines += self.postvars.first('raw_lines').splitlines() new_id = self.server.ledger.rewrite_block(old_id, new_lines) diff --git a/src/ledgplom/ledger.py b/src/ledgplom/ledger.py index 7d26eae..72b5fe8 100644 --- a/src/ledgplom/ledger.py +++ b/src/ledgplom/ledger.py @@ -10,7 +10,6 @@ from typing import Any, Iterator, Optional, Self _INDENT_CHARS = {' ', '\t'} _SEP_COMMENTS = ';' _PREFIX_DEF = '#def ' -DEFAULT_INDENT = 2 * ' ' class _Wealth(): @@ -120,15 +119,15 @@ class _DatLine: def __init__(self, text: str) -> None: self._raw = text - def _into_parts(self) -> tuple[str, str, str]: + def _into_parts(self) -> tuple[int, str, str]: stage_count = 0 - indent = '' + len_indent = 0 code = '' comment = '' for c in self._raw: if stage_count == 0: if c in _INDENT_CHARS: - indent += c + len_indent += 1 else: stage_count += 1 if stage_count == 1: @@ -138,11 +137,11 @@ class _DatLine: stage_count += 1 if stage_count == 2: comment += c - return indent, code, comment + return len_indent, code, comment @property - def indent(self) -> str: - 'All (maybe zero) the chars of whitespace line starts with.' + def len_indent(self) -> int: + 'Number (maybe zero) of chars of whitespace line starts with.' return self._into_parts()[0] @property @@ -224,7 +223,7 @@ class _IntroLine(_BookingLine): def errors(self) -> tuple[str, ...]: errors = [f'{name} empty' for name in self._field_names if not getattr(self, name)] - if self.indent: + if self.len_indent: errors += ['intro line indented'] try: dt_date.fromisoformat(self.date) @@ -235,7 +234,7 @@ class _IntroLine(_BookingLine): class _TransferLine(_BookingLine): 'Non-first _Booking line, expected to carry value movement.' - _field_names = {'account', 'amount', 'currency'} + _field_names = {'account', 'amount', 'currency', 'len_indent'} @property def account(self) -> str: @@ -261,7 +260,7 @@ class _TransferLine(_BookingLine): @property def errors(self) -> tuple[str, ...]: errors = [] - # if not self.indent: + # if not self.len_indent: # errors += ['transfer line not indented'] if not self.account: errors += ['account missing'] @@ -392,7 +391,7 @@ class _DatBlock(_LinesBlock): i_block: _DatBlock = cls() blocks = [] for dat_line in (_DatLine(line) for line in lines): - if (not dat_line.indent) and i_block.indented: + if (not dat_line.len_indent) and i_block.indented: blocks += [i_block] i_block.next = _DatBlock() i_block = i_block.next @@ -402,13 +401,13 @@ class _DatBlock(_LinesBlock): @property def indented(self) -> bool: 'Does the block contain any indented lines?' - return bool([line for line in self.lines if line.indent]) + return bool([line for line in self.lines if line.len_indent]) @property def gap_lines(self) -> tuple[_DatLine, ...]: 'Sequence of all included DatLines without code and indent.' return tuple(line for line in self.lines - if not line.indent + line.code) + if not (line.len_indent or line.code)) @property def redundant_empty_lines(self) -> tuple[_DatLine, ...]: @@ -433,7 +432,7 @@ class _DatBlock(_LinesBlock): def booking(self) -> Optional[_Booking]: 'Booking made from lines indented or with code.' booking_lines = tuple(_DatLine(line.raw) for line in self.lines - if line.indent or line.code) + if line.len_indent or line.code) if not booking_lines: return None booking = _Booking() diff --git a/src/templates/edit_structured.js b/src/templates/edit_structured.js index 00f0932..4e2da3e 100644 --- a/src/templates/edit_structured.js +++ b/src/templates/edit_structured.js @@ -21,11 +21,11 @@ eslint ], "max-lines": [ "error", - {"max": 355, "skipBlankLines": true, "skipComments": true} + {"max": 373, "skipBlankLines": true, "skipComments": true} ], "max-lines-per-function": [ "error", - 238 + 249 ], "max-params": [ "error", @@ -33,7 +33,7 @@ eslint ], "max-statements": [ "error", - 38 + 42 ], "multiline-comment-style": [ "error", @@ -56,6 +56,7 @@ import { } from "/taint.js"; const + DEFAULT_INPUT_LEN_INDENT = 2, IDX_LAST = -1, IDX_PAST_INTRO_LINE = 1, IDX_START = 0, @@ -67,9 +68,12 @@ const LEN_CURRENCY = 3, LEN_DATE = 10, LEN_EMPTY = 0, - LEN_INTRO_LINE = 3, + LEN_INTRO_LINE = 4, + LEN_LEN_INDENT = 1, LEN_LINE_STEP = 0, + LEN_STEP_INPUT_LEN_INDENT = 1, LEN_TARGET = 37, + MINIMUM_INPUT_LEN_INDENT = 1, bookingLines = {{ booking_lines|tojson|safe }}, rawGapLines = {{ raw_gap_lines|tojson|safe }}; @@ -82,7 +86,8 @@ const newBookingLine = ( amount, "comment": "", currency, - "errors": [] + "errors": [], + "len_indent": DEFAULT_INPUT_LEN_INDENT }); const taintAndUpdateForm = () => { @@ -96,7 +101,7 @@ const updateForm = () => { textarea = document.getElementById("gap_lines"); // empty and redo gapLines textarea, empty bookingLines table - textarea.innerHTML = "" + textarea.innerHTML = ""; rawGapLines.forEach((line) => { textarea.innerHTML += `${line}\n`; }); @@ -176,7 +181,10 @@ const updateForm = () => { td.appendChild(input); input.name = `line_${idx}_${name}`; input.size = size; - input.setAttribute("value", value.trim()); + input.setAttribute( + "value", + value.trim() + ); input.oninput = taint; return input; }; @@ -249,6 +257,14 @@ const updateForm = () => { LEN_TARGET ); } else { + const indentInput = addTdInput( + "len_indent", + `${bookingLine.len_indent}`, + LEN_LEN_INDENT + ); + indentInput.type = "number"; + indentInput.min = MINIMUM_INPUT_LEN_INDENT; + indentInput.step = LEN_STEP_INPUT_LEN_INDENT; const accInput = addTdInput( "account", bookingLine.account, diff --git a/src/tests/full.edit_structured.0 b/src/tests/full.edit_structured.0 index ea6ffe1..5519d39 100644 --- a/src/tests/full.edit_structured.0 +++ b/src/tests/full.edit_structured.0 @@ -111,7 +111,7 @@ to - + @@ -127,6 +127,9 @@ to + + + @@ -149,6 +152,9 @@ to + + + diff --git a/src/tests/full.edit_structured.3 b/src/tests/full.edit_structured.3 index 469bcbb..ba00d20 100644 --- a/src/tests/full.edit_structured.3 +++ b/src/tests/full.edit_structured.3 @@ -110,7 +110,7 @@ to - + @@ -126,6 +126,9 @@ to + + + @@ -148,6 +151,9 @@ to + + + @@ -170,6 +176,9 @@ to + + + @@ -192,6 +201,9 @@ to + + + diff --git a/src/tests/full.edit_structured.4 b/src/tests/full.edit_structured.4 index c7097a3..6529f52 100644 --- a/src/tests/full.edit_structured.4 +++ b/src/tests/full.edit_structured.4 @@ -116,7 +116,7 @@ to - + @@ -132,6 +132,9 @@ to + + + @@ -154,6 +157,9 @@ to + + + @@ -176,6 +182,9 @@ to + + + @@ -198,6 +207,9 @@ to + + +