From fca83ffc1931608169323505cd6df45d026982f2 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Mon, 21 Dec 2015 05:44:44 -0500 Subject: [PATCH] Replace popwin with shackle; refactor window/buffer defuns --- Cask | 2 +- core/core-eval.el | 15 +- core/core-popup.el | 505 ++++++++++++++++++++++++++---------- core/core-ui.el | 36 +-- core/core-workgroups.el | 28 +- core/lib/defuns-buffers.el | 111 ++++---- core/lib/defuns-quickrun.el | 32 +-- core/lib/defuns-repl.el | 35 +++ private/my-bindings.el | 19 +- private/my-commands.el | 7 +- 10 files changed, 508 insertions(+), 282 deletions(-) create mode 100644 core/lib/defuns-repl.el diff --git a/Cask b/Cask index aefffbf0b..b685c95a9 100644 --- a/Cask +++ b/Cask @@ -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") diff --git a/core/core-eval.el b/core/core-eval.el index 4db902d1c..6afcfcd58 100644 --- a/core/core-eval.el +++ b/core/core-eval.el @@ -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 diff --git a/core/core-popup.el b/core/core-popup.el index be742504b..be2de6b86 100644 --- a/core/core-popup.el +++ b/core/core-popup.el @@ -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)) - (setq rtog/--last-buffer nil - narf-repl-buffer nil)) - (kill-this-buffer)) - (when popup-p - (popwin:close-popup-window t)))) + (defvar narf-popup-windows '() + "A list of windows that have been opened via shackle. Do not touch this!") - (defun narf/popup-open (buffer &optional height) - (popwin:popup-buffer buffer)) + (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)) + ((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-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 diff --git a/core/core-ui.el b/core/core-ui.el index ade6cc01e..6c939120d 100644 --- a/core/core-ui.el +++ b/core/core-ui.el @@ -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-help]" - "\\\\[helm-select-action]" - "\\\\[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 diff --git a/core/core-workgroups.el b/core/core-workgroups.el index 5e1fc4bc9..ce09d3934 100644 --- a/core/core-workgroups.el +++ b/core/core-workgroups.el @@ -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 diff --git a/core/lib/defuns-buffers.el b/core/lib/defuns-buffers.el index d914ef5a2..ed97510ae 100644 --- a/core/lib/defuns-buffers.el +++ b/core/lib/defuns-buffers.el @@ -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) - (wg-buffer-list-emacs) - (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))))) + + (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 "") + (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 "") @@ -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) diff --git a/core/lib/defuns-quickrun.el b/core/lib/defuns-quickrun.el index d3ff22214..c2e0536b7 100644 --- a/core/lib/defuns-quickrun.el +++ b/core/lib/defuns-quickrun.el @@ -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 "") - (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 diff --git a/core/lib/defuns-repl.el b/core/lib/defuns-repl.el new file mode 100644 index 000000000..2fa4b2038 --- /dev/null +++ b/core/lib/defuns-repl.el @@ -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 "") + (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 diff --git a/private/my-bindings.el b/private/my-bindings.el index 92c518e5c..fafd2fb4e 100644 --- a/private/my-bindings.el +++ b/private/my-bindings.el @@ -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 "" (λ! (kill-buffer) - (if (narf/popup-p (current-buffer)) - (narf/popup-close) - (evil-window-delete)))))) + :n "" 'narf/popup-close))) ;; Line-wise mouse selection on margin (global-set-key (kbd " ") 'narf/mouse-drag-line) diff --git a/private/my-commands.el b/private/my-commands.el index 414aa1c3c..418943a45 100644 --- a/private/my-commands.el +++ b/private/my-commands.el @@ -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)