Replace popwin with shackle; refactor window/buffer defuns

This commit is contained in:
Henrik Lissner 2015-12-21 05:44:44 -05:00
parent 6b38183786
commit fca83ffc19
10 changed files with 508 additions and 282 deletions

2
Cask
View file

@ -24,7 +24,7 @@
(depends-on "applescript-mode")
;; Popups --- core/core-popup.el
(depends-on "popwin")
(depends-on "shackle")
;; UI --- core/core-ui.el
(depends-on "visual-fill-column")

View file

@ -9,8 +9,8 @@
quickrun-replace-region
helm-quickrun)
:config
(setq quickrun-focus-p t)
(add-hook! quickrun/mode '(linum-mode yascroll-bar-mode))
(setq quickrun-focus-p nil)
(add-hook! quickrun/mode '(linum-mode))
(add-to-list 'quickrun-file-alist '("\\.gvy$" . "groovy")))
(use-package repl-toggle
@ -18,14 +18,15 @@
:init
(setq rtog/mode-repl-alist '())
(defvar repl-p nil)
(make-variable-buffer-local 'repl-p)
(defun narf|repl-init ()
(yascroll-bar-mode +1)
(evil-initialize-state 'emacs)
(setq mode-line-format nil))
(add-hook! repl-toggle-mode 'narf|repl-init)
:config
(map! :map repl-toggle-mode-map
"ESC ESC" 'narf/popup-close))
(setq mode-line-format nil
repl-p t))
(add-hook! repl-toggle-mode 'narf|repl-init))
(provide 'core-eval)
;;; core-eval.el ends here

View file

@ -1,182 +1,409 @@
;;; core-popup.el --- hacks for better popwin integration
(use-package popwin
:init
(use-package shackle
:config
(setq popwin:popup-window-height 0.3)
(mapc (lambda (rule) (push rule popwin:special-display-config))
'(("*Help*" :position bottom :height 0.25 :stick t)
(debugger-mode :position bottom :height 15 :dedicated t :stick t)
("*evil-registers*" :position bottom :height 0.3 :stick t)
("*scratch*" :position bottom :height 20 :stick t)
("*Apropos*" :position bottom :height 40 :stick t)
("*Backtrace*" :position bottom :height 15 :dedicated t :stick t)
("*Flycheck errors*" :position bottom :height 15 :stick t)
("*quickrun*" :position bottom :height 15 :stick t)
("*minor-modes*" :position bottom :height 0.5 :stick t)
("^\\*CPU-Profiler-Report .+\\*$" :regexp t :position bottom :height 0.35)
(shackle-mode 1)
(setq shackle-rules
'(;; Plugins
("*Flycheck errors*" :align below :ratio 0.3 :select t)
("\\` ?\\*[hH]elm.*?\\*\\'" :regexp t :align below :ratio 0.25 :select t)
(" *NeoTree*" :align left :select t)
("*evil-registers*" :align below :ratio 0.3)
("*quickrun*" :align below :ratio 0.1 :noselect t)
("*eval*" :align below :ratio 0.25)
;; vcs
("^\\*git-gutter.+\\*$" :regexp t :position bottom :height 0.4 :stick t)
("*vc-diff*" :position bottom :height 0.4 :stick t)
("*vc-change-log*" :position bottom :stick t :noselect t)
("^\\*git-gutter.+\\*$" :regexp t :align below :ratio 0.4 :noselect t)
("*vc-diff*" :align below :ratio 0.4 :noselect t)
("*vc-change-log*" :align below :select t)
(vc-annotate-mode :same t)
;; Helm
("^\\*[Hh]elm.*?\\*\\'" :regexp t :position bottom :height 0.2)
("*helm-mode-find-file-at-point*" :position bottom :height 10)
("*helm-mode-ffap*" :position bottom :height 10)
("*Apropos*" :align below :ratio 0.3)
("*minor-modes*" :align below :ratio 0.5 :noselect t)
;; Org
(org-src-mode :position bottom :height 0.5 :stick t)
(org-agenda-mode :position bottom :height 0.4 :stick t)
("^\\*Org-Babel.*\\*$" :regexp t :position bottom :height 15 :tail t)
("*Agenda Commands*" :position bottom :height 0.5)
(" *Org todo*" :position bottom :height 5)
("*Org Links*" :position bottom :height 2)
("^\\*Org Src .+\\*$" :regexp t :align below :ratio 0.4 :select t)
("^\\*Org-Babel.*\\*$" :regexp t :align below :ratio 0.4)
(org-agenda-mode :align below :ratio 0.4)
("*Agenda Commands*" :align below :ratio 0.5)
(" *Org todo*" :align below :noselect t)
("*Org Links*" :align below :ratio 0.05)
;; Emacs
("^\\*.+-Profiler-Report .+\\*$" :regexp t :align below :ratio 0.3)
("*Backtrace*" :align below :ratio 0.25 :noselect t)
("*scratch*" :align below :ratio 0.3 :select t)
("*Help*" :align below :ratio 0.25)
("*Messages*" :align below :ratio 0.35 :select t)
(debugger-mode :align below :ratio 0.25 :noselect t)
(compilation-mode :noselect t)
;; REPLs
((lambda (buffer) (with-current-buffer buffer (bound-and-true-p repl-toggle-mode)))
:position bottom :height 0.2 :stick t)
((:custom (lambda (b &rest _)
(when (string-prefix-p "*" (buffer-name (get-buffer b)))
(with-current-buffer b repl-p))))
:popup t :align below :ratio 0.3)
))
(popwin-mode 1)
(after! helm
;; This is a good alternative to either popwin or shackle, specifically for helm. If
;; either fail me (for the last time), this is where I'll turn.
;;(add-to-list 'display-buffer-alist
;; `(,(rx bos "*helm" (* not-newline) "*" eos)
;; (display-buffer-in-side-window)
;; (inhibit-same-window . t)
;; (window-height . 0.4)))
(after! evil
;; Fix disruptive errors w/ hidden buffers caused by popwin
(defadvice evil-ex-hl-do-update-highlight (around evil-ex-hidden-buffer-ignore-errors activate)
(ignore-errors ad-do-it)))
;; Helm tries to clean up after itself, but shackle has already done this. This fixes
;; that. To reproduce, add a helm rule in `shackle-rules', open two splits
;; side-by-side, move to the buffer on the right and invoke helm. It will close all
;; but th left-most buffer.
(setq-default helm-split-window-in-side-p t))
(after! neotree
(when neo-persist-show
(add-hook! 'popwin:before-popup-hook (setq neo-persist-show nil))
(add-hook! 'popwin:after-popup-hook (setq neo-persist-show t))))
(after! helm-ag
;; Helm-ag needs a little coaxing for it to cooperate with shackle. Mostly to prevent
;; it from switching between windows and buffers.
(defadvice helm-ag--edit-abort (around helm-ag-edit-abort-popup-compat activate)
(cl-letf (((symbol-function 'select-window) 'ignore)) ad-do-it)
(narf/popup-close nil t t))
(defadvice helm-ag--edit-commit (around helm-ag-edit-commit-popup-compat activate)
(cl-letf (((symbol-function 'select-window) 'ignore)) ad-do-it)
(narf/popup-close nil t t))
(defadvice helm-ag--edit (around helm-ag-edit-popup-compat activate)
(cl-letf (((symbol-function 'other-window) 'ignore)
((symbol-function 'switch-to-buffer) 'narf/popup-buffer))
ad-do-it)))
(after! quickrun
;; This allows us to run code several times in a row without having to close the popup
;; window and move back to the code buffer.
(defun narf*quickrun-close-popwin (&optional _ _ _ _)
(when (get-buffer quickrun/buffer-name)
(quickrun/kill-quickrun-buffer)
(popwin:close-popup-window-if-necessary)))
(defun quickrun/pop-to-buffer (buf cb)
(popwin:pop-to-buffer buf)
(with-current-buffer buf
(evil-resize-window 5)
(funcall cb)
(setq mode-line-format nil)))
(defun narf/quickrun-after-run ()
(with-selected-window popwin:popup-window
(let* ((lines (count-lines (point-min) (point-max)))
(act-lines (max 5 (min 40 (count-lines (point-min) (point-max))))))
(evil-resize-window act-lines)
(goto-char (point-min)))))
(add-hook! quickrun-after-run 'narf/quickrun-after-run)
(let* ((buffer (get-buffer quickrun/buffer-name))
(window (and buffer (get-buffer-window buffer))))
(when buffer
(shut-up! (quickrun/kill-running-process))
(narf/popup-close window nil t))))
(advice-add 'quickrun :before 'narf*quickrun-close-popwin)
(advice-add 'quickrun-region :before 'narf*quickrun-close-popwin))
(advice-add 'quickrun-region :before 'narf*quickrun-close-popwin)
(after! helm
(defun narf/helm-split-window (&optional window)
"Minimalistic split-fn; leaves popwin to handle helm buffers."
popwin:popup-window)
;; Turns on `yascroll-bar-mode' and `nlinum-mode', and ensures window is scrolled to
;; EOF and that the scrollbar is showing.
(defun narf|quickrun-after-run ()
(let ((window (get-buffer-window quickrun/buffer-name)))
(with-selected-window window
(yascroll-bar-mode +1)
(narf|nlinum-enable)
(setq mode-line-format nil)
(let* ((lines (count-lines (point-min) (point-max)))
(act-lines (max 5 (min 30 lines))))
(set-window-start window (evil-line-position (+ 2 (- lines act-lines))))
(evil-resize-window act-lines)
(yascroll:safe-show-scroll-bar) ; scroll-bar starts hidden, but not anymore!
))))
(add-hook 'quickrun-after-run-hook 'narf|quickrun-after-run)
(setq-default
helm-split-window-preferred-function 'narf/helm-split-window
helm-display-function 'popwin:pop-to-buffer)
;; I let `narf|quickrun-after-run' handle scrolling, so quickrun shouldn't have to!
(advice-add 'quickrun/recenter :override 'ignore))
(defadvice helm-ag--edit-abort (around helm-ag-edit-abort-popwin-compat activate)
(cl-letf (((symbol-function 'select-window) 'ignore)) ad-do-it))
(defadvice helm-ag--edit-commit (around helm-ag-edit-commit-popwin-compat activate)
(cl-letf (((symbol-function 'select-window) 'ignore)) ad-do-it))
;; I remove any attempt to kill the helm-ag window, because popwin handles it.
(defun helm-ag--edit (_candidate)
(let ((default-directory helm-ag--default-directory))
(with-current-buffer (get-buffer-create "*helm-ag-edit*")
(erase-buffer)
(setq-local helm-ag--default-directory helm-ag--default-directory)
(let (buf-content)
(with-current-buffer (get-buffer "*helm-ag*")
(goto-char (point-min))
(forward-line 1)
(let* ((body-start (point))
(marked-lines (cl-loop for ov in (overlays-in body-start (point-max))
when (eq 'helm-visible-mark (overlay-get ov 'face))
return (helm-marked-candidates))))
(if (not marked-lines)
(setq buf-content (buffer-substring-no-properties
body-start (point-max)))
(setq buf-content (concat (mapconcat 'identity marked-lines "\n") "\n")))))
(insert buf-content)
(add-text-properties (point-min) (point-max)
'(read-only t rear-nonsticky t front-sticky t))
(let ((inhibit-read-only t))
(setq header-line-format
(format "[%s] C-c C-c: Commit, C-c C-k: Abort"
(abbreviate-file-name helm-ag--default-directory)))
(goto-char (point-min))
(while (re-search-forward "^\\(\\(?:[^:]+:\\)\\{1,2\\}\\)\\(.*\\)$" nil t)
(let ((file-line-begin (match-beginning 1))
(file-line-end (match-end 1))
(body-begin (match-beginning 2))
(body-end (match-end 2)))
(add-text-properties file-line-begin file-line-end
'(face font-lock-function-name-face
intangible t))
(remove-text-properties body-begin body-end '(read-only t))
(set-text-properties body-end (1+ body-end)
'(read-only t rear-nonsticky t))))))))
(popwin:display-buffer (get-buffer "*helm-ag-edit*"))
;; (other-window 1)
;; (switch-to-buffer (get-buffer "*helm-ag-edit*"))
(goto-char (point-min))
(setq next-error-function 'compilation-next-error-function)
(setq-local compilation-locs (make-hash-table :test 'equal :weakness 'value))
(use-local-map helm-ag-edit-map)))
(after! neotree
;; Ever since neotree removed the neo-modern-sidebar option, neotree's buffer-opening
;; behavior can't be controlled externally. This fixes that and is surprisingly
;; stable!
(defun neo-global--create-window ()
"Create global neotree window."
(let ((window nil)
(buffer (neo-global--get-buffer t)))
(narf/popup-buffer buffer)
(setq window
(select-window
(neo-global--get-position-window neo-window-position)))
(neo-window--init window buffer)
(neo-global--attach)
(neo-global--reset-width)
window)))
(after! repl-toggle
(map! :map repl-toggle-mode-map
"ESC ESC" 'narf/popup-close))
(add-hook! org-load
;; (defun org-src-switch-to-buffer (buffer context)
;; (popwin:popup-buffer (get-buffer buffer) :height 0.5))
;; This ensures org-src-edit yields control of its buffer to shackle.
(defun org-src-switch-to-buffer (buffer context)
(pop-to-buffer buffer))
;; And these for org-todo, org-link and agenda
(defun org-pop-to-buffer-same-window (&optional buffer-or-name norecord label)
"Pop to buffer specified by BUFFER-OR-NAME in the selected window."
(display-buffer buffer-or-name))
(defun org-switch-to-buffer-other-window (&rest args)
(mapc (lambda (b)
(let ((buf (if (stringp b) (get-buffer-create b) b)))
(popwin:pop-to-buffer buf t t)))
(pop-to-buffer buf t t)))
args)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun narf/popup-p (&optional buffer)
(and (popwin:popup-window-live-p)
(if buffer (eq buffer popwin:popup-buffer) t)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun narf/popup-close ()
(let ((popup-p (popwin:popup-window-live-p))
(comint-p (derived-mode-p 'comint-mode)))
(when comint-p
(when (eq rtog/--last-buffer (current-buffer))
(defvar narf-popup-windows '()
"A list of windows that have been opened via shackle. Do not touch this!")
(defun narf*popup-add (&rest _)
(add-to-list 'narf-popup-windows (get-buffer-window shackle-last-buffer)))
(advice-add 'shackle-display-buffer :after 'narf*popup-add)
(defun narf--popup-remove (window)
(setq narf-popup-windows (delete window narf-popup-windows)))
(defun narf/popup-p (&optional window)
(and narf-popup-windows
(-any? (lambda (w)
(if (window-live-p w) t (narf--popup-remove w) nil))
narf-popup-windows)
(if window
(-any? (lambda (w) (eq window w)) narf-popup-windows)
t)))
(defun narf/popup-buffer (buffer &optional plist)
(let ((buffer-name (if (stringp buffer) buffer (buffer-name buffer))))
(shackle-display-buffer (get-buffer-create buffer-name)
nil (or plist (shackle-match buffer-name)))))
(defun narf/popup-close (&optional window dont-kill dont-close-all)
(interactive)
(when (not window)
(if (narf/popup-p (selected-window))
(setq window (selected-window))
(unless dont-close-all
(narf-popup-close-all dont-kill))))
(when (and window (window-live-p window))
;; REPL buffer
(cond ((and (derived-mode-p 'comint-mode)
(featurep 'repl-toggle)
repl-toggle-mode)
(setq rtog/--last-buffer nil
narf-repl-buffer nil))
(kill-this-buffer))
(when popup-p
(popwin:close-popup-window t))))
((eq major-mode 'messages-buffer-mode)
(bury-buffer)
(setq dont-kill t)))
(narf--popup-remove window)
(unless dont-kill
(kill-buffer (window-buffer window)))
(delete-window window)))
(defun narf/popup-open (buffer &optional height)
(popwin:popup-buffer buffer))
(defun narf-popup-close-all (&optional dont-kill-buffers)
(interactive)
(mapc (lambda (w) (narf/popup-close w dont-kill-buffers))
narf-popup-windows)
(setq narf-popup-windows nil))
;;;;;
(defun narf/popup-toggle ()
(interactive)
(if (popwin:popup-window-live-p)
(popwin:close-popup-window)
(popwin:popup-last-buffer)))
(if (narf/popup-p)
(narf/popup-close t)
(narf/popup-last-buffer)))
(defun narf:popup-last-buffer ()
(defun narf/popup-last-buffer ()
(interactive)
(popwin:popup-last-buffer))
(if shackle-last-buffer
(narf/popup-buffer shackle-last-buffer)
(narf/popup-messages)))
(defun narf:popup-messages ()
(defun narf/popup-messages ()
(interactive)
(popwin:messages)))
(narf/popup-buffer "*Messages*")))
;; (use-package popwin
;; :disabled t
;; :config
;; (setq popwin:popup-window-height 0.3)
;; (mapc (lambda (rule) (push rule popwin:special-display-config))
;; '(("*Help*" :position bottom :height 0.3 :stick t)
;; (debugger-mode :position bottom :height 15 :dedicated t :stick t)
;; ("*evil-registers*" :position bottom :height 0.3 :stick t)
;; ("*scratch*" :position bottom :height 20 :stick t)
;; ("*Apropos*" :position bottom :height 40 :stick t)
;; ("*Backtrace*" :position bottom :height 15 :dedicated t :stick t)
;; ("*flycheck errors*" :position bottom :height 15 :stick t)
;; ("*quickrun*" :position bottom :height 15 :stick t)
;; ("*minor-modes*" :position bottom :height 0.5 :stick t)
;; ("^\\*CPU-Profiler-Report .+\\*$" :regexp t :position bottom :height 0.35)
;; ;; vcs
;; ("^\\*git-gutter.+\\*$" :regexp t :position bottom :height 0.4 :stick t)
;; ("*vc-diff*" :position bottom :height 0.4 :stick t)
;; ("*vc-change-log*" :position bottom :stick t :noselect t)
;; ;; Helm
;; ;; ("^\\*[Hh]elm.*?\\*\\'" :regexp t :position bottom :height 0.2)
;; ;; ("*helm-mode-**" :regexp t :position bottom :height 10)
;; ;; ("*helm-ag*" :position bottom :height 0.4 :stick t)
;; ;; Org
;; (org-src-mode :position bottom :height 0.5 :stick t)
;; (org-agenda-mode :position bottom :height 0.4 :stick t)
;; ("^\\*Org-Babel.*\\*$" :regexp t :position bottom :height 15 :tail t)
;; ("*Agenda Commands*" :position bottom :height 0.5)
;; (" *Org todo*" :position bottom :height 5)
;; ("*Org Links*" :position bottom :height 2)
;; ;; REPLs
;; ((lambda (buffer) (with-current-buffer buffer (bound-and-true-p repl-toggle-mode)))
;; :position bottom :height 0.2 :stick t)
;; ))
;; (popwin-mode 1)
;; (after! evil
;; ;; Fix disruptive errors w/ hidden buffers caused by popwin
;; (defadvice evil-ex-hl-do-update-highlight (around evil-ex-hidden-buffer-ignore-errors activate)
;; (ignore-errors ad-do-it)))
;; (after! neotree
;; (when neo-persist-show
;; (add-hook! 'popwin:before-popup-hook (setq neo-persist-show nil))
;; (add-hook! 'popwin:after-popup-hook (setq neo-persist-show t))))
;; (after! quickrun
;; (defun narf*quickrun-close-popwin (&optional _ _ _ _)
;; (when (get-buffer quickrun/buffer-name)
;; (quickrun/kill-quickrun-buffer)
;; (narf/popup-close "*quickrun*")))
;; (defun quickrun/pop-to-buffer (buf cb)
;; (popwin:pop-to-buffer buf)
;; (with-current-buffer buf
;; (evil-resize-window 5)
;; (funcall cb)
;; (setq mode-line-format nil)))
;; (defun narf/quickrun-after-run ()
;; (with-selected-window popwin:popup-window
;; (let* ((lines (count-lines (point-min) (point-max)))
;; (act-lines (max 5 (min 40 (count-lines (point-min) (point-max))))))
;; (evil-resize-window act-lines)
;; (goto-char (point-min)))))
;; (add-hook! quickrun-after-run 'narf/quickrun-after-run)
;; (advice-add 'quickrun :before 'narf*quickrun-close-popwin)
;; (advice-add 'quickrun-region :before 'narf*quickrun-close-popwin))
;; (after! helm
;; ;; Faster than popwin!
;; (add-to-list 'display-buffer-alist
;; `(,(rx bos "*helm" (* not-newline) "*" eos)
;; (display-buffer-in-side-window)
;; (inhibit-same-window . t)
;; (window-height . 0.4)))
;; ;; (defun narf/helm-split-window (&optional window)
;; ;; "Minimalistic split-fn; leaves popwin to handle helm buffers."
;; ;; popwin:popup-window)
;; (setq-default
;; ;; helm-split-window-preferred-function 'narf/helm-split-window
;; helm-split-window-default-side 'below
;; helm-split-window-in-side-p t
;; ;; helm-display-function 'popwin:popup-buffer
;; )
;; ;; (defadvice helm-ag--edit-abort (around helm-ag-edit-abort-popwin-compat activate)
;; ;; (cl-letf (((symbol-function 'select-window) 'ignore)) ad-do-it))
;; ;; (defadvice helm-ag--edit-commit (around helm-ag-edit-commit-popwin-compat activate)
;; ;; (cl-letf (((symbol-function 'select-window) 'ignore)) ad-do-it))
;; ;; I remove any attempt to kill the helm-ag window, because popwin handles it.
;; ;; (defun helm-ag--edit (_candidate)
;; ;; (let ((default-directory helm-ag--default-directory))
;; ;; (with-current-buffer (get-buffer-create "*helm-ag-edit*")
;; ;; (erase-buffer)
;; ;; (setq-local helm-ag--default-directory helm-ag--default-directory)
;; ;; (let (buf-content)
;; ;; (with-current-buffer (get-buffer "*helm-ag*")
;; ;; (goto-char (point-min))
;; ;; (forward-line 1)
;; ;; (let* ((body-start (point))
;; ;; (marked-lines (cl-loop for ov in (overlays-in body-start (point-max))
;; ;; when (eq 'helm-visible-mark (overlay-get ov 'face))
;; ;; return (helm-marked-candidates))))
;; ;; (if (not marked-lines)
;; ;; (setq buf-content (buffer-substring-no-properties
;; ;; body-start (point-max)))
;; ;; (setq buf-content (concat (mapconcat 'identity marked-lines "\n") "\n")))))
;; ;; (insert buf-content)
;; ;; (add-text-properties (point-min) (point-max)
;; ;; '(read-only t rear-nonsticky t front-sticky t))
;; ;; (let ((inhibit-read-only t))
;; ;; (setq header-line-format
;; ;; (format "[%s] C-c C-c: Commit, C-c C-k: Abort"
;; ;; (abbreviate-file-name helm-ag--default-directory)))
;; ;; (goto-char (point-min))
;; ;; (while (re-search-forward "^\\(\\(?:[^:]+:\\)\\{1,2\\}\\)\\(.*\\)$" nil t)
;; ;; (let ((file-line-begin (match-beginning 1))
;; ;; (file-line-end (match-end 1))
;; ;; (body-begin (match-beginning 2))
;; ;; (body-end (match-end 2)))
;; ;; (add-text-properties file-line-begin file-line-end
;; ;; '(face font-lock-function-name-face
;; ;; intangible t))
;; ;; (remove-text-properties body-begin body-end '(read-only t))
;; ;; (set-text-properties body-end (1+ body-end)
;; ;; '(read-only t rear-nonsticky t))))))))
;; ;; (popwin:display-buffer (get-buffer "*helm-ag-edit*"))
;; ;; ;; (other-window 1)
;; ;; ;; (switch-to-buffer (get-buffer "*helm-ag-edit*"))
;; ;; (goto-char (point-min))
;; ;; (setq next-error-function 'compilation-next-error-function)
;; ;; (setq-local compilation-locs (make-hash-table :test 'equal :weakness 'value))
;; ;; (use-local-map helm-ag-edit-map))
;; )
;; (add-hook! org-load
;; ;; (defun org-src-switch-to-buffer (buffer context)
;; ;; (popwin:popup-buffer (get-buffer buffer) :height 0.5))
;; (defun org-switch-to-buffer-other-window (&rest args)
;; (mapc (lambda (b)
;; (let ((buf (if (stringp b) (get-buffer-create b) b)))
;; (popwin:pop-to-buffer buf t t)))
;; args)))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (defun narf/popup-p (&optional buffer)
;; (and (popwin:popup-window-live-p)
;; (if buffer (eq buffer popwin:popup-buffer) t)))
;; (defun narf/popup-close ()
;; (let ((popup-p (popwin:popup-window-live-p))
;; (comint-p (derived-mode-p 'comint-mode)))
;; (when comint-p
;; (when (eq rtog/--last-buffer (current-buffer))
;; (setq rtog/--last-buffer nil
;; narf-repl-buffer nil))
;; (kill-this-buffer))
;; (when popup-p
;; (popwin:close-popup-window t))))
;; (defun narf/popup-buffer (buffer &optional height)
;; (popwin:popup-buffer buffer))
;; (defun narf/popup-toggle ()
;; (interactive)
;; (if (popwin:popup-window-live-p)
;; (popwin:close-popup-window)
;; (popwin:popup-last-buffer)))
;; (defun narf/popup-last-buffer ()
;; (interactive)
;; (popwin:popup-last-buffer))
;; (defun narf/popup-messages ()
;; (interactive)
;; (popwin:messages)))
(provide 'core-popup)
;;; core-popup.el ends here

View file

@ -491,41 +491,7 @@ Supports both Emacs and Evil cursor conventions."
(global :when active)
("%l/%c" *buffer-position)
*hud
))
(spaceline-define-segment helm-id
"Number of helm candidates."
(buffer-name)
:when (bound-and-true-p helm-alive-p)
:tight t)
(spaceline-define-segment helm-number
"Number of helm candidates."
(format "%d/%s (%s total)"
(helm-candidate-number-at-point)
(helm-get-candidate-number t)
(helm-get-candidate-number))
:when (bound-and-true-p helm-alive-p))
(spaceline-define-segment helm-help
"Helm keybindings help."
(-interleave
(mapcar (lambda (s)
(propertize (substitute-command-keys s) 'face 'bold))
'("\\<helm-map>\\[helm-help]"
"\\<helm-map>\\[helm-select-action]"
"\\<helm-map>\\[helm-maybe-exit-minibuffer]/F1/F2..."))
'("(help)" "(actions)" "(action)"))
:when (bound-and-true-p helm-alive-p))
(defun narf|helm-mode-line (source &optional force)
"Set up a custom helm modeline."
(setq spaceline--helm-current-source source
mode-line-format '("%e" (:eval (spaceline--prepare
'(helm-number helm-id)
'(helm-help)))))
(when force (force-mode-line-update)))
(advice-add 'helm-display-mode-line :after 'narf|helm-mode-line))
)))
(provide 'core-ui)
;;; core-ui.el ends here

View file

@ -23,30 +23,36 @@
wg-list-display-decor-previous-left ""
wg-list-display-decor-previous-right "")
:config
;; Don't mess with the modeline!
(advice-add 'wg-change-modeline :override 'ignore)
(defvar narf/helm-source-wg
'((name . "Workgroups")
(candidates . wg-workgroup-names)
(action . narf/wg-helm-switch-to-workgroup)))
(add-to-list 'savehist-additional-variables 'narf-wg-names)
(defvar narf-wg-frames '())
(defvar narf-wg-names '())
(unless (file-exists-p wg-workgroup-directory)
(mkdir wg-workgroup-directory))
(defvar narf-wg-frames '()
"A list of all the frames opened as separate workgroups. See
lib/defuns-workgroups.el.")
(defvar narf-wg-names '()
"A list of fixed names for workgroups. If a name is set, workgroup names aren't
automatically renamed to the project name.")
;; Remember the set names in between sessions
(add-to-list 'savehist-additional-variables 'narf-wg-names)
(after! projectile
;; Create a new workgroup on switch-project
(setq projectile-switch-project-action 'narf/wg-projectile-switch-project))
;; Don't remember popwin windows
(add-hook! (kill-emacs wg-before-switch-to-workgroup) 'popwin:close-popup-window)
;; Save the session every 10 minutes
(run-with-timer 0 600 'narf/wg-autosave)
;; Initialize!
(add-hook! after-init 'workgroups-mode))
;; Don't mess with the modeline!
(advice-add 'wg-change-modeline :override 'ignore)
;; Don't remember popup windows
(add-hook! (kill-emacs) 'narf-popup-close-all))
(provide 'core-workgroups)
;;; core-workgroups.el ends here

View file

@ -36,22 +36,35 @@ Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
;; Buffer Life and Death ;;;;;;;;;;;;;;;
;;;###autoload
(defun narf/get-all-buffers ()
"Get all buffers across all workgroups. Depends on
`wg-mess-with-buffer-list'."
(if (and (featurep 'workgroups2) workgroups-mode wg-mess-with-buffer-list)
(defun narf/get-buffers (&optional project-p all-p)
"Get all buffers in the current workgroup.
If PROJECT-P is non-nil, get all buffers in current workgroup
If ALL-P is non-nil, get all buffers across all workgroups
If both are non-nil, get all project buffers across all workgroups"
(let* ((wg (wg-current-workgroup t))
(buffers (if (and wg (not all-p))
(wg-workgroup-associated-buffers wg)
(if wg-mess-with-buffer-list
(wg-buffer-list-emacs)
(buffer-list)))
(buffer-list)))))
(let (project-root)
(if (and project-p (setq project-root (narf/project-root t)))
(funcall (if (eq project-p 'not) '-remove '-filter)
(lambda (b) (projectile-project-buffer-p b project-root))
buffers)
buffers))))
;;;###autoload
(defun narf/get-buffers ()
"Get all buffers in the current workgroup. Depends on
`wg-mess-with-buffer-list'."
(wg-workgroup-associated-buffers (wg-current-workgroup)))
(defun narf/get-all-buffers (&optional project-p)
"Get all buffers across all workgroups and projects (unless PROJECT-P is non-nil)."
(narf/get-buffers project-p t))
;;;###autoload
(defun narf/get-visible-windows ()
(-map #'get-buffer-window (narf/get-visible-buffers (narf/get-all-buffers))))
(defun narf/get-visible-windows (&optional buffer-list)
(-map #'get-buffer-window
(narf/get-visible-buffers (or buffer-list (narf/get-all-buffers)))))
;;;###autoload
(defun narf/get-visible-buffers (&optional buffer-list)
@ -76,7 +89,7 @@ Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
(-filter #'narf/real-buffer-p (or buffer-list (narf/get-buffers))))
;;;###autoload
(defun narf:kill-real-buffer ()
(defun narf/kill-real-buffer ()
"Kill buffer (but only bury scratch buffer), then switch to a real buffer."
(interactive)
(let ((bname (buffer-name)))
@ -90,13 +103,13 @@ Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
(get-buffer-window-list (current-buffer) nil nil)))
;; Then kill
(kill-this-buffer))))
(if (narf/popup-p (current-buffer))
(if (narf/popup-p (selected-window))
(narf/popup-close)
(unless (narf/real-buffer-p (current-buffer))
(narf/previous-real-buffer))))
;;;###autoload
(defun narf:kill-unreal-buffers ()
(defun narf/kill-unreal-buffers ()
"Kill all buried, unreal buffers in current frame. See `narf-unreal-buffers'"
(interactive)
(let* ((all-buffers (narf/get-all-buffers))
@ -104,11 +117,11 @@ Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
(kill-list (--filter (not (memq it real-buffers))
(narf/get-buried-buffers all-buffers))))
(mapc 'kill-buffer kill-list)
(narf:kill-process-buffers)
(narf/kill-process-buffers)
(message "Cleaned up %s buffers" (length kill-list))))
;;;###autoload
(defun narf:kill-process-buffers ()
(defun narf/kill-process-buffers ()
"Kill all buffers that represent running processes and aren't visible."
(interactive)
(let ((buffer-list (narf/get-buffers))
@ -127,7 +140,7 @@ Inspired from http://demonastery.org/2013/04/emacs-evil-narrow-region/"
(message "Cleaned up %s processes" killed-processes)))
;;;###autoload
(defun narf:kill-matching-buffers (regexp &optional buffer-list)
(defun narf/kill-matching-buffers (regexp &optional buffer-list)
(interactive)
(let ((i 0))
(mapc (lambda (b)
@ -179,40 +192,47 @@ left, create a scratch buffer."
(defun narf/next-real-buffer ()
"Switch to the next buffer and avoid special buffers."
(interactive)
(narf/cycle-real-buffers -1))
(narf/cycle-real-buffers +1))
;;;###autoload
(defun narf/previous-real-buffer ()
"Switch to the previous buffer and avoid special buffers."
(interactive)
(narf/cycle-real-buffers +1))
(narf/cycle-real-buffers -1))
;;;###autoload (autoload 'narf:kill-buried-buffers "defuns-buffers" nil t)
(evil-define-command narf:kill-buried-buffers (&optional bang)
"Kill buried buffers and report how many it found."
:repeat nil
(interactive "<!>")
(let ((buffers (narf/get-buried-buffers (if bang (projectile-project-buffers) (narf/get-buffers))))
(defun narf--kill-buffers (buffers &optional filter-func)
(let ((buffers (if filter-func (funcall filter-func buffers) buffers))
(affected 0))
(mapc (lambda (b) (when (kill-buffer b) (incf affected))) buffers)
(message "Cleaned up %s buffers" affected)))
(unless (narf/real-buffer-p)
(narf/previous-real-buffer))
(message "Killed %s buffers" affected)))
;;;###autoload (autoload 'narf:kill-all-buffers "defuns-buffers" nil t)
(evil-define-command narf:kill-all-buffers (&optional bang)
"Kill all project buffers. If BANG, kill *all* buffers."
:repeat nil
"Kill all project buffers. If BANG, kill *all* buffers (in workgroup)."
(interactive "<!>")
(if (and (not bang) (projectile-project-p))
(projectile-kill-buffers)
(mapc 'kill-buffer (narf/get-buffers)))
(delete-other-windows)
(unless (narf/real-buffer-p)
(narf/previous-real-buffer)))
(narf--kill-buffers (narf/get-buffers (not bang)))
(delete-other-windows))
;;;###autoload (autoload 'narf:scratch-buffer "defuns-buffers" nil t)
(evil-define-operator narf:scratch-buffer (&optional beg end bang)
"Send a selection to the scratch buffer. If BANG, then send it to org-capture
instead."
;;;###autoload (autoload 'narf:kill-buried-buffers "defuns-buffers" nil t)
(evil-define-command narf:kill-buried-buffers (&optional bang)
"Kill buried project buffers (in workgroup) and report how many it found. BANG = get all
buffers regardless of project."
(interactive "<!>")
(narf-kill-buffers (narf/get-buffers (not bang)) 'narf/get-buried-buffers))
;;;###autoload (autoload 'narf:kill-buried-buffers "defuns-buffers" nil t)
(evil-define-command narf:kill-matching-buffers (&optional bang pattern)
"Kill project buffers matching regex pattern PATTERN. If BANG, then extend search to
buffers regardless of project."
:repeat nil
(interactive "<!><a>")
(narf-kill-buffers (narf/get-matching-buffers pattern (narf/get-buffers (not bang)))))
;;;###autoload (autoload 'narf:send-to-scratch-or-org "defuns-buffers" nil t)
(evil-define-operator narf:send-to-scratch-or-org (&optional beg end bang)
"Send a selection to the scratch buffer. If BANG, then send it to org-capture instead."
:move-point nil
:type inclusive
(interactive "<r><!>")
@ -220,16 +240,17 @@ left, create a scratch buffer."
(text (when (and (evil-visual-state-p) beg end)
(buffer-substring beg end))))
(if bang
(switch-to-buffer "*scratch*")
(org-capture-string text)
;; or scratch buffer by default
(let* ((project-dir (narf/project-root t))
(buffer-name "*scratch*"))
(narf/popup-open (get-buffer-create buffer-name))
(when (eq (get-buffer buffer-name) (current-buffer))
(narf/popup-buffer buffer-name)
(with-current-buffer buffer-name
(when project-dir
(cd project-dir))
(if text (insert text))
(funcall mode))))))
(funcall mode))
))))
;;;###autoload (autoload 'narf:cd "defuns-buffers" nil t)
(evil-define-command narf:cd (dir)
@ -240,10 +261,10 @@ left, create a scratch buffer."
;;;###autoload
(defun narf/kill-all-buffers-do-not-remember ()
"Kill all buffers so that workgroups2 will forget its current session."
"Kill all buffers so that workgroups2 will wipe its current session."
(interactive)
(let ((confirm-kill-emacs nil))
(mapc 'kill-buffer (buffer-list))
(mapc 'kill-buffer (narf/get-buffers))
(kill-this-buffer)
(delete-other-windows)
(wg-save-session t)

View file

@ -55,7 +55,7 @@ If ARG is nil this function calls `recompile', otherwise it calls
(insert out)
(goto-char (point-min))
(read-only-mode 1)
(narf/popup-open buf))))))
(narf/popup-buffer buf))))))
(t (quickrun-region beg end))))
;;;###autoload (autoload 'narf:eval-region-and-replace "defuns-quickrun" nil t)
@ -70,35 +70,5 @@ If ARG is nil this function calls `recompile', otherwise it calls
(insert (current-kill 0)))))
(t (quickrun-replace-region beg end))))
(defvar narf--repl-buffer nil)
;;;###autoload (autoload 'narf:repl "defuns-quickrun" nil t)
(evil-define-command narf:repl (&optional bang)
:repeat nil
(interactive "<!>")
(if (and narf--repl-buffer (buffer-live-p narf--repl-buffer))
(if (popwin:popup-window-live-p)
(popwin:select-popup-window)
(popwin:pop-to-buffer narf--repl-buffer))
(rtog/toggle-repl (if (use-region-p) 4))
(setq narf--repl-buffer (current-buffer))))
;;;###autoload (autoload 'narf:repl-eval "defuns-quickrun" nil t)
(evil-define-operator narf:repl-eval (&optional beg end bang)
:type inclusive
:repeat nil
(interactive "<r><!>")
(let ((region-p (use-region-p))
(selection (s-trim (buffer-substring-no-properties beg end))))
(narf:repl bang)
(when (and region-p beg end)
(let* ((buf narf--repl-buffer)
(win (get-buffer-window buf)))
(unless (eq buf popwin:popup-buffer)
(popwin:pop-to-buffer buf nil t))
(when (and narf--repl-buffer (buffer-live-p narf--repl-buffer))
(with-current-buffer narf--repl-buffer
(goto-char (point-max))
(insert selection)))))))
(provide 'defuns-quickrun)
;;; defuns-quickrun.el ends here

35
core/lib/defuns-repl.el Normal file
View file

@ -0,0 +1,35 @@
;;; defuns-repl.el
(defvar narf--repl-buffer nil)
;;;###autoload (autoload 'narf:repl "defuns-repl" nil t)
(evil-define-command narf:repl (&optional bang)
:repeat nil
(interactive "<!>")
(if (and narf--repl-buffer (buffer-live-p narf--repl-buffer))
(if (popwin:popup-window-live-p)
(popwin:select-popup-window)
(popwin:pop-to-buffer narf--repl-buffer))
(rtog/toggle-repl (if (use-region-p) 4))
(setq narf--repl-buffer (current-buffer))))
;;;###autoload (autoload 'narf:repl-eval "defuns-repl" nil t)
(evil-define-operator narf:repl-eval (&optional beg end bang)
:type inclusive
:repeat nil
(interactive "<r><!>")
(let ((region-p (use-region-p))
(selection (s-trim (buffer-substring-no-properties beg end))))
(narf:repl bang)
(when (and region-p beg end)
(let* ((buf narf--repl-buffer)
(win (get-buffer-window buf)))
(unless (eq buf popwin:popup-buffer)
(popwin:pop-to-buffer buf nil t))
(when (and narf--repl-buffer (buffer-live-p narf--repl-buffer))
(with-current-buffer narf--repl-buffer
(goto-char (point-max))
(insert selection)))))))
(provide 'defuns-repl)
;;; defuns-repl.el ends here

View file

@ -30,8 +30,8 @@
"M-b" 'narf:build
"M-t" 'narf:workgroup-new
"M-T" 'narf/workgroup-display
"A-`" 'narf-switch-to-iterm
"C-`" 'popwin:messages
"A-`" 'os-switch-to-term
"C-`" 'narf/popup-messages
"C-~" 'rtog/toggle-repl
"M-`" 'narf/popup-toggle
@ -192,11 +192,13 @@
:n "zr" 'narf/evil-open-folds
:n "zm" 'narf/evil-close-folds
:n "zx" 'narf:kill-real-buffer
:n "zx" 'narf/kill-real-buffer
:n "ZX" 'bury-buffer
:n "]b" 'narf/next-real-buffer
:n "[b" 'narf/previous-real-buffer
;; These are intentionally reversed
:n "]b" 'narf/previous-real-buffer
:n "[b" 'narf/next-real-buffer
:m "]d" 'narf/vcs-next-hunk
:m "[d" 'narf/vcs-prev-hunk
:m "]e" 'narf/flycheck-next-error
@ -334,17 +336,14 @@
(:after help-mode
(:map help-map
"e" 'narf:popup-messages
"e" 'narf/popup-messages
;; Remove slow/annoying help subsections
"h" nil
"g" nil)
(:map help-mode-map
:n "]]" 'help-go-forward
:n "[[" 'help-go-back
:n "<escape>" (λ! (kill-buffer)
(if (narf/popup-p (current-buffer))
(narf/popup-close)
(evil-window-delete))))))
:n "<escape>" 'narf/popup-close)))
;; Line-wise mouse selection on margin
(global-set-key (kbd "<left-margin> <down-mouse-1>") 'narf/mouse-drag-line)

View file

@ -33,12 +33,13 @@
(exmap "git[hub]" 'narf:github-browse-file)
;; Dealing with buffers
(exmap "k[ill]" 'kill-this-buffer) ; Kill current buffer
(exmap "k[ill]" 'narf/kill-real-buffer) ; Kill current buffer
(exmap "k[ill]all" 'narf:kill-all-buffers) ; Kill all buffers (bang = in project)
(exmap "k[ill]buried" 'narf:kill-buried-buffers) ; Kill all buried buffers (bang = in project)
(exmap "k[ill]o" 'narf:kill-unreal-buffers)
(exmap "l[ast]" 'narf:popup-last-buffer)
(exmap "m[sg]" 'narf:popup-messages)
(exmap "k[ill]match" 'narf:kill-matching-buffers)
(exmap "l[ast]" 'narf/popup-last-buffer)
(exmap "m[sg]" 'narf/popup-messages)
;; Project navigation
(exmap "a" 'helm-projectile-find-other-file)