diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-11 14:25:55 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-11 14:25:55 -0500 |
| commit | 8d790f371e54a8cc3e79a5ce72cd4dd5b3fa4513 (patch) | |
| tree | ff6c1a496c4e7727bd823979a582dc21ef25b811 /.ai/scripts/lint-org.el | |
| parent | bdc9a5d6e1320032770f54c747c210e4f465c399 (diff) | |
| download | rulesets-8d790f371e54a8cc3e79a5ce72cd4dd5b3fa4513.tar.gz rulesets-8d790f371e54a8cc3e79a5ce72cd4dd5b3fa4513.zip | |
feat(org): table standard as a rule, reflow helper, and lint check
Wide org tables overflow the page in exported PDF/docx, and hand-wrapping a cell into continuation rows is tedious and error-prone. The standard existed only as a work-project convention with nothing enforcing it.
claude-rules/org-tables.md carries the generalized standard: 120-column budget measured at render width (a link counts as its visible label and is never split), over-budget cells wrap onto continuation rows, and a rule sits under the header and every logical row.
wrap-org-table.el reflows a table to that shape mechanically. Columns shrink from natural width toward a floor of their widest atomic token, cells wrap link-safe, and rule-delimited continuation groups merge back into their logical row before re-wrapping, which makes the reflow idempotent. A table whose floors still exceed the budget reflows best-effort and stays flagged for restructuring.
lint-org.el gains an org-table-standard judgment check: width overruns and missing rules surface during the sweep with a pointer to the helper. Conformant wrapped tables don't false-flag, since the check reuses the helper's continuation-group reading. The check is judgment-only by design: reflowing is a visible layout change the sweep shouldn't make silently.
Diffstat (limited to '.ai/scripts/lint-org.el')
| -rw-r--r-- | .ai/scripts/lint-org.el | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/.ai/scripts/lint-org.el b/.ai/scripts/lint-org.el index 85886af..5d47644 100644 --- a/.ai/scripts/lint-org.el +++ b/.ai/scripts/lint-org.el @@ -42,6 +42,7 @@ (require 'org-lint) (require 'cl-lib) (require 'subr-x) +(require 'wrap-org-table) ; render-width + table parsing for the table check (defvar lo-fixes 0 "Count of mechanical fixes applied (or would-apply in --check) on the last file.") @@ -285,6 +286,62 @@ Craig-specific annotation marker rather than Babel src-block syntax." (lo--emit-judgment name line msg))))) ;;; --------------------------------------------------------------------------- +;;; org-table-standard check (claude-rules/org-tables.md) +;; +;; Not an org-lint checker — a custom scan run alongside the org-lint pass. +;; Violations surface as judgment items (checker `org-table-standard'), never +;; auto-fixed: reflowing a table is a visible layout change that +;; wrap-org-table.el performs on request, not something a lint sweep does +;; silently. + +(defun lo--table-violations (lines) + "Standard violations for the table given as LINES, as message strings. +Width is render-measured (links count as their labels, per wot-render-width). +Rules: an hline must follow the header and every logical data row, closing +rule included; continuation lines inside a rule-delimited group are one +logical row, matching wrap-org-table.el's grouping." + (let ((violations nil) + (max-width (apply #'max (mapcar #'wot-render-width lines)))) + (when (> max-width wot-default-budget) + (push (format "renders %d wide (budget %d)" max-width wot-default-budget) + violations)) + (let* ((parsed (mapcar #'wot--parse-row lines)) + (header-p (and (listp (car parsed)) (eq (cadr parsed) 'hline))) + (data (if header-p (cddr parsed) parsed))) + (when (and (cl-some #'listp data) + (not (eq (car (last data)) 'hline))) + (push "no closing rule" violations)) + (let ((group nil)) + (cl-loop for e in data + if (eq e 'hline) do (setq group nil) + else do (push e group) + when (and (> (length group) 1) + (not (wot--continuation-group-p (reverse group)))) + return (push "missing rule between rows" violations)))) + (nreverse violations))) + +(defun lo--check-tables () + "Scan the current buffer for org tables violating the table standard. +Emits one judgment item per violating table." + (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) + (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 "; "))))))))) + +;;; --------------------------------------------------------------------------- ;;; File processing (defun lo--backup (file) @@ -314,6 +371,9 @@ left unmodified and mechanical entries are recorded with :preview t." (lambda (a b) (> (lo--line a) (lo--line b)))))) (dolist (item sorted) (lo--handle-item item))) + ;; After org-lint items: the custom table-standard scan. Runs on the + ;; post-fix buffer; judgment-only, so order doesn't perturb fixes. + (lo--check-tables) (when (and (not lo-check-only) (buffer-modified-p)) (save-buffer))) (with-current-buffer buf (set-buffer-modified-p nil)) |
