├── .gitignore ├── Cask ├── README.org └── fullframe.el /.gitignore: -------------------------------------------------------------------------------- 1 | .cask/* 2 | *.elc 3 | -------------------------------------------------------------------------------- /Cask: -------------------------------------------------------------------------------- 1 | (source melpa) 2 | 3 | (package-file "fullframe.el") 4 | 5 | (development 6 | (depends-on "ecukes") 7 | (depends-on "espuds")) 8 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | Development takes now place at sourcehut: https://sr.ht/~tomterl/tomtel/ . 2 | 3 | * Generalized automatic execution in a single frame 4 | 5 | [[https://stable.melpa.org/#/fullframe][file:http://stable.melpa.org/packages/fullframe-badge.svg]] 6 | [[https://melpa.org/#/fullframe][file:http://melpa.org/packages/fullframe-badge.svg]] 7 | 8 | This is a library that package developers can use to provide user 9 | friendly single window per frame execution of buffer exposing 10 | commands, as well as to use in personal emacs configurations to attain 11 | the same goal for packages that don't use =fullframe= or the likes of 12 | it themselves. 13 | 14 | Example: Setup =magit-status= to open in one window in the current 15 | frame when called: 16 | 17 | #+BEGIN_SRC emacs-lisp 18 | (require 'fullframe) 19 | (fullframe magit-status magit-mode-quit-window) 20 | #+END_SRC 21 | 22 | ** API 23 | 24 | Fullframe exposes one function, =fullframe= 25 | 26 | #+BEGIN_SRC emacs-lisp 27 | (fullframe enter-command 28 | exit-command 29 | &optional kill-buffer-after-exit-command 30 | after-command-on-func) 31 | #+END_SRC 32 | 33 | - =enter-command= is the function you want to execute in a single window in the current frame. 34 | - =exit-command= is the symbol of a function -- or a list of function symbols -- which, when called, should restore the window configuration. 35 | - =kill-buffer-after-exit-command= can be set to true if 36 | =exit-command= does not kill the buffer =enter-command= created, and 37 | you want that buffer gone. 38 | - =after-command-on-func= will be called after =command-on= was 39 | called and the buffer generated by it is visible in the only window 40 | in the current frame 41 | 42 | *** =after-command-on-func= example 43 | 44 | This call will show the current buffer and the =rgrep= result only; if the =rgrep= result buffer is closed (with =q=), the previous window configuration is restored. 45 | 46 | #+BEGIN_SRC emacs-lisp 47 | (fullframe rgrep quit-window 48 | nil 49 | (lambda () 50 | (let ((wconf (fullframe/current-buffer-window-config)) 51 | (new-window (split-window-below))) 52 | (set-window-buffer new-window "*grep*") 53 | (fullframe/erase-current-buffer-window-config) 54 | (with-current-buffer "*grep*" 55 | (fullframe/set-current-buffer-window-config wconf))))) 56 | #+END_SRC 57 | 58 | ** Installation 59 | 60 | =fullframe= is available on [[http://melpa.org/#/fullframe][melpa]] and [[http://stable.melpa.org][melpa-stable]]. 61 | 62 | [[http://melpa.org/#/getting-started][Add melpa to your package sources]], then execute the following in emacs: 63 | 64 | #+BEGIN_SRC emacs-lisp 65 | M-x package-install fullframe 66 | #+END_SRC 67 | 68 | If you use =cask= for your package-management, make sure you have 69 | =(source 'melpa)= in your =Cask= file and add 70 | 71 | #+BEGIN_SRC emacs-lisp 72 | (depends-on "fullframe") 73 | #+END_SRC 74 | 75 | to it. 76 | ** Configuration 77 | 78 | The simple usage does not need configuration. 79 | 80 | If you want to fullframe functions, but your workflow makes you use 81 | multiple commands to exit the buffer in question, you don't have to 82 | use multiple calls to ~fullframe~. 83 | 84 | You have two possibilities: 85 | 86 | - Pass a list of all possible exit-commands to ~fullframe~ 87 | - Revise the customization list ~fullframe/generic-quit-commands~ and 88 | set ~fullframe/advice-generic-quit-commands~ to ~t~. 89 | - mix both 90 | -------------------------------------------------------------------------------- /fullframe.el: -------------------------------------------------------------------------------- 1 | ;;; fullframe.el --- Generalized automatic execution in a single frame 2 | 3 | ;; Copyright (C) 2013 Tom Regner 4 | 5 | ;; Author: Tom Regner 6 | ;; Maintainer: Tom Regner 7 | ;; Version: 0.5.0 8 | ;; Keywords: fullscreen 9 | ;; Package-Requires: ((cl-lib "0.5")) 10 | 11 | ;; This file is NOT part of GNU Emacs 12 | ;; 13 | ;; This program is free software: you can redistribute it and/or modify 14 | ;; it under the terms of the GNU General Public License as published by 15 | ;; the Free Software Foundation, either version 3 of the License, or 16 | ;; (at your option) any later version. 17 | ;; 18 | ;; This program is distributed in the hope that it will be useful, 19 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | ;; GNU General Public License for more details. 22 | ;; 23 | ;; You should have received a copy of the GNU General Public License 24 | ;; along with this program. If not, see . 25 | ;; 26 | ;; SPDX-License-Identifier: GPL-3.0-or-later 27 | 28 | ;;; Commentary: 29 | ;; Generalized automatic execution in a single frame 30 | ;; 31 | ;; This is a library that package developers can use to provide user 32 | ;; friendly single window per frame execution of buffer exposing 33 | ;; commands, as well as to use in personal Emacs configurations to attain 34 | ;; the same goal for packages that don't use =fullframe= or the likes of 35 | ;; it themself. 36 | ;; 37 | ;; Example: Setup =magit-status= to open in one window in the current 38 | ;; frame when called 39 | ;; Example: 40 | ;; - Open magit-status in a single window in fullscreen 41 | ;; (require 'fullframe) 42 | ;; (fullframe magit-status magit-mode-quit-window nil) 43 | ;; 44 | ;;; Code: 45 | 46 | 47 | (require 'cl-lib) 48 | 49 | ;; customization 50 | ;; 51 | 52 | (defcustom fullframe/advice-generic-quit-commands nil 53 | "If set to a non-nil value, on each call to fullframe ALL 54 | functions in `fullframe/generic-exit-frame-commands' will be 55 | adviced to restore the previous window configuration, not only 56 | the one given as `exit-cmd' to the fullframe-call. 57 | 58 | The default value is `nil'." 59 | :type '(boolean) 60 | :group 'fullframe) 61 | 62 | (defcustom fullframe/generic-quit-commands 63 | '(kill-this-buffer kill-current-buffer kill-buffer-and-window kill-other-buffer-and-window bury-buffer) 64 | "List of functions that will adviced in addition to `command-off', iff `fullframe/advice-generic-quit-commands' is not `nil'" 65 | :type '(set :value-type function) 66 | :group 'fullframe) 67 | 68 | ;; variables 69 | (defvar fullframe/previous-window-configuration nil 70 | "The window configuration to restore.") 71 | (make-variable-buffer-local 'fullframe/previous-window-configuration) 72 | 73 | ;; internal functions 74 | 75 | (defmacro fullframe/with-gensym (names &rest body) 76 | "Make macros relying on multiple `cl-gensym' calls more readable. 77 | Takes a list of symbols NAMES and defines `cl-gensym' variables 78 | in a `let' that has BODY as body. The symbol names generated 79 | are prefixed with \"fullframe/--\", the variable names are as 80 | given in NAMES. 81 | 82 | Example: 83 | 84 | \(fullframe/with-gensym (one two three) 85 | (progn 86 | `(let ((,one \"one\") 87 | (,two \"two\") 88 | (,three \"three\")) 89 | (message \"%s:%s:%s\\n\" ,one ,two ,three))\) 90 | 91 | Instead of 92 | 93 | \(let ((one (cl-gensym \"sym-one\")) 94 | (two (cl-gensym \"sym-two\")) 95 | (three (cl-gensym \"sym-three\"))) 96 | `(let ((,one \"one\") 97 | (,two \"two\") 98 | (,three \"three\")) 99 | (message \"%s:%s:%s\\n\" ,one ,two ,three))) 100 | 101 | Idea attributed to Peter Seibel where I found it." 102 | (declare (indent defun)) 103 | `(let 104 | ,(cl-loop for n in names collect 105 | `(,n (cl-gensym (concat "fullframe/--" 106 | (symbol-name (quote ,n)))))) 107 | ,@body)) 108 | 109 | (defun fullframe/maybe-restore-configuration (config) 110 | "Restore CONFIG if non-nil." 111 | (when config 112 | (condition-case nil 113 | (set-window-configuration config) 114 | (error (message "Failed to restore all windows."))))) 115 | 116 | ;; API 117 | ;;;###autoload 118 | (defun fullframe/current-buffer-window-config () 119 | "Return the window-configuration stored for the current buffer." 120 | fullframe/previous-window-configuration) 121 | 122 | ;;;###autoload 123 | (defun fullframe/erase-current-buffer-window-config () 124 | "Forget the window config associated with the current buffer." 125 | (setq fullframe/previous-window-configuration nil)) 126 | 127 | ;;;###autoload 128 | (defun fullframe/set-current-buffer-window-config (wconf) 129 | "Associate the current buffer with the window-configuration WCONF." 130 | (setq fullframe/previous-window-configuration wconf)) 131 | 132 | ;;;###autoload 133 | (defmacro fullframe/split-screen (command-on command-off second-buffer &optional direction switch-to-second-buffer size) 134 | "After COMMAND-ON is executed and only one window present in 135 | the current frame, split the frame in two windows ('below or 136 | 'right, depending on DIRECTION being `horizontal' or 137 | `vertical') and switch the new window to the buffer 138 | SECOND-BUFFER (name or symbol). If SWITCH-TO-SECOND-BUFFER is 139 | not `nil', the window holding SECOND-BUFFER will be activated. 140 | " 141 | `(fullframe ,command-on 142 | ,command-off 143 | nil 144 | (lambda () 145 | (let ((wconf (fullframe/current-buffer-window-config)) 146 | (new-window (if (eq 'horizontal ,direction)(split-window-right)(split-window-below)))) 147 | (set-window-buffer new-window ,second-buffer) 148 | (fullframe/erase-current-buffer-window-config) 149 | (if ,switch-to-second-buffer (select-window new-window)) 150 | (with-current-buffer ,second-buffer 151 | (fullframe/set-current-buffer-window-config wconf)))))) 152 | 153 | ;;;###autoload 154 | (defmacro fullframe (command-on command-off &optional kill-on-coff after-command-on-func) 155 | "Save window/frame state when executing COMMAND-ON. 156 | 157 | Advises COMMAND-ON so that the buffer it displays will appear in 158 | a full-frame window. The previous window configuration will be 159 | restored when COMMAND-OFF is executed in that buffer. If 160 | KILL-ON-COFF is non-nil, then the buffer will also be killed 161 | after COMMAND-OFF has completed. 162 | 163 | This function uses `defadvice' on versions of emacs < 24.4, 164 | `advice-add' otherwise. 165 | 166 | AFTER-COMMAND-ON-FUNC is called after COMMAND-ON was called and 167 | the window it generated is the only one in in the frame. 168 | " 169 | (when (keywordp kill-on-coff) 170 | (error "The register parameter for fullframe has been removed")) 171 | (fullframe/with-gensym (window-config window-config-post buf) 172 | (let ((on-code `(let ((,window-config-post (current-window-configuration))) 173 | (delete-other-windows) 174 | (unless (equal ,window-config-post (current-window-configuration)) 175 | (setq fullframe/previous-window-configuration ,window-config)) 176 | ,@(when after-command-on-func 177 | (list `(funcall #',after-command-on-func))))) 178 | (off-code `(progn 179 | (fullframe/maybe-restore-configuration ,window-config) 180 | ,@(when kill-on-coff (list `(kill-buffer ,buf))))) 181 | (exit-cmds `(append (if fullframe/advice-generic-quit-commands fullframe/generic-quit-commands nil) 182 | (if (and (not (functionp ',command-off)) (listp ',command-off)) ',command-off (list ',command-off))))) 183 | (if (version< emacs-version "24.4") 184 | `(progn 185 | (require 'fullframe) 186 | (defadvice ,command-on (around fullframe activate) 187 | (let ((,window-config (current-window-configuration))) 188 | ad-do-it 189 | ,on-code)) 190 | (dolist (coff ,exit-cmds) 191 | (defadvice coff (around fullframe activate) 192 | (let ((,window-config fullframe/previous-window-configuration) 193 | (,buf (current-buffer))) 194 | (prog1 195 | ad-do-it 196 | ,off-code))))) 197 | `(progn 198 | (require 'fullframe) 199 | (advice-add #',command-on :around 200 | #'(lambda (orig-fun &rest args) 201 | (let ((,window-config (current-window-configuration))) 202 | (apply orig-fun args) 203 | ,on-code)) 204 | '((name . "fullframe-command-on-advice"))) 205 | (dolist (coff ,exit-cmds) 206 | (progn 207 | (advice-add coff :around 208 | #'(lambda (orig-fun &rest args) 209 | (let ((,window-config fullframe/previous-window-configuration) 210 | (,buf (current-buffer))) 211 | (prog1 212 | (apply orig-fun args) 213 | ,off-code))) 214 | '((name . "fullframe-command-off-advice")))))))))) 215 | 216 | ;; interactive functions 217 | ;; - none 218 | 219 | (provide 'fullframe) 220 | ;;; fullframe.el ends here 221 | --------------------------------------------------------------------------------