-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathwrap-region.el
266 lines (236 loc) · 10 KB
/
wrap-region.el
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
;;; wrap-region.el --- Wrap text with punctation or markup tag.
;; Copyright 2008 Johan Andersson
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; License ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 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 2 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, write to the Free
;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
;; MA 02111-1307 USA
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;; Vocabulary ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Punctuation - Is everything in written language other than the
;; actual letters or numbers ([, (, ., ", etc...).
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;; Description ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Wrap region is a minor mode that wraps a region. That of course
;; only happens when there is a region selected in the buffer. If no
;; region is selected that punctuation is inserted. And if
;; `wrap-region-insert-twice' is set to t, the corresponding
;; punctuation is inserted as weel, and the cursor is placed between
;; them. An exception to this is if `wrap-region-tag-active' is set
;; to t. Then "<" will be interped as a markup tag (<tag>...</tag>),
;; and that tag will wrap the region.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;; Installation ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; To use this mode you first have to make sure that this file is in
;; your load-path variable:
;; (add-to-list 'load-path "/path/to/directory/or/file")
;;
;; Then require it:
;; (require 'wrap-region)
;;
;; Then start it:
;; (wrap-region-mode t) or M-x wrap-region-mode
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;; Commentary ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; First of all you want to activate this mode for all major modes
;; you want to use this in:
;;
;; (add-hook 'ruby-mode-hook
;; '(lambda()
;; (wrap-region-mode t)
;; ))
;;
;; By only doing this you will activate all default punctuations. But
;; you may not want some punctuation to be used for a certain mode. If
;; That is the case you want to use `wrap-region-set-mode-punctuations'.
;;
;; (add-hook 'ruby-mode-hook
;; '(lambda()
;; (wrap-region-set-mode-punctuations '("\"" "'" "("))
;; (wrap-region-mode t)
;; ))
;;
;; This will activate the punctuations ", ', and ( only, and it will be
;; activated for ruby-mode.
;;
;; You can also pass a major mode to this function if you want to set
;; all mode specific punctuations at the same place:
;;
;; (wrap-region-set-mode-punctuations '("\"" "'" "(") 'ruby-mode)
;; (wrap-region-set-mode-punctuations '("[" "{" "(") 'java-mode)
;;
;;
;; You can also customize if you want to insert one or two punctuations
;; (and then move in between them) if there is no region selected.
;; This is configured by the variable `wrap-region-insert-twice'.
;; t means to insert two punctuations and then move in between them,
;; and nil means to only insert that punctuation.
;;
;; Insert both and move in between:
;; (setq wrap-region-insert-twice t)
;;
;; Insert punctuation only:
;; (setq wrap-region-insert-twice nil)
;;
;;
;; If noting is said, "<" will be used as a regular punctuation with
;; ">" as it's corresponding. This is desirable in languages such as
;; Java where this is syntax is used:
;; Set<Object> set = new HashSet<Object>();
;;
;; But in markup languages, such as x(HTML), XML, etc... you use tags
;; and want to make use of the tags functionality. That is controlled
;; by the variable `wrap-region-tag-active'. By setting this to t,
;; when pressing "<" you will be prompted to enter a tag, which you
;; can do in two ways.
;;
;; The first is to enter some tag such as "div". The selected region
;; will then be wrapped with the div tag:
;; <div>selected region</div>
;;
;; The second way is to also enter attributes for the tag, such as
;; class, id, name, etc... If you enter:
;; div class="some_class" id="some_id"
;; you will end up with this:
;; <div class="some_class" id="some_id">selected region</div>
;;
;;
;; This mode comes with some default punctuations
;; (see `wrap-region-punctuations-table'). This might not always be
;; enough. And there's where `wrap-region-add-punctuation' comes
;; in handy. As an example we add # as a punctuation and # as it's
;; corresponding punctuation:
;; (wrap-region-add-punctuation "#" "#")
;;
;; Note that even if you use `wrap-region-set-mode-punctuations'
;; for mode specific punctuations, you still need to use
;; `wrap-region-add-punctuation'. This is because that's how the
;; corresponding punctuation is found.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;; Variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defcustom wrap-region-insert-twice t
"If this is true, when inserting a punctuation,
the corresponding punctuation will be inserted after and
the cursor will be placed between them."
:group 'wrap-region)
(defvar wrap-region-mode-map (make-sparse-keymap)
"Keymap for `wrap-region-mode'.")
(defvar wrap-region-punctuations-table (make-hash-table :test 'equal)
"A list with all possible punctuations and their right
corresponding punctuation.")
(puthash "\"" "\"" wrap-region-punctuations-table)
(puthash "'" "'" wrap-region-punctuations-table)
(puthash "(" ")" wrap-region-punctuations-table)
(puthash "{" "}" wrap-region-punctuations-table)
(puthash "[" "]" wrap-region-punctuations-table)
(puthash "<" ">" wrap-region-punctuations-table)
(puthash "|" "|" wrap-region-punctuations-table)
(puthash "\\" "\\" wrap-region-punctuations-table)
(defvar wrap-region-tag-active nil
"This variable tells whether < are to be used
as a tag or a regular punctuation.")
(make-variable-buffer-local 'wrap-region-tag-active)
(defvar wrap-region-mode-punctuations (make-hash-table)
"Use this if you want mode specific punctuations.
Key is the symbol name of the major mode and the value is a list
of punctuations.")
(defvar wrap-region-before-hook '()
"Evaluated before the region is wrapped.
Two variables are available in the hook:
wrap-region-beginning which is the beginning of the region
and wrap-region-end which is the end of the region.")
(defvar wrap-region-after-hook '()
"Evaluated after the region is wrapped.
Two variables are available in the hook:
wrap-region-beginning which is the beginning of the region
and wrap-region-end which is the end of the region.")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun wrap-region-with-punctuation-or-insert (left)
"Wraps a region if any, else inserts the punctuation(s)."
(interactive)
(if mark-active
(wrap-region left (wrap-region-corresponding-punctuation left) (region-beginning) (region-end))
(wrap-region-insert left)))
(defun wrap-region-with-punctuations (left right)
"Wraps a region with LEFT and RIGHT."
(wrap-region left right (region-beginning) (region-end)))
(defun wrap-region-with-tag-or-insert ()
"Wraps a region with a tag if any region is selected.
Otherwise the punctuation(s) are inserted."
(interactive)
(if mark-active
(call-interactively 'wrap-region-with-tag)
(wrap-region-insert "<")))
(defun wrap-region-with-tag (tag)
"Wraps a region with a tag."
(interactive "*sTag (with optional attributes): ")
(let* ((elements (split-string tag " "))
(tag-name (car elements))
(tag-right (concat "</" tag-name ">"))
(tag-left (concat "<" (if (= (length elements) 1) tag-name tag) ">")))
(wrap-region tag-left tag-right (region-beginning) (region-end))))
(defun wrap-region-insert (left)
"Inserts LEFT or LEFT and it's corresponding punctuation
if `wrap-region-insert-twice' is set to t."
(insert left)
(cond (wrap-region-insert-twice
(insert (wrap-region-corresponding-punctuation left))
(backward-char))))
(defun wrap-region (left right beg end)
"Wraps region with LEFT and RIGHT."
(let ((wrap-region-beginning beg) (wrap-region-end end))
(run-hooks 'wrap-region-before-hook)
(save-excursion
(goto-char beg)
(insert left)
(goto-char (+ end (length left)))
(insert right))
(run-hooks 'wrap-region-after-hook)))
(defun wrap-region-corresponding-punctuation (punctuation)
"Returns the corresponding punctuation to the given punctuation
or nil if the punctuation does not exists."
(gethash punctuation wrap-region-punctuations-table))
(defun wrap-region-add-punctuation (left right)
"Adds a new punctuation pair to the punctuation list."
(puthash left right wrap-region-punctuations-table))
(defun wrap-region-set-mode-punctuations (punctuations &optional mode)
"Use this when the punctuations should be
customized depending on the major mode. MODE argument
is optional and will be set to `major-mode' as default."
(puthash (or mode major-mode) punctuations wrap-region-mode-punctuations))
(define-minor-mode wrap-region-mode
"Wrap region with punctuations or insert."
:init-value nil
:lighter " wr"
:keymap wrap-region-mode-map
(if wrap-region-mode
(let ((punctuations (gethash major-mode wrap-region-mode-punctuations)))
(unless punctuations
(maphash (lambda (k v) (add-to-list 'punctuations k)) wrap-region-punctuations-table))
(dolist (key punctuations)
(define-key wrap-region-mode-map key `(lambda () (interactive) (wrap-region-with-punctuation-or-insert ,key))))
(if wrap-region-tag-active
(define-key wrap-region-mode-map "<" 'wrap-region-with-tag-or-insert)))))
(provide 'wrap-region)
;;; wrap-region.el ends here