1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
;;; m-buffer-macro.el --- Create and dispose of markers -*- lexical-binding: t -*-
;;; Header:
;; This file is not part of Emacs
;; The contents of this file are subject to the GPL License, Version 3.0.
;; Copyright (C) 2014, Phillip Lord, Newcastle University
;; 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 <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This file provides some utility macros which help to support stateless
;; operation on buffers, by restoring global state after to what it was before
;; the macro starts.
;; These macros are quite useful, but with the exception of
;; `m-buffer-with-markers', they are mostly meant to underpin `m-buffer-at'. The
;; aim is that all the cases where one of these macros is used with a single form
;; from core Emacs should be provided by m-buffer-at (although this is not the
;; case yet). These macros might be more efficient if there are a lot of calls to
;; group together.
;;; Code:
;; ** Markers
;; Markers are generally much nicer than integers, but needs cleaning up
;; afterwards if a lot are created. It's possible to do this using
;; `m-buffer-nil-marker', but it can be a bit painful. This form looks like a
;; `let' form, but removes markers at the end.
;; #+begin_src emacs-lisp
(defmacro m-buffer-with-markers (varlist &rest body)
"Bind variables after VARLIST then eval BODY.
VARLIST is of the same form as `let'. All variables should
contain markers or collections of markers. All markers are niled
after BODY."
;; indent let part specially, and debug like let
(declare (indent 1)(debug let))
;; so, create a rtn var with make-symbol (for hygene)
(let* ((rtn-var (make-symbol "rtn-var"))
(marker-vars
(mapcar 'car varlist))
(full-varlist
(append
varlist
`((,rtn-var
(progn
,@body))))))
`(let* ,full-varlist
(m-buffer-nil-marker
(list ,@marker-vars))
,rtn-var)))
;; #+end_src
;; ** Point and Buffer
;; These macros are extensions of `with-current-buffer', and `save-excursion',
;; which set the current buffer and location.
;; #+begin_src emacs-lisp
(defmacro m-buffer-with-current-marker
(marker &rest body)
"At MARKER location run BODY."
(declare (indent 1) (debug t))
`(with-current-buffer
(marker-buffer ,marker)
(save-excursion
(goto-char ,marker)
,@body)))
(defmacro m-buffer-with-current-position
(buffer location &rest body)
"In BUFFER at LOCATION, run BODY."
(declare (indent 2)
(debug t))
`(with-current-buffer
,buffer
(save-excursion
(goto-char ,location)
,@body)))
;; #+end_src
;; Combines the last two!
;; #+begin_src emacs-lisp
(defmacro m-buffer-with-current-location
(location &rest body)
"At LOCATION, run BODY.
LOCATION should be a list. If a one element list, it is a marker.
If a two element, it is a buffer and position."
(declare (indent 1) (debug t))
;; multiple eval of location!
(let ((loc (make-symbol "loc")))
`(let ((,loc ,location))
(if (= 1 (length ,loc))
(m-buffer-with-current-marker
(nth 0 ,loc)
,@body)
(if (= 2 (length ,loc))
(m-buffer-with-current-position
(nth 0 ,loc)
(nth 1 ,loc)
,@body)
(error "m-buffer-with-current-location requires a list of one or two elements"))))))
(provide 'm-buffer-macro)
;;; m-buffer-macro.el ends here
;; #+end_src
|