【本人原创】Emacs的rect-mark.el脚本的一个增强(这个好像没在这发过)
;; **************************************************************************************************************;; By zklhp
;; Email:zklhp@
;; QQ:493165744
;; 2012.4.30
;; 转载请保持完整
;; **************************************************************************************************************
感觉起题目的水平下降了 Emacs用了没几天 第一次发这种东西 不当处望方家指正~
rect- mark.el是个常用的脚本 用于增强Emacs的矩形操作(Rectangle 咋翻译啊 我就管这个叫矩形操作得了 如果你不明白可以试试Word里的Alt+鼠标拖拽 就是这个意思 某些时候这个叫列模式 Column Mode 我感觉这都是指的一个东西) 可以在这里得到
http://www.
这个脚本很不错 我一直用 不过里面的一个功能和我的习惯不一样
218行的 rm-mouse-drag-region 拖动鼠标选择一个矩形块 一般我们的操作习惯是 拖动区域的时候能自动卷屏(Scroll) 但这个脚本不这样 貌似还报个错
代码如下
(defun rm-mouse-drag-region (start-event)
"Highlight a rectangular region of text as the the mouse is dragged over it.
This must be bound to a button-down mouse event."
(interactive "e")
(let* ((start-posn (event-start start-event))
(start-point (posn-point start-posn))
(start-window (posn-window start-posn))
(start-frame (window-frame start-window))
(bounds (window-edges start-window))
(top (nth 1 bounds))
(bottom (if (window-minibuffer-p start-window)
(nth 3 bounds)
;; Don't count the mode line.
(1- (nth 3 bounds))))
(click-count (1- (event-click-count start-event))))
(setq mouse-selection-click-count click-count)
(mouse-set-point start-event)
(rm-activate-mark)
(let (end-event
end-posn
end-point
end-window)
(track-mouse
(while (progn
(setq end-event (read-event)
end-posn (event-end end-event)
end-point (posn-point end-posn)
end-window (posn-window end-posn))
(or (mouse-movement-p end-event)
(eq (car-safe end-event) 'switch-frame)))
(cond
;; Ignore switch-frame events.
((eq (car-safe end-event) 'switch-frame)
nil)
;; Are we moving within the original window?
((and (eq end-window start-window)
(integer-or-marker-p end-point))
(goto-char end-point)
(rm-highlight-rectangle start-point end-point))
;; Are we moving on a different window on the same frame?
((and (windowp end-window)
(eq (window-frame end-window) start-frame))
(let ((mouse-row (+ (nth 1 (window-edges end-window))
(cdr (posn-col-row end-posn)))))
(cond
((< mouse-row top)
(mouse-scroll-subr (- mouse-row top)
nil start-point))
((and (not (eobp))
(>= mouse-row bottom))
(mouse-scroll-subr (1+ (- mouse-row bottom))
nil start-point)))))
(t
(let ((mouse-y (cdr (cdr (mouse-position))))
(menu-bar-lines (or (cdr (assq 'menu-bar-lines
(frame-parameters)))
0)))
;; Are we on the menu bar?
(and (integerp mouse-y) (< mouse-y menu-bar-lines)
(mouse-scroll-subr (- mouse-y menu-bar-lines)
nil start-point)))))))
(and (eq (get (event-basic-type end-event) 'event-kind) 'mouse-click)
(eq end-window start-window)
(numberp end-point)
(if (= start-point end-point)
(setq deactivate-mark t)
(push-mark start-point t t)
(goto-char end-point)
(rm-kill-ring-save start-point end-point)))
)))
elisp学过皮毛 我感觉 这里猫腻出在 mouse-scroll-subr 也就是下面三句
(mouse-scroll-subr (- mouse-row top) nil start-point)
(mouse-scroll-subr (- mouse-y menu-bar-lines) nil start-point)
(mouse-scroll-subr (1+ (- mouse-row bottom)) nil start-point)
因为只有这里跟卷屏有关 那这个函数咋用呢
在我的Emacs 24里(GNU Emacs是本文的环境 其他的没试) C-h f 呵呵 也就是看函数描述 结果如下
mouse-scroll-subr is a compiled Lisp function in `mouse.el'.
(mouse-scroll-subr WINDOW JUMP &optional OVERLAY START)
Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
If OVERLAY is an overlay, let it stretch from START to the far edge of
the newly visible text.
Upon exit, point is at the far edge of the newly visible text.
第一个参数是WINDOW(写中文有可能有误会 关于这个欢迎看Emacs的Tutorial) 而这里没写
我猜测这里是个bug 可能作者写这个脚本的年代这个函数和现在不一样罢(95年的脚本了 和一样都是90后诶 不过90后比较年轻90后的代码就很老了。。) Emacs的版本更新了但脚本没有做到与时俱进 导致了bug
改正方法 我的改法是加个参数 变成这样
(mouse-scroll-subr start-window (- mouse-row top) nil start-point)
(mouse-scroll-subr start-window (- mouse-y menu-bar-lines) nil start-point)
(mouse-scroll-subr start-window (1+ (- mouse-row bottom)) nil start-point)
由于我们拖动的时候一般只在一个Window里 所以我默认和开始的是一样的 把上面三个分别替换成我上面写的语句 这个脚本的行为就和我们的预期一样了
改后的代码再帖一下
;;;###autoload
(defun rm-mouse-drag-region (start-event)
"Highlight a rectangular region of text as the the mouse is dragged over it.
This must be bound to a button-down mouse event."
(interactive "e")
(let* ((start-posn (event-start start-event))
(start-point (posn-point start-posn))
(start-window (posn-window start-posn))
(start-frame (window-frame start-window))
(bounds (window-edges start-window))
(top (nth 1 bounds))
(bottom (if (window-minibuffer-p start-window)
(nth 3 bounds)
;; Don't count the mode line.
(1- (nth 3 bounds))))
(click-count (1- (event-click-count start-event))))
(setq mouse-selection-click-count click-count)
(mouse-set-point start-event)
(rm-activate-mark)
(let (end-event
end-posn
end-point
end-window)
(track-mouse
(while (progn
(setq end-event (read-event)
end-posn (event-end end-event)
end-point (posn-point end-posn)
end-window (posn-window end-posn))
(or (mouse-movement-p end-event)
(eq (car-safe end-event) 'switch-frame)))
(cond
;; Ignore switch-frame events.
((eq (car-safe end-event) 'switch-frame)
nil)
;; Are we moving within the original window?
((and (eq end-window start-window)
(integer-or-marker-p end-point))
(goto-char end-point)
(rm-highlight-rectangle start-point end-point))
;; Are we moving on a different window on the same frame?
((and (windowp end-window)
(eq (window-frame end-window) start-frame))
(let ((mouse-row (+ (nth 1 (window-edges end-window))
(cdr (posn-col-row end-posn)))))
(cond
((< mouse-row top)
;; patched here! Use start-window as the first parameter.
(mouse-scroll-subr start-window (- mouse-row top)
nil start-point))
((and (not (eobp))
(>= mouse-row bottom))
;; patched here! Use start-window as the first parameter.
(mouse-scroll-subr start-window (1+ (- mouse-row bottom))
nil start-point)))))
(t
(let ((mouse-y (cdr (cdr (mouse-position))))
(menu-bar-lines (or (cdr (assq 'menu-bar-lines
(frame-parameters)))
0)))
;; Are we on the menu bar?
(and (integerp mouse-y) (< mouse-y menu-bar-lines)
;; patched here! Use start-window as the first parameter.
(mouse-scroll-subr start-window (- mouse-y menu-bar-lines)
nil start-point)))))))
(and (eq (get (event-basic-type end-event) 'event-kind) 'mouse-click)
(eq end-window start-window)
(numberp end-point)
(if (= start-point end-point)
(setq deactivate-mark t)
(push-mark start-point t t)
(goto-char end-point)
(rm-kill-ring-save start-point end-point)))
)))
习惯了 必须总结一下
1 Emacs真是历史悠久(随便一个脚本都和我差不多大)扩展性强(本身不具备的功能可以用elisp扩充)的神的编辑器啊!!!
2 历史悠久 带来的历史问题也就比较突出了 比如Ctrl键位 比如上面的Window 比如这个脚本
3 通过脚本扩展功能是开源软件的优点 类似的例子是Firefox 这些软件具有无限的扩展性 但扩展带来的问题可能比软件本身大
4 接上面 由于扩展尤其是脚本类的扩展是直接给出代码的 新手也可以比较容易的修改 总的来说利大于弊 特别是对于喜欢自己动手的人来说
5 貌似没人发现这个问题 反正我找的时候没发现有人提 为啥啊 可能这个是比较偏的功能罢
[ 本帖最后由 zklhp 于 2012-9-7 21:29 编辑 ]