Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
2026-04-30 Bob Weiner <rsw@gnu.org>

* kotl/kvspec.el (kvspec:update): If updating an existing viewspec, mark
buffer as modified so new viewspec is saved when writing out the file.

* kotl/kfile.el (kfile:insert-attributes-v3): Fix to handle alpha and legal
numbering properly plus a period with no following spaces as the separator.
Update to 'save-excursion' and force start at (point-min) and make
args optional so can be called in 'kfile:write' as well as 'kfile:read'.

* kotl/kotl-mode.el (kotl-mode): Prevent 'delete-trailing-whitespace-mode'
from deleting trailing whitespace from any lines within kcells. Ensure
"stripmode" package does not delete trailing whitespace from cells whose
first line is blank or editing will not start at the proper column.

* kotl/kotl-mode.el (kotl-mode:just-one-space): Add optional N arg of how
many spaces to leave that 'just-one-space supports and update doc string.
Since works for a single line only, does not support -N for removing
newlines as 'just-one-space' does.

2026-04-29 Bob Weiner <rsw@gnu.org>

* kotl/kfile.el (kfile:write): Ensure "stripmode" package does not delete
trailing whitespace from cells whose first line is blank or editing
will not start at the proper column.
(kfile:insert-attributes-v3): When reading in an exising
* kotl/kfile.el (kfile:insert-attributes-v3): When reading in an exising
Koutline, repair any cells that start with a blank line and have had
the label separator removed or where lines of just whitespace have been
remove due to packages that delete trailing spaces. Also ensure search
Expand Down
247 changes: 134 additions & 113 deletions kotl/kfile.el
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
;; Author: Bob Weiner
;;
;; Orig-Date: 10/31/93
;; Last-Mod: 30-Apr-26 at 02:33:14 by Bob Weiner
;; Last-Mod: 30-Apr-26 at 13:24:40 by Bob Weiner
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
Expand Down Expand Up @@ -348,11 +348,8 @@ VISIBLE-ONLY-P is non-nil. Signal an error if kotl is not attached to a file."
;; Set-visited-file-name clears local-write-file-hooks that we use to save
;; koutlines properly, so reinitialize local variables.
(kotl-mode)
;; Prevent "stripspace" package from deleting trailing whitespace from the
;; first line of cells which are blank. These need to maintain spaces after
;; the relative identifier to ensure proper editing of the first line.
(when (bound-and-true-p stripspace-local-mode)
(stripsapce-local-mode 0))
(kfile:insert-attributes-v3)
;; Force a save
(set-buffer-modified-p t)
;; This next line must come before the save-buffer so write-file-functions
;; can make use of it.
Expand Down Expand Up @@ -392,120 +389,144 @@ included in the list."
kotl-structure)
(nreverse cell-list)))

