]> code.delx.au - gnu-emacs-elpa/commitdiff
Merged from upstream with StefanM's changes
authorAlexey Veretennikov <alexey.veretennikov@gmail.com>
Wed, 27 Jan 2016 23:50:37 +0000 (00:50 +0100)
committerAlexey Veretennikov <alexey.veretennikov@gmail.com>
Wed, 27 Jan 2016 23:50:37 +0000 (00:50 +0100)
1  2 
packages/ztree/README.md
packages/ztree/ztree-diff-model.el
packages/ztree/ztree-diff.el
packages/ztree/ztree-dir.el
packages/ztree/ztree-util.el
packages/ztree/ztree-view.el
packages/ztree/ztree.el

diff --combined packages/ztree/README.md
index f96adb4b5ecb8b2a9c451f10e455d46cb03dd212,dc1907a31823f35188895072974f23c2627f3d0c..dc1907a31823f35188895072974f23c2627f3d0c
@@@ -54,7 -54,9 +54,9 @@@ Then you need to specify the left and r
   * `F5` forces the full rescan.
  
  ### Customizations
- By default all files starting with dot (like `.gitignore`) are not shown and excluded from the difference status for directories. One can add an additional regexps to the list `ztree-diff-filter-list`. 
+ By default all files starting with dot (like `.gitignore`) are not shown and excluded from the difference status for directories. One can add an additional regexps to the list `ztree-diff-filter-list`.
+ One also could turn on unicode characters to draw the tree with instead of normal ASCII-characters. This is controlled by the `ztree-draw-unicode-lines` variable.
  
  ### Screenshots
  
