branch: externals/hyperbole
commit eaf031aa6f660c6dec424a0dfc6ac3a43dc8a91e
Author: Bob Weiner <[email protected]>
Commit: Bob Weiner <[email protected]>

    Redo Koutine idstamp handling for increased efficiency/smaller files
---
 ChangeLog               |  50 +++++++++++++++++++
 kotl/EXAMPLE.kotl       | 130 ++++++++++++++++++++++++------------------------
 kotl/kcell.el           |  70 ++++++++++----------------
 kotl/kfile.el           |  36 ++++++++++----
 kotl/kotl-mode.el       |  35 +++++++------
 kotl/kproperty.el       |   9 +++-
 kotl/kview.el           |  99 +++++++++++++++++++++---------------
 test/kotl-mode-tests.el |  20 ++++----
 8 files changed, 263 insertions(+), 186 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7feb66db8a..b3c444e198 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,53 @@
+2022-04-03  Kathy  <[email protected]>
+
+* test/kotl-mode-tests.el (setup-kotl-mode-example-test): Fix so handles 
multiple buffers with same
+    buffer name prefix.
+
+* kotl/kproperty.el (kproperty:remove-properties): Add and use in 
kcell-view:remove-attr.
+
+* test/kotl-mode-tests.el 
(kotl-mode-copy-kotl-file-updates-root-id-attributes): Change from 'file attr
+    test to 'label-type.
+
+* kotl/kview.el (kcell-view:idstamp-integer): Add to return idstamp as int 
instead of string.
+
+* kotl/kcell.el (kcell-data:create): Add idstamp as 2nd parameter.
+  kotl/kfile.el (kfile:update): Call kcell-data:create with 2nd parameter.
+
+* kotl/kotl-mode.el (kotl-mode:exchange-cells): Give idstamp as second arg to 
kcell-view:set-cell calls.
+                    (kotl-mode:cell-help, kotl-mode:print-attributes, 
kotl-mode:get-cell-attribute):
+    Handle separate idstamp attribute.
+  kotl/kview.el (kcell-view:set-cell, kotl-mode:copy-after, 
kotl-mode:copy-before): Set kcell and
+    idstamp as separate text properties.
+
+* kotl/kview.el (kcell-view:idstamp, kcell-view:get-attr, kcell-view:set-attr,
+    kcell-view:remove-attr, kcell-view:create): Always move to point with 
cell's text properties
+    and handle text property idstamp.
+                (kcell-view:create): Pass idstamp as a parameter.
+                (kview:add-cell):
+  kotl/kcell.el (kcell:create):
+  kotl/kfile.el (kfile:insert-attributes-v2, kfile:insert-attributes-v3): 
Store idstamp as a
+    koutline text property outside the kcell, for efficiency.
+* kotl/kcell.el (kcell:set-idstamp): Remove, use kcell-view:set-attr instead.
+                (kcell:idstamp): Remove, use kcell-view:idstamp instead.
+                (kcell-data:to-kcell-v2, kcell-data:to-kcell-v3): Remove use 
of view-based idstamp.
+
+* kotl/kcell.el (kcell-data:create): idstamp is no longer stored in a kcell's 
property list, so
+    don't try to delete it from the plist when creating the persistent 
representation keyed
+    by the numeric value of the idstamp.
+
+* kotl/kfile.el (kfile:insert-attributes-v2, kfile:insert-attributes-v3): In 
Koutline buffer,
+    store kcell properties as a single 'kcell text property, as previously in 
Hyperbole 7.1.3.
+    This allows other text properties to be stored at the same position 
without being written
+    out as kcell properties.
+  kotl/kcell.el (kcell:create): Stop writing 'kcell attr out to save space.
+                (kcell:is-p): Test for 'creator attr rather than 'kcell since 
no longer
+    writing that attr.
+  kotl/kview.el (kcell-view:cell): Update to use 'kcell text property.
+
+* kotl/kview.el (kview:create):
+  kotl/kfile.el (kfile:write, file:update): Remove read/write of Koutline 
'file attribute;
+    just use buffer-file-name.
+
 2022-04-02  Mats Lidell  <[email protected]>
 
 * test/kotl-mode-tests.el (kotl-mode-move-tree-forward)
