update packages
This commit is contained in:
@@ -16,13 +16,13 @@
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;; Not autoloaded, but user-facing functions.
|
||||
|
||||
;; Not autoloaded, but user-facing functions.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'hl-line)
|
||||
(require 'button)
|
||||
(require 'f)
|
||||
(require 's)
|
||||
(require 'dash)
|
||||
(require 'treemacs-core-utils)
|
||||
@@ -47,6 +47,7 @@
|
||||
cfrs-read)
|
||||
|
||||
(treemacs-import-functions-from "treemacs"
|
||||
treemacs-find-file
|
||||
treemacs-select-window)
|
||||
|
||||
(treemacs-import-functions-from "treemacs-tags"
|
||||
@@ -113,7 +114,7 @@ them instead."
|
||||
(interactive "P")
|
||||
(treemacs-do-for-button-state
|
||||
:on-root-node-open (treemacs--collapse-root-node btn arg)
|
||||
:on-root-node-closed (treemacs--expand-root-node btn)
|
||||
:on-root-node-closed (treemacs--expand-root-node btn arg)
|
||||
:on-dir-node-open (treemacs--collapse-dir-node btn arg)
|
||||
:on-dir-node-closed (treemacs--expand-dir-node btn :recursive arg)
|
||||
:on-file-node-open (treemacs--collapse-file-node btn arg)
|
||||
@@ -166,8 +167,10 @@ This function's exact configuration is stored in `treemacs-TAB-actions-config'."
|
||||
(treemacs-pulse-on-failure "No TAB action defined for node of type %s."
|
||||
(propertize (format "%s" state) 'face 'font-lock-type-face)))))
|
||||
|
||||
(defun treemacs-goto-parent-node ()
|
||||
"Select parent of selected node, if possible."
|
||||
(defun treemacs-goto-parent-node (&optional _arg)
|
||||
"Select parent of selected node, if possible.
|
||||
|
||||
ARG is optional and only available so this function can be used as an action."
|
||||
(interactive)
|
||||
(--if-let (-some-> (treemacs-current-button) (treemacs-button-get :parent))
|
||||
(goto-char it)
|
||||
@@ -191,7 +194,8 @@ This function's exact configuration is stored in `treemacs-TAB-actions-config'."
|
||||
|
||||
(defun treemacs-visit-node-vertical-split (&optional arg)
|
||||
"Open current file or tag by vertically splitting `next-window'.
|
||||
Stay in current window with a prefix argument ARG."
|
||||
Stay in the current window with a single prefix argument ARG, or close the
|
||||
treemacs window with a double prefix argument."
|
||||
(interactive "P")
|
||||
(treemacs--execute-button-action
|
||||
:split-function #'split-window-vertically
|
||||
@@ -199,12 +203,13 @@ Stay in current window with a prefix argument ARG."
|
||||
:dir-action (dired (treemacs-safe-button-get btn :path))
|
||||
:tag-section-action (treemacs--visit-or-expand/collapse-tag-node btn arg nil)
|
||||
:tag-action (treemacs--goto-tag btn)
|
||||
:save-window arg
|
||||
:window-arg arg
|
||||
:no-match-explanation "Node is neither a file, a directory or a tag - nothing to do here."))
|
||||
|
||||
(defun treemacs-visit-node-horizontal-split (&optional arg)
|
||||
"Open current file or tag by horizontally splitting `next-window'.
|
||||
Stay in current window with a prefix argument ARG."
|
||||
Stay in the current window with a single prefix argument ARG, or close the
|
||||
treemacs window with a double prefix argument."
|
||||
(interactive "P")
|
||||
(treemacs--execute-button-action
|
||||
:split-function #'split-window-horizontally
|
||||
@@ -212,27 +217,38 @@ Stay in current window with a prefix argument ARG."
|
||||
:dir-action (dired (treemacs-safe-button-get btn :path))
|
||||
:tag-section-action (treemacs--visit-or-expand/collapse-tag-node btn arg nil)
|
||||
:tag-action (treemacs--goto-tag btn)
|
||||
:save-window arg
|
||||
:window-arg arg
|
||||
:no-match-explanation "Node is neither a file, a directory or a tag - nothing to do here."))
|
||||
|
||||
(defun treemacs-visit-node-close-treemacs (&optional _)
|
||||
"Open current node without and close treemacs.
|
||||
Works just like calling `treemacs-visit-node-no-split' with a double prefix
|
||||
arg."
|
||||
(interactive "P")
|
||||
(treemacs-visit-node-no-split '(16)))
|
||||
|
||||
(defun treemacs-visit-node-no-split (&optional arg)
|
||||
"Open current file or tag within the window the file is already opened in.
|
||||
If the file/tag is no visible opened in any window use `next-window' instead.
|
||||
Stay in current window with a prefix argument ARG."
|
||||
"Open current node without performing any window split or window selection.
|
||||
The node will be displayed in the window next to treemacs, the exact selection
|
||||
is determined by `next-window'. If the node is already opened in some other
|
||||
window then that window will be selected instead.
|
||||
Stay in the current window with a single prefix argument ARG, or close the
|
||||
treemacs window with a double prefix argument."
|
||||
(interactive "P")
|
||||
(treemacs--execute-button-action
|
||||
:file-action (find-file (treemacs-safe-button-get btn :path))
|
||||
:dir-action (dired (treemacs-safe-button-get btn :path))
|
||||
:tag-section-action (treemacs--visit-or-expand/collapse-tag-node btn arg nil)
|
||||
:tag-action (treemacs--goto-tag btn)
|
||||
:save-window arg
|
||||
:window-arg arg
|
||||
:ensure-window-split t
|
||||
:window (-some-> btn (treemacs--nearest-path) (get-file-buffer) (get-buffer-window))
|
||||
:no-match-explanation "Node is neither a file, a directory or a tag - nothing to do here."))
|
||||
|
||||
(defun treemacs-visit-node-ace (&optional arg)
|
||||
"Open current file or tag in window selected by `ace-window'.
|
||||
Stay in current window with a prefix argument ARG."
|
||||
Stay in the current window with a single prefix argument ARG, or close the
|
||||
treemacs window with a double prefix argument."
|
||||
(interactive "P")
|
||||
(treemacs--execute-button-action
|
||||
:window (aw-select "Select window")
|
||||
@@ -240,13 +256,14 @@ Stay in current window with a prefix argument ARG."
|
||||
:dir-action (dired (treemacs-safe-button-get btn :path))
|
||||
:tag-section-action (treemacs--visit-or-expand/collapse-tag-node btn arg nil)
|
||||
:tag-action (treemacs--goto-tag btn)
|
||||
:save-window arg
|
||||
:window-arg arg
|
||||
:ensure-window-split t
|
||||
:no-match-explanation "Node is neither a file, a directory or a tag - nothing to do here."))
|
||||
|
||||
(defun treemacs-visit-node-in-most-recently-used-window (&optional arg)
|
||||
"Open current file or tag in window selected by `get-mru-window'.
|
||||
Stay in current window with a prefix argument ARG."
|
||||
Stay in the current window with a single prefix argument ARG, or close the
|
||||
treemacs window with a double prefix argument."
|
||||
(interactive "P")
|
||||
(treemacs--execute-button-action
|
||||
:window (get-mru-window (selected-frame) nil :not-selected)
|
||||
@@ -254,13 +271,14 @@ Stay in current window with a prefix argument ARG."
|
||||
:dir-action (dired (treemacs-safe-button-get btn :path))
|
||||
:tag-section-action (treemacs--visit-or-expand/collapse-tag-node btn arg nil)
|
||||
:tag-action (treemacs--goto-tag btn)
|
||||
:save-window arg
|
||||
:window-arg arg
|
||||
:ensure-window-split t
|
||||
:no-match-explanation "Node is neither a file, a directory or a tag - nothing to do here."))
|
||||
|
||||
(defun treemacs-visit-node-ace-horizontal-split (&optional arg)
|
||||
"Open current file by horizontally splitting window selected by `ace-window'.
|
||||
Stay in current window with a prefix argument ARG."
|
||||
Stay in the current window with a single prefix argument ARG, or close the
|
||||
treemacs window with a double prefix argument."
|
||||
(interactive "P")
|
||||
(treemacs--execute-button-action
|
||||
:split-function #'split-window-horizontally
|
||||
@@ -269,12 +287,13 @@ Stay in current window with a prefix argument ARG."
|
||||
:dir-action (dired (treemacs-safe-button-get btn :path))
|
||||
:tag-section-action (treemacs--visit-or-expand/collapse-tag-node btn arg nil)
|
||||
:tag-action (treemacs--goto-tag btn)
|
||||
:save-window arg
|
||||
:window-arg arg
|
||||
:no-match-explanation "Node is neither a file, a directory or a tag - nothing to do here."))
|
||||
|
||||
(defun treemacs-visit-node-ace-vertical-split (&optional arg)
|
||||
"Open current file by vertically splitting window selected by `ace-window'.
|
||||
Stay in current window with a prefix argument ARG."
|
||||
Stay in the current window with a single prefix argument ARG, or close the
|
||||
treemacs window with a double prefix argument."
|
||||
(interactive "P")
|
||||
(treemacs--execute-button-action
|
||||
:split-function #'split-window-vertically
|
||||
@@ -283,7 +302,7 @@ Stay in current window with a prefix argument ARG."
|
||||
:dir-action (dired (treemacs-safe-button-get btn :path))
|
||||
:tag-section-action (treemacs--visit-or-expand/collapse-tag-node btn arg nil)
|
||||
:tag-action (treemacs--goto-tag btn)
|
||||
:save-window arg
|
||||
:window-arg arg
|
||||
:no-match-explanation "Node is neither a file, a directory or a tag - nothing to do here."))
|
||||
|
||||
(defun treemacs-visit-node-default (&optional arg)
|
||||
@@ -327,6 +346,33 @@ ACTION should be one of the `treemacs-visit-node-*' commands."
|
||||
(setf treemacs-TAB-actions-config (assq-delete-all state treemacs-TAB-actions-config))
|
||||
(push (cons state action) treemacs-TAB-actions-config))
|
||||
|
||||
(defun treemacs-COLLAPSE-action (&optional arg)
|
||||
"Run the appropriate COLLAPSE action for the current button.
|
||||
|
||||
In the default configuration this usually means to close the content of the
|
||||
currently selected node. A potential prefix ARG is passed on to the executed
|
||||
action, if possible.
|
||||
|
||||
This function's exact configuration is stored in
|
||||
`treemacs-COLLAPSE-actions-config'."
|
||||
(interactive "P")
|
||||
(-when-let (state (treemacs--prop-at-point :state))
|
||||
(--if-let (cdr (assq state treemacs-COLLAPSE-actions-config))
|
||||
(progn
|
||||
(funcall it arg)
|
||||
(treemacs--evade-image))
|
||||
(treemacs-pulse-on-failure "No COLLAPSE action defined for node of type %s."
|
||||
(propertize (format "%s" state) 'face 'font-lock-type-face)))))
|
||||
|
||||
(defun treemacs-define-COLLAPSE-action (state action)
|
||||
"Define the behaviour of `treemacs-COLLAPSE-action'.
|
||||
Determines that a button with a given STATE should lead to the execution of
|
||||
ACTION.
|
||||
The list of possible states can be found in `treemacs-valid-button-states'.
|
||||
ACTION should be one of the `treemacs-visit-node-*' commands."
|
||||
(setf treemacs-COLLAPSE-actions-config (assq-delete-all state treemacs-COLLAPSE-actions-config))
|
||||
(push (cons state action) treemacs-COLLAPSE-actions-config))
|
||||
|
||||
(defun treemacs-visit-node-in-external-application ()
|
||||
"Open current file according to its mime type in an external application.
|
||||
Treemacs knows how to open files on linux, windows and macos."
|
||||
@@ -340,8 +386,12 @@ Treemacs knows how to open files on linux, windows and macos."
|
||||
('darwin
|
||||
(shell-command (format "open \"%s\"" path)))
|
||||
('gnu/linux
|
||||
(let ((process-connection-type nil))
|
||||
(start-process "" nil "xdg-open" path)))
|
||||
(let (process-connection-type)
|
||||
(start-process
|
||||
"" nil "sh" "-c"
|
||||
;; XXX workaround for #633
|
||||
(format "xdg-open %s; sleep 1"
|
||||
(shell-quote-argument path)))))
|
||||
(_ (treemacs-pulse-on-failure "Don't know how to open files on %s."
|
||||
(propertize (symbol-name system-type) 'face 'font-lock-string-face))))
|
||||
(treemacs-pulse-on-failure "Nothing to open here.")))
|
||||
@@ -365,120 +415,11 @@ With a prefix ARG call `treemacs-kill-buffer' instead."
|
||||
(kill-buffer-and-window))
|
||||
(run-hooks 'treemacs-kill-hook)))
|
||||
|
||||
(defun treemacs-delete (&optional arg)
|
||||
"Delete node at point.
|
||||
A delete action must always be confirmed. Directories are deleted recursively.
|
||||
By default files are deleted by moving them to the trash. With a prefix ARG
|
||||
they will instead be wiped irreversibly."
|
||||
(interactive "P")
|
||||
(treemacs-block
|
||||
(treemacs-unless-let (btn (treemacs-current-button))
|
||||
(treemacs-pulse-on-failure "Nothing to delete here.")
|
||||
(treemacs-error-return-if (not (memq (treemacs-button-get btn :state)
|
||||
'(file-node-open file-node-closed dir-node-open dir-node-closed)))
|
||||
"Only files and directories can be deleted.")
|
||||
(treemacs--without-filewatch
|
||||
(let* ((delete-by-moving-to-trash (not arg))
|
||||
(path (treemacs-button-get btn :path))
|
||||
(file-name (propertize (treemacs--filename path) 'face 'font-lock-string-face)))
|
||||
(cond
|
||||
((f-symlink? path)
|
||||
(if (yes-or-no-p (format "Remove link '%s -> %s' ? "
|
||||
file-name
|
||||
(propertize (file-symlink-p path) 'face 'font-lock-face)))
|
||||
(delete-file path delete-by-moving-to-trash)
|
||||
(treemacs-return (treemacs-log "Cancelled."))))
|
||||
((f-file? path)
|
||||
(if (yes-or-no-p (format "Delete '%s' ? " file-name))
|
||||
(delete-file path delete-by-moving-to-trash)
|
||||
(treemacs-return (treemacs-log "Cancelled."))))
|
||||
((f-directory? path)
|
||||
(if (yes-or-no-p (format "Recursively delete '%s' ? " file-name))
|
||||
(delete-directory path t delete-by-moving-to-trash)
|
||||
(treemacs-return (treemacs-log "Cancelled."))))
|
||||
(t
|
||||
(treemacs-error-return
|
||||
(treemacs-pulse-on-failure
|
||||
"Item is neither a file, a link or a directory - treemacs does not know how to delete it. (Maybe it no longer exists?)"))))
|
||||
(treemacs--on-file-deletion path)
|
||||
(treemacs-without-messages
|
||||
(treemacs-run-in-every-buffer
|
||||
(treemacs-delete-single-node path)))
|
||||
(treemacs-log "Deleted %s."
|
||||
(propertize path 'face 'font-lock-string-face))))
|
||||
(treemacs--evade-image))))
|
||||
|
||||
(defun treemacs-create-file ()
|
||||
"Create a new file.
|
||||
Enter first the directory to create the new file in, then the new file's name.
|
||||
The pre-selection for what directory to create in is based on the \"nearest\"
|
||||
path to point - the containing directory for tags and files or the directory
|
||||
itself, using $HOME when there is no path at or near point to grab."
|
||||
(interactive)
|
||||
(treemacs--create-file/dir t))
|
||||
|
||||
(defun treemacs-move-file ()
|
||||
"Move file (or directory) at point.
|
||||
Destination may also be a filename, in which case the moved file will also
|
||||
be renamed."
|
||||
(interactive)
|
||||
(treemacs--copy-or-move :move))
|
||||
|
||||
(defun treemacs-copy-file ()
|
||||
"Copy file (or directory) at point.
|
||||
Destination may also be a filename, in which case the copied file will also
|
||||
be renamed."
|
||||
(interactive)
|
||||
(treemacs--copy-or-move :copy))
|
||||
|
||||
(cl-defun treemacs-rename ()
|
||||
"Rename the currently selected node.
|
||||
Buffers visiting the renamed file or visiting a file inside a renamed directory
|
||||
and windows showing them will be reloaded. The list of recent files will
|
||||
likewise be updated."
|
||||
(interactive)
|
||||
(treemacs-block
|
||||
(-let [btn (treemacs-current-button)]
|
||||
(treemacs-error-return-if (null btn)
|
||||
"Nothing to rename here.")
|
||||
(let* ((old-path (treemacs-button-get btn :path))
|
||||
(project (treemacs--find-project-for-path old-path))
|
||||
(new-path nil)
|
||||
(new-name nil)
|
||||
(dir nil))
|
||||
(treemacs-error-return-if (null old-path)
|
||||
"Found nothing to rename here.")
|
||||
(treemacs-error-return-if (not (file-exists-p old-path))
|
||||
"The file to be renamed does not exist.")
|
||||
(setq new-name (treemacs--read-string "New name: " (file-name-nondirectory old-path))
|
||||
dir (f-dirname old-path)
|
||||
new-path (f-join dir new-name))
|
||||
(treemacs-error-return-if (file-exists-p new-path)
|
||||
"A file named %s already exists."
|
||||
(propertize new-name 'face font-lock-string-face))
|
||||
(treemacs--without-filewatch (rename-file old-path new-path))
|
||||
(treemacs--replace-recentf-entry old-path new-path)
|
||||
(-let [treemacs-silent-refresh t]
|
||||
(treemacs-run-in-every-buffer
|
||||
(treemacs--on-rename old-path new-path treemacs-filewatch-mode)
|
||||
(treemacs--do-refresh (current-buffer) project)))
|
||||
(treemacs--reload-buffers-after-rename old-path new-path)
|
||||
(treemacs-goto-file-node new-path project)
|
||||
(treemacs-pulse-on-success "Renamed %s to %s."
|
||||
(propertize (treemacs--filename old-path) 'face font-lock-string-face)
|
||||
(propertize new-name 'face font-lock-string-face))))))
|
||||
|
||||
(defun treemacs-create-dir ()
|
||||
"Create a new directory.
|
||||
Enter first the directory to create the new dir in, then the new dir's name.
|
||||
The pre-selection for what directory to create in is based on the \"nearest\"
|
||||
path to point - the containing directory for tags and files or the directory
|
||||
itself, using $HOME when there is no path at or near point to grab."
|
||||
(interactive)
|
||||
(treemacs--create-file/dir nil))
|
||||
|
||||
(defun treemacs-toggle-show-dotfiles ()
|
||||
"Toggle the hiding and displaying of dotfiles."
|
||||
"Toggle the hiding and displaying of dotfiles.
|
||||
|
||||
For toggling the display of git-ignored files see
|
||||
`treemacs-hide-gitignored-files-mode'."
|
||||
(interactive)
|
||||
(setq treemacs-show-hidden-files (not treemacs-show-hidden-files))
|
||||
(treemacs-run-in-every-buffer
|
||||
@@ -487,14 +428,17 @@ itself, using $HOME when there is no path at or near point to grab."
|
||||
(if treemacs-show-hidden-files "displayed." "hidden.")))
|
||||
|
||||
(defun treemacs-toggle-fixed-width ()
|
||||
"Toggle whether the treemacs buffer should have a fixed width.
|
||||
"Toggle whether the local treemacs buffer should have a fixed width.
|
||||
See also `treemacs-width.'"
|
||||
(interactive)
|
||||
(setq treemacs--width-is-locked (not treemacs--width-is-locked)
|
||||
window-size-fixed (when treemacs--width-is-locked 'width))
|
||||
(treemacs-log "Window width has been %s."
|
||||
(propertize (if treemacs--width-is-locked "locked" "unlocked")
|
||||
'face 'font-lock-string-face)))
|
||||
(-if-let (buffer (treemacs-get-local-buffer))
|
||||
(with-current-buffer buffer
|
||||
(setq treemacs--width-is-locked (not treemacs--width-is-locked)
|
||||
window-size-fixed (when treemacs--width-is-locked 'width))
|
||||
(treemacs-log "Window width has been %s."
|
||||
(propertize (if treemacs--width-is-locked "locked" "unlocked")
|
||||
'face 'font-lock-string-face)))
|
||||
(treemacs-log-failure "There is no treemacs buffer in the current scope.")))
|
||||
|
||||
(defun treemacs-set-width (&optional arg)
|
||||
"Select a new value for `treemacs-width'.
|
||||
@@ -507,6 +451,38 @@ With a prefix ARG simply reset the width of the treemacs window."
|
||||
(read-number))))
|
||||
(treemacs--set-width treemacs-width))
|
||||
|
||||
(defun treemacs-increase-width (&optional arg)
|
||||
"Increase the value for `treemacs-width' with `treemacs-width-increment'.
|
||||
With a prefix ARG add the increment value multiple times."
|
||||
(interactive "P")
|
||||
(let* ((treemacs-window (treemacs-get-local-window))
|
||||
(multiplier (if (numberp arg) arg 1))
|
||||
(old-width (window-body-width treemacs-window))
|
||||
(new-width (+ old-width (* multiplier treemacs-width-increment))))
|
||||
(setq treemacs-width new-width)
|
||||
(treemacs--set-width new-width)
|
||||
(let ((current-size (window-body-width treemacs-window)))
|
||||
(when (not (eq current-size new-width))
|
||||
(setq treemacs-width old-width)
|
||||
(treemacs--set-width old-width)
|
||||
(treemacs-pulse-on-failure "Could not increase window width!")))))
|
||||
|
||||
(defun treemacs-decrease-width (&optional arg)
|
||||
"Decrease the value for `treemacs-width' with `treemacs-width-increment'.
|
||||
With a prefix ARG substract the increment value multiple times."
|
||||
(interactive "P")
|
||||
(let* ((treemacs-window (treemacs-get-local-window))
|
||||
(multiplier (if (numberp arg) arg 1))
|
||||
(old-width (window-body-width treemacs-window))
|
||||
(new-width (- old-width (* multiplier treemacs-width-increment))))
|
||||
(setq treemacs-width new-width)
|
||||
(treemacs--set-width new-width)
|
||||
(let ((current-size (window-body-width treemacs-window)))
|
||||
(when (not (eq current-size new-width))
|
||||
(setq treemacs-width old-width)
|
||||
(treemacs--set-width old-width)
|
||||
(treemacs-pulse-on-failure "Could not decrease window width!")))))
|
||||
|
||||
(defun treemacs-copy-absolute-path-at-point ()
|
||||
"Copy the absolute path of the node at point."
|
||||
(interactive)
|
||||
@@ -516,8 +492,10 @@ With a prefix ARG simply reset the width of the treemacs window."
|
||||
"There is nothing to copy here")
|
||||
(treemacs-error-return-if (not (stringp path))
|
||||
"Path at point is not a file.")
|
||||
(-let [copied (-> path (f-full) (kill-new))]
|
||||
(treemacs-pulse-on-success "Copied absolute path: %s" (propertize copied 'face 'font-lock-string-face))))))
|
||||
(when (file-directory-p path)
|
||||
(setf path (treemacs--add-trailing-slash path)))
|
||||
(kill-new path)
|
||||
(treemacs-pulse-on-success "Copied absolute path: %s" (propertize path 'face 'font-lock-string-face)))))
|
||||
|
||||
(defun treemacs-copy-relative-path-at-point ()
|
||||
"Copy the path of the node at point relative to the project root."
|
||||
@@ -529,7 +507,9 @@ With a prefix ARG simply reset the width of the treemacs window."
|
||||
"There is nothing to copy here")
|
||||
(treemacs-error-return-if (not (stringp path))
|
||||
"Path at point is not a file.")
|
||||
(-let [copied (-> path (f-full) (file-relative-name (treemacs-project->path project)) (kill-new))]
|
||||
(when (file-directory-p path)
|
||||
(setf path (treemacs--add-trailing-slash path)))
|
||||
(-let [copied (-> path (file-relative-name (treemacs-project->path project)) (kill-new))]
|
||||
(treemacs-pulse-on-success "Copied relative path: %s" (propertize copied 'face 'font-lock-string-face))))))
|
||||
|
||||
(defun treemacs-copy-project-path-at-point ()
|
||||
@@ -602,7 +582,7 @@ without the need to call `treemacs-resort' with a prefix arg."
|
||||
((or 'file-node-open 'file-node-closed 'tag-node-open 'tag-node-closed 'tag-node)
|
||||
(let* ((parent (treemacs-button-get btn :parent)))
|
||||
(while (and parent
|
||||
(not (-some-> parent (treemacs-button-get :path) (f-directory?))))
|
||||
(not (-some-> parent (treemacs-button-get :path) (file-directory-p))))
|
||||
(setq parent (treemacs-button-get parent :parent)))
|
||||
(if parent
|
||||
(let ((line (line-number-at-pos))
|
||||
@@ -791,12 +771,14 @@ With a prefix ARG select project to remove by name."
|
||||
save-pos (not (equal project (treemacs-project-at-point)))))
|
||||
(pcase (if save-pos
|
||||
(treemacs-save-position
|
||||
(treemacs-do-remove-project-from-workspace project))
|
||||
(treemacs-do-remove-project-from-workspace project))
|
||||
(treemacs-do-remove-project-from-workspace project nil :ask))
|
||||
(treemacs-do-remove-project-from-workspace project nil :ask))
|
||||
(`success
|
||||
(whitespace-cleanup)
|
||||
(treemacs-pulse-on-success "Removed project %s from the workspace."
|
||||
(propertize (treemacs-project->name project) 'face 'font-lock-type-face)))
|
||||
(`user-cancel
|
||||
(ignore))
|
||||
(`cannot-delete-last-project
|
||||
(treemacs-pulse-on-failure "Cannot delete the last project."))
|
||||
(`(invalid-project ,reason)
|
||||
@@ -890,21 +872,22 @@ workspaces."
|
||||
(interactive)
|
||||
(treemacs-unless-let (btn (treemacs-current-button))
|
||||
(treemacs-log-failure "There is nothing to refresh.")
|
||||
(treemacs--do-refresh (current-buffer) (treemacs-project-of-node btn))))
|
||||
(treemacs-without-recenter
|
||||
(treemacs--do-refresh (current-buffer) (treemacs-project-of-node btn)))))
|
||||
|
||||
(defun treemacs-collapse-project (&optional arg)
|
||||
"Close the project at point.
|
||||
With a prefix ARG also forget about all the nodes opened in the project."
|
||||
(interactive "P")
|
||||
(treemacs-unless-let (btn (treemacs-current-button))
|
||||
(treemacs-unless-let (project (treemacs-project-at-point))
|
||||
(treemacs-pulse-on-failure "There is nothing to close here.")
|
||||
(while (not (treemacs-button-get btn :project))
|
||||
(setq btn (treemacs-button-get btn :parent)))
|
||||
(when (eq 'root-node-open (treemacs-button-get btn :state))
|
||||
(treemacs--forget-last-highlight)
|
||||
(goto-char btn)
|
||||
(treemacs--collapse-root-node btn arg)
|
||||
(treemacs--maybe-recenter 'on-distance))))
|
||||
(-let [btn (treemacs-project->position project)]
|
||||
(when (treemacs-is-node-expanded? btn)
|
||||
(treemacs--forget-last-highlight)
|
||||
(goto-char btn)
|
||||
(treemacs--collapse-root-node btn arg)
|
||||
(treemacs--maybe-recenter 'on-distance)))
|
||||
(treemacs-pulse-on-success "Collapsed current project")))
|
||||
|
||||
(defun treemacs-collapse-all-projects (&optional arg)
|
||||
"Collapses all projects.
|
||||
@@ -917,47 +900,29 @@ With a prefix ARG also forget about all the nodes opened in the projects."
|
||||
(when (eq 'root-node-open (treemacs-button-get pos :state))
|
||||
(goto-char pos)
|
||||
(treemacs--collapse-root-node pos arg)))))
|
||||
(treemacs--maybe-recenter 'on-distance))
|
||||
(treemacs--maybe-recenter 'on-distance)
|
||||
(treemacs-pulse-on-success "Collapsed all projects"))
|
||||
|
||||
(defun treemacs-collapse-other-projects (&optional arg)
|
||||
"Collapses all projects except the project at point.
|
||||
With a prefix ARG also forget about all the nodes opened in the projects."
|
||||
(interactive "P")
|
||||
(save-excursion
|
||||
(-let [curr-project (-some-> (treemacs-current-button)
|
||||
(treemacs--nearest-path)
|
||||
(treemacs--find-project-for-path))]
|
||||
(-let [curr-project (treemacs-project-at-point)]
|
||||
(dolist (project (treemacs-workspace->projects (treemacs-current-workspace)))
|
||||
(unless (eq project curr-project)
|
||||
(-when-let (pos (treemacs-project->position project))
|
||||
(when (eq 'root-node-open (treemacs-button-get pos :state))
|
||||
(goto-char pos)
|
||||
(treemacs--collapse-root-node pos arg)))))))
|
||||
(treemacs--maybe-recenter 'on-distance))
|
||||
(treemacs--maybe-recenter 'on-distance)
|
||||
(treemacs-pulse-on-success "Collapsed all other projects"))
|
||||
|
||||
(defun treemacs-peek ()
|
||||
"Peek at the content of the node at point.
|
||||
This will display the file (or tag) at point in `next-window' much like
|
||||
`treemacs-visit-node-no-split' would. The difference that the file is not
|
||||
really (or rather permanently) opened - any command other than `treemacs-peek',
|
||||
`treemacs-next-line-other-window', `treemacs-previous-line-other-window',
|
||||
`treemacs-next-page-other-window' or `treemacs-previous-page-other-window' will
|
||||
cause it to be closed again and the previously shown buffer to be restored. The
|
||||
buffer visiting the peeked file will also be killed again, unless it was already
|
||||
open before being used for peeking."
|
||||
(interactive)
|
||||
(treemacs--execute-button-action
|
||||
:save-window t
|
||||
:ensure-window-split t
|
||||
:window (-some-> btn (treemacs--nearest-path) (get-file-buffer) (get-buffer-window))
|
||||
:no-match-explanation "Only files and tags are peekable."
|
||||
:file-action (treemacs--setup-peek-buffer btn)
|
||||
:tag-action (treemacs--setup-peek-buffer btn t)))
|
||||
|
||||
(defun treemacs-root-up ()
|
||||
(defun treemacs-root-up (&optional _)
|
||||
"Move treemacs' root one level upward.
|
||||
Only works with a single project in the workspace."
|
||||
(interactive)
|
||||
(interactive "P")
|
||||
(treemacs-block
|
||||
(unless (= 1 (length (treemacs-workspace->projects (treemacs-current-workspace))))
|
||||
(treemacs-error-return
|
||||
@@ -968,9 +933,9 @@ Only works with a single project in the workspace."
|
||||
(let* ((project (-> btn (treemacs--nearest-path) (treemacs--find-project-for-path)))
|
||||
(old-root (treemacs-project->path project))
|
||||
(new-root (treemacs--parent old-root))
|
||||
(new-name (if (f-root? new-root)
|
||||
"/"
|
||||
(file-name-nondirectory new-root)))
|
||||
(new-name (pcase new-root
|
||||
("/" new-root)
|
||||
(_ (file-name-nondirectory new-root))))
|
||||
(treemacs--no-messages t)
|
||||
(treemacs-pulse-on-success nil))
|
||||
(unless (treemacs-is-path old-root :same-as new-root)
|
||||
@@ -979,10 +944,10 @@ Only works with a single project in the workspace."
|
||||
(treemacs-do-add-project-to-workspace new-root new-name)
|
||||
(treemacs-goto-file-node old-root))))))
|
||||
|
||||
(defun treemacs-root-down ()
|
||||
(defun treemacs-root-down (&optional _)
|
||||
"Move treemacs' root into the directory at point.
|
||||
Only works with a single project in the workspace."
|
||||
(interactive)
|
||||
(interactive "P")
|
||||
(treemacs-block
|
||||
(treemacs-error-return-if (/= 1 (length (treemacs-workspace->projects (treemacs-current-workspace))))
|
||||
"Free navigation is only possible when there is but a single project in the workspace.")
|
||||
@@ -997,8 +962,7 @@ Only works with a single project in the workspace."
|
||||
(treemacs-do-remove-project-from-workspace (treemacs-project-at-point) :ignore-last-project-restriction)
|
||||
(treemacs--reset-dom) ;; remove also the previous root's dom entry
|
||||
(treemacs-do-add-project-to-workspace new-root (file-name-nondirectory new-root))
|
||||
(treemacs-goto-file-node new-root)
|
||||
(treemacs-toggle-node)))
|
||||
(treemacs-goto-file-node new-root)))
|
||||
(_
|
||||
(treemacs-pulse-on-failure "Button at point is not a directory."))))))
|
||||
|
||||
@@ -1012,8 +976,8 @@ Only works with a single project in the workspace."
|
||||
'(("* Directory Extensions" . directory)
|
||||
("* Project Extensions" . project)
|
||||
("* Root Extetensions" . root)) )
|
||||
(let ((top-name (symbol-value (intern (s-lex-format "treemacs--${name}-top-extensions"))))
|
||||
(bottom-name (symbol-value (intern (s-lex-format "treemacs--${name}-bottom-extensions")))))
|
||||
(let ((top-name (symbol-value (intern (format "treemacs--%s-top-extensions" name))))
|
||||
(bottom-name (symbol-value (intern (format "treemacs--%s-bottom-extensions" name)))))
|
||||
(push headline txt)
|
||||
(pcase-dolist
|
||||
(`(,pos-txt . ,pos-val)
|
||||
@@ -1091,6 +1055,8 @@ Only works with a single project in the workspace."
|
||||
"Finish editing your workspaces and apply the change."
|
||||
(interactive)
|
||||
(treemacs-block
|
||||
(treemacs-error-return-if (not (equal (buffer-name) treemacs--org-edit-buffer-name))
|
||||
"This is not a valid treemacs workspace edit buffer")
|
||||
(treemacs--org-edit-remove-validation-msg)
|
||||
(widen)
|
||||
(whitespace-cleanup)
|
||||
@@ -1102,16 +1068,25 @@ Only works with a single project in the workspace."
|
||||
(treemacs--org-edit-display-validation-msg err-msg err-line))
|
||||
('success
|
||||
(treemacs--invalidate-buffer-project-cache)
|
||||
(f-write (apply #'concat (--map (concat it "\n") lines)) 'utf-8 treemacs-persist-file)
|
||||
(kill-buffer)
|
||||
(write-region
|
||||
(apply #'concat (--map (concat it "\n") lines))
|
||||
nil
|
||||
treemacs-persist-file
|
||||
nil :silent)
|
||||
(treemacs--restore)
|
||||
(-if-let (ws (treemacs--select-workspace-by-name
|
||||
(treemacs-workspace->name (treemacs-current-workspace))))
|
||||
(setf (treemacs-current-workspace) ws)
|
||||
(treemacs--find-workspace))
|
||||
(treemacs--consolidate-projects)
|
||||
(-some-> (get-buffer treemacs--org-edit-buffer-name) (kill-buffer))
|
||||
(if (and (treemacs-get-local-window)
|
||||
(= 2 (length (window-list))))
|
||||
(kill-buffer)
|
||||
(quit-window)
|
||||
(kill-buffer-and-window))
|
||||
(run-hooks 'treemacs-workspace-edit-hook)
|
||||
(when treemacs-hide-gitignored-files-mode
|
||||
(treemacs--prefetch-gitignore-cache 'all))
|
||||
(treemacs-log "Edit completed successfully."))))))
|
||||
|
||||
(defun treemacs-collapse-parent-node (arg)
|
||||
@@ -1219,6 +1194,20 @@ absolute path of the node (if it is present)."
|
||||
(message "%s" (pfuture-callback-output))
|
||||
(kill-buffer buffer)))))
|
||||
|
||||
(defun treemacs-narrow-to-current-file ()
|
||||
"Close everything except the view on the current file.
|
||||
This command is best understood as a combination of
|
||||
`treemacs-collapse-all-projects' followed by `treemacs-find-file'."
|
||||
(interactive)
|
||||
(treemacs-unless-let (buffer (treemacs-get-local-buffer))
|
||||
(treemacs-log-failure "There is no treemacs buffer")
|
||||
(let* ((treemacs-pulse-on-success nil)
|
||||
(treemacs-pulse-on-failure nil)
|
||||
(treemacs--no-messages t))
|
||||
(with-current-buffer buffer
|
||||
(treemacs-collapse-all-projects :forget-all))
|
||||
(treemacs-find-file))))
|
||||
|
||||
(defun treemacs-select-scope-type ()
|
||||
"Select the scope for treemacs buffers.
|
||||
The default (and only) option is scoping by frame, which means that every Emacs
|
||||
@@ -1244,6 +1233,79 @@ To programmatically set the scope type see `treemacs-set-scope-type'."
|
||||
(treemacs-log "Scope of type %s is now in effect."
|
||||
(propertize selection 'face 'font-lock-type-face))))))
|
||||
|
||||
(defun treemacs-cleanup-litter ()
|
||||
"Collapse all nodes matching any of `treemacs-litter-directories'."
|
||||
(interactive)
|
||||
(-let [litter-list (-map #'regexp-quote treemacs-litter-directories)]
|
||||
(treemacs-run-in-every-buffer
|
||||
(treemacs-save-position
|
||||
(dolist (project (treemacs-workspace->projects workspace))
|
||||
(treemacs-walk-reentry-dom (-> project treemacs-project->path treemacs-find-in-dom)
|
||||
(lambda (dom-node)
|
||||
(-let [path (treemacs-dom-node->key dom-node)]
|
||||
(when (and (stringp path)
|
||||
(--any? (string-match-p it path) litter-list))
|
||||
(--when-let (treemacs-find-node path project)
|
||||
(goto-char it)
|
||||
(treemacs-toggle-node :purge)))))))))
|
||||
(treemacs-pulse-on-success "Cleanup complete.")))
|
||||
|
||||
(defun treemacs-fit-window-width ()
|
||||
"Make treemacs wide enough to display its entire content.
|
||||
|
||||
Specifically this will increase (or reduce) the width of the treemacs window to
|
||||
that of the longest line, counting all lines, not just the ones that are
|
||||
visible."
|
||||
(interactive)
|
||||
(let ((longest 0)
|
||||
(depth 0))
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (= 0 (forward-line 1))
|
||||
(-let [new-len (- (point-at-eol) (point-at-bol))]
|
||||
(when (> new-len longest)
|
||||
(setf longest new-len
|
||||
depth (treemacs--prop-at-point :depth))))))
|
||||
(let* ((icon-px-diff (* depth (- treemacs--icon-size (frame-char-width))))
|
||||
(icon-offset (% icon-px-diff (frame-char-width)))
|
||||
(new-width (+ longest icon-offset)))
|
||||
(setf treemacs-width new-width)
|
||||
(treemacs--set-width new-width)
|
||||
(treemacs-pulse-on-success "Width set to %s"
|
||||
(propertize (format "%s" new-width) 'face 'font-lock-string-face)))))
|
||||
|
||||
(defun treemacs-extra-wide-toggle ()
|
||||
"Expand the treemacs window to an extr-wide state (or turn it back).
|
||||
|
||||
Specifically this will toggle treemacs' width between
|
||||
`treemacs-wide-toggle-width' and the normal `treemacs-width'."
|
||||
(interactive)
|
||||
(if (get 'treemacs-extra-wide-toggle :toggle-on)
|
||||
(progn
|
||||
(treemacs--set-width treemacs-width)
|
||||
(put 'treemacs-extra-wide-toggle :toggle-on nil)
|
||||
(treemacs-log "Switched to normal width display"))
|
||||
(treemacs--set-width treemacs-wide-toggle-width)
|
||||
(put 'treemacs-extra-wide-toggle :toggle-on t)
|
||||
(treemacs-log "Switched to extra width display")))
|
||||
|
||||
(defun treemacs-next-workspace (&optional arg)
|
||||
"Switch to the next workspace.
|
||||
With a prefix ARG switch to the previous workspace instead."
|
||||
(interactive)
|
||||
(treemacs-block
|
||||
(treemacs-error-return-if (= 1 (length treemacs--workspaces))
|
||||
"There is only 1 workspace.")
|
||||
(let* ((ws (treemacs-current-workspace))
|
||||
(ws-count (length treemacs--workspaces))
|
||||
(idx (--find-index (eq it ws) treemacs--workspaces))
|
||||
(new-idx (% (+ ws-count (if arg (1- idx) (1+ idx))) ws-count))
|
||||
(new-ws (nth new-idx treemacs--workspaces)))
|
||||
(treemacs-do-switch-workspace new-ws)
|
||||
(treemacs-pulse-on-success "Switched to workdpace '%s'"
|
||||
(propertize (treemacs-workspace->name new-ws)
|
||||
'face 'font-lock-string-face)))))
|
||||
|
||||
(defun treemacs-icon-catalogue ()
|
||||
"Showcase a catalogue of all treemacs themes and their icons."
|
||||
(interactive)
|
||||
|
||||
Reference in New Issue
Block a user