/ Update
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:
(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))))
;; begining of word. surround next word
;; middle or end of word. surround current word
(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))
;;(save-mark-and-excursion
(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)) ;; insert nbsp
(goto-char (point))
(insert 160))
;; else
(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
;; (when (and transient-mark-mode mark-active (> (point) (mark)))
;; (exchange-point-and-mark))
(save-mark-and-excursion
(dotimes (i n) (insert-pair
insert-direction
open close)))
(if (> (point) (mark))
(right-char))
))
;; go past the emphasize character added
;; avoiding the rabbit-hold that position the mark after the word,
;; but before the emphasize marker
;; and indiscernable when `org-hide-emphasis-markers' is t)
(when (= (char-after (point)) close)
(right-char))
)
)
(global-set-key (kbd "C-=") 'insert-character-pair)
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"