[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/treeview 7fc5f30552 03/25: Initial commit of treeview.el
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/treeview 7fc5f30552 03/25: Initial commit of treeview.el |
Date: |
Sat, 10 Sep 2022 17:59:37 -0400 (EDT) |
branch: elpa/treeview
commit 7fc5f30552253627e3c35680b8b6c7b07a5f9a47
Author: Tilman Rassy <tilman.rassy@googlemail.com>
Commit: Tilman Rassy <tilman.rassy@googlemail.com>
Initial commit of treeview.el
---
treeview.el | 867 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 867 insertions(+)
diff --git a/treeview.el b/treeview.el
new file mode 100644
index 0000000000..d41aeab7f3
--- /dev/null
+++ b/treeview.el
@@ -0,0 +1,867 @@
+;;; treeview.el --- A generic tree navigation library -*- lexical-binding: t
-*-
+
+;; Copyright (C) 2018 Tilman Rassy
+
+;; Author: Tilman Rassy <tilman.rassy@googlemail.com>
+;; URL: TODO
+;; Package-Version: 1.0.0
+;; Keywords: lisp, tools, internal, convenience
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Abstract framework for tree navigation. Based on this framework, specific
libraries for
+;; particular hierarchical data can be implemented, for example, file systems.
+;;
+;; A typical tree would look like the following:
+;;
+;; [+] Node 1
+;; [-] Node 2
+;; | [+] Node 21
+;; | [+] Node 22
+;; | [-] Node 23
+;; | | [+] Node 231
+;; | | Leaf 231
+;; | | Leaf 232
+;; | | Leaf 233
+;; | [+] Node 24
+;; [+] Node 3
+;; [+] Node 4
+;;
+;; Each node has a "label". Non-leaf nodes also have a "control". The label
is the text by which
+;; the node is represented. The control is a clickable piece of text in
front of the label which
+;; allows the user to fold or unfold the node. Nodes without children usually
don't have a control.
+;; Nodes can also have an icon, but this is optional. Icons are implemented
as symbols in an icon
+;; font. Control, icon, and label are always displayed in this order, and are
always displayed in
+;; one line. Thus, multi-line nodes are not supported by this library.
+;;
+;; Nodes are represented by lists of the form:
+;;
+;; (NAME PROPS PARENT CHILDREN)
+;;
+;; where the elements have the following meaning:
+;;
+;; NAME The name of the node. A string.
+;;
+;; PROPS The properties of the node. A plist. See below for details.
+;;
+;; PARENT The parent of the node. Another node-representing list.
+;;
+;; CHILDREN The children of the node. List of node-representing lists.
+;;
+;; Node properties are implemented as plists with Lisp symbols as keys. The
following
+;; properties exist:
+;;
+;; node-line-overlay
+;; The overlay containing the node line
+;;
+;; indent-overlay
+;; The overlay containing the node indentation
+;;
+;; label-overlay
+;; The overlay containing the node label
+;;
+;; control-overlay
+;; The overlay containing the node control
+;;
+;; icon-overlay
+;; The overlay containing the node icon
+;;
+;; start A marker at the position where the node begins
+;;
+;; end A marker at the position where the node ends
+;;
+;; state The state of the node. See below for details
+;;
+;; Node states: Each node is in exactly one of three states, which are
represented by the
+;; following Lisp symbols:
+;;
+;; folded-unread The node is folded and has not been unfolded before
+;;
+;; folded-read The node is folded, but has been unfolded before
+;;
+;; expanded The node is expanded
+;;
+;; Initially, a node is in the state 'folded-unread'. If it gets expanded for
the first time,
+;; the state changes to 'expanded'. If it gets folded again, the state
changes to 'folded-read'.
+;; From then, the state toggles between 'expanded' and 'folded-read' each time
the node is
+;; expanded or folded.
+;;
+;; The framework is used by implementing several functions which are defined
as function variables,
+;; thus, variables whose values are function symbols. Here is a list of that
variables:
+;;
+;; treeview-node-leaf-p-function
+;; treeview-update-node-children-function
+;; treeview-get-indent-function
+;; treeview-get-indent-face-function
+;; treeview-get-control-function
+;; treeview-get-control-margin-left-function
+;; treeview-get-control-margin-right-function
+;; treeview-get-icon-function
+;; treeview-get-icon-margin-left-function
+;; treeview-get-icon-margin-right-function
+;; treeview-get-label-function
+;; treeview-get-label-margin-left-function
+;; treeview-get-control-keymap-function
+;; treeview-get-control-face-function
+;; treeview-get-control-mouse-face-function
+;; treeview-get-label-keymap-function
+;; treeview-get-label-face-function
+;; treeview-get-label-mouse-face-function
+;; treeview-get-icon-keymap-function
+;; treeview-get-icon-face-function
+;; treeview-get-icon-mouse-face-function
+;; treeview-suggest-point-pos-in-control-function
+;;
+;; A description of each variable can be found in the repsetive documentation
strings. All
+;; variables are buffer-local. Libraries using this framework should create a
new buffer and
+;; set the variables to particular functions in that buffer. Then, the root
node should be
+;; created and rendered in the buffer by a call to treeview-display-node.
+;;
+;; See library "dir-treeview" for an example where this framework is used.
+
+;;; Code:
+
+(intern "treeview")
+(intern "treeview-node")
+(intern "start")
+(intern "end")
+(intern "node-line-overlay")
+(intern "indent-overlay")
+(intern "control-overlay")
+(intern "icon-overlay")
+(intern "label-overlay")
+(intern "state")
+(intern "folded-unread")
+(intern "folded-read")
+(intern "expanded")
+
+(define-error 'treeview-error "Treeview error" 'error)
+(define-error 'treeview-invalid-node-state-error "Invalid node state"
'treeview-error)
+
+(defun treeview-new-node ()
+ "Create and return a new node.
+The name, parent and children of the new node are nil. The properties have
only
+the entry `state' with the value `folder-unread'."
+ (list nil ;; name
+ (list 'state 'folded-unread) ;; properties
+ nil ;; parent
+ nil)) ;; children
+
+(defun treeview-get-node-name (node)
+ "Return the name of NODE."
+ (car node))
+
+(defun treeview-set-node-name (node name)
+ "Set NODE's name to NAME."
+ (setcar node name))
+
+(defun treeview-get-node-props (node)
+ "Return the properties of NODE."
+ (nth 1 node))
+
+(defun treeview-set-node-props (node props)
+ "Set the properties of NODE to PROPS."
+ (setcar (nthcdr 1 node) props))
+
+(defun treeview-get-node-prop (node key)
+ "Return the property KEY of NODE."
+ (plist-get (treeview-get-node-props node) key))
+
+(defun treeview-set-node-prop (node key value)
+ "Set the property KEY of NODE to VALUE."
+ (let ( (props (treeview-get-node-props node)) )
+ (treeview-set-node-props node (plist-put props key value))))
+
+(defun treeview-get-node-state (node)
+ "Return the state of NODE."
+ (treeview-get-node-prop node 'state))
+
+(defun treeview-set-node-state (node state)
+ "Set the state of NODE to STATE."
+ (unless (memq state '(folded-unread folded-read expanded))
+ (error 'treeview-invalid-node-state-error state))
+ (treeview-set-node-prop node 'state state))
+
+(defun treeview-node-unread-p (node)
+ "Return non-nil if NODE's children have not been read yet.
+This is the case if, and only if, NODE's state is `folded-unread'."
+ (eq (treeview-get-node-state node) 'folded-unread))
+
+(defun treeview-node-folded-p (node)
+ "Return non-nil if NODE is folded.
+This is the case is and only if NODES's state is `folded-unred' or
`folded-read'."
+ (memq (treeview-get-node-state node) '(folded-unread folded-read)))
+
+(defun treeview-node-expanded-p (node)
+ "Return non-nil if NODE is expanded, otherwise nil."
+ (eq (treeview-get-node-state node) 'expanded))
+
+(defun treeview-get-node-parent (node)
+ "Return the parent of NODE."
+ (nth 2 node))
+
+(defun treeview-set-node-parent (node parent)
+ "Set the parent of NODE to PARENT."
+ (setcar (nthcdr 2 node) parent))
+
+(defun treeview-get-node-children (node)
+ "Return the children of NODE."
+ (nth 3 node))
+
+(defun treeview-set-node-children (node children)
+ "Set the children of NODE to CHILDREN."
+ (setcar (nthcdr 3 node) children))
+
+(defun treeview-get-parent-children (node)
+ "Return the children of the parent of NODE.
+If NODE has no parent, return nil."
+ (let ( (parent (treeview-get-node-parent node)) )
+ (if parent (treeview-get-node-children parent) )))
+
+(defun treeview-last-child-p (node)
+ "Return non-nil of NODE is the last child, otherwise nil."
+ (let ( (parent (treeview-get-node-parent node)) )
+ (or (not parent)
+ (let* ( (parent-children (treeview-get-node-children parent))
+ (last-parent-child (if parent-children (car (last
parent-children)))) )
+ (eq last-parent-child node)))))
+
+(defun treeview-parent-is-last-child-p (node)
+ "Return non-nil if the parent of NODE is the last child of its parent,
otherwise nil."
+ (let ( (parent (treeview-get-node-parent node)) )
+ (if parent (treeview-last-child-p parent) t)))
+
+(defvar treeview-node-leaf-p-function
+ (lambda (node)
+ (or (treeview-node-unread-p node) (not (treeview-get-node-children node))))
+ "Function that returns non-nil if NODE is a leaf of the tree.
+The default implementation considers a node to be a leaf if, and only if, the
+node has no children or is unread (i.e., its state is 'folded-unred'.")
+
+(make-variable-buffer-local 'treeview-node-leaf-p-function)
+
+(defun treeview-node-leaf-p (node)
+ "Return non-nil if NODE is a leaf of the tree; otherwise, return nil.
+Calls the buffer local function `treeview-node-leaf-p-function' with one
argument, NODE."
+ (funcall treeview-node-leaf-p-function node))
+
+(defun treeview-put (&rest args)
+ "Insert ARGS at point.
+Each element of ARGS may be a string, a character, nil, or a list. If nil, the
+element is ignored. If a list, the function recursively calls itself."
+ (while args
+ (let ( (arg (car args)) )
+ (if arg (if (listp arg) (apply 'treeview-put arg) (insert arg)))
+ (setq args (cdr args)) )))
+
+(defun treeview-return-nil (_node)
+ "Return nil.
+Default implementation of functions that provide optional data, e.g.,
+`treeview-get-control-face-function'. The argument _NODE is ignored."
+ nil)
+
+(defun treeview--not-nil-or-empty-string-p (str)
+ "Return non-nil if STR is neither nil nor the empty string."
+ (and str (not (string-equal str ""))))
+
+(defvar treeview-update-node-children-function nil
+ "Function that updates the children of a node.
+Called with one argument, the node. For example, if the nodes represent
+directories, this function could re-read the directory to update the children.
+The function should not redisplay the node, this is done automatically.")
+
+(make-variable-buffer-local 'treeview-update-node-children-function)
+
+(defvar treeview-get-indent-function nil
+ "Function to create the indentation before a node.
+Called with one argument, the node. Should return a list of strings. These
are
+concatenated to the indentation.")
+
+(make-variable-buffer-local 'treeview-get-indent-function)
+
+(defvar treeview-get-control-function 'treeview-return-nil
+ "Function to create and return the control of a node.
+Called with one argument, the node. Should return a string or nil. In the
+latter case the node does not get a control.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-control-function)
+
+(defvar treeview-get-control-margin-left-function 'treeview-return-nil
+ "Function to create the left margin of a node control.
+Called with one argument, the node. The return value is inserted with
+`treeview-put'. Thus, the return value must be a string, a character, nil, or
+a list. If nil, the left margin is suppressed.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-control-margin-left-function)
+
+(defvar treeview-get-control-margin-right-function 'treeview-return-nil
+ "Function to create the right margin of a node control.
+Called with one argument, the node. The return value is inserted with
+`treeview-put'. Thus, the return value must be a string, a character, nil, or
+a list. If nil, the right margin is suppressed.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-control-margin-right-function)
+
+(defvar treeview-get-icon-function 'treeview-return-nil
+ "Function to create and return the icon of a node.
+Called with one argument, the node. Should return a string or nil. In the
+latter case the node does not get an icon.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-icon-function)
+
+(defvar treeview-get-icon-margin-left-function 'treeview-return-nil
+ "Function to create the left margin of a node icon.
+Called with one argument, the node. The return value is inserted with
+`treeview-put'. Thus, the return value must be a string, a character, nil, or
+a list. If nil, the left margin is suppressed.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-icon-margin-left-function)
+
+(defvar treeview-get-icon-margin-right-function 'treeview-return-nil
+ "Function to create the right margin of a node icon.
+Called with one argument, the node. The return value is inserted with
+`treeview-put'. Thus, the return value must be a string, a character, nil, or
+a list. If nil, the right margin is suppressed.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-icon-margin-right-function)
+
+(defvar treeview-get-label-function 'treeview-return-nil
+ "Function to create and retrun the label of a node.
+Called with one argument, the node. Should return a string or nil. In the
+latter case the node does not get a label.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-label-function)
+
+(defvar treeview-get-label-margin-left-function 'treeview-return-nil
+ "Function to create the left margin of a node label.
+Called with one argument, the node. The return value is inserted with
+`treeview-put'. Thus, the return value must be a string, a character, nil, or
+a list. If nil, the left margin is suppressed.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-label-margin-left-function)
+
+(defvar treeview-get-control-keymap-function 'treeview-return-nil
+ "Function to get the keymap of the control of a node.
+Called with one argument, the node. The return value is passed as the KEYMAP
+argument to `treeview-make-node-component-overlay'. Thus, the return value
must
+be a keymap or nil.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-control-keymap-function)
+
+(defvar treeview-get-indent-face-function 'treeview-return-nil
+ "Function to get the face of the indentation of a node.
+Called with one argument, the node. The return value is passed as the FACE
+argument to `treeview-make-node-component-overlay'. Thus, the return value
must
+be a face or nil.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-indent-face-function)
+
+(defvar treeview-get-control-face-function 'treeview-return-nil
+ "Function to get the face of the control of a node.
+Called with one argument, the node. The return value is passed as the FACE
+argument to `treeview-make-node-component-overlay'. Thus, the return value
must
+be a face or nil.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-control-face-function)
+
+(defvar treeview-get-control-mouse-face-function 'treeview-return-nil
+ "Function to get the mouse face of the control of a node.
+Called with one argument, the node. The return value is passed as the
+MOUSE-FACE argument to `treeview-make-node-component-overlay'. Thus, the
return
+value must be a face or nil.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-control-mouse-face-function)
+
+(defvar treeview-get-label-keymap-function 'treeview-return-nil
+ "Function to get the keymap of the label of a node.
+Called with one argument, the node. The return value is passed as the KEYMAP
+argument to `treeview-make-node-component-overlay'. Thus, the return value
must
+be a keymap or nil.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-label-keymap-function)
+
+(defvar treeview-get-label-face-function 'treeview-return-nil
+ "Function to get the mouse face of the label of a node.
+Called with one argument, the node. The return value is passed as the
+MOUSE-FACE argument to `treeview-make-node-component-overlay'. Thus, the
+return value must be a face or nil.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-label-face-function)
+
+(defvar treeview-get-label-mouse-face-function 'treeview-return-nil
+ "Function to get the mouse face of the label of a node.
+Called with one argument, the node. The return value is passed as the
+MOUSE-FACE argument to `treeview-make-node-component-overlay'. Thus, the
+return value must be a face or nil.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-label-mouse-face-function)
+
+(defvar treeview-get-icon-keymap-function 'treeview-return-nil
+ "Function to get the keymap of the icon of a node.
+Called with one argument, the node. The return value is passed as the KEYMAP
+argument to `treeview-make-node-component-overlay'. Thus, the return value
must
+be a keymap or nil.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-icon-keymap-function)
+
+(defvar treeview-get-icon-face-function 'treeview-return-nil
+ "Function to get the mouse face of the icon of a node.
+Called with one argument, the node. The return value is passed as the
+MOUSE-FACE argument to `treeview-make-node-component-overlay'. Thus, the
return
+value must be a face or nil.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-icon-face-function)
+
+(defvar treeview-get-icon-mouse-face-function 'treeview-return-nil
+ "Function to get the mouse face of the icon of a node.
+Called with one argument, the node. The return value is passed as the
+MOUSE-FACE argument to `treeview-make-node-component-overlay'. Thus, the
+return value must be a face or nil.
+
+The default implementation is `treeview-return-nil'.")
+
+(make-variable-buffer-local 'treeview-get-icon-mouse-face-function)
+
+(defun treeview-get-node-at-pos (pos)
+ "Return the node at the buffer position POS, or nil if there is no node at
that position."
+ (let ( (overlays (overlays-at pos t))
+ (node nil) )
+ (while (and overlays (not node))
+ (setq node (overlay-get (car overlays) 'treeview-node)
+ overlays (cdr overlays)))
+ node))
+
+(defun treeview-get-node-at-point ()
+ "Return the node at point, or nil if there is no node at point."
+ (treeview-get-node-at-pos (point)))
+
+(defun treeview-get-node-at-event (event)
+ "Return the node at the position of EVENT.
+If there is no node at that position, nil is returned. The function assumes
+that the event occurred in the current buffer, and that the current buffer is a
+treeview buffer. It should be called only if this is guaranteed."
+ (treeview-get-node-at-pos (posn-point (event-start event))))
+
+(defun treeview-first-line-p ()
+ "Return non-nil if point is in the first line of the buffer, otherwise nil."
+ (save-excursion
+ (beginning-of-line)
+ (bobp)))
+
+(defun treeview-last-line-p ()
+ "Return non-nil if point is in the last line of the buffer, otherwise nil."
+ (save-excursion
+ (end-of-line)
+ (eobp)))
+
+(defun treeview-find-node-in-current-line ()
+ "Find and return the node in the current line.
+If there is no node in the current line, return nil."
+ (treeview-get-node-at-pos (point)))
+
+(defun treeview-find-next-node ()
+ "Find and return the next node in the lines following the current line.
+If no such node exists, return nil."
+ (save-excursion
+ (let ( (node nil) )
+ (while (not (or (treeview-last-line-p) node))
+ (forward-line)
+ (setq node (treeview-get-node-at-point)))
+ node)))
+
+(defun treeview-find-previous-node ()
+ "Find and return the previous node.
+This is the closest node in the lines preceeding the current line. If no such
+node exists, return nil."
+ (save-excursion
+ (let ( (node nil) )
+ (while (not (or (treeview-first-line-p) node))
+ (forward-line -1)
+ (setq node (treeview-get-node-at-point)))
+ node)))
+
+(defun treeview-inside-node-p (pos node)
+ "Return non-nil if POS is a position inside NODE, otherwise nil."
+ (and (<= (marker-position (treeview-get-node-prop node 'start)) pos)
+ (<= pos (marker-position (treeview-get-node-prop node 'end)))))
+
+(defun treeview-make-node-component-overlay (node content &optional keymap
face mouse-face)
+ "Create an overlay representing a specific component of a node.
+
+This function is used to create the imdemtation, control, icon, and label
+overlays of nodes. NODE is the node to which the overlay belongs. The
+`treeview-node' property of the overlay is set to NODE. CONTENT is a string.
+It is inserted as the content of the overlay. If non-nil, KEYMAP, FACE, and
+MOUSE-FACE are the keymap, face, and mouse face of the overlay, respectively.
+
+The overlay is inserted at the current point position. Thus, the overlay
+starts where the point was when the function was called. The point is moved
+to the position after the overlay end by this function.
+
+The overlay gets the priority 300.
+
+The function returns the new overlay."
+ (let* ( (start (point))
+ (overlay (progn (treeview-put content) (make-overlay start
(point)))) )
+ (overlay-put overlay 'treeview t)
+ (overlay-put overlay 'treeview-node node)
+ (overlay-put overlay 'priority 300)
+ (if keymap (overlay-put overlay 'keymap keymap))
+ (if face (overlay-put overlay 'face face))
+ (if mouse-face (overlay-put overlay 'mouse-face mouse-face))
+ overlay))
+
+(defun treeview-make-node-line-overlay (node start end)
+ "Create the overlay covering the line of NODE.
+
+NODE is the node to which the overlay belongs. The `treeview-node' property of
+the overlay is set to NODE. START and END are the start and end positions of
+the overlay (integers or markers). They should point to the beginning and end
+of the line containing NODE, respectively.
+
+The overlay gets the priority 200.
+
+The function returns the new overlay."
+ (let ( (overlay (make-overlay start end)) )
+ (overlay-put overlay 'treeview t)
+ (overlay-put overlay 'treeview-node node)
+ (overlay-put overlay 'priority 200)
+ overlay))
+
+(defun treeview-make-text-overlay (text &optional keymap face mouse-face)
+ "Insert TEXT at point and create and return an overlay containing that text.
+If non-nil, KEYMAP, FACE, and MOUSE-FACE become the keymap, face, and mouse
face
+of the overlay, respectively (see overlay documentation in the Emacs Lisp
reference)."
+ (let* ( (start (point))
+ (overlay (progn (insert text) (make-overlay start (point)))) )
+ (if keymap (overlay-put overlay 'keymap keymap))
+ (if face (overlay-put overlay 'face face))
+ (if mouse-face (overlay-put overlay 'mouse-face mouse-face))
+ overlay))
+
+(defun treeview-set-node-start (node &optional pos)
+ "Set the start marker of NODE to POS.
+If POS is nil, do nothing."
+ (if pos (treeview-set-node-prop node 'start (copy-marker pos))))
+
+(defun treeview-set-node-end (node &optional pos type)
+ "Set the end marker of NODE.
+The end marker is set to POS and its insertion type to TYPE (see
+`marker-insertion-type'). POS must be an integer buffer position or a marker,
+and defaults to the current end marker of NODE (this can be used to change the
+latter's insertion type). If POS is nil and its default is also nil, nothing
+is done."
+ (if (not pos) (setq pos (treeview-get-node-prop node 'end)))
+ (if pos (treeview-set-node-prop node 'end (copy-marker pos type))))
+
+(defun treeview-display-node-internal (node &optional append-newline-p)
+ "Display NODE, i.e., render it in the current buffer.
+The node is placed at the current line. All descendent nodes are rendered by
+calling this function recursively. If APPEND-NEWLINE-P is non-nil, a newline
+is appended to the node.
+
+This is an auxiliary function used in `treeview-display-node'."
+ (let ( (start nil)
+ ;; Indentation:
+ (indent (funcall treeview-get-indent-function node))
+ (indent-face (funcall treeview-get-indent-face-function node))
+ (indent-overlay nil)
+ ;; Control:
+ (control-margin-left (funcall
treeview-get-control-margin-left-function node))
+ (control-content (funcall treeview-get-control-function node))
+ (control-keymap (funcall treeview-get-control-keymap-function node))
+ (control-face (funcall treeview-get-control-face-function node))
+ (control-mouse-face (funcall treeview-get-control-mouse-face-function
node))
+ (control-margin-right (funcall
treeview-get-control-margin-right-function node))
+ (control-overlay nil)
+ ;; Icon:
+ (icon-margin-left (funcall treeview-get-icon-margin-left-function
node))
+ (icon-content (funcall treeview-get-icon-function node))
+ (icon-keymap (funcall treeview-get-icon-keymap-function node))
+ (icon-face (funcall treeview-get-icon-face-function node))
+ (icon-mouse-face (funcall treeview-get-icon-mouse-face-function node))
+ (icon-margin-right (funcall treeview-get-icon-margin-right-function
node))
+ (icon-overlay nil)
+ ;; Label:
+ (label-margin-left (funcall treeview-get-label-margin-left-function
node))
+ (label-content (funcall treeview-get-label-function node))
+ (label-keymap (funcall treeview-get-label-keymap-function node))
+ (label-face (funcall treeview-get-label-face-function node))
+ (label-mouse-face (funcall treeview-get-label-mouse-face-function
node))
+ (label-overlay nil)
+ ;; Node line:
+ (node-line-overlay nil) )
+ (beginning-of-line)
+ (setq start (point))
+ (treeview-set-node-start node start)
+ (treeview-set-node-end node start t)
+ ;; Indentation:
+ (when indent
+ (setq indent-overlay
+ (treeview-make-node-component-overlay node indent nil
indent-face)))
+ ;; Control:
+ (treeview-put control-margin-left)
+ (when control-content
+ (setq control-overlay
+ (treeview-make-node-component-overlay node control-content
control-keymap control-face control-mouse-face)))
+ (treeview-put control-margin-right)
+ ;; Icon:
+ (treeview-put icon-margin-left)
+ (when icon-content
+ (setq icon-overlay
+ (treeview-make-node-component-overlay node icon-content
icon-keymap icon-face icon-mouse-face)))
+ (treeview-put icon-margin-right)
+ ;; Label:
+ (treeview-put label-margin-left)
+ (setq label-overlay
+ (treeview-make-node-component-overlay node label-content
label-keymap label-face label-mouse-face))
+ ;; Node line:
+ (setq node-line-overlay (treeview-make-node-line-overlay node start
(point)))
+ (unless (treeview-node-folded-p node)
+ (let ( (children (treeview-get-node-children node)) )
+ (if children (newline))
+ (while children
+ (treeview-display-node-internal (car children) (setq children (cdr
children)))) ))
+ (treeview-set-node-end node nil nil)
+ (if append-newline-p (newline))
+ (treeview-set-node-prop node 'indent-overlay indent-overlay)
+ (treeview-set-node-prop node 'control-overlay control-overlay)
+ (treeview-set-node-prop node 'icon-overlay icon-overlay)
+ (treeview-set-node-prop node 'label-overlay label-overlay)
+ (treeview-set-node-prop node 'node-line-overlay node-line-overlay) ))
+
+(defun treeview-set-node-end-after-display (node)
+ "Set the insertion type of the end marker of NODE and its descendants to t.
+This is an auxiliary function used in `treeview-display-node'."
+ (treeview-set-node-end node nil t)
+ (unless (treeview-node-folded-p node)
+ (let ( (children (treeview-get-node-children node)) )
+ (while children
+ (progn
+ (treeview-set-node-end-after-display (car children))
+ (setq children (cdr children))) ))))
+
+(defun treeview-display-node (node &optional append-newline-p)
+ "Display NODE, i.e., render it in the current buffer.
+
+The node is placed at the current line. All descendent nodes are rendered as
+well unless they are folded. If APPEND-NEWLINE-P is non-nil, a newline is
+appended to the node.
+
+The main implementation is outsourced and split into two other functions:
+`treeview-display-node-internal' and `treeview-set-node-end-after-display'.
+The first one does the rendering, the latter one fixes the
+`marker-insertion-type's of the end markers of the rendered nodes."
+ (let ( (read-only-p buffer-read-only) )
+ (setq buffer-read-only nil)
+ (treeview-display-node-internal node append-newline-p)
+ (treeview-set-node-end-after-display node)
+ (setq buffer-read-only read-only-p) ))
+
+(defun treeview--recursivlely-remove-overlays (node)
+ "Remove all overlays of NODE and its descendents."
+ (let ( (overlay-prop-keys '(indent-overlay control-overlay icon-overlay
label-overlay node-line-overlay)) )
+ (while overlay-prop-keys
+ (let* ( (overlay-prop-key (car overlay-prop-keys))
+ (overlay (treeview-get-node-prop node overlay-prop-key)) )
+ (treeview-set-node-prop node overlay-prop-key nil)
+ (if overlay (delete-overlay overlay))
+ (setq overlay-prop-keys (cdr overlay-prop-keys)) )))
+ (let ( (children (treeview-get-node-children node)) )
+ (while children
+ (progn
+ (treeview--recursivlely-remove-overlays (car children))
+ (setq children (cdr children)) ))) )
+
+(defun treeview-erase-node (node)
+ "Remove NODE and all its descendents from the display in the buffer.
+
+The 'start' and 'end' properties of NODE are set to nil. Except this, the
+internal representation of the tree is not altered. Neither NODE or its
+descendents are removed from the children of their respective parents.
+
+The main purpose of this function is to implement the
+`treeview-redisplay-node' function."
+ (let* ( (read-only-p buffer-read-only)
+ (start (treeview-get-node-prop node 'start))
+ (end (treeview-get-node-prop node 'end)) )
+ (treeview--recursivlely-remove-overlays node)
+ (setq buffer-read-only nil)
+ (delete-region start end)
+ (treeview-set-node-prop node 'start nil)
+ (treeview-set-node-prop node 'end nil)
+ (setq buffer-read-only read-only-p)))
+
+(defun treeview-redisplay-node (node)
+ "Redisplay NODE.
+
+NODE is erased by `treeview-erase-node' and displayed again by
+`treeview-display-node'. This function can be used to update the display of a
+node after it has changed."
+ (let ( (start-marker (treeview-get-node-prop node 'start)) )
+ (treeview-erase-node node)
+ (goto-char start-marker)
+ (treeview-display-node node)))
+
+(defun treeview-expand-node (node)
+ "Expands NODE."
+ (treeview-set-node-state node 'expanded)
+ (funcall treeview-update-node-children-function node))
+
+(defun treeview-fold-node (node)
+ "Folds NODE."
+ (treeview-set-node-state node 'folded-read)
+ (funcall treeview-update-node-children-function node))
+
+(defun treeview-update-node (node)
+ "Update NODE.
+
+If NODE is not folded, the following is done: First, the function calls
+`treeview-update-node-children-function' for NODE. Then, the function
+calls itself for all children of NODE.
+
+If NODE is not folded, does nothing."
+ (unless (treeview-node-folded-p node)
+ (funcall treeview-update-node-children-function node)
+ (let ( (children (treeview-get-node-children node)) )
+ (while children
+ (progn
+ (treeview-update-node (car children))
+ (setq children (cdr children))) )) ))
+
+(defun treeview-toggle-node-state (node)
+ "Unfolds NODE if it is folded, folds it if it is unfolded."
+ (if (treeview-node-folded-p node) (treeview-expand-node node)
(treeview-fold-node node))
+ (treeview-redisplay-node node))
+
+(defun treeview-toggle-node-state-at-event (event)
+ "Toggle the state of the node where EVENT occurred.
+
+EVENT may for example be a mouse click. If there there is no node at the
+position where EVENT occurred, does nothing.
+
+See also `treeview-toggle-node-state'."
+ (interactive "@e")
+ (let ( (node (treeview-get-node-at-event event)) )
+ (when node
+ (treeview-toggle-node-state node)
+ (mouse-set-point event))))
+
+(defun treeview-toggle-node-state-at-point ()
+ "Toggle the state of the node at point.
+If there is no node at point, does nothing.
+
+See also `treeview-toggle-node-state'."
+ (interactive)
+ (let ( (node (treeview-get-node-at-pos (point))) )
+ (if node
+ (let ( (old-pos (point)) )
+ (treeview-toggle-node-state (treeview-get-node-at-pos (point)))
+ (goto-char old-pos)))))
+
+(defun treeview-get-overlay-center (overlay)
+ "Return the position of the center of OVERLAY."
+ (let* ( (start (overlay-start overlay))
+ (end (overlay-end overlay))
+ (offset (/ (- end start) 2)) )
+ (+ start offset)))
+
+(defvar treeview-suggest-point-pos-in-control-function
'treeview-get-overlay-center
+ "Function to suggest an appropriate position for the point in a node control.
+Called with one argument, the control overlay. Auxiliary for implementing
+functions with move the point to the control of a node.")
+
+(make-variable-buffer-local 'treeview-suggest-point-pos-in-control-function)
+
+(defun treeview-place-point-in-node (node)
+ "Move the point to an appropriate position in NODE.
+
+If NODE has a control, point is placed at the position obtained by calling
+`treeview-suggest-point-pos-in-control-function' with the control overlay as
+argument. Otherwise, point is placed at the beginning of the label."
+ (goto-char
+ (or
+ ;; Control:
+ (let ( (control-overlay (treeview-get-node-prop node 'control-overlay)) )
+ (if control-overlay
+ (funcall treeview-suggest-point-pos-in-control-function
control-overlay)))
+ ;; Label:
+ (overlay-start (treeview-get-node-prop node 'label-overlay)))))
+
+(defun treeview-next-line ()
+ "Move the point one line down, and, if there is a node in that line, move
the point to the node."
+ (interactive)
+ (forward-line)
+ (let ( (node (treeview-get-node-at-point)) )
+ (if node (treeview-place-point-in-node node))))
+
+(defun treeview-previous-line ()
+ "Move the point one line up, and, if there is a node in that line, move the
point to the node."
+ (interactive)
+ (forward-line -1)
+ (let ( (node (treeview-get-node-at-point)) )
+ (if node (treeview-place-point-in-node node))))
+
+(defun treeview-make-keymap (key-table)
+ "Create and return a keymap from KEY-TABLE.
+The latter must be an alist whose car's are strings describing key sequences in
+a format understood by `kbd', and whose cdr's are commands."
+ (let ( (keymap (make-keymap)) )
+ (while key-table
+ (let* ( (key-def (car key-table))
+ (key-seq (car key-def))
+ (key-cmd (cdr key-def)) )
+ (define-key keymap (kbd key-seq) key-cmd)
+ (setq key-table (cdr key-table))))
+ keymap))
+
+(provide 'treeview)
+
+;;; treeview.el ends here
- [nongnu] elpa/treeview 00a4ab92bd 19/25: Changed http to https in link to GNU licenses, (continued)
- [nongnu] elpa/treeview 00a4ab92bd 19/25: Changed http to https in link to GNU licenses, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview e601230367 20/25: Removed needless intern statements, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview 07ea52cd7f 16/25: Added package dependency on emacs 24.4, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview 8382de4bdd 18/25: Sharp-quoted function name, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview f0c0711070 04/25: Insering/removing nodes; treeview-after-node-expanded-function and treeview-after-node-folded-function, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview 5dff23aac0 09/25: New functions for navigation; misc. improvements, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview 3038ebf96e 08/25: Fixed bug when removing first child, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview 34ecd7a320 24/25: Fixed issues detected by flycheck; updated documentation, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview a82bc8c5d1 17/25: Removed needless progn around body of while, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview 4a341b05bc 14/25: Bugfix for updating hidden nodes, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview 7fc5f30552 03/25: Initial commit of treeview.el,
ELPA Syncer <=
- [nongnu] elpa/treeview 270cfbd5bd 06/25: Using 'let' to set buffer-read-only temporarily to t, ELPA Syncer, 2022/09/10
- [nongnu] elpa/treeview 0bdd3187c7 07/25: Reworked treeview-put so it can insert images, ELPA Syncer, 2022/09/10