@@@ -87,3 -89,20 +89,20 @@@ Set the `ztree-dir-move-focus` variabl
  
  ![ztree emacsx11](https://github.com/fourier/ztree/raw/screenshots/screenshots/emacs_xterm.png "Emacs in xterm with ztree-dir")
  
+ ## Contributions
+ You can contribute to **ztree** in one of the following ways.
+ - Submit a bug report
+ - Submit a feature request
+ - Submit a simple pull request (with changes < 15 lines)
+ ### Copyright issues
+ Since **ztree** is a part of [GNU ELPA](https://elpa.gnu.org/), it is copyrighted by the [Free Software Foundation, Inc.](http://www.fsf.org/). Therefore in order to submit nontrivial changes (with total amount of lines > 15), one needs to to grant the right to include your works in GNU Emacs to the FSF.
+ For this you need to complete [this](https://raw.githubusercontent.com/fourier/ztree/contributions/request-assign.txt) form, and send it to [assign@gnu.org](mailto:assign@gnu.org). The FSF will send you the assignment contract that both you and the FSF will sign.
+ For more information one can read [here](http://www.gnu.org/licenses/why-assign.html) to understand why it is needed.
+ As soon as the paperwork is done one can contribute to **ztree** with bigger pull requests.
+ Note what pull requests without paperwork done will not be accepted, so please notify the [maintainer](mailto:alexey.veretennikov@gmail.com) if everything is in place.
index f0b4e4aa3768ba668eae753d2dde8afb91e681c8,b4ad75fdec7bcf085ca9b8d3182f1040e3da7a44..b4ad75fdec7bcf085ca9b8d3182f1040e3da7a44
@@@ -1,10 -1,10 +1,10 @@@
  ;;; ztree-diff-model.el --- diff model for directory trees -*- lexical-binding: t; -*-
  
- ;; Copyright (C) 2013-2015  Free Software Foundation, Inc.
+ ;; Copyright (C) 2013-2016  Free Software Foundation, Inc.
  ;;
- ;; Author: Alexey Veretennikov <alexey dot veretennikov at gmail dot com>
+ ;; Author: Alexey Veretennikov <alexey.veretennikov@gmail.com>
  ;; 
- ;; Created: 2013-11-1l
+ ;; Created: 2013-11-11
  ;;
  ;; Keywords: files tools
  ;; URL: https://github.com/fourier/ztree
  (require 'ztree-util)
  (eval-when-compile (require 'cl-lib))
  
- (defvar ztree-diff-model-wait-message nil
-   "Message showing while constructing the diff tree.")
- (make-variable-buffer-local 'ztree-diff-model-wait-message)
- (defvar ztree-diff-model-ignore-fun nil
+ (defvar-local ztree-diff-model-ignore-fun nil
    "Function which determines if the node should be excluded from comparison.")
- (make-variable-buffer-local 'ztree-diff-model-ignore-fun)
  
- (defun ztree-diff-model-update-wait-message ()
-   "Update the wait mesage with one more '.' progress indication."
-   (when ztree-diff-model-wait-message
-     (setq ztree-diff-model-wait-message (concat ztree-diff-model-wait-message "."))
-     (message ztree-diff-model-wait-message)))
+ (defvar-local ztree-diff-model-progress-fun nil
+   "Function which should be called whenever the progress indications is updated.")
+ (defun ztree-diff-model-update-progress ()
+   "Update the progress."
+   (when ztree-diff-model-progress-fun
+     (funcall ztree-diff-model-progress-fun)))
  
  ;; Create a record ztree-diff-node with defined fields and getters/setters
  ;; here:
  ;; right-path is the full path of the right side,
  ;; short-name - is the file or directory name
  ;; children - list of nodes - files or directories if the node is a directory
- ;; different = {nil, 'new, 'diff} - means comparison status
+ ;; different = {nil, 'same, 'new, 'diff, 'ignore} - means comparison status
  (cl-defstruct (ztree-diff-node
                 (:constructor)
                 (:constructor ztree-diff-node-create
                  (parent left-path right-path
                          different
-                         &aux (short-name (ztree-file-short-name
-                                           (or left-path right-path)))
-                         (right-short-name (ztree-file-short-name
-                                            (or right-path left-path))))))
+                         &aux
+                         (short-name (ztree-file-short-name
+                                      (or left-path right-path)))
+                         (right-short-name
+                          (if (and left-path right-path)
+                              (ztree-file-short-name right-path)
+                            short-name)))))
    parent left-path right-path short-name right-short-name children different)
  
  (defun ztree-diff-model-ignore-p (node)
  
  (defun ztree-diff-node-to-string (node)
    "Construct the string with contents of the NODE given."
-   (let* ((string-or-nil #'(lambda (x) (if x
-                                           (cond ((stringp x) x)
-                                                 ((eq x 'new) "new")
-                                                 ((eq x 'diff) "different")
-                                                 (t (ztree-diff-node-short-name x)))
-                                         "(empty)")))
-          (children (ztree-diff-node-children node))
-          (ch-str ""))
+   (let ((string-or-nil #'(lambda (x) (if x
+                                          (cond ((stringp x) x)
+                                                ((eq x 'new) "new")
+                                                ((eq x 'diff) "different")
+                                                ((eq x 'ignore) "ignored")
+                                                ((eq x 'same) "same")
+                                                (t (ztree-diff-node-short-name x)))
+                                        "(empty)")))
+         (children (ztree-diff-node-children node))
+         (ch-str ""))
      (dolist (x children)
-       (setq ch-str (concat ch-str "\n   * " (ztree-diff-node-short-name x))))
+       (setq ch-str (concat ch-str "\n   * " (ztree-diff-node-short-name x)
+                            ": "
+                            (funcall string-or-nil (ztree-diff-node-different x)))))
      (concat "Node: " (ztree-diff-node-short-name node)
              "\n"
-             ;; " * Parent: " (let ((parent (ztree-diff-node-parent node)))
-             ;;                 (if parent (ztree-diff-node-short-name parent) "nil"))
              " * Parent: " (funcall string-or-nil (ztree-diff-node-parent node))
              "\n"
+             " * Status: " (funcall string-or-nil (ztree-diff-node-different node))
+             "\n"
              " * Left path: " (funcall string-or-nil (ztree-diff-node-left-path node))
              "\n"
              " * Right path: " (funcall string-or-nil (ztree-diff-node-right-path node))
@@@ -123,6 -128,7 +128,7 @@@ RIGHT if only on the right side.
      (if (and left right) 'both
        (if left 'left 'right))))
  
  (defun ztree-diff-node-equal (node1 node2)
    "Determines if NODE1 and NODE2 are equal."
    (and (string-equal (ztree-diff-node-short-name node1)
@@@ -156,9 -162,9 +162,9 @@@ Returns t if equal.
    ;; file(1|2).
    (let* ((file1-untrampified (ztree-diff-untrampify-filename (ztree-diff-modef-quotify-string file1)))
           (file2-untrampified (ztree-diff-untrampify-filename (ztree-diff-modef-quotify-string file2)))
-          (diff-command (concat "diff -q" " " file1-untrampified " " file2-untrampified))
+          (diff-command (concat diff-command " -q" " " file1-untrampified " " file2-untrampified))
           (diff-output (shell-command-to-string diff-command)))
-     (not (> (length diff-output) 2))))
+     (if (<= (length diff-output) 2) 'same 'diff)))
  
  (defun ztree-directory-files (dir)
    "Return the list of full paths of files in a directory DIR.
@@@ -169,32 -175,29 +175,29 @@@ Filters out . and ..
                  (directory-files dir 'full)))
  
  (defun ztree-diff-model-partial-rescan (node)
-   "Rescan the NODE."
-   ;; assuming what parent is always exists
-   ;; otherwise the UI shall force the full rescan
-   (let ((isdir (ztree-diff-node-is-directory node))
-         (left (ztree-diff-node-left-path node))
-         (right (ztree-diff-node-right-path node)))
-     ;; if node is a directory - traverse
-     (when (and left right
-                (file-exists-p left)
-                (file-exists-p right))
-       (if isdir
-         (let ((traverse (ztree-diff-node-traverse
-                          node
-                          left
-                          right)))
-           (setf (ztree-diff-node-different node) (car traverse))
-           (setf (ztree-diff-node-children node) (cdr traverse)))
-         ;; node is a file
-         (setf (ztree-diff-node-different node)
-               (if (ztree-diff-model-files-equal left right)
-                   nil
-                 'diff))))))
- (defun ztree-diff-model-subtree (parent path side)
+   "Rescan the NODE.
+ The node is a either a file or directory with both
+ left and right parts existing."
+   ;; if a directory - recreate
+   (if (ztree-diff-node-is-directory node)
+       (ztree-diff-node-recreate node)
+     ;; if a file, change a status
+     (setf (ztree-diff-node-different node)
+           (if (or (ztree-diff-model-ignore-p node) ; if should be ignored
+                   (eql (ztree-diff-node-different node) 'ignore) ; was ignored
+                   (eql (ztree-diff-node-different ; or parent was ignored
+                         (ztree-diff-node-parent node))
+                        'ignore))
+               'ignore
+             (ztree-diff-model-files-equal (ztree-diff-node-left-path node)
+                                           (ztree-diff-node-right-path node)))))
+   ;; update all parents statuses
+   (ztree-diff-node-update-all-parents-diff node))
+ (defun ztree-diff-model-subtree (parent path side diff)
    "Create a subtree with given PARENT for the given PATH.
- Argument SIDE either 'left or 'right side."
+ Argument SIDE either 'left or 'right side.
+ Argument DIFF different status to be assigned to all created nodes."
    (let ((files (ztree-directory-files path))
          (result nil))
      (dolist (file files)
                          parent
                          (when (eq side 'left) file)
                          (when (eq side 'right) file)
-                         'new))
-                  (children (ztree-diff-model-subtree node file side)))
+                         diff))
+                  (children (ztree-diff-model-subtree node file side diff)))
              (setf (ztree-diff-node-children node) children)
              (push node result))
          (push (ztree-diff-node-create
                 parent
                 (when (eq side 'left) file)
                 (when (eq side 'right) file)
-                'new)
+                diff)
                result)))
      result))
  
  (defun ztree-diff-node-update-diff-from-children (node)
    "Set the diff status for the NODE based on its children."
-   (let ((children (ztree-diff-node-children node))
-         (diff nil))
-     (dolist (child children)
-       (unless (ztree-diff-model-ignore-p child)
-         (setq diff
-               (ztree-diff-model-update-diff
-                diff
-                (ztree-diff-node-different child)))))
-     (setf (ztree-diff-node-different node) diff)))
+   (unless (eql (ztree-diff-node-different node) 'ignore)
+     (let ((diff (cl-reduce #'ztree-diff-model-update-diff
+                            (ztree-diff-node-children node)
+                            :initial-value 'same
+                            :key 'ztree-diff-node-different)))
+       (setf (ztree-diff-node-different node) diff))))
  
  (defun ztree-diff-node-update-all-parents-diff (node)
    "Recursively update all parents diff status for the NODE."
  
  
  (defun ztree-diff-model-update-diff (old new)
-   "Get the diff status depending if OLD or NEW is not nil."
-   (if new
-       (if (or (not old)
-               (eq old 'new))
-           new
-         old)
-     old))
- (defun ztree-diff-node-traverse (parent path1 path2)
-   "Traverse 2 paths creating the list nodes with PARENT defined and diff status.
- Function traversing 2 paths PATH1 and PATH2 returning the list where the
- first element is the difference status (nil, 'diff, 'new') and
- the rest is the combined list of nodes."
-   (let ((list1 (ztree-directory-files path1))
-         (list2 (ztree-directory-files path2))
-         (different-dir nil)
-         (result nil))
-     (ztree-diff-model-update-wait-message)
+   "Get the diff status depending if OLD or NEW is not nil.
+ If the OLD is 'ignore, do not change anything"
+   ;; if the old whole directory is ignored, ignore children's status
+   (cond ((eql old 'ignore) 'ignore)
+         ;; if the new status is ignored, use old
+         ((eql new 'ignore) old)
+         ;; if the old or new status is different, return different
+         ((or (eql old 'diff)
+              (eql new 'diff)) 'diff)
+         ;; if new is 'new, return new
+         ((eql new 'new) 'new)
+         ;; all other cases return old
+         (t old)))
+ (defun ztree-diff-node-update-diff-from-parent (node)
+   "Recursively update diff status of all children of NODE.
+ This function will traverse through all children recursively
+ setting status from the NODE, unless they have an ignore status"
+   (let ((status (ztree-diff-node-different node))
+         (children (ztree-diff-node-children node)))
+     ;; if the parent has ignore status, force all kids this status
+     ;; otherwise only update status when the child status is not ignore
+     (mapc (lambda (child)
+             (when (or (eql status 'ignore)
+                       (not 
+                        (or (eql status 'ignore)
+                            (eql (ztree-diff-node-different child) 'ignore))))
+               (setf (ztree-diff-node-different child) status)
+               (ztree-diff-node-update-diff-from-parent child)))
+             children)))
+         
+     
+ (defun ztree-diff-model-find-in-files (list shortname is-dir)
+   "Find in LIST of files the file with name SHORTNAME.
+ If IS-DIR searching for directories; assume files otherwise"
+   (ztree-find list
+               (lambda (x) (and (string-equal (ztree-file-short-name x)
+                                              shortname)
+                                (eq is-dir (file-directory-p x))))))
+ (defun ztree-diff-model-should-ignore (node)
+   "Determine if the NODE and its children should be ignored.
+ If no parent - never ignore;
+ if in ignore list - ignore
+ if parent has ignored status - ignore"
+   (let ((parent (ztree-diff-node-parent node)))
+     (and parent
+          (or (eql (ztree-diff-node-different parent) 'ignore)
+              (ztree-diff-model-ignore-p node)))))
+ (defun ztree-diff-node-recreate (node)
+   "Traverse 2 paths defined in the NODE updating its children and status."
+   (let* ((list1 (ztree-directory-files (ztree-diff-node-left-path node))) ;; left list of liles
+          (list2 (ztree-directory-files (ztree-diff-node-right-path node))) ;; right list of files
+          (should-ignore (ztree-diff-model-should-ignore node))
+          ;; status automatically assigned to children of the node
+          (children-status (if should-ignore 'ignore 'new))
+          (children nil))    ;; list of children
+     ;; update waiting status
+     (ztree-diff-model-update-progress)
+     ;; update node status ignore status either inhereted from the
+     ;; parent or the own
+     (when should-ignore
+       (setf (ztree-diff-node-different node) 'ignore))
      ;; first - adding all entries from left directory
      (dolist (file1 list1)
        ;; for every entry in the first directory
        ;; we are creating the node
        (let* ((simple-name (ztree-file-short-name file1))
               (isdir (file-directory-p file1))
-              (children nil)
-              (different nil)
-              ;; create the current node to be set as parent to
-              ;; subdirectories
-              (node (ztree-diff-node-create parent file1 nil nil))
-              ;; 1. find if the file is in the second directory and the type
-              ;;    is the same - i.e. both are directories or both are files
-              (file2 (ztree-find list2
-                                 #'(lambda (x) (and (string-equal (ztree-file-short-name x)
-                                                                  simple-name)
-                                                    (eq isdir (file-directory-p x)))))))
-         ;; 2. if it is not in the second directory, add it as a node
-         (if (not file2)
-             (progn
-               ;; 2.1 if it is a directory, add the whole subtree
-               (when (file-directory-p file1)
-                 (setq children (ztree-diff-model-subtree node file1 'left)))
-               ;; 2.2 update the difference status for this entry
-               (setq different 'new))
-           ;; 3. if it is found in second directory and of the same type
-           ;; 3.1 if it is a file
-           (if (not (file-directory-p file1))
-               ;; 3.1.1 set difference status to this entry
-               (setq different (if (ztree-diff-model-files-equal file1 file2) nil 'diff))
-             ;; 3.2 if it is the directory
-             ;; 3.2.1 get the result of the directories comparison together with status
-             (let ((traverse (ztree-diff-node-traverse node file1 file2)))
-               ;; 3.2.2 update the difference status for whole comparison from
-               ;;       difference result from the 2 subdirectories comparison
-               (setq different (car traverse))
-               ;; 3.2.3 set the children list from the 2 subdirectories comparison
-               (setq children (cdr traverse)))))
-         ;; update calculated parameters of the node
-         (setf (ztree-diff-node-right-path node) file2)
-         (setf (ztree-diff-node-children node) children)
-         (setf (ztree-diff-node-different node) different)
-         ;; 2.3 update difference status for the whole comparison
-         ;; depending if the node should participate in overall result
-         (unless (ztree-diff-model-ignore-p node)
-           (setq different-dir (ztree-diff-model-update-diff different-dir different)))
-         ;; push the created node to the result list
-         (push node result)))
+              ;; find if the file is in the second directory and the type
+              ;; is the same - i.e. both are directories or both are files
+              (file2 (ztree-diff-model-find-in-files list2 simple-name isdir))
+              ;; create a child. The current node is a parent
+              ;; new by default - will be overriden below if necessary
+              (child
+               (ztree-diff-node-create node file1 file2 children-status)))
+         ;; update child own ignore status
+         (when (ztree-diff-model-should-ignore child)
+           (setf (ztree-diff-node-different child) 'ignore))
+         ;; if exists on a right side with the same type,
+         ;; remove from the list of files on the right side
+         (when file2
+           (setf list2 (cl-delete file2 list2 :test #'string-equal)))
+         (cond
+          ;; when exist just on a left side and is a directory, add all
+          ((and isdir (not file2))
+           (setf (ztree-diff-node-children child)
+                 (ztree-diff-model-subtree child
+                                           file1
+                                           'left
+                                           (ztree-diff-node-different child))))
+          ;; if 1) exists on both sides and 2) it is a file
+          ;; and 3) not ignored file
+          ((and file2 (not isdir) (not (eql (ztree-diff-node-different child) 'ignore)))
+           (setf (ztree-diff-node-different child)
+                 (ztree-diff-model-files-equal file1 file2)))
+          ;; if exists on both sides and it is a directory, traverse further
+          ((and file2 isdir)
+           (ztree-diff-node-recreate child)))
+         ;; push the created node to the children list
+         (push child children)))
      ;; second - adding entries from the right directory which are not present
      ;; in the left directory
      (dolist (file2 list2)
        ;; for every entry in the second directory
        ;; we are creating the node
-       (let* ((simple-name (ztree-file-short-name file2))
-              (isdir (file-directory-p file2))
-              (children nil)
-              ;; create the node to be added to the results list
-              (node (ztree-diff-node-create parent nil file2 'new))
-              ;; 1. find if the file is in the first directory and the type
-              ;;    is the same - i.e. both are directories or both are files
-              (file1 (ztree-find list1
-                                 #'(lambda (x) (and (string-equal (ztree-file-short-name x)
-                                                                  simple-name)
-                                                    (eq isdir (file-directory-p x)))))))
-         ;; if it is not in the first directory, add it as a node
-         (unless file1
+       (let* ((isdir (file-directory-p file2))
+              ;; create the child to be added to the results list
+              (child
+               (ztree-diff-node-create node nil file2 children-status)))
+         ;; update ignore status of the child
+         (when (ztree-diff-model-should-ignore child)
+           (setf (ztree-diff-node-different child) 'ignore))
            ;; if it is a directory, set the whole subtree to children
-           (when (file-directory-p file2)
-             (setq children (ztree-diff-model-subtree node file2 'right)))
-           ;; set calculated children to the node
-           (setf (ztree-diff-node-children node) children)
-           ;; update the different status for the whole comparison
-           ;; depending if the node should participate in overall result
-           (unless (ztree-diff-model-ignore-p node)
-             (setq different-dir (ztree-diff-model-update-diff different-dir 'new)))
-           ;; push the created node to the result list
-           (push node result))))
-     ;; result is a pair: difference status and nodes list
-     (cons different-dir result)))
- (defun ztree-diff-model-create (dir1 dir2 &optional ignore-p)
-   "Create a node based on DIR1 and DIR2.
- IGNORE-P is the optional filtering function, taking node as
- an argument, which determines if the node should be excluded
- from comparison."
-   (unless (file-directory-p dir1)
-     (error "Path %s is not a directory" dir1))
-   (unless (file-directory-p dir2)
-     (error "Path %s is not a directory" dir2))
-   (setf ztree-diff-model-ignore-fun ignore-p)
-   (setq ztree-diff-model-wait-message (concat "Comparing " dir1 " and " dir2 " ..."))
-   (let* ((model
-           (ztree-diff-node-create nil dir1 dir2 nil))
-          (traverse (ztree-diff-node-traverse model dir1 dir2)))
-     (setf (ztree-diff-node-children model) (cdr traverse))
-     (setf (ztree-diff-node-different model) (car traverse))
-     (message "Done.")
-     model))
+         (when isdir
+           (setf (ztree-diff-node-children child)
+                 (ztree-diff-model-subtree child
+                                           file2
+                                           'right
+                                           (ztree-diff-node-different child))))
+         ;; push the created node to the result list
+         (push child children)))
+     ;; finally set different status based on all children
+     ;; depending if the node should participate in overall result
+     (unless should-ignore
+       (setf (ztree-diff-node-different node)
+             (cl-reduce #'ztree-diff-model-update-diff
+                        children
+                        :initial-value 'same
+                        :key 'ztree-diff-node-different)))
+     ;; and set children
+     (setf (ztree-diff-node-children node) children)))
  
  (defun ztree-diff-model-update-node (node)
    "Refresh the NODE."
-   (setq ztree-diff-model-wait-message
-         (concat "Updating " (ztree-diff-node-short-name node) " ..."))
-   (let ((traverse (ztree-diff-node-traverse node
-                                             (ztree-diff-node-left-path node)
-                                             (ztree-diff-node-right-path node))))
-     (setf (ztree-diff-node-children node) (cdr traverse))
-     (setf (ztree-diff-node-different node) (car traverse))
-     (message "Done.")))
+   (ztree-diff-node-recreate node))
  
+ (defun ztree-diff-model-set-ignore-fun (ignore-p)
+   "Set the buffer-local ignore function to IGNORE-P.
+ Ignore function is a function of one argument (ztree-diff-node)
+ which returns t if the node should be ignored (like files starting
+ with dot etc)."
+   (setf ztree-diff-model-ignore-fun ignore-p))
  
+ (defun ztree-diff-model-set-progress-fun (progess-fun)
+   (setf ztree-diff-model-progress-fun progess-fun)) 
  
  (provide 'ztree-diff-model)
  
index ea66a6e99587219660bffdd89b79d9f16f6c3a2a,ed3d5f9360ff1c30d7f90a9a7ada0992cc0fc1c8..ed3d5f9360ff1c30d7f90a9a7ada0992cc0fc1c8
@@@ -1,10 -1,10 +1,10 @@@
  ;;; ztree-diff.el --- Text mode diff for directory trees -*- lexical-binding: t; -*-
  
- ;; Copyright (C) 2013-2015  Free Software Foundation, Inc.
+ ;; Copyright (C) 2013-2016  Free Software Foundation, Inc.
  ;;
- ;; Author: Alexey Veretennikov <alexey dot veretennikov at gmail dot com>
+ ;; Author: Alexey Veretennikov <alexey.veretennikov@gmail.com>
  ;; 
- ;; Created: 2013-11-1l
+ ;; Created: 2013-11-11
  ;;
  ;; Keywords: files tools
  ;; URL: https://github.com/fourier/ztree
@@@ -63,29 -63,39 +63,39 @@@ By default all filest starting with do
    :group 'Ztree-diff :group 'font-lock-highlighting-faces)
  (defvar ztreep-diff-model-add-face 'ztreep-diff-model-add-face)
  
+ (defface ztreep-diff-model-ignored-face
+   '((((type tty pc) (class color) (min-colors 256)) :foreground "#2f2f2f")
+     (((type tty pc) (class color) (min-colors 8))   :foreground "white")
+     (t                   (:foreground "#7f7f7f" :strike-through t)))
+   "*Face used for non-modified files in Ztree-diff."
+   :group 'Ztree-diff :group 'font-lock-highlighting-faces)
+ (defvar ztreep-diff-model-ignored-face 'ztreep-diff-model-ignored-face)
  (defface ztreep-diff-model-normal-face
-   '((t                   (:foreground "#7f7f7f")))
+   '((((type tty pc) (class color) (min-colors 8)) :foreground "white")
+     (t                   (:foreground "#7f7f7f")))
    "*Face used for non-modified files in Ztree-diff."
    :group 'Ztree-diff :group 'font-lock-highlighting-faces)
  (defvar ztreep-diff-model-normal-face 'ztreep-diff-model-normal-face)
  
  
- (defvar ztree-diff-filter-list (list ztree-diff-hidden-files-regexp)
+ (defvar-local ztree-diff-filter-list (list ztree-diff-hidden-files-regexp)
    "List of regexp file names to filter out.
  By default paths starting with dot (like .git) are ignored")
- (make-variable-buffer-local 'ztree-diff-filter-list)
  
- (defvar ztree-diff-dirs-pair nil
+ (defvar-local ztree-diff-dirs-pair nil
    "Pair of the directories stored.  Used to perform the full rescan.")
- (make-variable-buffer-local 'ztree-diff-dirs-pair)
  
- (defvar ztree-diff-show-equal-files t
+ (defvar-local ztree-diff-show-equal-files t
    "Show or not equal files/directories on both sides.")
- (make-variable-buffer-local 'ztree-diff-show-equal-files)
  
- (defvar ztree-diff-show-filtered-files nil
+ (defvar-local ztree-diff-show-filtered-files nil
    "Show or not files from the filtered list.")
  
+ (defvar-local ztree-diff-wait-message nil
+   "Message showing while constructing the diff tree.")
  ;;;###autoload
  (define-minor-mode ztreediff-mode
    "A minor mode for displaying the difference of the directory trees in text mode."
      (,(kbd "v") . ztree-diff-view-file)
      (,(kbd "d") . ztree-diff-simple-diff-files)
      (,(kbd "r") . ztree-diff-partial-rescan)
+     (,(kbd "R") . ztree-diff-full-rescan)
      ([f5] . ztree-diff-full-rescan)))
  
  
  (defun ztree-diff-node-face (node)
    "Return the face for the NODE depending on diff status."
    (let ((diff (ztree-diff-node-different node)))
-     (cond ((eq diff 'diff) ztreep-diff-model-diff-face)
+     (cond ((eq diff 'ignore) ztreep-diff-model-ignored-face)
+           ((eq diff 'diff) ztreep-diff-model-diff-face)
            ((eq diff 'new)  ztreep-diff-model-add-face)
-           (t ztreep-diff-model-normal-face))))
+           ((eq diff 'same) ztreep-diff-model-normal-face))))
  
  (defun ztree-diff-insert-buffer-header ()
    "Insert the header to the ztree buffer."
    (insert "\n")
    (ztree-insert-with-face " Mismatch file " ztreep-diff-model-diff-face)
    (ztree-insert-with-face "- different from other side" ztreep-diff-header-small-face)
+   (insert "\n ")
+   (ztree-insert-with-face "Ignored file" ztreep-diff-model-ignored-face)
+   (ztree-insert-with-face " - ignored from comparison" ztreep-diff-header-small-face)
    (insert "\n")
    (ztree-insert-with-face "==============" ztreep-diff-header-face)
    (insert "\n"))
  
      (if (not parent)
          (when ztree-diff-dirs-pair
            (ztree-diff (car ztree-diff-dirs-pair) (cdr ztree-diff-dirs-pair)))
-       (progn
-         (ztree-diff-model-partial-rescan common)
-         (ztree-diff-node-update-all-parents-diff node)
-         (ztree-refresh-buffer (line-number-at-pos))))))
+       (ztree-diff-update-wait-message
+            (concat "Updating " (ztree-diff-node-short-name common) " ..."))
+       (ztree-diff-model-partial-rescan common)
+       (message "Done")
+       (ztree-refresh-buffer (line-number-at-pos)))))
  
  
  (defun ztree-diff-partial-rescan ()
@@@ -220,10 -237,10 +237,10 @@@ Argument NODE node containing paths to 
          ;; FIXME: The GNU convention is to only use "path" for lists of
          ;; directories as in load-path.
          (open-f #'(lambda (path) (if hard (find-file path)
-                               (let ((split-width-threshold nil))
-                                 (view-file-other-window path))))))
+                                   (let ((split-width-threshold nil))
+                                     (view-file-other-window path))))))
      (cond ((and left right)
-            (if (not (ztree-diff-node-different node))
+            (if (eql (ztree-diff-node-different node) 'same)
                 (funcall open-f left)
               (if hard
                   (ediff left right)
@@@ -251,16 -268,17 +268,17 @@@ COPY-TO-RIGHT specifies which side of t
                   (error error-trap))))
        ;; error message if failed
        (if err (message (concat "Error: " (nth 2 err)))
-         (progn              ; otherwise:
-           ;; assuming all went ok when left and right nodes are the same
-           ;; set both as not different
-           (setf (ztree-diff-node-different node) nil)
-           ;; update left/right paths
-           (if copy-to-right
-               (setf (ztree-diff-node-right-path node) target-path)
-             (setf (ztree-diff-node-left-path node) target-path))
-           (ztree-diff-node-update-all-parents-diff node)
-           (ztree-refresh-buffer (line-number-at-pos)))))))
+         ;; otherwise:
+         ;; assuming all went ok when left and right nodes are the same
+         ;; set both as not different if they were not ignored
+         (unless (eq (ztree-diff-node-different node) 'ignore)
+           (setf (ztree-diff-node-different node) 'same))
+         ;; update left/right paths
+         (if copy-to-right
+             (setf (ztree-diff-node-right-path node) target-path)
+           (setf (ztree-diff-node-left-path node) target-path))
+         (ztree-diff-node-update-all-parents-diff node)
+         (ztree-refresh-buffer (line-number-at-pos))))))
  
  
  (defun ztree-diff-copy-dir (node source-path destination-path copy-to-right)
@@@ -281,17 -299,23 +299,23 @@@ COPY-TO-RIGHT specifies which side of t
                       nil)
                   (error error-trap))))
        ;; error message if failed
-       (if err (message (concat "Error: " (nth 1 err)))
-         (progn
-           (message target-full-path)
-           (if copy-to-right
-               (setf (ztree-diff-node-right-path node)
-                     target-full-path)
-             (setf (ztree-diff-node-left-path node)
-                   target-full-path))
-           (ztree-diff-model-update-node node)
-           (ztree-diff-node-update-all-parents-diff node)
-           (ztree-refresh-buffer (line-number-at-pos)))))))
+       (if err
+           (progn
+             (message (concat "Error: " (nth 1 err)))
+             ;; and do rescan of the node
+             (ztree-diff-do-partial-rescan node))
+         ;; if everything is ok, update statuses
+         (message target-full-path)
+         (if copy-to-right
+             (setf (ztree-diff-node-right-path node) target-full-path)
+           (setf (ztree-diff-node-left-path node) target-full-path))
+         (ztree-diff-update-wait-message
+          (concat "Updating " (ztree-diff-node-short-name node) " ..."))
+         ;; TODO: do not rescan the node. Use some logic like in delete
+         (ztree-diff-model-update-node node)
+         (message "Done.")
+         (ztree-diff-node-update-all-parents-diff node)
+         (ztree-refresh-buffer (line-number-at-pos))))))
  
  
  (defun ztree-diff-copy ()
        (let* ((node (car found))
               (side (cdr found))
               (node-side (ztree-diff-node-side node))
-              (delete-from-left t)
-              (remove-path nil)
-              (parent (ztree-diff-node-parent node)))
-         (when parent                    ; do not delete the root node
-           ;; algorithm for determining what to delete similar to copy:
-           ;; 1. if the file is present on both sides, delete
-           ;;    from the side currently selected
-           (setq delete-from-left (if (eq node-side 'both)
-                                      (eq side 'left)
-                                    ;; 2) if one of sides is absent, delete
-                                    ;; from the side where the file is present
-                                    (eq node-side 'left)))
-           (setq remove-path (if delete-from-left
-                                 (ztree-diff-node-left-path node)
-                               (ztree-diff-node-right-path node)))
-           (when (yes-or-no-p (format "Delete the file [%s]%s ?"
-                                      (if delete-from-left "LEFT" "RIGHT")
-                                      remove-path))
-             (let* ((delete-command
-                     (if (file-directory-p remove-path)
-                         #'delete-directory
-                       #'delete-file))
-                    (children (ztree-diff-node-children parent))
-                    (err
-                     (condition-case error-trap
-                         (progn
-                           (funcall delete-command remove-path t)
-                           nil)
-                       (error error-trap))))
-               (if err
-                   (progn
-                     (message (concat "Error: " (nth 2 err)))
-                     ;; when error happened while deleting the
-                     ;; directory, rescan the node
-                     ;; and update the parents with a new status
-                     ;; of this node
-                     (when (file-directory-p remove-path)
-                       (ztree-diff-model-partial-rescan node)
-                       (ztree-diff-node-update-all-parents-diff node)))
-                 ;; if everything ok 
+              (parent (ztree-diff-node-parent node))
+              ;; algorithm for determining what to delete similar to copy:
+              ;; 1. if the file is present on both sides, delete
+              ;;    from the side currently selected
+              ;; 2. if one of sides is absent, delete
+              ;;    from the side where the file is present
+              (delete-from-left
+               (or (eql node-side 'left)
+                   (and (eql node-side 'both)
+                        (eql side 'left))))
+              (remove-path (if delete-from-left
+                               (ztree-diff-node-left-path node)
+                             (ztree-diff-node-right-path node))))
+         (when (and parent                    ; do not delete the root node
+                    (yes-or-no-p (format "Delete the file [%s]%s ?"
+                                         (if delete-from-left "LEFT" "RIGHT")
+                                         remove-path)))
+           (let* ((delete-command
+                   (if (file-directory-p remove-path)
+                       #'delete-directory
+                     #'delete-file))
+                  (children (ztree-diff-node-children parent))
+                  (err
+                   (condition-case error-trap
+                       (progn
+                         (funcall delete-command remove-path t)
+                         nil)
+                     (error error-trap))))
+             (if err
                  (progn
-                   ;; remove the node from children
-                   (setq children (ztree-filter
-                                   #'(lambda (x) (not (ztree-diff-node-equal x node)))
-                                   children))
-                   (setf (ztree-diff-node-children parent) children))
-                 (ztree-diff-node-update-all-parents-diff node)
-                 ;;(ztree-diff-model-partial-rescan node)
-                 (ztree-refresh-buffer (line-number-at-pos))))))))))
+                   (message (concat "Error: " (nth 2 err)))
+                   ;; when error happened while deleting the
+                   ;; directory, rescan the node
+                   ;; and update the parents with a new status
+                   ;; of this node
+                   (when (file-directory-p remove-path)
+                     (ztree-diff-model-partial-rescan node)))
+               ;; if everything ok
+               ;; if was only on one side
+               ;; remove the node from children
+               (if (or (and (eql node-side 'left)
+                            delete-from-left)
+                       (and (eql node-side 'right)
+                            (not delete-from-left)))
+                   (setf (ztree-diff-node-children parent)
+                         (ztree-filter
+                          (lambda (x) (not (ztree-diff-node-equal x node)))
+                          children))
+                 ;; otherwise update only one side
+                 (mapc (if delete-from-left
+                           (lambda (x) (setf (ztree-diff-node-left-path x) nil))
+                         (lambda (x) (setf (ztree-diff-node-right-path x) nil)))
+                       (cons node (ztree-diff-node-children node)))
+                 ;; and update diff status
+                 ;; if was ignored keep the old status
+                 (unless (eql (ztree-diff-node-different node) 'ignore)
+                   (setf (ztree-diff-node-different node) 'new))
+                 ;; finally update all children statuses
+                 (ztree-diff-node-update-diff-from-parent node)))
+             (ztree-diff-node-update-all-parents-diff node)
+             (ztree-refresh-buffer (line-number-at-pos))))))))
  
  
  
@@@ -433,44 -469,68 +469,68 @@@ unless it is a parent node.
  
  (defun ztree-node-is-visible (node)
    "Determine if the NODE should be visible."
-   ;; visible then
-   ;; 1) either it is a parent
-   (or (not (ztree-diff-node-parent node))    ; parent is always visible
-       (and
-        ;; 2.1) or it is not in ignore list and 
-        (or ztree-diff-show-filtered-files ; show filtered files regardless
-            (not (ztree-diff-node-ignore-p node)))
-        ;; 2.2) it has different status
-        (or ztree-diff-show-equal-files  ; show equal files regardless
-            (ztree-diff-node-different node)))))
+   (let ((diff (ztree-diff-node-different node)))
+     ;; visible then
+     ;; either it is a root. root have no parent
+     (or (not (ztree-diff-node-parent node))    ; parent is always visible
+         ;; or the files are different or orphan
+         (or (eql diff 'new)
+             (eql diff 'diff))
+         ;; or it is ignored but we show ignored for now
+         (and (eql diff 'ignore)
+              ztree-diff-show-filtered-files) 
+         ;; or they are same but we show same for now
+         (and (eql diff 'same)
+              ztree-diff-show-equal-files))))
  
  (defun ztree-diff-toggle-show-equal-files ()
    "Toggle visibility of the equal files."
    (interactive)
    (setq ztree-diff-show-equal-files (not ztree-diff-show-equal-files))
+   (message (concat (if ztree-diff-show-equal-files "Show" "Hide") " equal files"))
    (ztree-refresh-buffer))
  
  (defun ztree-diff-toggle-show-filtered-files ()
    "Toggle visibility of the filtered files."
    (interactive)
    (setq ztree-diff-show-filtered-files (not ztree-diff-show-filtered-files))
+   (message (concat (if ztree-diff-show-filtered-files "Show" "Hide") " filtered files"))
    (ztree-refresh-buffer))
  
  
+ (defun ztree-diff-update-wait-message (&optional msg)
+   "Update the wait mesage with one more '.' progress indication."
+   (if msg
+       (setq ztree-diff-wait-message msg)
+     (when ztree-diff-wait-message
+       (setq ztree-diff-wait-message (concat ztree-diff-wait-message "."))))
+   (message ztree-diff-wait-message))
  ;;;###autoload
  (defun ztree-diff (dir1 dir2)
    "Create an interactive buffer with the directory tree of the path given.
  Argument DIR1 left directory.
  Argument DIR2 right directory."
    (interactive "DLeft directory \nDRight directory ")
-   (let* ((difference (ztree-diff-model-create dir1 dir2 #'ztree-diff-node-ignore-p))
+   (unless (and dir1 (file-directory-p dir1))
+     (error "Path %s is not a directory" dir1))
+   (unless (file-exists-p dir1)
+     (error "Path %s does not exist" dir1))
+   (unless (and dir2 (file-directory-p dir2))
+     (error "Path %s is not a directory" dir2))
+   (unless (file-exists-p dir2)
+     (error "Path %s does not exist" dir2))
+   (let* ((model
+           (ztree-diff-node-create nil dir1 dir2 nil))
           (buf-name (concat "*"
-                            (ztree-diff-node-short-name difference)
+                            (ztree-diff-node-short-name model)
                             " <--> "
-                            (ztree-diff-node-right-short-name difference)
+                            (ztree-diff-node-right-short-name model)
                             "*")))
+     ;; after this command we are in a new buffer,
+     ;; so all buffer-local vars are valid
      (ztree-view buf-name
-                 difference
+                 model
                  'ztree-node-is-visible
                  'ztree-diff-insert-buffer-header
                  'ztree-diff-node-short-name-wrapper
                  'ztree-diff-node-action
                  'ztree-diff-node-side)
      (ztreediff-mode)
+     (ztree-diff-model-set-ignore-fun #'ztree-diff-node-ignore-p)
+     (ztree-diff-model-set-progress-fun #'ztree-diff-update-wait-message)
      (setq ztree-diff-dirs-pair (cons dir1 dir2))
+     (ztree-diff-update-wait-message (concat "Comparing " dir1 " and " dir2 " ..."))
+     (ztree-diff-node-recreate model)
+     (message "Done.")
+     
      (ztree-refresh-buffer)))
  
  
  
  
  (provide 'ztree-diff)
  ;;; ztree-diff.el ends here
index 08f4041175b59c207a58f637302615c1d0fe8c88,d3d3b25f0c89ce9e4be4ad6ddd9686b182064912..d3d3b25f0c89ce9e4be4ad6ddd9686b182064912
@@@ -1,10 -1,10 +1,10 @@@
  ;;; ztree-dir.el --- Text mode directory tree -*- lexical-binding: t; -*-
  
- ;; Copyright (C) 2013-2015  Free Software Foundation, Inc.
+ ;; Copyright (C) 2013-2016  Free Software Foundation, Inc.
  ;;
- ;; Author: Alexey Veretennikov <alexey dot veretennikov at gmail dot com>
+ ;; Author: Alexey Veretennikov <alexey.veretennikov@gmail.com>
  ;; 
- ;; Created: 2013-11-1l
+ ;; Created: 2013-11-11
  ;;
  ;; Keywords: files tools
  ;; URL: https://github.com/fourier/ztree
@@@ -45,6 -45,7 +45,7 @@@
  
  (require 'ztree-util)
  (require 'ztree-view)
+ (eval-when-compile (require 'cl-lib))
  
  ;;
  ;; Constants
@@@ -60,7 -61,18 +61,18 @@@ By default all filest starting with do
  
  (defvar ztree-dir-move-focus nil
    "If set to true moves the focus to opened window when the
- user press RETURN on file ")t
+ user press RETURN on file ")
+ (defvar-local ztree-dir-filter-list (list ztree-hidden-files-regexp)
+   "List of regexp file names to filter out.
+ By default paths starting with dot (like .git) are ignored.
+ One could add own filters in the following way:
+ (setq-default ztree-dir-filter-list (cons \"^.*\\.pyc\" ztree-dir-filter-list))
+ ")
+ (defvar-local ztree-dir-show-filtered-files nil
+   "Show or not files from the filtered list.")
  
  
  ;;
  (defvar ztreep-header-face 'ztreep-header-face)
  
  
+ (define-minor-mode ztreedir-mode
+   "A minor mode for displaying the directory trees in text mode."
+   ;; initial value
+   nil
+   ;; modeline name
+   " Dir"
+   ;; The minor mode keymap
+   `(
+     (,(kbd "H") . ztree-dir-toggle-show-filtered-files)))
  ;;
  ;; File bindings to the directory tree control
  ;;
  
  (defun ztree-file-not-hidden (filename)
    "Determines if the file with FILENAME should be visible."
-   (not (string-match ztree-hidden-files-regexp
-                      (ztree-file-short-name filename))))
+   (let ((name (ztree-file-short-name filename)))
+     (and (not (or (string= name ".") (string= name "..")))
+          (or 
+           ztree-dir-show-filtered-files 
+           (not (cl-find-if (lambda (rx) (string-match rx name)) ztree-dir-filter-list))))))
  
  (defun ztree-find-file (node hard)
    "Find the file at NODE.
@@@ -107,6 -136,17 +136,17 @@@ Otherwise, the ztree window is used to 
            (t 
             (find-file node)))))
  
+ (defun ztree-dir-toggle-show-filtered-files ()
+   "Toggle visibility of the filtered files."
+   (interactive)
+   (setq ztree-dir-show-filtered-files (not ztree-dir-show-filtered-files))
+   (message (concat (if ztree-dir-show-filtered-files "Show" "Hide") " filtered files"))
+   (ztree-refresh-buffer))
  ;;;###autoload
  (defun ztree-dir (path)
    "Create an interactive buffer with the directory tree of the PATH given."
                    #'string-equal
                    (lambda (x) (directory-files x 'full))
                    nil                   ; face
-                   #'ztree-find-file)))) ; action
+                   #'ztree-find-file)    ; action
+       (ztreedir-mode))))
  
  
  (provide 'ztree-dir)
index 40fe12ef0930c6923f35f7200d07e9e584aad8d1,ec4945781a3ba7a33c2283292a9b480125ed7e68..ec4945781a3ba7a33c2283292a9b480125ed7e68
@@@ -1,10 -1,10 +1,10 @@@
  ;;; ztree-util.el --- Auxiliary utilities for the ztree package -*- lexical-binding: t; -*-
  
- ;; Copyright (C) 2013-2015  Free Software Foundation, Inc.
+ ;; Copyright (C) 2013-2016  Free Software Foundation, Inc.
  ;;
- ;; Author: Alexey Veretennikov <alexey dot veretennikov at gmail dot com>
+ ;; Author: Alexey Veretennikov <alexey.veretennikov@gmail.com>
  ;; 
- ;; Created: 2013-11-1l
+ ;; Created: 2013-11-11
  ;;
  ;; Keywords: files tools
  ;; URL: https://github.com/fourier/ztree
index 4a5a766ea600bd022b87f5ffb1554ad57dce044b,3244ccc0954305fa08fc6ad63b87a09208194843..3244ccc0954305fa08fc6ad63b87a09208194843
@@@ -1,10 -1,10 +1,10 @@@
  ;;; ztree-view.el --- Text mode tree view (buffer) -*- lexical-binding: t; -*-
  
- ;; Copyright (C) 2013-2015  Free Software Foundation, Inc.
+ ;; Copyright (C) 2013-2016  Free Software Foundation, Inc.
  ;;
- ;; Author: Alexey Veretennikov <alexey dot veretennikov at gmail dot com>
+ ;; Author: Alexey Veretennikov <alexey.veretennikov@gmail.com>
  ;; 
- ;; Created: 2013-11-1l
+ ;; Created: 2013-11-11
  ;;
  ;; Keywords: files tools
  ;; URL: https://github.com/fourier/ztree
  ;; Globals
  ;;
  
- (defvar ztree-expanded-nodes-list nil
+ (defvar ztree-draw-unicode-lines nil
+   "If set forces ztree to draw lines with unicode characters.")
+ (defvar-local ztree-expanded-nodes-list nil
    "A list of Expanded nodes (i.e. directories) entries.")
- (make-variable-buffer-local 'ztree-expanded-nodes-list)
  
- (defvar ztree-start-node nil
+ (defvar-local ztree-start-node nil
    "Start node(i.e. directory) for the window.")
- (make-variable-buffer-local 'ztree-start-node)
  
- (defvar ztree-line-to-node-table nil
+ (defvar-local ztree-line-to-node-table nil
    "List of tuples with full node(i.e. file/directory name and the line.")
- (make-variable-buffer-local 'ztree-line-to-node-table)
  
- (defvar ztree-start-line nil
+ (defvar-local ztree-start-line nil
    "Index of the start line - the root.")
- (make-variable-buffer-local 'ztree-start-line)
  
- (defvar ztree-parent-lines-array nil
+ (defvar-local ztree-parent-lines-array nil
    "Array of parent lines.
  The ith value of the array is the parent line for line i.
  If ith value is i - it is the root line")
- (make-variable-buffer-local 'ztree-parent-lines-array)
  
- (defvar ztree-count-subsequent-bs nil
+ (defvar-local ztree-count-subsequent-bs nil
    "Counter for the subsequest BS keys (to identify double BS).
  Used in order to not to use cl package and `lexical-let'")
- (make-variable-buffer-local 'ztree-count-subsequent-bs)
  
- (defvar ztree-line-tree-properties nil
+ (defvar-local ztree-line-tree-properties nil
    "Hash with key - line number, value - property ('left, 'right, 'both).
  Used for 2-side trees, to determine if the node exists on left or right
  or both sides")
- (make-variable-buffer-local 'ztree-line-tree-properties)
  
- (defvar ztree-tree-header-fun nil
+ (defvar-local ztree-tree-header-fun nil
    "Function inserting the header into the tree buffer.
  MUST inster newline at the end!")
- (make-variable-buffer-local 'ztree-tree-header-fun)
  
- (defvar ztree-node-short-name-fun nil
+ (defvar-local ztree-node-short-name-fun nil
    "Function which creates a pretty-printable short string from the node.")
- (make-variable-buffer-local 'ztree-node-short-name-fun)
  
- (defvar ztree-node-is-expandable-fun nil
+ (defvar-local ztree-node-is-expandable-fun nil
    "Function which determines if the node is expandable.
  For example if the node is a directory")
- (make-variable-buffer-local 'ztree-node-is-expandable-fun)
  
- (defvar ztree-node-equal-fun nil
+ (defvar-local ztree-node-equal-fun nil
    "Function which determines if the 2 nodes are equal.")
- (make-variable-buffer-local 'ztree-node-equal-fun)
  
- (defvar ztree-node-contents-fun nil
+ (defvar-local ztree-node-contents-fun nil
    "Function returning list of node contents.")
- (make-variable-buffer-local 'ztree-node-contents-fun)
  
- (defvar ztree-node-side-fun nil
+ (defvar-local ztree-node-side-fun nil
    "Function returning position of the node: 'left, 'right or 'both.
  If not defined(by default) - using single screen tree, otherwise
  the buffer is split to 2 trees")
- (make-variable-buffer-local 'ztree-node-side-fun)
  
- (defvar ztree-node-face-fun nil
+ (defvar-local ztree-node-face-fun nil
    "Function returning face for the node.")
- (make-variable-buffer-local 'ztree-node-face-fun)
  
- (defvar ztree-node-action-fun nil
+ (defvar-local ztree-node-action-fun nil
    "Function called when Enter/Space pressed on the node.")
- (make-variable-buffer-local 'ztree-node-action-fun)
  
- (defvar ztree-node-showp-fun nil
+ (defvar-local ztree-node-showp-fun nil
    "Function called to decide if the node should be visible.")
- (make-variable-buffer-local 'ztree-node-showp-fun)
  
  
  ;;
  (define-derived-mode ztree-mode special-mode "Ztree"
    "A major mode for displaying the directory tree in text mode."
    ;; only spaces
-   (setq indent-tabs-mode nil))
+   (setq indent-tabs-mode nil)
+   (setq       buffer-read-only t))
  
  (defun ztree-find-node-in-line (line)
    "Return the node for the LINE specified.
@@@ -343,45 -332,66 +332,66 @@@ Optional argument FACE face to use to d
      (goto-char (+ x (-(point) 1)))
      (delete-char 1)
      (insert-char c 1)
-     (put-text-property (1- (point)) (point) 'face (if face face 'ztreep-arrow-face))))
+     (put-text-property (1- (point)) (point) 'font-lock-face (if face face 'ztreep-arrow-face))))
+ (defun ztree-vertical-line-char ()
+   "Return the character used to draw vertical line"
+   (if ztree-draw-unicode-lines #x2502 ?\|))
+ (defun ztree-horizontal-line-char ()
+   "Return the character used to draw vertical line"
+   (if ztree-draw-unicode-lines #x2500 ?\-))
+ (defun ztree-left-bottom-corner-char ()
+   "Return the character used to draw vertical line"
+   (if ztree-draw-unicode-lines #x2514 ?\`))
+ (defun ztree-left-intersection-char ()
+   "Return left intersection character.
+ It is just vertical bar when unicode disabled"
+   (if ztree-draw-unicode-lines #x251C ?\|))
  
  (defun ztree-draw-vertical-line (y1 y2 x &optional face)
    "Draw a vertical line of '|' characters from Y1 row to Y2 in X column.
  Optional argument FACE face to draw line with."
-   (let ((count (abs (- y1 y2))))
+   (let ((ver-line-char (ztree-vertical-line-char))
+         (count (abs (- y1 y2))))
      (if (> y1 y2)
          (progn
            (dotimes (y count)
-             (ztree-draw-char ?\| x (+ y2 y) face))
-           (ztree-draw-char ?\| x (+ y2 count) face))
+             (ztree-draw-char ver-line-char x (+ y2 y) face))
+           (ztree-draw-char ver-line-char x (+ y2 count) face))
        (progn
          (dotimes (y count)
-           (ztree-draw-char ?\| x (+ y1 y) face))
-         (ztree-draw-char ?\| x (+ y1 count) face)))))
+           (ztree-draw-char ver-line-char x (+ y1 y) face))
+         (ztree-draw-char ver-line-char x (+ y1 count) face)))))
  
  (defun ztree-draw-vertical-rounded-line (y1 y2 x &optional face)
    "Draw a vertical line of '|' characters finishing with '`' character.
  Draws the line from Y1 row to Y2 in X column.
  Optional argument FACE facet to draw the line with."
-   (let ((count (abs (- y1 y2))))
+   (let ((ver-line-char (ztree-vertical-line-char))
+         (corner-char (ztree-left-bottom-corner-char))
+         (count (abs (- y1 y2))))
      (if (> y1 y2)
          (progn
            (dotimes (y count)
-             (ztree-draw-char ?\| x (+ y2 y) face))
-           (ztree-draw-char ?\` x (+ y2 count) face))
+             (ztree-draw-char ver-line-char x (+ y2 y) face))
+           (ztree-draw-char corner-char x (+ y2 count) face))
        (progn
          (dotimes (y count)
-           (ztree-draw-char ?\| x (+ y1 y) face))
-         (ztree-draw-char ?\` x (+ y1 count) face)))))
+           (ztree-draw-char ver-line-char x (+ y1 y) face))
+         (ztree-draw-char corner-char x (+ y1 count) face)))))
  
  
  (defun ztree-draw-horizontal-line (x1 x2 y)
    "Draw the horizontal line from column X1 to X2 in the row Y."
-   (if (> x1 x2)
-       (dotimes (x (1+ (- x1 x2)))
-         (ztree-draw-char ?\- (+ x2 x) y))
-     (dotimes (x (1+ (- x2 x1)))
-       (ztree-draw-char ?\- (+ x1 x) y))))
+   (let ((hor-line-char (ztree-horizontal-line-char)))
+     (if (> x1 x2)
+         (dotimes (x (1+ (- x1 x2)))
+           (ztree-draw-char hor-line-char (+ x2 x) y))
+       (dotimes (x (1+ (- x2 x1)))
+         (ztree-draw-char hor-line-char (+ x1 x) y)))))
  
  
  (defun ztree-draw-tree (tree depth start-offset)
@@@ -396,6 -406,8 +406,8 @@@ Argument START-OFFSET column to start d
             (line-start (+ 3 offset))
             (line-end-leaf (+ 7 offset))
             (line-end-node (+ 4 offset))
+            (corner-char (ztree-left-bottom-corner-char))
+            (intersection-char (ztree-left-intersection-char))
             ;; determine if the line is visible. It is always the case
             ;; for 1-sided trees; however for 2 sided trees
             ;; it depends on which side is the actual element
                                            (funcall visible (ztree-car-atom x)))))
                (x-offset (+ 2 offset)))
            (when last-child
-             (ztree-draw-vertical-rounded-line (1+ root)
-                                               (ztree-car-atom last-child)
-                                               x-offset)))
-         ;; draw recursively
-         (dolist (child children)
-           (ztree-draw-tree child (1+ depth) start-offset)
-           (let ((end (if (listp child) line-end-node line-end-leaf)))
-             (when (funcall visible (ztree-car-atom child))
-               (ztree-draw-horizontal-line line-start
-                                           end
-                                           (ztree-car-atom child)))))))))
+             (ztree-draw-vertical-line (1+ root)
+                                       (ztree-car-atom last-child)
+                                       x-offset))
+           ;; draw recursively
+           (dolist (child children)
+             (ztree-draw-tree child (1+ depth) start-offset)
+             (let ((end (if (listp child) line-end-node line-end-leaf))
+                   (row (ztree-car-atom child)))
+               (when (funcall visible (ztree-car-atom child))
+                 (ztree-draw-char intersection-char (1- line-start) row)
+                 (ztree-draw-horizontal-line line-start
+                                             end
+                                             row))))
+           ;; finally draw the corner at the end of vertical line
+           (when last-child
+             (ztree-draw-char corner-char
+                              x-offset
+                              (ztree-car-atom last-child))))))))
  
  (defun ztree-fill-parent-array (tree)
    "Set the root lines array.
@@@ -538,29 -557,33 +557,33 @@@ Writes a string with given DEPTH, prefi
  and [-] or [+] depending on if it is EXPANDED from the specified OFFSET.
  Optional argument FACE face to write text with."
    (let ((node-sign #'(lambda (exp)
-                        (insert "[" (if exp "-" "+") "]")
-                        (set-text-properties (- (point) 3)
-                                             (point)
-                                             '(face ztreep-expand-sign-face)))))
-     (move-to-column offset t)
+                        (let ((sign (concat "[" (if exp "-" "+") "]")))
+                          (insert (propertize sign 
+                                              'font-lock-face
+                                              ztreep-expand-sign-face)))))
+         ;; face to use. if FACE is not null, use it, otherwise
+         ;; deside from the node type
+         (entry-face (cond (face face)
+                           (expandable 'ztreep-node-face)
+                           (t ztreep-leaf-face))))
+     ;; move-to-column in contrast to insert reuses the last property
+     ;; so need to clear it
+     (let ((start-pos (point)))
+       (move-to-column offset t)
+       (remove-text-properties start-pos (point) '(font-lock-face nil)))
      (delete-region (point) (line-end-position))
+     ;; every indentation level is 4 characters
      (when (> depth 0)
-       (dotimes (_ depth)
-         (insert " ")
-         (insert-char ?\s 3)))           ; insert 3 spaces
+       (insert-char ?\s (* 4 depth)))           ; insert 4 spaces
      (when (> (length short-name) 0)
-       (if expandable
-           (progn
-             (funcall node-sign expanded)   ; for expandable nodes insert "[+/-]"
-             (insert " ")
-             (put-text-property 0 (length short-name)
-                                'face (if face face 'ztreep-node-face) short-name)
-             (insert short-name))
-         (progn
-           (insert "    ")
-           (put-text-property 0 (length short-name)
-                              'face (if face face 'ztreep-leaf-face) short-name)
-           (insert short-name))))))
+       (let ((start-pos (point)))
+         (if expandable
+             (funcall node-sign expanded))   ; for expandable nodes insert "[+/-]"
+         ;; indentation for leafs 4 spaces from the node name
+         (insert-char ?\s (- 4 (- (point) start-pos))))
+       (insert (propertize short-name 'font-lock-face entry-face)))))
  
  (defun ztree-jump-side ()
    "Jump to another side for 2-sided trees."
@@@ -605,7 -628,8 +628,8 @@@ Optional argument LINE scroll to the li
                     children-fun
                     face-fun
                     action-fun
-                    &optional node-side-fun
+                    &optional
+                    node-side-fun
                     )
    "Create a ztree view buffer configured with parameters given.
  Argument BUFFER-NAME Name of the buffer created.
diff --combined packages/ztree/ztree.el
index b591756c8612828e5d414912b755fb0d5e43d247,300ed85d083328a3f6770c281bdb3f5336338aa0..300ed85d083328a3f6770c281bdb3f5336338aa0
@@@ -3,8 -3,8 +3,8 @@@
  ;; Copyright (C) 2013-2016  Free Software Foundation, Inc.
  ;;
  ;; Author: Alexey Veretennikov <alexey.veretennikov@gmail.com>
- ;; Created: 2013-11-1l
- ;; Version: 1.0.2
+ ;; Created: 2013-11-11
+ ;; Version: 1.0.3
  ;; Package-Requires: ((cl-lib "0"))
  ;; Keywords: files tools
  ;; URL: https://github.com/fourier/ztree