diff --git a/kotl/EXAMPLE.kotl b/kotl/EXAMPLE.kotl
index 7b6efacf50..7af7d5e8ef 100644
--- a/kotl/EXAMPLE.kotl
+++ b/kotl/EXAMPLE.kotl
@@ -413,133 +413,133 @@ alpha ;; label-type
 [[0
   (idstamp 0 creator "[email protected]" create-time "20220117:22:23:52" id-counter 
82 file "/Users/bk/Dropbox/emacs/hyperbole/kotl/EXAMPLE.kotl")]
  [20
-  (creator "[email protected]" create-time "19940104:17:38:28" no-fill t 
rear-nonsticky t idstamp 20 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:28" no-fill t)]
  [2
-  (creator "[email protected]" create-time "19940104:17:38:28" no-fill t 
rear-nonsticky t idstamp 2 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:28" no-fill t)]
  [34
-  (creator "[email protected]" create-time "19940610:16:43:55" rear-nonsticky t 
idstamp 34 kcell t)]
+  (creator "[email protected]" create-time "19940610:16:43:55")]
  [35
-  (creator "[email protected]" create-time "19940610:16:44:03" rear-nonsticky t 
idstamp 35 kcell t)]
+  (creator "[email protected]" create-time "19940610:16:44:03")]
  [4
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 4 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [5
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 5 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [6
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 6 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [14
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 14 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [67
-  (creator "[email protected]" create-time "19951028:04:29:13" no-fill t 
rear-nonsticky t idstamp 67 kcell t)]
+  (creator "[email protected]" create-time "19951028:04:29:13" no-fill t)]
  [15
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 15 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [31
-  (creator "[email protected]" create-time "19940306:18:11:43" rear-nonsticky t 
idstamp 31 kcell t)]
+  (creator "[email protected]" create-time "19940306:18:11:43")]
  [7
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 7 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [46
-  (creator "[email protected]" create-time "19950614:21:35:17" rear-nonsticky t 
idstamp 46 kcell t)]
+  (creator "[email protected]" create-time "19950614:21:35:17")]
  [43
-  (creator "[email protected]" create-time "19940610:22:00:46" rear-nonsticky t 
idstamp 43 kcell t)]
+  (creator "[email protected]" create-time "19940610:22:00:46")]
  [22
-  (creator "[email protected]" create-time "19940127:22:41:42" rear-nonsticky t 
idstamp 22 kcell t)]
+  (creator "[email protected]" create-time "19940127:22:41:42")]
  [82
-  (no-fill t create-time "20220126:04:52:26" creator "[email protected]" idstamp 82 
kcell t fontified t)]
+  (creator "[email protected]" create-time "20220126:04:52:26" no-fill t fontified 
t)]
  [32
-  (creator "[email protected]" create-time "19940610:16:31:28" rear-nonsticky t 
idstamp 32 kcell t)]
+  (creator "[email protected]" create-time "19940610:16:31:28")]
  [41
-  (creator "[email protected]" create-time "19940610:18:55:09" rear-nonsticky t 
idstamp 41 kcell t)]
+  (creator "[email protected]" create-time "19940610:18:55:09")]
  [42
-  (creator "[email protected]" create-time "19940610:18:55:57" rear-nonsticky t 
idstamp 42 kcell t)]
+  (creator "[email protected]" create-time "19940610:18:55:57")]
  [33
-  (creator "[email protected]" create-time "19940610:16:31:29" rear-nonsticky t 
idstamp 33 kcell t)]
+  (creator "[email protected]" create-time "19940610:16:31:29")]
  [47
-  (creator "[email protected]" create-time "19951022:22:59:26" no-fill t 
rear-nonsticky t idstamp 47 kcell t)]
+  (creator "[email protected]" create-time "19951022:22:59:26")]
  [8
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 8 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [28
-  (creator "[email protected]" create-time "19940128:22:50:44" rear-nonsticky t 
idstamp 28 kcell t)]
+  (creator "[email protected]" create-time "19940128:22:50:44")]
  [29
-  (creator "[email protected]" create-time "19940128:22:50:54" rear-nonsticky t 
idstamp 29 kcell t)]
+  (creator "[email protected]" create-time "19940128:22:50:54")]
  [10
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 10 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [30
-  (creator "[email protected]" create-time "19940129:00:27:59" rear-nonsticky t 
idstamp 30 kcell t)]
+  (creator "[email protected]" create-time "19940129:00:27:59")]
  [62
-  (creator "[email protected]" create-time "19951026:08:32:57" no-fill t 
rear-nonsticky t idstamp 62 kcell t)]
+  (creator "[email protected]" create-time "19951026:08:32:57" no-fill t)]
  [70
-  (creator "[email protected]" create-time "19951030:19:18:49" no-fill t 
rear-nonsticky t idstamp 70 kcell t)]
+  (creator "[email protected]" create-time "19951030:19:18:49" no-fill t)]
  [71
-  (creator "[email protected]" create-time "19951030:19:19:40" no-fill t 
rear-nonsticky t idstamp 71 kcell t)]
+  (creator "[email protected]" create-time "19951030:19:19:40" no-fill t)]
  [73
-  (creator "[email protected]" create-time "19951030:19:23:09" no-fill t 
rear-nonsticky t idstamp 73 kcell t)]
+  (creator "[email protected]" create-time "19951030:19:23:09" no-fill t)]
  [63
-  (creator "[email protected]" create-time "19951026:19:31:34" no-fill t 
rear-nonsticky t idstamp 63 kcell t)]
+  (creator "[email protected]" create-time "19951026:19:31:34" no-fill t)]
  [64
-  (creator "[email protected]" create-time "19951026:19:33:01" no-fill t 
rear-nonsticky t idstamp 64 kcell t)]
+  (creator "[email protected]" create-time "19951026:19:33:01" no-fill t)]
  [69
-  (creator "[email protected]" create-time "19951029:06:24:35" no-fill t 
rear-nonsticky t idstamp 69 kcell t)]
+  (creator "[email protected]" create-time "19951029:06:24:35" no-fill t)]
  [68
-  (creator "[email protected]" create-time "19951029:06:24:27" no-fill t 
rear-nonsticky t idstamp 68 kcell t)]
+  (creator "[email protected]" create-time "19951029:06:24:27" no-fill t)]
  [65
-  (creator "[email protected]" create-time "19951026:19:33:08" no-fill t 
rear-nonsticky t idstamp 65 kcell t)]
+  (creator "[email protected]" create-time "19951026:19:33:08" no-fill t)]
  [66
-  (creator "[email protected]" create-time "19951026:19:33:15" no-fill t 
rear-nonsticky t idstamp 66 kcell t)]
+  (creator "[email protected]" create-time "19951026:19:33:15" no-fill t)]
  [77
-  (creator "[email protected]" create-time "19980226:19:54:44" no-fill t 
rear-nonsticky t idstamp 77 kcell t)]
+  (creator "[email protected]" create-time "19980226:19:54:44" no-fill t)]
  [48
-  (creator "[email protected]" create-time "19951023:05:55:19" no-fill t 
rear-nonsticky t idstamp 48 kcell t)]
+  (creator "[email protected]" create-time "19951023:05:55:19" no-fill t)]
  [57
-  (creator "[email protected]" create-time "19951023:10:07:06" no-fill t 
rear-nonsticky t idstamp 57 kcell t)]
+  (creator "[email protected]" create-time "19951023:10:07:06" no-fill t)]
  [58
-  (creator "[email protected]" create-time "19951023:10:07:26" no-fill t 
rear-nonsticky t idstamp 58 kcell t)]
+  (creator "[email protected]" create-time "19951023:10:07:26" no-fill t)]
  [49
-  (creator "[email protected]" create-time "19951023:05:55:55" no-fill t 
rear-nonsticky t idstamp 49 kcell t)]
+  (creator "[email protected]" create-time "19951023:05:55:55" no-fill t)]
  [55
-  (creator "[email protected]" create-time "19951023:08:56:41" no-fill t 
rear-nonsticky t idstamp 55 kcell t)]
+  (creator "[email protected]" create-time "19951023:08:56:41" no-fill t)]
  [50
-  (creator "[email protected]" create-time "19951023:05:57:26" no-fill t 
rear-nonsticky t idstamp 50 kcell t)]
+  (creator "[email protected]" create-time "19951023:05:57:26" no-fill t)]
  [51
-  (creator "[email protected]" create-time "19951023:05:58:31" no-fill t 
rear-nonsticky t idstamp 51 kcell t)]
+  (creator "[email protected]" create-time "19951023:05:58:31" no-fill t)]
  [56
-  (creator "[email protected]" create-time "19951023:08:57:09" no-fill t 
rear-nonsticky t idstamp 56 kcell t)]
+  (creator "[email protected]" create-time "19951023:08:57:09" no-fill t)]
  [52
-  (creator "[email protected]" create-time "19951023:05:59:59" no-fill t 
rear-nonsticky t idstamp 52 kcell t)]
+  (creator "[email protected]" create-time "19951023:05:59:59" no-fill t)]
  [53
-  (creator "[email protected]" create-time "19951023:06:00:48" no-fill t 
rear-nonsticky t idstamp 53 kcell t)]
+  (creator "[email protected]" create-time "19951023:06:00:48" no-fill t)]
  [54
-  (creator "[email protected]" create-time "19951023:06:05:50" no-fill t 
rear-nonsticky t idstamp 54 kcell t)]
+  (creator "[email protected]" create-time "19951023:06:05:50" no-fill t)]
  [26
-  (creator "[email protected]" create-time "19940128:03:56:23" rear-nonsticky t 
idstamp 26 kcell t)]
+  (creator "[email protected]" create-time "19940128:03:56:23")]
  [27
-  (creator "[email protected]" create-time "19940128:22:36:54" rear-nonsticky t 
idstamp 27 kcell t)]
+  (creator "[email protected]" create-time "19940128:22:36:54")]
  [59
-  (creator "[email protected]" create-time "19951024:03:40:05" no-fill t 
rear-nonsticky t idstamp 59 kcell t)]
+  (creator "[email protected]" create-time "19951024:03:40:05" no-fill t)]
  [60
-  (creator "[email protected]" create-time "19951024:03:40:13" no-fill t 
rear-nonsticky t idstamp 60 kcell t)]
+  (creator "[email protected]" create-time "19951024:03:40:13" no-fill t)]
  [61
-  (creator "[email protected]" create-time "19951024:03:40:42" no-fill t 
rear-nonsticky t idstamp 61 kcell t)]
+  (creator "[email protected]" create-time "19951024:03:40:42" no-fill t)]
  [1
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 1 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [11
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 11 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [80
-  (no-fill t create-time "20220117:22:26:40" creator "[email protected]" idstamp 80 
kcell t fontified t)]
+  (no-fill t create-time "20220117:22:26:40" creator "[email protected]")]
  [81
-  (no-fill t create-time "20220117:22:26:47" creator "[email protected]" idstamp 81 
kcell t fontified t)]
+  (no-fill t create-time "20220117:22:26:47" creator "[email protected]")]
  [78
-  (no-fill t create-time "20220117:22:26:33" creator "[email protected]" idstamp 78 
kcell t fontified t)]
+  (no-fill t create-time "20220117:22:26:33" creator "[email protected]")]
  [12
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 12 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [44
-  (creator "[email protected]" create-time "19940728:21:56:49" rear-nonsticky t 
idstamp 44 kcell t)]
+  (creator "[email protected]" create-time "19940728:21:56:49")]
  [36
-  (creator "[email protected]" create-time "19940610:16:49:34" rear-nonsticky t 
idstamp 36 kcell t)]
+  (creator "[email protected]" create-time "19940610:16:49:34")]
  [37
-  (creator "[email protected]" create-time "19940610:16:50:02" rear-nonsticky t 
idstamp 37 kcell t)]
+  (creator "[email protected]" create-time "19940610:16:50:02")]
  [38
-  (creator "[email protected]" create-time "19940610:16:50:13" rear-nonsticky t 
idstamp 38 kcell t)]
+  (creator "[email protected]" create-time "19940610:16:50:13")]
  [13
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 13 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  [16
-  (creator "[email protected]" create-time "19940104:17:38:29" rear-nonsticky t 
idstamp 16 kcell t)]
+  (creator "[email protected]" create-time "19940104:17:38:29")]
  nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil]
