* • [2020-04-24 Fri] Inserting characters pairs :code:elisp:
:PROPERTIES:
:ID: 97554b2fb1ee6912f232d68f906cfa11
:END:
/ Update [2022-09-18 Sun] The function will now
emphasize previous word when at the end of it (you
can type a word, then emphasize it) or the current
word (e.g. when the cursor is over it)./
An easy way to emphasize or enclose words or region
with pairs matching : “”, «», [], and parentheses of course.
Unbreakable spaces are also inserted around where the typographical
convention demands it.
Better than org-emphasize.
In my book, the org formatting becomes, when the
cursor is at the beginning of word or over a region:
: C-= *
bold
: C-= /
italic
: C-= _
underline
: C-= (
(parentheses)
: C-= “
“ quotes ”
And I must say there is much confort in doing so.
The binding to C-= can be discussed.
The code:
#+begin_src elisp
(add-to-list 'insert-pair-alist '(171 187)) (add-to-list 'insert-pair-alist '(8220 8221)) (setq insert-non-breakable-space-with-pair-list '(171 8220))
(defun insert-character-pair (&optional arg)
"Interactively calls insert-pair, with the next
(not last) typed character.
If `parens-require-spaces' is non-nil, this
command also inserts a space before and after,
depending on the surrounding characters.
Look into `insert-non-breakable-space-with-pair-list'
for the opening character of a pair wich needs the
insertion of a non-breakable space in-between.
Typically « quotes ».
If region is active, insert enclosing characters
at region boundaries.
[2022-01-02 Sun] did something changed with the
point position after insert-pair ? "
(interactive "c")
(let* ((pair (assq arg insert-pair-alist))
(space-required parens-require-spaces)
(n (prefix-numeric-value current-prefix-arg))
(syntax-prev (syntax-class (syntax-after (- (point) 1))))
(syntax-next (syntax-class (syntax-after (point))))
(previous-char-is-whitespace (and syntax-prev (= 0 syntax-prev)))
(next-char-is-whitespace (and syntax-next (= 0 syntax-next))))
(setq insert-direction (if previous-char-is-whitespace 1 -1))
(if pair
(setq open (car pair)
close (car(cdr pair)))
(setq open arg
close arg))
(if (memq open insert-non-breakable-space-with-pair-list)
(if (and transient-mark-mode mark-active)
(save-mark-and-excursion
(when (> (point) (mark)) (exchange-point-and-mark))
(insert-pair 1 open close)
(save-mark-and-excursion
(goto-char (mark))
(insert 160)) (goto-char (point))
(insert 160))
(progn
(save-excursion (insert-pair insert-direction open close))
(when (= 1 insert-direction) (right-char))
(setq parens-require-spaces nil)
(save-excursion (insert-pair insert-direction 160 160))
(setq parens-require-spaces space-required)))
(progn
(save-mark-and-excursion
(dotimes (i n) (insert-pair
insert-direction
open close)))
(if (> (point) (mark))
(right-char))
))
(when (= (char-after (point)) close)
(right-char))
)
)
(global-set-key (kbd "C-=") 'insert-character-pair)
#+end_src
Perhaps somebody already wrote this function and there is
certainly rooms for improvement. It took me several attempt
to write it down correctly and I learned 100% of the elisp
functions invocated while doing so. I hope it will be of any
use to you dear reader.
Current known limitations
- It won't work on lone characters used to emphasize expressions,
such as ( " < > “ » and will look for either the next pairing
character and emphasize the next word.
- ( ) trying here, between the parentheses returns:
forward-sexp: Scan error: "Containing expression ends prematurely"