受 @manateelazycat 的 delete-block 启发,编写了下面的函数:
(defun toki/backward-fragment-pos ()
"Return the position one fragment before point."
(cond
((bobp) (point))
((bolp) (1- (point)))
(t
(let* ((syntax-move-pos (save-excursion
(forward-same-syntax -1)
(point)))
(subword-move-pos (save-excursion
(subword-backward)
(point))))
(max syntax-move-pos subword-move-pos (line-beginning-position))))))
(defun toki/forward-fragment-pos ()
"Return the position one fragment after point."
(cond
((eobp) (point))
((eolp) (1+ (point)))
(t
(let* ((syntax-move-pos (save-excursion
(forward-same-syntax)
(point)))
(subword-move-pos (save-excursion
(subword-forward)
(point))))
(min syntax-move-pos subword-move-pos (line-end-position))))))
(defun toki-backward-word ()
"A finer version of `backward-word'.
If there's *only one* space, '-' or '_' between point and previous word, move
before it, then jump back by a fragment. A fragment is a continuous region with
the same syntax, like a word, a bunch of whitespaces/punctuations, etc.
This doesn't fly over most punctuations, while `backward-word' does. So I find
this command easier to use."
(interactive)
(ignore-errors
(when (and (member (char-before) '(?\s ?\t ?- ?_))
(eq (char-syntax (char-before (1- (point)))) ?w))
(backward-char)))
(goto-char (toki/backward-fragment-pos)))
(defun toki-forward-word ()
"A finer version of `forward-word'.
If there's *only one* space, '-' or '_' between point and next word, move after
it, then jump forward by a fragment. A fragment is a continuous region with the
same syntax, like a word, a bunch of whitespaces/punctuations, etc.
This doesn't fly over most punctuations, while `backward-word' does. So I find
this command easier to use."
(interactive)
(ignore-errors
(when (and (member (char-after) '(?\s ?\t ?- ?_))
(eq (char-syntax (char-after (1+ (point)))) ?w))
(forward-char)))
(goto-char (toki/forward-fragment-pos)))
(defun toki-backward-kill-word ()
"A finer version of `backward-kill-word'.
Kills the region between current point and the point after calling
`toki-backward-word'. See its documentation for details."
(interactive)
(let ((prev-point (point)))
(toki-backward-word)
(kill-region (point) prev-point)))
(defun toki-forward-kill-word ()
"A finer version of `forward-kill-word'.
Kills the region between current point and the point after calling
`toki-forward-word'. See its documentation for details."
(interactive)
(let ((prev-point (point)))
(toki-forward-word)
(kill-region (point) prev-point)))
依赖 subword
,我直接启用了 global-subword-mode
:
(use-package subword
:config
(global-subword-mode))
动机:默认的函数在大多数时候都挺好用,但偶尔目标单词和光标之间有连续空格,标点,\\
(倾斜牙签)时,默认的命令会把它们都带走,这点比较烦。所以写了这几个函数,规定只有目标单词和光标之间仅有一个连字符或空格时才能带走。详细请看函数文档。
Update: 增强了行首/行尾的处理