diff --git a/kotl/kcell.el b/kotl/kcell.el
index be35508882..95b721797f 100644
--- a/kotl/kcell.el
+++ b/kotl/kcell.el
@@ -2,8 +2,8 @@
 ;;
 ;; Author:       Bob Weiner
 ;;
-;; Orig-Date:    5/1/1993
-;; Last-Mod:     12-Feb-22 at 19:02:00 by Bob Weiner
+;; Orig-Date:     1-May-93
+;; Last-Mod:      3-Apr-22 at 16:23:56 by Bob Weiner
 ;;
 ;; Copyright (C) 1993-2021  Free Software Foundation, Inc.
 ;; See the "../HY-COPY" file for license information.
@@ -12,9 +12,13 @@
 
 ;;; Commentary:
 ;;
-;;   Defines kcells, nodes in Koutlines, along with a persistent representation
-;;   called kcell-data for writing to files.  Node text content is stored
-;;   separately in kview for efficiency. 
+;;   Defines kcells, in-memory, individually addressable elements of Koutlines,
+;;   along with a persistent representation called kcell-data for writing to
+;;   files.  Node text content is stored separately in the kview for 
efficiency.
+;;
+;;   For compatibility between kcell and kcell-data representations,
+;;   the unique per Koutline permanent idstamp for each kcell is also stored
+;;   separately.  This also allows fast retrieval.
 
 ;;; Code:
 ;;; ************************************************************************
