类似 imenu ,但是要更自定义一些,而不是根据语法来的。这样就可以通过注释来实现了
不是很清楚这有什么用处,大佬你可以尝试实现一下。
imenu 本身也是通过正则匹配的,我当时帮别人修 ahk-mode 的 bug 时搞过类似的:
;imenu
开头的注释就可以被 imenu 捕捉到
感觉用 outline 可以凑合用啊。
修改 outline-regrex
类似为 .* ;;;;;
这样的。
我都是优先使用内置包,不够用了就用第三方或者自己扩展
outline的部份可以用这个:
目录buffer我昨天正好写了一个。感觉没有想象中的那么有用,尤其是在小屏幕。
https://github.com/casouri/lunarymacs/blob/master/site-lisp/sidebar.el
Changelog:
- 2020-07-02 增加了
shell-command-on-region
的一个使用场景 (以ydcv
为例)
shell-command-on-region
的妙用
在注释看到不认识的单词,一般做法是复制、打开终端、然后调用外部程序
ydcv
来翻译。
最近发现了shell-command-on-region
之后,可以省掉前2个步骤了!
例如papaya
单词不认识,那么选中它,然后M-|
(shell-command-on-region
)运行一下,输入ydcv
然后执行。如果输出内容比较少,则
直接会在echo area
处显示(当resize-mini-windows
不为nil
时由
max-mini-window-height
决定)。如果想强制它输出在buffer
下(方便复制),可以在
上面再封装一层、例用advice
机制,或者提前创建一个名叫*Shell Command Output*
的
buffer
。
以下是一个advice
的例子(不推荐使用advice
,有较大的侵入性,这里只是做个演示)
(define-advice shell-command-on-region (:around (func &rest args))
(let ((max-mini-window-height 0))
(apply func args)))
甚至可以直接封装一个叫做ydcv
的命令来完成这个工作!
(defun ydcv (beg end)
(interactive "r")
(let ((max-mini-window-height 0))
(shell-command-on-region beg end "ydcv")))
当然还可以有ydcv-at-point
, ydcv-dwim
等一系列函数!
一人血书求更(
在写了在写了(
woman和info蛮好用的(
楼主加油,又发掘出好些忽略的built-in好工具
我也加几个内置的 mode, 直接上代码, 不需要解释.
(global-prettify-symbols-mode t)
(global-display-fill-column-indicator-mode t)
(savehist-mode t)
(recentf-mode t)
(save-place-mode t)
(electric-pair-mode t)
(add-hook 'prog-mode-hook 'display-line-numbers-mode)
不过还是要提示下, 你打开越多的 mode, emacs 速度越慢 …
Changelog:
- 2020-08-22 增加了
winner-undo
与transient-map
搭配的例子 - 2020-08-22 增加了
strokes-mode
的介绍 - 2020-08-25 增加了
webjump
的介绍 - 2020-08-30 增加了
transient-map
的小技巧
winner-mode
winner-mode
是一个全局的minor mode
,它的主要功能是记录窗体的变动。例如当前有
2 个窗口,然后你关了一个,这时可以通过winner-undo
来恢复。还可以再winner-redo
来撤销刚才的undo
.
它默认按键绑定为:
C-c Left winner-undo
C-c Right winner-redo
如果不想它绑定在C-c前缀按键上,可以通过
(setq winner-dont-bind-my-keys nil)
来禁止。
建议配置:
(use-package winner-mode
:ensure nil
:hook (after-init . winner-mode))
同时,它也可以应用在ediff
上,恢复由ediff
导致的窗体变动。
(use-package ediff
:ensure nil
:hook (ediff-quit . winner-undo)
winner-undo 搭配 transient-map
如果平常有注意观察text-scale-adjust
(C-x C-=) 的行为,会发现只需要
按全一次C-x C-=,之后可以只按+
、-
或者0
来缩放字体。而如果触发了
其他按钮则会退出这个状态,它背后主要依赖transient-map
机制。
我们可以仿照着写一个transient-winner-undo
的版本,在需要连续执行winner-undo
的
时候只需要按一个u
就好了。
(defun transient-winner-undo ()
"Transient version of `winner-undo'."
(interactive)
(let ((echo-keystrokes nil))
(winner-undo)
(message "Winner: [u]ndo [r]edo")
(set-transient-map
(let ((map (make-sparse-keymap)))
(define-key map [?u] #'winner-undo)
(define-key map [?r] #'winner-redo)
map)
t)))
着实方便许多!
strokes
如果你想用鼠标来控制Emacs
的行为,有点像现在浏览器上的鼠标手势。不过它只能识别
鼠标移动轨迹所描绘的形状,不能判断它的方向。
- 执行
strokes-mode
打开minor-mode
- 执行
strokes-global-set-stroke
在弹出的buffer
内使用Shift
+鼠标左键(也可以用中键) 绘出想作为快捷操作的大致形状,假设是一个 C 的形状,然后鼠标右键结束绘制。稍后 会提示输入与stroke
对应的命令,假设是strokes-help
- 移动鼠标,使得它的轨迹是个 C 的形状
-
Shift
+鼠标中键以执行与这个stroke
对应的命令,也就是strokes-help
想要更详细的信息?请M-x strokes-help
.
webjump
你想在Emacs
里快速调用搜索引擎搜索吗?原来这个功能早已经内置了!
由于webjump-sites
早已有默认值了,如果想急着体验一下可以立即M-x webjump
。其原
理也是相当简单,通过用户选择它想要用的搜索引擎+查询内容构造出实际url
,然后通过
browse-url
调用托管给浏览器。
我的配置是这样的:
(use-package webjump
:ensure nil
:bind ("C-c /" . webjump)
:custom
(webjump-sites '(
;; Emacs.
("Emacs Home Page" .
"www.gnu.org/software/emacs/emacs.html")
("Savannah Emacs page" .
"savannah.gnu.org/projects/emacs")
;; Internet search engines.
("DuckDuckGo" .
[simple-query "duckduckgo.com"
"duckduckgo.com/?q=" ""])
("Google" .
[simple-query "www.google.com"
"www.google.com/search?q=" ""])
("Google Groups" .
[simple-query "groups.google.com"
"groups.google.com/groups?q=" ""])
("Wikipedia" .
[simple-query "wikipedia.org" "wikipedia.org/wiki/" ""]))))
如果只是想要简单的查询,那么可以作为 engine-mode的内置替换方案了。
当然,还可以配置多级查询选项,可参考webjump-to-iwin
的实现。
transient-map 小技巧
因为transient-map
的优先级比其他keymap
都要高,所以可以将它当作菜单来使用。
如果嫌set-transient-map
用起来不方便,可以使用hydra代替。
编辑时拷贝 (配合 avy)
如果在编辑文字时发现要拷贝一个url
,但是当前窗口内有多个url
,类似的场景如下:
/// url1: https://www.google.com
/// url2: https://www.baidu.com
/// url3: https://duckduckgo.com
int foo(int x) {
const char* url = "";
}
想要为url
赋值为注释内的 3 个 url 之一。
- 首先将光标移动到想复制的
url
处 - 再将这个
url
复制到kill-ring
当中 - 再回到原来的位置
- 再粘贴
(defhydra hydra-copy (:color blue)
"Copy"
("w" copy-word-at-point "word")
("u" copy-url-at-point "url")
("q" nil "cancel"))
(defun copy-url-at-point ()
"Copy url at point."
(interactive)
(save-excursion
(avy-goto-word-or-subword-1)
(kill-new (thing-at-point 'url))))
这里使用hydra
来偷懒一下。
效果图:
好文章好文章,感谢
hydra-copy 这个注意不错。
我试了一下,个人感觉先跳位置、再选类型比较顺手。
我常年养成的习惯是,先盯住要选的位置,然后快捷键呼出 avy,输入高亮字符。此时如果 minibuffer 先弹出个窗口,眼睛会不自觉地往下瞄一下,这样先前盯住的焦点就跑了,需要眼睛再次搜索。如果先跳好位置就跑不掉了,可以从容思考拷贝什么类型。
方法定义如下:
(defun avy-copy-thing-at-point ()
"Copy thing at point."
(interactive)
(save-excursion
(avy-goto-word-or-subword-1)
(let ((thing
(cl-case (read-char
(format
"Copy thing at point (%s: word %s: symbol %s: list %s: url): "
(propertize "w" 'face 'error)
(propertize "s" 'face 'error)
(propertize "l" 'face 'error)
(propertize "u" 'face 'error)))
(?w 'word)
(?s 'symbol)
(?l 'list)
(?u 'url))))
(kill-new (thing-at-point thing))
(message "%s copied" thing))))
如果想要美观一点就换 hydra,我这里先用 read-char
顶着。
下面这个提示用的熟了之后可以直接无视,因为绑定的前缀按键跟单词的前缀一样。
Changelog:
- 2020-09-04
newcomment
模块注释与反注释 - 2020-09-04 打字打累了?看一下
type-break
- 2020-09-04 通过
timeclock
来管理时间 - 2020-09-18 增加
elide-head
的介绍 - 2020-09-19 增加
midnight-mode
的介绍
newcomment
如果你想要一个足够简单的注释与反注释功能,那么自带的newcomment
就可以做到。
(use-package newcomment
:ensure nil
:bind ([remap comment-dwim] . #'comment-or-uncomment)
:config
(defun comment-or-uncomment ()
(interactive)
(if (region-active-p)
(comment-or-uncomment-region (region-beginning) (region-end))
(if (save-excursion
(beginning-of-line)
(looking-at "\\s-*$"))
(call-interactively 'comment-dwim)
(comment-or-uncomment-region (line-beginning-position) (line-end-position)))))
:custom
(comment-auto-fill-only-comments t))
上方的函数它可以完成:
- 当用户选中区间时,在对应区间上注释或者反注释
- 如果当前行是空的,那么会插入一个注释并且将它对齐 (偷懒,直接调用了
comment-dwim
) - 其他情况则对当前行注释或者反注释
这个行为也与evil-nerd-commenter保持一致。
这里有必要比较一下其他comment
函数:
-
comment-dwim
- 当用户选中区间时,会在对应区间注释或者反注释
- 如果当前行是空的,那么会插入一个注释并且将它对齐
- 如果使用C-u前缀,会则调用
comment-kill
来删除这个注释 - 其他情况下则调用
comment-indent
在尾部插入注释并对齐
-
comment-line
- 当用户选中区间时,会在对应区间再加上下一行进行注释或者反注释
- 如果当前行是空的,那么只会跳到下一行不会插入注释
- 其他情况下则会将当前行注释或者反注释并跳到下一行
-
comment-box
看例子就行
(defun add (a b)
(+ a b))
;;;;;;;;;;;;;;;;;;;;;;
;; (defun add (a b) ;;
;; (+ a b)) ;;
;;;;;;;;;;;;;;;;;;;;;;
type-break
历史老物,1994 年的时候就已经出现了。
打字打累了,想休息一下?看代码看累了,想放松一下?
那么它可能会适合你。如果在一段时间内的敲击键盘次数大于阈值,那么它会假设平均速度35 wpm
,每个单词长度5来推算出要休息多少分钟。
而到达休息状态时,它可能会显示出一个汉诺塔移动的动画。可以M-x type-break
立即体验!
timeclock
这是一个计算时间到底去哪里了的包,不过都有org-mode
了,真的还会有人来用这个吗?
org | timeclock |
---|---|
org-clock-in |
timeclock-in |
org-clock-out |
timeclock-out |
功能与org-mode
几乎一致,不过它可以随时timeclock-out
不用管记录时间的文件打开与否,而在org-mode
中clock-out
则要保证运行clock
的那个文件还处于打开状态。
elide-head
依旧是怀旧向的内置包,可以将源代码文件的头部中大量的license
说明折叠起来,效果
跟hideshow
包类似。可以通过配置elide-head-headers-to-hide
来自定义想要的折叠区间。
midnight 深夜模式
在晚上零点的时候定期执行一些任务,默认是clean-buffer-list
,可以设置midnight-hook
来自定义行为。
M-x midnight-mode 来开启深夜模式。嗯,又到了深夜网抑云音乐时间了。
发现一个可以给 evil-mode 实现相对行号的方法:
;;; relative line number
(defun my-enable-relative-line-number ()
(interactive)
(display-line-numbers-mode -1)
(setq display-line-numbers-type 'relative)
(display-line-numbers-mode 1))
(defun my-disable-relative-line-number ()
(interactive)
(display-line-numbers-mode -1)
(setq display-line-numbers-type t)
(display-line-numbers-mode 1))
(add-hook 'evil-normal-state-entry-hook 'my-enable-relative-line-number)
(add-hook 'evil-insert-state-entry-hook 'my-disable-relative-line-number)
(add-hook 'evil-insert-state-exit-hook 'my-enable-relative-line-number)
Deferred-Eval 如果一个计算结果在未来不必需要,那么您应该想避免对其进行耗时的计算,这种情况下 对一个表达式的延迟求值就显得很有用了。 thunk.el 就是这样一个支持延迟求值的库。
;;; 只有当 derived-number 变量被调用时才会对其后跟着的表达式进行求值运算
(setq lexical-binding t)
(require 'thunk)
(defun f (number)
(thunk-let ((derived-number
(progn (message "Calculating 1 plus 2 times %d" number)
(1+ (* 2 number)))))
(if (> number 10)
derived-number
number)))
(f 5) ; ⇒ 5
(f 12); ⊣ Calculating 1 plus 2 times 12 ⇒ 25
(setq lexical-binding t)
(require 'thunk)
(thunk-let* ((x (prog2 (message "Calculating x...")
(+ 1 1)
(message "Finished calculating x")))
(y (prog2 (message "Calculating y...")
(+ x 1)
(message "Finished calculating y")))
(z (prog2 (message "Calculating z...")
(+ y 1)
(message "Finished calculating z")))
(a (prog2 (message "Calculating a...")
(+ z 1)
(message "Finished calculating a"))))
(* z x))
;⊣ Calculating z...
;⊣ Calculating y...
;⊣ Calculating x...
;⊣ Finished calculating x
;⊣ Finished calculating y
;⊣ Finished calculating z
;⇒ 8
PS: 发完才发现是内置 mode 的介绍,囧…