(defun kfile:insert-attributes-v2 (_kview kcell-list)
"Set cell attributes within KVIEW for each element in KCELL-LIST.
Assume all cell contents are already in kview and that no cells are
hidden."
(let (buffer-read-only
idstamp
kcell-data)
(while
(progn
(skip-chars-forward "\n")
;; !! TODO: Won't work if label-type is 'no.
;; Here we search past the cell identifier
;; for the location at which to place cell properties.
;; Be sure not to skip past a period which may terminate the label.
(when (re-search-forward "[A-Za-z0-9]\\(\\.?[A-Za-z0-9]\\)*" nil t)
(setq kcell-data (car kcell-list)
;; Repair invalid idstamps on the fly.
idstamp (if (vectorp kcell-data)
(or (kcell-data:idstamp kcell-data) (kview:id-increment kotl-kview))
(kview:id-increment kotl-kview)))
(kproperty:set 'idstamp idstamp)
(kproperty:set 'kcell (car kcell-list))
(setq kcell-list (cdr kcell-list)))
(search-forward "\n\n" nil t)))))

(defun kfile:insert-attributes-v3 (kview kcell-vector)
"Set cell attributes within KVIEW for each element in KCELL-VECTOR.
Assume all cell contents are already in kview and that no cells are
hidden."
(let* ((kcell-num 1)
(label-separator (kview:label-separator kview))
(label-separator-regexp (regexp-quote label-separator))
(label-and-separator-regexp
(format "^[ \t]*\\([0-9]\\(\\.?[A-Za-z0-9]\\)*\\)\\([ \n]\\|%s\\)"
label-separator-regexp))
(cell-start-or-cells-end-regexp
(concat label-and-separator-regexp "\\|\\'"))
mod-flag
buffer-read-only
idstamp
kcell-data
indent
start
end
next)
(cl-flet ((kotl-mode:pre-self-insert-command () nil))
(while (progn
(skip-chars-forward "\n")
;; !! TODO: Won't work if label-type is 'no.
;; Here we search past the cell identifier
;; for the location at which to place cell properties.
;; Be sure not to skip past a period which may terminate the label.
(when (re-search-forward label-and-separator-regexp nil t)
(goto-char (match-end 1))
;; Repair any cells that start with blank lines and have had
;; the label separator removed, typically due to packages that delete
;; trailing spaces.
(unless (looking-at label-separator-regexp)
(setq mod-flag t)
;; Remove any existing padding between label and first char of
;; cell text and then insert label-separator
(delete-region (point)
(min (+ (point) (length label-separator))
(save-excursion
(skip-chars-forward "^\n") (point))))
(save-excursion (insert label-separator)))
(setq kcell-data (aref kcell-vector kcell-num)
;; Repair invalid idstamps on the fly.
idstamp (if (vectorp kcell-data)
(or (kcell-data:idstamp kcell-data)
(kview:id-increment kotl-kview))
(kview:id-increment kotl-kview)))
(kproperty:set 'idstamp idstamp)
(kproperty:set 'kcell (kcell-data:to-kcell-v3 kcell-data))
(setq kcell-num (1+ kcell-num)))
(search-forward "\n\n" nil t)))

;; Repair any blank lines within cells whose indent has been
;; removed due to packages that delete trailing spaces.
(goto-char (point-min))
(when (re-search-forward label-and-separator-regexp nil t)
(goto-char (1- (match-end 0)))
(defun kfile:insert-attributes-v2 (&optional kview kcell-list)
"Set cell attributes within optional KVIEW for each element in KCELL-LIST.
Also, fix any wrong idstamps. When null, KVIEW defaults to the value
of the local variable, `kotl-kview'.

Assume all cell contents are already in kview and that no cells are hidden."
(unless kview
(setq kview kotl-kview))
(save-excursion
(goto-char (point-min))
(let* ((label-separator (kview:label-separator kview))
(label-separator-regexp (regexp-quote label-separator))
(label-and-separator-regexp
(format "^[ \t]*\\([0-9]\\([.0-9]*[0-9]\\|[A-Za-z0-9]*\\)\\)\\([. \n]\\|%s\\)"
label-separator-regexp))

buffer-read-only
idstamp
kcell-data)
(cl-flet ((kotl-mode:pre-self-insert-command () nil))
(while
(progn
(skip-chars-forward "\n")
;; !! TODO: Won't work if label-type is 'no.
;; Here we search past the cell identifier
;; for the location at which to place cell properties.
;; Be sure not to skip past a period which may terminate the label.
(when (re-search-forward label-and-separator-regexp nil t)
(goto-char (match-end 1))
(setq kcell-data (car kcell-list)
;; Repair invalid idstamps on the fly.
idstamp (if (vectorp kcell-data)
(or (kcell-data:idstamp kcell-data) (kview:id-increment kotl-kview))
(kview:id-increment kotl-kview)))
(kproperty:set 'idstamp idstamp)
(kproperty:set 'kcell (car kcell-list))
(setq kcell-list (cdr kcell-list)))
(search-forward "\n\n" nil t)))))))

(defun kfile:insert-attributes-v3 (&optional kview kcell-vector)
"Set cell attributes within optional KVIEW for each element in KCELL-VECTOR.
Also, fix any wrong label separators, idstamps and line indents. When
null, KVIEW defaults to the value of the local variable, `kotl-kview'. If
KCELL-VECTOR is null, ignore cell attribute setting.

Assume all cell contents are already in kview and that no cells are hidden."
(unless kview
(setq kview kotl-kview))
(save-excursion
(goto-char (point-min))
(let* ((kcell-num 1)
(label-separator (kview:label-separator kview))
(label-separator-regexp (regexp-quote label-separator))
(label-and-separator-regexp
(format "^[ \t]*\\([0-9]\\([.0-9]*[0-9]\\|[A-Za-z0-9]*\\)\\)\\([. \n]\\|%s\\)"
label-separator-regexp))
(cell-start-or-cells-end-regexp
(concat label-and-separator-regexp "\\|\\'"))
mod-flag
buffer-read-only
idstamp
kcell-data
indent
start
end
next)
(cl-flet ((kotl-mode:pre-self-insert-command () nil))
(while (progn
(skip-chars-forward "\n")
;; !! TODO: Won't work if label-type is 'no.
;; Here we search past the cell identifier
;; for the location at which to place cell properties.
;; Be sure not to skip past a period which may terminate the label.
(setq start (point)
indent nil)
(when (re-search-forward cell-start-or-cells-end-regexp nil t)
(goto-char
(if (= (match-end 0) (point-max))
(point-max)
(1- (match-end 0))))
(setq next (point-marker))
(goto-char (match-beginning 0))
(skip-chars-backward "\n")
(setq end (point-marker)) ;; end of prior cell text
(goto-char start)
(while (and (< (point) end) (search-forward "\n\n" end t))
(when (re-search-forward label-and-separator-regexp nil t)
(goto-char (match-end 1))
;; Repair any cells that start with blank lines and have
;; had the label separator removed, typically due to
;; packages that delete trailing spaces.
(unless (looking-at label-separator-regexp)
(setq mod-flag t)
(backward-char 1)
(unless indent (setq indent (kcell-view:indent)))
(insert-char ?\ indent)
(forward-char 1))
(unless (= next (point-max))
(goto-char next))))))

(when (markerp end)
(set-marker end nil))
(when (markerp next)
(set-marker next nil))
(when mod-flag (save-buffer)))))
;; Remove any existing padding between label and first
;; char of cell text and then insert label-separator
(delete-region (point)
(min (+ (point) (length label-separator))
(save-excursion
(skip-chars-forward "^\n") (point))))
(save-excursion (insert label-separator)))

(when kcell-vector
(setq kcell-data (aref kcell-vector kcell-num)
;; Repair invalid idstamps on the fly.
idstamp (if (vectorp kcell-data)
(or (kcell-data:idstamp kcell-data)
(kview:id-increment kotl-kview))
(kview:id-increment kotl-kview)))
(kproperty:set 'idstamp idstamp)
(kproperty:set 'kcell (kcell-data:to-kcell-v3 kcell-data))
(setq kcell-num (1+ kcell-num))))
(search-forward "\n\n" nil t)))

;; Repair any blank lines within cells whose indent has been
;; removed due to packages that delete trailing spaces.
(goto-char (point-min))
(when (re-search-forward label-and-separator-regexp nil t)
(goto-char (1- (match-end 0)))
(while (progn
(skip-chars-forward "\n")
;; !! TODO: Won't work if label-type is 'no.
;; Here we search past the cell identifier for the
;; location at which to place cell properties. Be sure
;; not to skip past a period which may terminate the
;; label.
(setq start (point)
indent nil)
(when (re-search-forward cell-start-or-cells-end-regexp nil t)
(goto-char
(if (= (match-end 0) (point-max))
(point-max)
(1- (match-end 0))))
(setq next (point-marker))
(goto-char (match-beginning 0))
(skip-chars-backward "\n")
(setq end (point-marker)) ;; end of prior cell text
(goto-char start)
(while (and (< (point) end) (search-forward "\n\n" end t))
(setq mod-flag t)
(backward-char 1)
(unless indent (setq indent (kcell-view:indent)))
(insert-char ?\ indent)
(forward-char 1))
(unless (= next (point-max))
(goto-char next))))))

(when (markerp end)
(set-marker end nil))
(when (markerp next)
(set-marker next nil))
(when mod-flag (save-buffer))))))

(defun kfile:narrow-to-kcells ()
"Narrow kotl file to kcell section only."
Expand Down
21 changes: 17 additions & 4 deletions kotl/kotl-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
;; Author: Bob Weiner
;;
;; Orig-Date: 6/30/93
;; Last-Mod: 12-Apr-26 at 11:24:21 by Bob Weiner
;; Last-Mod: 30-Apr-26 at 13:34:27 by Bob Weiner
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
Expand Down Expand Up @@ -32,7 +32,9 @@
(defvar completion-to-accept)
(defvar mwheel-scroll-down-function) ; "mwheel"

(declare-function delete-trailing-whitespace-mode "simple")
(declare-function outline-invisible-in-p "hyperbole")
(declare-function stripspace-local-mode "ext:stripspace")

;;; ************************************************************************
;;; Public variables
Expand Down Expand Up @@ -132,6 +134,16 @@ It provides the following keys:
paragraph-separate
paragraph-start
selective-display-ellipses))
;; Prevent 'delete-trailing-whitespace-mode' from deleting trailing
;; whitespace from any lines within kcells.
(when (bound-and-true-p delete-trailing-whitespace-mode)
(delete-trailing-whitespace-mode 0))
;; Prevent "stripspace" package from deleting trailing whitespace from the
;; first line of cells which are blank. These need to maintain spaces after
;; the relative identifier to ensure proper editing of the first line.
(when (bound-and-true-p stripspace-local-mode)
(stripspace-local-mode 0))
;; Fix any wrong label separators and line indents.
;; Enable Org Table editing minor mode so that necessary key binding
;; overrides are made. If not desired, the user can disable it via
;; `kotl-mode-hook'.
Expand Down Expand Up @@ -719,14 +731,15 @@ With optional prefix argument TOP-P non-nil, refill all cells in the outline."
;; Temporarily expand, then refill cells lacking no-fill property.
(kview:map-expanded-tree (lambda (_kview) (kotl-mode:fill-cell)) kotl-kview top-p))

(defun kotl-mode:just-one-space ()
"Delete all spaces and tabs around point and leave one space."
(defun kotl-mode:just-one-space (&optional N)
"Delete all spaces and tabs around point, leaving one or optional N spaces.
Does not remove any newlines as `just-one-space' does when given a negative N."
(interactive "*")
(save-excursion
(save-restriction
(save-excursion
(narrow-to-region (kotl-mode:beginning-of-line) (kotl-mode:to-end-of-line)))
(just-one-space))))
(just-one-space n))))

(defun kotl-mode:kill-line (&optional arg)
"Kill ARG lines from point."
Expand Down
6 changes: 4 additions & 2 deletions kotl/kvspec.el
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
;; Author: Bob Weiner
;;
;; Orig-Date: 21-Oct-95 at 15:17:07
;; Last-Mod: 21-Nov-23 at 13:20:57 by Bob Weiner
;; Last-Mod: 30-Apr-26 at 10:20:02 by Bob Weiner
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
Expand Down Expand Up @@ -181,7 +181,9 @@ ${hyperb:dir}/kotl/EXAMPLE.kotl#3b19c=042 for details on valid view specs."
(if (string-match "\\([abcd]+\\)" view-spec)
(replace-match "\\1e" t nil view-spec)
(concat "e" view-spec))))
(setq kvspec:current view-spec))
(unless (equal kvspec:current view-spec)
(set-buffer-modified-p t)
(setq kvspec:current view-spec)))
((or (eq view-spec t) (null kvspec:current))
(setq kvspec:current (kvspec:compute))))
;; Update display using current specs.
Expand Down