@@ -37,42 +41,33 @@ Add to this list but don't remove any of the default 
elements.")
 ;;; ************************************************************************
 
 ;;;
-;;; kcell
+;;; kcell - In-memory representation of Koutline cells
 ;;;
 
 (defun kcell:copy (kcell)
   "Return a copy of KCELL."
   (copy-tree kcell))
 
-(defun kcell:create (idstamp &optional plist)
-  "Return a new kcell which has permanent IDSTAMP (an integer) and optional 
additional property list, PLIST.
+(defun kcell:create (&optional plist)
+  "Return a new kcell with optional property list, PLIST.
 User id of `creator' of cell and `create-time' are added to cell's PLIST if
 not already there."
-  (unless (klabel:idstamp-p idstamp)
-      (error "(kcell:create): Invalid `idstamp' argument: '%s'" idstamp))
   (nconc
-   (unless (memq 'kcell plist)
-     (list 'kcell t))
-   (unless (memq 'idstamp plist)
-     (list 'idstamp idstamp))
    (unless (memq 'creator plist)
      (list 'creator hyperb:user-email
           'create-time (htz:date-sortable-gmt)))
    plist))
 
 (defun kcell:create-top (&optional top-cell-attributes)
-  "Return a new koutline top cell optionally attached to FILE with current 
idstamp COUNTER."
-  (kcell:create 0 top-cell-attributes))
+  "Return a new koutline top cell with optional property list of 
TOP-CELL-ATTRIBUTES.
+The idstamp of the top cell is always 0 and this cell stores the 
idstamp-counter."
+  (kcell:create top-cell-attributes))
 
 (defalias 'kcell:get-attr 'plist-get)
 
-(defun kcell:idstamp (kcell)
-  "Return permanent idstamp of KCELL as an integer."
-  (kcell:get-attr kcell 'idstamp))
-
 (defun kcell:is-p (object)
   "Is OBJECT a kcell?"
-  (and (listp object) (plist-get object 'kcell)))
+  (and (listp object) (plist-get object 'creator)))
 
 (defalias 'kcell:plist 'identity)
 
@@ -183,25 +178,20 @@ Augment capabilities not yet implemented and ignored for 
now:
   "Store the current user's id as the creator of KCELL."
   (kcell:set-attr kcell 'creator hyperb:user-email))
 
-(defun kcell:set-idstamp (kcell idstamp)
-  "Set KCELL's permanent IDSTAMP (an integer) and return IDSTAMP."
-  (kcell:set-attr kcell 'idstamp idstamp)
-  (kcell:idstamp kcell))
-
 ;;;
-;;; kcell-data - Persistent representation of kotl cells (written to files).
+;;; kcell-data - Persistent representation of Koutline cells (written to files)
 ;;;
 
-(defun kcell-data:create (cell)
-  "Given a kotl CELL, return a kcell-data structure to write to a file.
+(defun kcell-data:create (cell idstamp)
+  "Given a kotl CELL and IDSTAMP (an integer), return a kcell-data structure 
to write to a file.
 If CELL, its idstamp, or its property list are nil, this repairs the cell by
 assuming it is the cell at point and filling in the missing information."
-   (let ((idstamp (kcell:idstamp cell))
-        (plist (nthcdr 2 (kcell:plist cell))))
+   (let ((plist (kcell:plist cell)))
      (if (and cell idstamp plist)
         (vector idstamp plist)
        (kcell-data:create
-       (kcell:create (or idstamp (kview:id-increment kview)) plist)))))
+       (kcell:create plist)
+       (or idstamp (kview:id-increment kview))))))
 
 (defun kcell-data:idstamp (kcell-data)
   (aref kcell-data 0))
@@ -214,21 +204,13 @@ assuming it is the cell at point and filling in the 
missing information."
 
 (defun kcell-data:to-kcell-v2 (kcell-data)
   (if (vectorp kcell-data)
-      (kcell:create
-       ;; Repair invalid idstamps on the fly.
-       (or (kcell-data:idstamp kcell-data) (kview:id-increment kview))
-       (kcell-data:plist-v2 kcell-data))
-    ;; Repair invalid cells on the fly.
-    (kcell:create (kview:id-increment kview))))
+      (kcell:create (kcell-data:plist-v2 kcell-data))
+    (kcell:create)))
 
 (defun kcell-data:to-kcell-v3 (kcell-data)
   (if (vectorp kcell-data)
-      (kcell:create
-       ;; Repair invalid idstamps on the fly.
-       (or (kcell-data:idstamp kcell-data) (kview:id-increment kview))
-       (kcell-data:plist-v3 kcell-data))
-    ;; Repair invalid cells on the fly.
-    (kcell:create (kview:id-increment kview))))
+      (kcell:create (kcell-data:plist-v3 kcell-data))
+    (kcell:create)))
 
 (provide 'kcell)
 
diff --git a/kotl/kfile.el b/kotl/kfile.el
index 4c906f7bb2..ba7a80fd4b 100644
--- a/kotl/kfile.el
+++ b/kotl/kfile.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    10/31/93
-;; Last-Mod:     12-Feb-22 at 10:42:20 by Mats Lidell
+;; Last-Mod:      3-Apr-22 at 16:17:53 by Bob Weiner
 ;;
 ;; Copyright (C) 1993-2021  Free Software Foundation, Inc.
 ;; See the "../HY-COPY" file for license information.
@@ -258,7 +258,7 @@ If V3-FLAG is true, read as a version-3 buffer."
 Leave outline file expanded with structure data showing unless optional
 VISIBLE-ONLY-P is non-nil.  Signal an error if kotl is not attached to a file."
   (let* ((top (kview:top-cell kview))
-        (file (kcell:get-attr top 'file))
+        (file buffer-file-name)
         (label-type (kview:label-type kview))
         (label-min-width (kview:label-min-width kview))
         (label-separator (kview:label-separator kview))
@@ -285,13 +285,13 @@ VISIBLE-ONLY-P is non-nil.  Signal an error if kotl is 
not attached to a file."
          (setq cell (kcell-view:cell))
          (aset kcell-data
                kcell-num
-               (kcell-data:create cell))
+               (kcell-data:create cell (kcell-view:idstamp-integer)))
          (setq kcell-num (1+ kcell-num)))
        kview t)
       ;; Save top cell, 0, last since above loop may increment the total
       ;; number of cells counter stored in it, if any invalid cells are
       ;; encountered.
-      (aset kcell-data 0 (kcell-data:create top))
+      (aset kcell-data 0 (kcell-data:create top 0))
       (setq id-counter (kcell:get-attr top 'id-counter))
       ;;
       (widen)
@@ -342,7 +342,6 @@ VISIBLE-ONLY-P is non-nil.  Signal an error if kotl is not 
attached to a file."
   (when (and (file-directory-p file) buffer-file-name)
     (setq file (concat (file-name-as-directory file)
                       (file-name-nondirectory buffer-file-name))))
-  (kcell:set-attr (kview:top-cell kview) 'file file)
   (set-visited-file-name file)
   ;; Set-visited-file-name clears local-write-file-hooks that we use to save
   ;; koutlines properly, so reinitialize local variables.
@@ -390,7 +389,9 @@ included in the 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)
+  (let (buffer-read-only
+       idstamp
+       kcell-data)
     (while
        (progn
          (skip-chars-forward "\n")
@@ -399,16 +400,24 @@ hidden."
          ;; 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)
-           (kproperty:add-properties (car kcell-list))
+           (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 kview))
+                           (kview:id-increment 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.
+  "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)
-       (buffer-read-only))
+       buffer-read-only
+       idstamp
+       kcell-data)
     (while
        (progn
          (skip-chars-forward "\n")
@@ -417,8 +426,13 @@ hidden."
          ;; 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)
-           (kproperty:add-properties
-            (kcell-data:to-kcell-v3 (aref kcell-vector kcell-num)))
+           (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 kview))
+                           (kview:id-increment 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)))))
 
diff --git a/kotl/kotl-mode.el b/kotl/kotl-mode.el
index 7b61253ce2..33b8aa04ad 100644
--- a/kotl/kotl-mode.el
+++ b/kotl/kotl-mode.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    6/30/93
-;; Last-Mod:     20-Mar-22 at 22:34:26 by Bob Weiner
+;; Last-Mod:      3-Apr-22 at 23:08:47 by Bob Weiner
 ;;
 ;; Copyright (C) 1993-2021  Free Software Foundation, Inc.
 ;; See the "../HY-COPY" file for license information.
@@ -1033,8 +1033,7 @@ Leave point at the start of the root cell of the new 
tree."
   ;; Alter the copied tree so each cell appears to be newly created.
   (kview:map-tree
    (lambda (view)
-     (kcell-view:set-cell
-      (kcell:create (kview:id-increment view))))
+     (kcell-view:set-cell (kcell:create) (kview:id-increment view)))
    kview))
 
 (defun kotl-mode:copy-before (from-cell-ref to-cell-ref parent-p)
@@ -1059,8 +1058,7 @@ Leave point at the start of the root cell of the new 
tree."
   ;; Alter the copied tree so each cell appears to be newly created.
   (kview:map-tree
    (lambda (view)
-     (kcell-view:set-cell
-      (kcell:create (kview:id-increment view))))
+     (kcell-view:set-cell (kcell:create) (kview:id-increment view)))
    kview))
 
 (defun kotl-mode:move-after (from-cell-ref to-cell-ref child-p
@@ -2309,13 +2307,13 @@ to one level and kotl-mode:refill-flag is treated as 
true."
       ;; Save cell-1 attributes
       (kotl-mode:goto-cell cell-ref-1 t)
       (setq kcell-1 (kcell-view:cell)
-           idstamp-1 (kcell-view:idstamp)
+           idstamp-1 (kcell-view:idstamp-integer)
            contents-1 (kcell-view:contents))
       ;;
       ;; Save cell-2 attributes
       (kotl-mode:goto-cell cell-ref-2 t)
       (setq kcell-2 (cl-copy-list (kcell-view:cell))
-           idstamp-2 (kcell-view:idstamp)
+           idstamp-2 (kcell-view:idstamp-integer)
            contents-2 (kcell-view:contents))
 
       ;; Substitute cell-1 contents into cell-2 location.
@@ -2345,19 +2343,19 @@ to one level and kotl-mode:refill-flag is treated as 
true."
        ;;
        (kotl-mode:goto-cell cell-ref-2 t)
        ;; Set kcell properties.
-       (kcell-view:set-cell kcell-1)
+       (kcell-view:set-cell kcell-1 idstamp-1)
        ;; If idstamp labels are on, then must exchange labels in view.
        (when (eq (kview:label-type kview) 'id)
-         (klabel:set idstamp-1)))
+         (klabel:set (format "0%d" idstamp-1))))
 
       ;;
       ;; Substitute cell-2 attributes into cell-1 location.
       ;;
       ;; Set kcell properties.
-      (kcell-view:set-cell kcell-2)
+      (kcell-view:set-cell kcell-2 idstamp-2)
       ;; If idstamp labels are on, then must exchange labels in view.
       (when (eq (kview:label-type kview) 'id)
-       (klabel:set idstamp-2)))))
+       (klabel:set (format "0%d" idstamp-2))))))
 
 (defun kotl-mode:kill-contents (arg)
   "Kill contents of cell from point to cell end.
@@ -2937,7 +2935,8 @@ See also the documentation for 
`kotl-mode:cell-attributes'."
        (if (or (member cell-ref '("0" 0))
                (<= cells-flag 0))
            (progn
-             (hattr:report (kcell:plist (kview:top-cell kview)))
+             (hattr:report (append '(idstamp 0)
+                                   (kcell:plist (kview:top-cell kview))))
              (terpri)
              (cond ((= cells-flag 1) nil)
                    ((> cells-flag 1)
@@ -2959,9 +2958,13 @@ ATTRIBUTE and ignore any value of POS.
 When called interactively, it displays the value in the minibuffer."
   (interactive "SCurrent cell attribute to get: ")
   (let ((value
-        (if top-cell-flag
+        (if (eq attribute 'idstamp)
+            (if top-cell-flag
+                0
+              (kproperty:get (kcell-view:plist-point pos) attribute))
+          (if top-cell-flag
             (kcell:get-attr (kview:top-cell kview) attribute)
-          (kcell-view:get-attr attribute pos))))
+          (kcell-view:get-attr attribute pos)))))
     (when (called-interactively-p 'interactive)
       (message "Attribute \"%s\" = `%s' in cell <%s>."
               attribute value (if top-cell-flag
@@ -3204,7 +3207,9 @@ upon the current view."
                       (progn (kview:end-of-actual-line)
                              (point)))))
   (terpri)
-  (hattr:report (kcell:plist (kcell-view:cell)))
+  (hattr:report
+   (append (list 'idstamp (kcell-view:idstamp-integer))
+          (kcell:plist (kcell-view:cell))))
   (terpri))
 
 (put 'outline 'reveal-toggle-invisible 'kotl-mode:reveal-toggle-invisible)
diff --git a/kotl/kproperty.el b/kotl/kproperty.el
index 3c0e395898..272b5b9135 100644
--- a/kotl/kproperty.el
+++ b/kotl/kproperty.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    7/27/93
-;; Last-Mod:     12-Feb-22 at 10:42:20 by Mats Lidell
+;; Last-Mod:      3-Apr-22 at 18:33:09 by Bob Weiner
 ;;
 ;; Copyright (C) 1993-2021  Free Software Foundation, Inc.
 ;; See the "../HY-COPY" file for license information.
@@ -31,6 +31,11 @@
   (kproperty:put (point) (min (+ 2 (point)) (point-max))
                 plist))
 
+(defun kproperty:remove-properties (plist)
+  "Remove properties at point and the following character from PLIST."
+  (kproperty:remove (point) (min (+ 2 (point)) (point-max))
+                plist))
+
 (defun kproperty:all-positions (property value)
   "Return a list of all non-narrowed buffer positions of kcells with PROPERTY 
set to VALUE, else nil.
 Use (kcell-view:start <position>) on each returned <position> to get
@@ -80,7 +85,7 @@ properties."
 The optional fourth argument, OBJECT, is the string or buffer containing the
 text.  PROPERTY-LIST should be a plist; if the value of a property is
 non-nil, then only a property with a matching value will be removed.
-Returns t if any property was changed, nil otherwise."
+Return t if any property was changed, nil otherwise."
   (let ((changed) plist property value next)
     (while property-list
       (setq property (car property-list)
diff --git a/kotl/kview.el b/kotl/kview.el
index b14d656502..8b665acea5 100644
--- a/kotl/kview.el
+++ b/kotl/kview.el
@@ -3,7 +3,7 @@
 ;; Author:       Bob Weiner
 ;;
 ;; Orig-Date:    6/30/93
-;; Last-Mod:     13-Feb-22 at 19:50:05 by Mats Lidell
+;; Last-Mod:      3-Apr-22 at 19:00:16 by Bob Weiner
 ;;
 ;; Copyright (C) 1993-2021  Free Software Foundation, Inc.
 ;; See the "../HY-COPY" file for license information.
@@ -113,7 +113,7 @@ Return t unless no such cell."
 
 (defun kcell-view:cell (&optional pos)
   "Return kcell at optional POS or point."
-  (kproperty:properties (kcell-view:plist-point pos)))
+  (kproperty:get (kcell-view:plist-point pos) 'kcell))
 
 (defun kcell-view:cell-from-ref (cell-ref)
   "Return a kcell referenced by CELL-REF, a cell label, id string or integer 
idstamp.
@@ -217,11 +217,14 @@ Any cell that is invisible is also collapsed as indicated 
by a call to
        (concat "\\([\n\r]\\)" (make-string indent ?\ ))
        (buffer-substring start end) "\\1"))))
 
-(defun kcell-view:create (kview cell contents level klabel &optional no-fill)
-  "Insert into KVIEW at point, CELL with CONTENTS at LEVEL (1 = first level) 
with KLABEL.
+(defun kcell-view:create (kview cell contents level idstamp klabel &optional 
no-fill)
+  "Insert into KVIEW at point, CELL with CONTENTS at LEVEL (1 = first level) 
with IDSTAMP and KLABEL.
+If the current view displays klabels, then KLABEL should be inserted
+prior to this call, with point following it.
+
 Optional NO-FILL non-nil suppresses filling of cell's contents upon insertion
 or movement."
-  (unless (zerop (kcell:idstamp cell))
+  (unless (zerop idstamp)
     (unless no-fill
       (setq no-fill (kcell:get-attr cell 'no-fill)))
     (let* ((label-min-width (kview:label-min-width kview))
@@ -264,7 +267,8 @@ or movement."
       (insert label-separator)
       (goto-char old-point)
       ;; Add cell's attributes to the text property list at point.
-      (kproperty:add-properties cell)
+      (kproperty:set 'idstamp idstamp)
+      (kproperty:set 'kcell cell)
       (goto-char new-point))))
 
 (defun kcell-view:end (&optional pos)
@@ -321,18 +325,29 @@ Return t unless no such cell."
     found))
 
 (defun kcell-view:get-attr (attribute &optional pos)
-  "Return ATTRIBUTE's value for current cell or cell at optional POS."
+  "Return ATTRIBUTE's value for current cell or cell at optional POS
+Use 0 for POS to retrieve top cell's attributes."
+  (if (eq pos 0)
+      (if (eq attribute 'idstamp)
+         0
+       (kcell:get-attr (kview:top-cell kview) attribute))
+    (save-excursion
+      (goto-char (or pos (kcell-view:plist-point)))
+      (if (eq attribute 'idstamp)
+         (kproperty:get (point) attribute)
+       (kcell:get-attr (kcell-view:cell) attribute)))))
+
+(defun kcell-view:idstamp-integer (&optional pos)
+  "Return idstamp integer >= 0 of cell at optional POS or point."
   (save-excursion
-    (when pos
-      (goto-char pos))
-    (kcell:get-attr (kcell-view:cell) attribute)))
+    (goto-char (or pos (kcell-view:plist-point)))
+    (kproperty:get (point) 'idstamp)))
 
 (defun kcell-view:idstamp (&optional pos)
   "Return idstamp string of cell at optional POS or point."
   (save-excursion
-    (when pos
-      (goto-char pos))
-    (format "0%s" (or (kcell:idstamp (kcell-view:cell)) ""))))
+    (goto-char (or pos (kcell-view:plist-point)))
+    (format "0%s" (or (kproperty:get (point) 'idstamp) ""))))
 
 (defun kcell-view:indent (&optional pos label-sep-len)
   "Return indentation of cell at optional POS or point.
@@ -485,31 +500,40 @@ or is nil), before it is returned."
          (kcell-view:label pos) (kcell-view:idstamp pos)))
 
 (defun kcell-view:remove-attr (attribute &optional pos)
-  "Remove ATTRIBUTE, if any, for current cell or cell at optional POS."
+  "Remove ATTRIBUTE, if any, for current cell or cell at optional POS.  Return 
the modified cell."
   (interactive "*SAttribute to remove: ")
-  (save-excursion
-    (when pos
-      (goto-char pos))
-
-    (let ((kcell (kcell:remove-attr (kcell-view:cell) attribute)))
-      (when (called-interactively-p 'interactive)
-       (message "Cell <%s> now has no %s attribute."
-                (kcell-view:label) attribute))
+  (unless (eq attribute 'idstamp) ;; Can't remove idstamp
+    (let (mod-cell)
+      (save-excursion
+       (goto-char (or pos (kcell-view:plist-point)))
+       (setq mod-cell (kcell:remove-attr (kcell-view:cell) attribute))
+       (kproperty:add-properties (list 'kcell mod-cell))
+       (when (called-interactively-p 'interactive)
+         (message "Cell <%s> now has no %s attribute."
+                  (kcell-view:label) attribute)))
       kcell)))
 
 (defun kcell-view:set-attr (attribute value &optional pos)
-  "Set ATTRIBUTE's VALUE for current cell or cell at optional POS and return 
the cell."
-  (save-excursion
-    (when pos
-      (goto-char pos))
-    ;; Returns kcell.
-    (kcell:set-attr (kcell-view:cell) attribute value)))
-
-(defun kcell-view:set-cell (kcell)
-  "Attach KCELL property to cell at point."
+  "Set ATTRIBUTE's VALUE for current cell or cell at optional POS and return 
the modified cell.
+Use 0 for POS to set top cell's attributes."
+  (unless (and (eq pos 0) (eq attribute 'idstamp)) ;; top cell idstamp set 
when Koutline is created
+    (save-excursion
+      (goto-char (or pos (kcell-view:plist-point)))
+      (if (eq attribute 'idstamp)
+         (progn (kproperty:set attribute value)
+                (kcell-view:cell))
+       ;; Returns kcell
+       (let ((mod-cell (kcell:set-attr (if (eq pos 0) (kview:top-cell kview) 
(kcell-view:cell))
+                                       attribute value)))
+         (kproperty:add-properties (list 'kcell mod-cell))
+         mod-cell)))))
+
+(defun kcell-view:set-cell (kcell idstamp)
+  "Attach KCELL and IDSTAMP (an integer) properties to cell at point."
   (save-excursion
     (kcell-view:to-label-end)
-    (kproperty:add-properties kcell)))
+    (kproperty:add-properties
+     (list 'idstamp idstamp 'kcell kcell))))
 
 (defun kcell-view:sibling-p (&optional pos visible-p label-sep-len)
   "Return t if cell at optional POS or point has a successor.
@@ -561,8 +585,8 @@ level."
   (let* ((idstamp (if (klabel:idstamp-p klabel)
                      (if (stringp klabel) (string-to-number klabel) klabel)
                    (kview:id-increment kview)))
-        (new-cell (kcell:create idstamp prop-list)))
-    (kcell-view:create kview new-cell contents level klabel no-fill)
+        (new-cell (kcell:create prop-list)))
+    (kcell-view:create kview new-cell contents level idstamp klabel no-fill)
     new-cell))
 
 (defun kview:beginning-of-actual-line ()
@@ -620,11 +644,8 @@ BLANK-LINES, LEVELS-TO-SHOW, and LINES-TO-SHOW may also be 
given, otherwise defa
     ;; Don't recreate view if it exists.
     (unless (and (boundp 'kview) (kview:is-p kview) (eq (kview:buffer kview) 
buf))
       (make-local-variable 'kview)
-      ;; File location may have changed since saved, so always inject the
-      ;; current file name here and update cell count id-counter.
-      (setq top-cell-attributes
-           (plist-put (plist-put top-cell-attributes 'id-counter id-counter)
-                      'file buffer-file-name))
+      ;; Update cell count id-counter.
+      (setq top-cell-attributes (plist-put top-cell-attributes 'id-counter 
id-counter))
       (setq kview
            (list 'kview 'plist
                  (list 'view-buffer (current-buffer)
diff --git a/test/kotl-mode-tests.el b/test/kotl-mode-tests.el
index bc234fd201..8bb18bc515 100644
--- a/test/kotl-mode-tests.el
+++ b/test/kotl-mode-tests.el
@@ -28,8 +28,8 @@
        (progn
          ,@body
          (should (equal major-mode 'kotl-mode))
-         (should (string= (buffer-name (current-buffer)) "EXAMPLE.kotl")))
-     (kill-buffer "EXAMPLE.kotl")))
+         (should (string-prefix-p "EXAMPLE.kotl" (buffer-name 
(current-buffer)))))
+     (kill-buffer (current-buffer))))
 
 (ert-deftest smart-menu-loads-kotl-example ()
   "Loading kotl-mode example file works."
@@ -43,7 +43,7 @@
 (ert-deftest kotl-mode-example-loads-kotl-example ()
   "Loading kotl-mode example file works."
   (setup-kotl-mode-example-test
-   (kotl-mode:example)))
+   (kotl-mode:example nil t)))
 
 (ert-deftest kotl-mode-move-between-cells ()
   "Loading kotl-mode example file works."
@@ -462,21 +462,21 @@
 
 (ert-deftest kotl-mode-copy-kotl-file-updates-root-id-attributes ()
   "Verify root id-attribute is updated when kotl mode is copied."
-  (let ((kotl-file (make-temp-file "hypb" nil ".kotl"))
-        (new-name (concat (make-temp-name (concat temporary-file-directory 
"hypb")) ".kotl")))
+  (let* ((kotl-file (make-temp-file "hypb" nil ".kotl"))
+         (indent (kcell:get-attr (kcell-view:cell-from-ref 0) 'level-indent))
+         (new-name (concat (make-temp-name (concat temporary-file-directory 
"hypb")) ".kotl")))
     (unwind-protect
         (progn
           (find-file kotl-file)
           (insert "a cell")
           (save-buffer)
-          (should (string= (kcell:get-attr (kcell-view:cell-from-ref 0) 'file) 
kotl-file))
+          (should (string= (kcell:get-attr (kcell-view:cell-from-ref 0) 
'level-indent) indent))
 
           (copy-file kotl-file new-name)
           (find-file new-name)
-          (should (string= (kcell:get-attr (kcell-view:cell-from-ref 0) 'file) 
new-name)))
-      (progn
-        (delete-file kotl-file)
-        (delete-file new-name)))))
+          (should (string= (kcell:get-attr (kcell-view:cell-from-ref 0) 
'level-indent) indent)))
+      (delete-file kotl-file)
+      (delete-file new-name))))
 
 (ert-deftest kotl-mode-hide-cell ()
   "Verify cell is hidden and unhidden on `action-key' press."

Reply via email to