比如,下面的代码:
;; (defun test (x)
;; (let ((var1 exp1)
;; (var2 exp2)
;; (var3 exp2))
;; body))
鼠标双击 let
左边的那个括号,或者使用 expand-region
好像都不能选中整个 let
表达式?
有什么好办法吗?
比如,下面的代码:
;; (defun test (x)
;; (let ((var1 exp1)
;; (var2 exp2)
;; (var3 exp2))
;; body))
鼠标双击 let
左边的那个括号,或者使用 expand-region
好像都不能选中整个 let
表达式?
有什么好办法吗?
没用过 expand-region
,就鼠标使用说下吧。
;;(defun test (x)
;;(let ((var1 exp1)
(var2 exp2)
(var3 exp2))
;; body))
;;
把上面的代码改成这个样子,然后双击 let 里面的第一个 (
,是可以选中 let
表达式的变量部分的,就像这样
但是在全部注释的情况下,点击这个 (
会得到 forward-sexp: Scan error: "Unbalanced parentheses"
的报错,这说明它和 forward-sexp
有关系。forward-sexp
应该是处理了注释相关的问题。
使用 C-h k
再原地双击两下可以找到调用的函数:
<down-mouse-1> at that spot runs the command mouse-drag-region
<mouse-1> at that spot runs the command mouse-set-point
<down-mouse-1> (translated from <double-down-mouse-1>) at that spot runs the command mouse-drag-region
<mouse-1> (translated from <double-mouse-1>) at that spot runs the command mouse-set-point
在 mouse-drag-region
里面可以找到它调用了哪些函数,主要关注的还是 mouse-drag-track
,它内部使用了 mouse-begin-end
来确定选中区域。这个函数我就不细说了,在单击次数为 2 时,如果鼠标在 (
或 )
上,它会使用 forward-sexp
和 backward-sexp
来找到对应的结束位置。
backward-sexp
直接调用 forward-sexp
。而 forward-sexp
默认使用 scan-sexps
函数来找到匹配括号。它在找不到时(也就对应上面有注释的时候)就会报错。不过我们可以通过 forward-sexp-function
来修改这个函数的行为。但还是算了,直接修改的话影响可能很大。
我想到的方法是给 mouse-begin-end
上个 around advice,当点击 (
或 )
时特殊处理一下,其他的交给原函数处理。其实也就是重写 forward-sexp
(defun my-forward-sexp (n)
;;n must be 1
(let ((curr-point (point))
(cnt 1))
(do ((i 1 (+ i 1)))
((or (= (+ curr-point i) (point-max))
(= cnt 0))
(goto-char (+ curr-point i)))
(cond
((= (char-syntax (char-after (+ curr-point i))) ?\( )
(cl-incf cnt))
((= (char-syntax (char-after (+ curr-point i))) ?\) )
(cl-decf cnt))))))
(defun my-backward-sexp (n)
;;n must be 1
(goto-char (1- (point)))
(let ((curr-point (point))
(cnt 1))
(do ((i 1 (+ i 1)))
((or (= (- curr-point i) (point-min))
(= cnt 0))
(goto-char (- curr-point i -1)))
(cond
((= (char-syntax (char-after (- curr-point i))) ?\) )
(cl-incf cnt))
((= (char-syntax (char-after (- curr-point i))) ?\( )
(cl-decf cnt))))))
(defun my-mouse-start-end (fn start end mode)
(if (and (= mode 1)
(= start end)
(char-after start)
(or (= (char-syntax (char-after start)) ?\( )
(= (char-syntax (char-after start)) ?\) )))
(letf (((symbol-function 'forward-sexp) 'my-forward-sexp)
((symbol-function 'backward-sexp) 'my-backward-sexp))
(funcall fn start end mode))
(funcall fn start end mode)))
(advice-add 'mouse-start-end :around 'my-mouse-start-end)
(advice-remove 'mouse-start-end 'my-mouse-start-end)
随手糊了个,可能准确性不是很好,只考虑了对 mouse-start-end
的配合。加张 gif 说明一下
多谢,可惜不会忽略中间的 ;;
。
原本考虑用块注释,但 Elisp 似乎不支持?
/*
Block
comment
*/
中间的 ;;
我也不知道咋弄,region 操作我不是很熟
Elisp 应该只有 ;
注释,就我所知的话, Scheme 里面有 #| |#
注释,其他就不清楚了。
其实我是想问,有没有插件已经实现了这类功能(能选择注释里面的括号),感觉挺常用的。
没想到你直接写了一个版本。。。
练练手吧,插件不是很清楚
那我们等等有没有现成的解决方案吧,我这个匹配的很粗糙,没有考虑字符串内括号,和 ?\( ?\)
之类的问题
对,separedit 或者 poporg之类的是正解
定义一个啥也不干的 comment 宏,把代码直接包裹在里面,无需注释符。