add lisp packages
This commit is contained in:
156
lisp/treemacs-magit.el
Normal file
156
lisp/treemacs-magit.el
Normal file
@@ -0,0 +1,156 @@
|
||||
;;; treemacs-magit.el --- Magit integration for treemacs -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2020 Alexander Miller
|
||||
|
||||
;; Author: Alexander Miller <alexanderm@web.de>
|
||||
;; Package-Requires: ((emacs "25.2") (treemacs "0.0") (pfuture "1.3" ) (magit "2.90.0"))
|
||||
;; Package-Version: 20200421.1426
|
||||
;; Package-Commit: 1ce0bd487f0b9178744e19bbc48b6692c55c590c
|
||||
;; Version: 0
|
||||
;; Homepage: https://github.com/Alexander-Miller/treemacs
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
;;; Closing the gaps for filewatch- and git-modes in conjunction with magit.
|
||||
;;; Specifically this package will hook into magit so as to artificially
|
||||
;;; produce filewatch events for changes that treemacs would otherwise
|
||||
;;; not catch, nameley the committing and (un)staging of files.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'treemacs)
|
||||
(require 'magit)
|
||||
(require 'pfuture)
|
||||
(require 'seq)
|
||||
|
||||
;; no need for dash for a single when-let
|
||||
(eval-when-compile
|
||||
(when (version< emacs-version "26")
|
||||
(defalias 'if-let* #'if-let)
|
||||
(defalias 'when-let* #'when-let)))
|
||||
|
||||
(defvar treemacs-magit--timers nil
|
||||
"Cached list of roots an update is scheduled for.")
|
||||
|
||||
(defun treemacs-magit--schedule-update ()
|
||||
"Schedule an update to potentially run after 3 seconds of idle time.
|
||||
In order for the update to fully run several conditions must be met:
|
||||
* A timer for an update for the given dir must not already exist
|
||||
(see `treemacs-magit--timers')
|
||||
* The dir must be part of a treemacs workspace, and
|
||||
* The project must not be set for refresh already."
|
||||
(when treemacs-git-mode
|
||||
(let ((magit-root (treemacs--canonical-path (magit-toplevel))))
|
||||
(unless (member magit-root treemacs-magit--timers)
|
||||
(push magit-root treemacs-magit--timers)
|
||||
(run-with-idle-timer
|
||||
3 nil
|
||||
(lambda ()
|
||||
(unwind-protect
|
||||
(pcase treemacs-git-mode
|
||||
('simple
|
||||
(treemacs-magit--simple-git-mode-update magit-root))
|
||||
((or 'extended 'deferred)
|
||||
(treemacs-magit--extended-git-mode-update magit-root)))
|
||||
(setf treemacs-magit--timers (delete magit-root treemacs-magit--timers)))))))))
|
||||
|
||||
(defun treemacs-magit--simple-git-mode-update (magit-root)
|
||||
"Update the project at the given MAGIT-ROOT.
|
||||
Without the parsing ability of extended git-mode this update uses
|
||||
filewatch-mode's mechanics to update the entire project."
|
||||
(treemacs-run-in-every-buffer
|
||||
(when-let* ((project (treemacs--find-project-for-path magit-root)))
|
||||
(let* ((project-root (treemacs-project->path project))
|
||||
(dom-node (treemacs-find-in-dom project-root)))
|
||||
(when (and dom-node
|
||||
(null (treemacs-dom-node->refresh-flag dom-node)))
|
||||
(treemacs--set-refresh-flags project-root 'magit-refresh project-root))))))
|
||||
|
||||
(defun treemacs-magit--extended-git-mode-update (magit-root)
|
||||
"Update the project at the given MAGIT-ROOT.
|
||||
This runs due to a commit or stash action, so we know that no files have
|
||||
actually been added or deleted. This allows us to forego rebuilding the entire
|
||||
project structure just to be sure we caught everything. Instead we grab the
|
||||
current git status and just go through the lines as they are right now."
|
||||
;; we run a single git process to update every buffer, so we need to gather
|
||||
;; the visible dirs in every buffer
|
||||
;; this collection may contain duplicates, but they are removed in python
|
||||
(-let [visible-dirs nil]
|
||||
(treemacs-run-in-every-buffer
|
||||
(dolist (dir (-some->> magit-root
|
||||
(treemacs-find-in-dom)
|
||||
(treemacs-dom-node->children)
|
||||
(-map #'treemacs-dom-node->key)))
|
||||
(push dir visible-dirs)))
|
||||
(pfuture-callback `(,treemacs-python-executable
|
||||
"-O" "-S"
|
||||
,treemacs--git-status.py
|
||||
,magit-root
|
||||
,(number-to-string treemacs-max-git-entries)
|
||||
,treemacs-git-command-pipe
|
||||
,@visible-dirs)
|
||||
:directory magit-root
|
||||
:on-success
|
||||
(progn
|
||||
(ignore status)
|
||||
(treemacs-magit--update-callback magit-root pfuture-buffer)))))
|
||||
|
||||
(defun treemacs-magit--update-callback (magit-root pfuture-buffer)
|
||||
"Run the update as a pfuture callback.
|
||||
Will update nodes under MAGIT-ROOT with output in PFUTURE-BUFFER."
|
||||
(let ((ht (read (pfuture-output-from-buffer pfuture-buffer))))
|
||||
(treemacs-run-in-every-buffer
|
||||
(let ((dom-node (or (treemacs-find-in-dom magit-root)
|
||||
(when-let* ((project
|
||||
(seq-find
|
||||
(lambda (pr) (treemacs-is-path (treemacs-project->path pr) :in magit-root))
|
||||
(treemacs-workspace->projects (treemacs-current-workspace)))))
|
||||
(treemacs-find-in-dom (treemacs-project->path project))))))
|
||||
(when (and dom-node
|
||||
(null (treemacs-dom-node->refresh-flag dom-node)))
|
||||
(save-excursion
|
||||
(goto-char (treemacs-dom-node->position dom-node))
|
||||
(forward-line 1)
|
||||
(let* ((node (treemacs-node-at-point))
|
||||
(start-depth (-some-> node (treemacs-button-get :depth)))
|
||||
(curr-depth start-depth)
|
||||
(path (-some-> node (treemacs-button-get :key))))
|
||||
(treemacs-with-writable-buffer
|
||||
(while (and node
|
||||
(file-exists-p path)
|
||||
(>= curr-depth start-depth))
|
||||
(put-text-property (treemacs-button-start node) (treemacs-button-end node) 'face
|
||||
(treemacs--get-node-face
|
||||
path ht
|
||||
(if (memq (treemacs-button-get node :state)
|
||||
'(file-node-open file-node-closed))
|
||||
'treemacs-git-unmodified-face
|
||||
'treemacs-directory-face)))
|
||||
(forward-line 1)
|
||||
(if (eobp)
|
||||
(setf node nil)
|
||||
(setf node (treemacs-node-at-point)
|
||||
path (-some-> node (treemacs-button-get :path))
|
||||
curr-depth (-some-> node (treemacs-button-get :depth)))))))))))))
|
||||
|
||||
(unless (featurep 'treemacs-magit)
|
||||
(add-hook 'magit-post-commit-hook #'treemacs-magit--schedule-update)
|
||||
(add-hook 'git-commit-post-finish-hook #'treemacs-magit--schedule-update)
|
||||
(add-hook 'magit-post-stage-hook #'treemacs-magit--schedule-update)
|
||||
(add-hook 'magit-post-unstage-hook #'treemacs-magit--schedule-update))
|
||||
|
||||
(provide 'treemacs-magit)
|
||||
|
||||
;;; treemacs-magit.el ends here
|
||||
Reference in New Issue
Block a user