update packages
This commit is contained in:
@@ -16,7 +16,8 @@
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;; General implementation details.
|
||||
|
||||
;; General implementation details.
|
||||
|
||||
;;; Code:
|
||||
|
||||
@@ -24,7 +25,6 @@
|
||||
(require 'dash)
|
||||
(require 's)
|
||||
(require 'ht)
|
||||
(require 'f)
|
||||
(require 'pfuture)
|
||||
(require 'treemacs-customization)
|
||||
(require 'treemacs-logging)
|
||||
@@ -37,6 +37,9 @@
|
||||
(treemacs-import-functions-from "cfrs"
|
||||
cfrs-read)
|
||||
|
||||
(treemacs-import-functions-from "treemacs-interface"
|
||||
treemacs-toggle-node)
|
||||
|
||||
(treemacs-import-functions-from "treemacs-tags"
|
||||
treemacs--expand-file-node
|
||||
treemacs--collapse-file-node
|
||||
@@ -134,28 +137,15 @@ Used in `treemacs-is-node-collapsed?'")
|
||||
"States marking a node as open.
|
||||
Used in `treemacs-is-node-expanded?'")
|
||||
|
||||
(defconst treemacs--buffer-name-prefix " *Treemacs-")
|
||||
|
||||
(defconst treemacs-dir
|
||||
;; locally we're in src/elisp, installed from melpa we're at the package root
|
||||
(-let [dir (-> (if load-file-name
|
||||
(file-name-directory load-file-name)
|
||||
default-directory)
|
||||
(expand-file-name))]
|
||||
(if (s-ends-with? "src/elisp/" dir)
|
||||
(-> dir (f-parent) (f-parent))
|
||||
dir))
|
||||
"The directory treemacs.el is stored in.")
|
||||
|
||||
(defvar-local treemacs--width-is-locked t
|
||||
"Keeps track of whether the width of the treemacs window is locked.")
|
||||
|
||||
(defvar-local treemacs--in-this-buffer nil
|
||||
"Non-nil only in buffers meant to show treemacs.
|
||||
Used to show an error message if someone mistakenly activates `treemacs-mode'.")
|
||||
|
||||
(defvar treemacs--pre-peek-state nil
|
||||
"List of window, buffer to restore and buffer to kill treemacs used for peeking.")
|
||||
(define-inline treemacs--unslash (path)
|
||||
"Remove the final slash in PATH."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(inline-letevals (path)
|
||||
(inline-quote
|
||||
(if (and (> (length ,path) 1)
|
||||
(eq ?/ (aref ,path (1- (length ,path)))))
|
||||
(substring ,path 0 -1)
|
||||
,path))))
|
||||
|
||||
(define-inline treemacs--parent-dir (path)
|
||||
"Return the parent of PATH is it's a file, or PATH if it is a directory.
|
||||
@@ -168,6 +158,26 @@ PATH: File Path"
|
||||
(file-name-directory)
|
||||
(treemacs--unslash)))))
|
||||
|
||||
(defconst treemacs--buffer-name-prefix " *Treemacs-")
|
||||
|
||||
(defconst treemacs-dir
|
||||
;; locally we're in src/elisp, installed from melpa we're at the package root
|
||||
(-let [dir (-> (if load-file-name
|
||||
(file-name-directory load-file-name)
|
||||
default-directory)
|
||||
(expand-file-name))]
|
||||
(if (s-ends-with? "src/elisp/" dir)
|
||||
(-> dir (treemacs--unslash) (treemacs--parent-dir) (treemacs--parent-dir))
|
||||
dir))
|
||||
"The directory treemacs.el is stored in.")
|
||||
|
||||
(defvar-local treemacs--width-is-locked t
|
||||
"Keeps track of whether the width of the treemacs window is locked.")
|
||||
|
||||
(defvar-local treemacs--in-this-buffer nil
|
||||
"Non-nil only in buffers meant to show treemacs.
|
||||
Used to show an error message if someone mistakenly activates `treemacs-mode'.")
|
||||
|
||||
(define-inline treemacs--remove-trailing-newline (str)
|
||||
"Remove final newline in STR."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
@@ -190,7 +200,7 @@ If STR already has a slash return it unchanged."
|
||||
|
||||
(define-inline treemacs--delete-line ()
|
||||
"Delete the current line.
|
||||
Unlike `kill-whole-line' this won't pollute the kill ring."
|
||||
Unlike the function `kill-whole-line' this won't pollute the kill ring."
|
||||
(inline-quote
|
||||
(delete-region (point-at-bol) (min (point-max) (1+ (point-at-eol))))))
|
||||
|
||||
@@ -218,7 +228,7 @@ button type on every call."
|
||||
,prop ,val))))
|
||||
|
||||
(define-inline treemacs-button-get (button prop)
|
||||
"Get the property of button BUTTON named PROP
|
||||
"Get the property of button BUTTON named PROP.
|
||||
Same as `button-get', but faster since it's inlined and does not query the
|
||||
button type on every call."
|
||||
(declare (side-effect-free t))
|
||||
@@ -258,16 +268,6 @@ button type on every call."
|
||||
(inline-quote
|
||||
(memq (treemacs-button-get ,btn :state) treemacs--closed-node-states)))
|
||||
|
||||
(define-inline treemacs--unslash (path)
|
||||
"Remove the final slash in PATH."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(inline-letevals (path)
|
||||
(inline-quote
|
||||
(if (and (> (length ,path) 1)
|
||||
(eq ?/ (aref ,path (1- (length ,path)))))
|
||||
(substring ,path 0 -1)
|
||||
,path))))
|
||||
|
||||
(define-inline treemacs--get-label-of (btn)
|
||||
"Return the text label of BTN."
|
||||
(declare (side-effect-free t))
|
||||
@@ -283,7 +283,7 @@ EXCLUDE-PREFIX: File Path"
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(inline-letevals (path exclude-prefix)
|
||||
(inline-quote
|
||||
(cdr (f-split (substring ,path (length ,exclude-prefix)))))))
|
||||
(treemacs-split-path (substring ,path (length ,exclude-prefix))))))
|
||||
|
||||
(defun treemacs--replace-recentf-entry (old-file new-file)
|
||||
"Replace OLD-FILE with NEW-FILE in the recent file list."
|
||||
@@ -311,14 +311,14 @@ EXCLUDE-PREFIX: File Path"
|
||||
(with-current-buffer buffer (treemacs--follow)))
|
||||
(run-hook-with-args 'treemacs-select-functions 'exists))))
|
||||
|
||||
(define-inline treemacs--button-symbol-switch (new-sym)
|
||||
"Replace icon in current line with NEW-SYM."
|
||||
(inline-letevals (new-sym)
|
||||
(define-inline treemacs--button-symbol-switch (new-symbol)
|
||||
"Replace icon in current line with NEW-SYMBOL."
|
||||
(inline-letevals (new-symbol)
|
||||
(inline-quote
|
||||
(save-excursion
|
||||
(let ((len (length ,new-sym)))
|
||||
(let ((len (length ,new-symbol)))
|
||||
(goto-char (- (treemacs-button-start (next-button (point-at-bol) t)) len))
|
||||
(insert ,new-sym)
|
||||
(insert ,new-symbol)
|
||||
(delete-char len))))))
|
||||
|
||||
(defun treemacs-project-of-node (node)
|
||||
@@ -417,7 +417,7 @@ extensions and special names like this."
|
||||
|
||||
(define-inline treemacs--on-file-deletion (path &optional no-buffer-delete)
|
||||
"Cleanup to run when treemacs file at PATH was deleted.
|
||||
Do not try to delete buffers for PATH when NO-BUFFER-DELETE is non-nil. This is
|
||||
Do not try to delete buffers for PATH when NO-BUFFER-DELETE is non-nil. This is
|
||||
necessary since interacting with magit can cause file delete events for files
|
||||
being edited to trigger."
|
||||
(inline-letevals (path no-buffer-delete)
|
||||
@@ -448,8 +448,10 @@ In practice this means expand PATH and remove its final slash."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(inline-letevals (path)
|
||||
(inline-quote
|
||||
(let (file-name-handler-alist)
|
||||
(-> ,path (expand-file-name) (treemacs--unslash))))))
|
||||
(if (file-remote-p ,path)
|
||||
(treemacs--unslash ,path)
|
||||
(let (file-name-handler-alist)
|
||||
(-> ,path (expand-file-name) (treemacs--unslash)))))))
|
||||
;; TODO(2020/12/28): alias is for backwards compatibility, remove it eventually
|
||||
(defalias 'treemacs--canonical-path #'treemacs-canonical-path)
|
||||
|
||||
@@ -472,7 +474,7 @@ In practice this means expand PATH and remove its final slash."
|
||||
(let* ((win-buff (window-buffer window))
|
||||
(buff-file (buffer-file-name win-buff)))
|
||||
(when buff-file
|
||||
(setq buff-file (f-long buff-file))
|
||||
(setq buff-file (expand-file-name buff-file))
|
||||
(when (treemacs-is-path buff-file :in old-path)
|
||||
(treemacs-without-following
|
||||
(with-selected-window window
|
||||
@@ -483,7 +485,7 @@ In practice this means expand PATH and remove its final slash."
|
||||
;; then the rest
|
||||
(--each (buffer-list)
|
||||
(-when-let (buff-file (buffer-file-name it))
|
||||
(setq buff-file (f-long buff-file))
|
||||
(setq buff-file (expand-file-name buff-file))
|
||||
(when (treemacs-is-path buff-file :in old-path)
|
||||
(let ((new-file (s-replace old-path new-path buff-file)))
|
||||
(kill-buffer it)
|
||||
@@ -530,9 +532,14 @@ Add a project for ROOT and NAME if they are non-nil."
|
||||
(setf run-hook? t)))
|
||||
(when root (treemacs-do-add-project-to-workspace (treemacs-canonical-path root) name))
|
||||
(with-no-warnings (setq treemacs--ready-to-follow t))
|
||||
(when (or treemacs-follow-after-init (with-no-warnings treemacs-follow-mode))
|
||||
(with-current-buffer origin-buffer
|
||||
(treemacs--follow)))
|
||||
(let* ((origin-file (buffer-file-name origin-buffer))
|
||||
(file-project (treemacs-is-path origin-file :in-workspace)))
|
||||
(cond
|
||||
((and (or treemacs-follow-after-init (with-no-warnings treemacs-follow-mode))
|
||||
file-project)
|
||||
(treemacs-goto-file-node origin-file file-project))
|
||||
(treemacs-expand-after-init
|
||||
(treemacs-toggle-node))))
|
||||
;; The hook should run at the end of the setup, but also only
|
||||
;; if a new buffer was created, as the other cases are already covered
|
||||
;; in their respective setup functions.
|
||||
@@ -563,50 +570,6 @@ selected tags or extension entry. Must be called from treemacs buffer."
|
||||
(-some-> (treemacs-button-get btn :parent)
|
||||
(treemacs--nearest-path)))))
|
||||
|
||||
(defun treemacs--create-file/dir (is-file?)
|
||||
"Interactively create either a file or directory, depending on IS-FILE.
|
||||
|
||||
IS-FILE?: Bool"
|
||||
(interactive)
|
||||
(let* ((curr-path (--if-let (treemacs-current-button)
|
||||
(treemacs--nearest-path it)
|
||||
(f-expand "~")))
|
||||
(path-to-create (read-file-name
|
||||
(if is-file? "Create File: " "Create Directory: ")
|
||||
(treemacs--add-trailing-slash
|
||||
(if (f-dir? curr-path)
|
||||
curr-path
|
||||
(f-dirname curr-path))))))
|
||||
(treemacs-block
|
||||
(treemacs-error-return-if (file-exists-p path-to-create)
|
||||
"%s already exists." (propertize path-to-create 'face 'font-lock-string-face))
|
||||
(treemacs--without-filewatch
|
||||
(if is-file?
|
||||
(-let [dir (f-dirname path-to-create)]
|
||||
(unless (f-exists? dir)
|
||||
(make-directory dir t))
|
||||
(f-touch path-to-create))
|
||||
(make-directory path-to-create t))
|
||||
(run-hook-with-args 'treemacs-create-file-functions path-to-create))
|
||||
(-when-let (project (treemacs--find-project-for-path path-to-create))
|
||||
(-when-let* ((created-under (treemacs--parent path-to-create))
|
||||
(created-under-pos (treemacs-find-visible-node created-under)))
|
||||
;; update only the part that changed to keep things smooth
|
||||
;; for files that's just their parent, for directories we have to take
|
||||
;; flattening into account
|
||||
(if (and (treemacs-button-get created-under-pos :parent)
|
||||
(or (treemacs-button-get created-under-pos :collapsed)
|
||||
;; count includes "." "..", so it'll be flattened
|
||||
(= 3 (length (directory-files created-under)))))
|
||||
(treemacs-do-update-node (-> created-under-pos
|
||||
(treemacs-button-get :parent)
|
||||
(treemacs-button-get :path)))
|
||||
(treemacs-do-update-node created-under)))
|
||||
(treemacs-goto-file-node (treemacs-canonical-path path-to-create) project)
|
||||
(recenter))
|
||||
(treemacs-pulse-on-success
|
||||
"Created %s." (propertize path-to-create 'face 'font-lock-string-face)))))
|
||||
|
||||
(define-inline treemacs--follow-path-elements (btn items)
|
||||
"Starting at BTN follow (goto and open) every single element in ITEMS.
|
||||
Return the button that is found or the symbol `follow-failed' if the search
|
||||
@@ -653,7 +616,7 @@ failed. PROJECT is used for determining whether Git actions are appropriate."
|
||||
;; consecutively try to move to /x/src, /x/src/confg and finally /x/src/config/foo.el
|
||||
(while ,dir-parts
|
||||
(setq dir-part (pop ,dir-parts)
|
||||
root (f-join root dir-part)
|
||||
root (treemacs-join-path root dir-part)
|
||||
,btn
|
||||
(let (current-btn)
|
||||
(cl-block search
|
||||
@@ -800,8 +763,8 @@ PATH: Node Path"
|
||||
|
||||
(defun treemacs-find-node (path &optional project)
|
||||
"Find position of node identified by PATH under PROJECT in the current buffer.
|
||||
In spite of the signature this function effectively supports two different calling
|
||||
conventions.
|
||||
In spite of the signature this function effectively supports two different
|
||||
calling conventions.
|
||||
|
||||
The first one is for movement towards a node that identifies a file. In this
|
||||
case the signature is applied as is, and this function diverges simply into
|
||||
@@ -810,16 +773,16 @@ optional, as treemacs is able to determine which project, if any, a given file
|
||||
belongs to. Providing the project is therefore only a matter of efficiency and
|
||||
convenience. If PROJECT is not given it will be found with
|
||||
`treemacs--find-project-for-path'. No attempt is made to verify that PATH falls
|
||||
under a project in the workspace. It is assumed that this check has already been
|
||||
made.
|
||||
under a project in the workspace. It is assumed that this check has already
|
||||
been made.
|
||||
|
||||
The second calling convention deals with custom nodes defined by an extension
|
||||
for treemacs. In this case the PATH is made up of all the node keys that lead to
|
||||
the node to be moved to.
|
||||
for treemacs. In this case the PATH is made up of all the node keys that lead
|
||||
to the node to be moved to.
|
||||
|
||||
For a directory extension, created with `treemacs-define-directory-extension',
|
||||
that means that the path's first element must be the filepath of its parent. For
|
||||
a project extension, created with `treemacs-define-project-extension', the
|
||||
that means that the path's first element must be the filepath of its parent.
|
||||
For a project extension, created with `treemacs-define-project-extension', the
|
||||
first element of the path must instead be the keyword `:custom', followed by the
|
||||
node's unique path. The second argument is therefore ignored in this case.
|
||||
|
||||
@@ -837,8 +800,8 @@ PROJECT Project Struct"
|
||||
(defun treemacs-goto-node (path &optional project ignore-file-exists)
|
||||
"Move point to button identified by PATH under PROJECT in the current buffer.
|
||||
Falls under the same constraints as `treemacs-find-node', but will actually move
|
||||
point. Will do nothing if file at PATH does not exist, unless IGNORE-FILE-EXISTS
|
||||
is non-nil.
|
||||
point. Will do nothing if file at PATH does not exist, unless
|
||||
IGNORE-FILE-EXISTS is non-nil.
|
||||
|
||||
PATH: Filepath | Node Path
|
||||
PROJECT Project Struct
|
||||
@@ -863,7 +826,7 @@ PROJECT: Project Struct"
|
||||
;; the path we're moving to minus the project root
|
||||
(path-minus-root (->> project (treemacs-project->path) (length) (substring path)))
|
||||
;; the parts of the path that we can try to go to until we arrive at the project root
|
||||
(dir-parts (nreverse (s-split (f-path-separator) path-minus-root :omit-nulls)))
|
||||
(dir-parts (nreverse (s-split "/" path-minus-root :omit-nulls)))
|
||||
;; the path we try to quickly move to because it's already open and thus in the dom
|
||||
(goto-path path)
|
||||
;; manual as in to be expanded manually after we moved to the next closest node we can find
|
||||
@@ -1126,44 +1089,6 @@ Will refresh every project when PROJECT is 'all."
|
||||
(unless treemacs-silent-refresh
|
||||
(treemacs-log "Refresh complete.")))))
|
||||
|
||||
(defun treemacs--setup-peek-buffer (btn &optional goto-tag?)
|
||||
"Setup the peek buffer and window for BTN.
|
||||
Additionally also navigate to BTN's tag if GOTO-TAG is t.
|
||||
|
||||
BTN: Button
|
||||
GOTO-TAG: Bool"
|
||||
(let ((path (file-truename
|
||||
(if goto-tag?
|
||||
(treemacs-with-button-buffer btn
|
||||
(treemacs--nearest-path btn))
|
||||
(treemacs-safe-button-get btn :path))))
|
||||
(buffer-to-restore (current-buffer))
|
||||
(buffer-to-kill nil))
|
||||
(-if-let (buffer (get-file-buffer path))
|
||||
(switch-to-buffer buffer)
|
||||
(find-file path)
|
||||
(setq buffer-to-kill (current-buffer)))
|
||||
(when goto-tag?
|
||||
(treemacs--goto-tag btn))
|
||||
(unless treemacs--pre-peek-state
|
||||
(setq treemacs--pre-peek-state `(,(selected-window) ,buffer-to-restore ,buffer-to-kill)))
|
||||
(add-hook 'post-command-hook #'treemacs--restore-peeked-window)))
|
||||
|
||||
(defun treemacs--restore-peeked-window ()
|
||||
"Revert the buffer displayed in the peek window before it was used for peeking."
|
||||
(unless (memq this-command
|
||||
'(treemacs-peek treemacs-next-line-other-window treemacs-previous-line-other-window
|
||||
treemacs-next-page-other-window treemacs-previous-page-other-window))
|
||||
(remove-hook 'post-command-hook #'treemacs--restore-peeked-window)
|
||||
(treemacs-without-following
|
||||
(when treemacs--pre-peek-state
|
||||
(-let [(window buffer-to-restore buffer-to-kill) treemacs--pre-peek-state]
|
||||
(setq treemacs--pre-peek-state nil)
|
||||
(when (buffer-live-p buffer-to-kill)
|
||||
(kill-buffer buffer-to-kill))
|
||||
(with-selected-window window
|
||||
(switch-to-buffer buffer-to-restore)))))))
|
||||
|
||||
(define-inline treemacs-is-node-file-or-dir? (node)
|
||||
"Return t when NODE is a file or directory."
|
||||
(inline-letevals (node)
|
||||
@@ -1183,57 +1108,6 @@ PATH: Node Path"
|
||||
(inline-quote
|
||||
(treemacs-find-in-dom ,path))))
|
||||
|
||||
(defun treemacs--copy-or-move (action)
|
||||
"Internal implementation for copying and moving files.
|
||||
ACTION will be either `:copy' or `:move', depending on whether we are calling
|
||||
from `treemacs-copy-file' or `treemacs-move-file'."
|
||||
(let ((no-node-msg)
|
||||
(wrong-type-msg)
|
||||
(prompt)
|
||||
(action-function)
|
||||
(finish-msg))
|
||||
(pcase action
|
||||
(:copy
|
||||
(setf no-node-msg "There is nothing to copy here."
|
||||
wrong-type-msg "Only files and directories can be copied."
|
||||
prompt "Copy to: "
|
||||
action-function #'f-copy
|
||||
finish-msg "Copied %s to %s"))
|
||||
(:move
|
||||
(setf no-node-msg "There is nothing to move here."
|
||||
wrong-type-msg "Only files and directories can be moved."
|
||||
prompt "Move to: "
|
||||
action-function #'f-move
|
||||
finish-msg "Moved %s to %s")))
|
||||
(treemacs-block
|
||||
(treemacs-unless-let (node (treemacs-node-at-point))
|
||||
(treemacs-error-return no-node-msg)
|
||||
(treemacs-error-return-if (not (treemacs-is-node-file-or-dir? node))
|
||||
wrong-type-msg)
|
||||
(let* ((source (treemacs-button-get node :path))
|
||||
(source-name (treemacs--filename source))
|
||||
(destination (treemacs--unslash (read-file-name prompt nil default-directory)))
|
||||
(target-is-dir? (file-directory-p destination))
|
||||
(target-name (if target-is-dir? (treemacs--filename source) (treemacs--filename destination)))
|
||||
(destination-dir (if target-is-dir? destination (treemacs--parent-dir destination)))
|
||||
(target (treemacs--find-repeated-file-name (f-join destination-dir target-name))))
|
||||
(unless (file-exists-p destination-dir)
|
||||
(make-directory destination-dir :parents))
|
||||
(when (eq action :move)
|
||||
;; do the deletion *before* moving the file, otherwise it will no longer exist and treemacs will
|
||||
;; not recognize it as a file path
|
||||
(treemacs-do-delete-single-node source))
|
||||
(treemacs--without-filewatch
|
||||
(funcall action-function source target))
|
||||
;; no waiting for filewatch, if we copied to an expanded directory refresh it immediately
|
||||
(-let [parent (treemacs--parent target)]
|
||||
(when (treemacs-is-path-visible? parent)
|
||||
(treemacs-do-update-node parent)))
|
||||
(treemacs-goto-file-node target)
|
||||
(treemacs-pulse-on-success finish-msg
|
||||
(propertize source-name 'face 'font-lock-string-face)
|
||||
(propertize destination 'face 'font-lock-string-face)))))))
|
||||
|
||||
(defun treemacs--find-repeated-file-name (path)
|
||||
"Find a fitting copy name for given file PATH.
|
||||
Returns a name in the /file/name (Copy 1).ext. If that also already
|
||||
@@ -1247,7 +1121,7 @@ exists it returns /file/name (Copy 2).ext etc."
|
||||
(new-path path))
|
||||
(while (file-exists-p new-path)
|
||||
(cl-incf n)
|
||||
(setf new-path (f-join dir (concat filename-no-ext (format template n) ext))))
|
||||
(setf new-path (treemacs-join-path dir (concat filename-no-ext (format template n) ext))))
|
||||
new-path))
|
||||
|
||||
(defun treemacs--read-string (prompt &optional initial-input)
|
||||
@@ -1262,6 +1136,17 @@ INITIAL-INPUT: String"
|
||||
('from-minibuffer (read-string prompt initial-input))
|
||||
(other (user-error "Unknown read-string-input value: `%s'" other))))
|
||||
|
||||
(defun treemacs-join-path (&rest items)
|
||||
"Join the given ITEMS to a single file PATH."
|
||||
(declare (side-effect-free t))
|
||||
(--reduce-from (expand-file-name it acc) "/" items))
|
||||
|
||||
(define-inline treemacs-split-path (path)
|
||||
"Split the given PATH into single items."
|
||||
(declare (pure t) (side-effect-free t))
|
||||
(inline-letevals (path)
|
||||
(inline-quote (split-string ,path "/" :omit-nulls))))
|
||||
|
||||
(provide 'treemacs-core-utils)
|
||||
|
||||
;;; treemacs-core-utils.el ends here
|
||||
|
||||
Reference in New Issue
Block a user