File: m-buffer-macro.el

package info (click to toggle)
m-buffer-el 0.15-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 212 kB
  • sloc: lisp: 1,189; makefile: 52
file content (123 lines) | stat: -rw-r--r-- 4,088 bytes parent folder | download | duplicates (2)
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