From 951b6fc63129577a80e1d46f46eeafff005fe636 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Tue, 14 Jul 2026 01:27:17 -0500 Subject: fix(scripts): stop org table helpers rewriting block content Both helpers treated any pipe-led line as a table row, so ASCII art in an example block got mangled into a bordered table (a work file took a 1949-line reformat on 2026-07-09). The scanners now track the open block's type and skip its content. Only the matching end marker closes a block, so a literal end_src quoted inside an example block can't re-expose it. The deeper cause was wrap-org-table's load-time dispatch: it fired when lint-org merely required the library, running the reformatter over files lint-org was only asked to report on. It now dispatches only when named as the entry script. lint-org's CLI is also report-only by default now. Writes require --fix, and the wrap-up workflow and lint command pass it. --- .ai/scripts/lint-org.el | 72 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 22 deletions(-) (limited to '.ai/scripts/lint-org.el') diff --git a/.ai/scripts/lint-org.el b/.ai/scripts/lint-org.el index 90b1b1d..55727ef 100644 --- a/.ai/scripts/lint-org.el +++ b/.ai/scripts/lint-org.el @@ -2,16 +2,19 @@ ;; ;; Usage: ;; emacs --batch -q -l lint-org.el FILE.org [FILE.org ...] +;; report only (the default) — categorize without modifying the file. +;; A linter reports, it doesn't write; mutation requires --fix. +;; --check is accepted as an explicit alias of this default. +;; +;; emacs --batch -q -l lint-org.el --fix FILE.org [FILE.org ...] ;; apply mechanical fixes in place, emit judgment items on stdout for the ;; command layer to walk ;; -;; emacs --batch -q -l lint-org.el --check FILE.org [FILE.org ...] -;; report only — categorize without modifying the file -;; -;; emacs --batch -q -l lint-org.el --followups-file=PATH FILE.org +;; emacs --batch -q -l lint-org.el --fix --followups-file=PATH FILE.org ;; apply mechanical fixes; if any judgment items remain, append them to ;; PATH as an org section dated today. Used by wrap-it-up to defer the ;; judgment walk to the next morning's review without blocking the wrap. +;; (--followups-file only writes in --fix mode.) ;; ;; Mechanical categories (auto-fixed): ;; item-number add [@N] directive to drifted bullets @@ -66,7 +69,9 @@ Each plist has :kind (mechanical-fixed | judgment), :line, :checker, :msg. Mechanical entries from --check mode also carry :preview t.") (defvar lo-check-only nil - "Non-nil means run in report-only mode — no buffer writes.") + "Non-nil means run in report-only mode — no buffer writes. +The CLI defaults this to t (a linter reports, it doesn't write); +`--fix' is what enables writes on a command-line run.") (defvar lo-current-file nil "Path of the file currently being processed.") (defvar lo-followups-file nil @@ -355,24 +360,40 @@ logical row, matching wrap-org-table.el's grouping." (defun lo--check-tables () "Scan the current buffer for org tables violating the table standard. -Emits one judgment item per violating table." +Emits one judgment item per violating table. Pipe-led lines inside +#+begin_/#+end_ blocks are content (ASCII art, shell pipes), not tables, +and are skipped — the same block rule `wot-process-file' applies." (save-excursion (goto-char (point-min)) - (while (re-search-forward "^[ \t]*|" nil t) - (let ((start-line (line-number-at-pos)) - (lines nil)) - (beginning-of-line) - (while (and (not (eobp)) (looking-at "[ \t]*|")) - (push (buffer-substring-no-properties (line-beginning-position) - (line-end-position)) - lines) + (let ((in-block nil)) ; the open block's type, e.g. "example" — nil outside + (while (not (eobp)) + (cond + ;; Type-matched close only: literal #+end_src quoted inside an + ;; example block must not clear the flag (see wot-process-file). + ((and (not in-block) + (looking-at "^[ \t]*#\\+begin_\\([^ \t\n]+\\)")) + (setq in-block (downcase (match-string 1))) + (forward-line 1)) + ((and in-block + (looking-at-p (format "^[ \t]*#\\+end_%s\\([ \t]\\|$\\)" + (regexp-quote in-block)))) + (setq in-block nil) (forward-line 1)) - (let ((violations (lo--table-violations (nreverse lines)))) - (when violations - (lo--emit-judgment - 'org-table-standard start-line - (format "table violates the org-table standard: %s — wrap-org-table.el reflows it" - (string-join violations "; "))))))))) + ((and (not in-block) (looking-at-p "^[ \t]*|")) + (let ((start-line (line-number-at-pos)) + (lines nil)) + (while (and (not (eobp)) (looking-at "[ \t]*|")) + (push (buffer-substring-no-properties (line-beginning-position) + (line-end-position)) + lines) + (forward-line 1)) + (let ((violations (lo--table-violations (nreverse lines)))) + (when violations + (lo--emit-judgment + 'org-table-standard start-line + (format "table violates the org-table standard: %s — wrap-org-table.el reflows it" + (string-join violations "; "))))))) + (t (forward-line 1))))))) ;;; --------------------------------------------------------------------------- ;;; level-2 dated-header check (claude-rules/todo-format.md) @@ -677,6 +698,13 @@ After printing, also append judgments to `lo-followups-file' when set." ;;; CLI (defun lo-main () + ;; Report-only is the CLI default; --fix is the only way a command-line run + ;; writes to disk. The old mutate-by-default reformatted five files in one + ;; pass before anyone confirmed anything (work project, 2026-07-09). + (setq lo-check-only t) + (when (member "--fix" command-line-args-left) + (setq lo-check-only nil) + (setq command-line-args-left (delete "--fix" command-line-args-left))) (when (member "--check" command-line-args-left) (setq lo-check-only t) (setq command-line-args-left (delete "--check" command-line-args-left))) @@ -688,7 +716,7 @@ After printing, also append judgments to `lo-followups-file' when set." (setq command-line-args-left (delete followups command-line-args-left)))) (if (null command-line-args-left) (progn - (princ "Usage: emacs --batch -q -l lint-org.el [--check] [--followups-file=PATH] FILE.org ...\n") + (princ "Usage: emacs --batch -q -l lint-org.el [--fix] [--check] [--followups-file=PATH] FILE.org ...\n") (kill-emacs 1)) (let ((files command-line-args-left)) (setq command-line-args-left nil) @@ -707,7 +735,7 @@ this file without firing the CLI dispatch — under `ert-run-tests-batch-and-exi the trailing args are things like `-f ert-run-tests-batch-and-exit'." (and command-line-args-left (cl-every (lambda (a) - (cond ((member a '("--check")) t) + (cond ((member a '("--check" "--fix")) t) ((string-prefix-p "--followups-file=" a) t) ((string-prefix-p "-" a) nil) (t (file-readable-p a)))) -- cgit v1.2.3