怎么定义一个elisp函数,比如my-load-theme
,使得(my-load-theme 'solarized)
实现以下这段代码的功能:
(add-hook 'after-make-frame-functions
(lambda (frame)
(select-frame frame)
(when (display-graphic-p frame)
(load-theme 'solarized t))))
我怎么都搞不定,问题出在after-make-frame-functions
需要frame
作为参数的lambda函数,但load-theme
是嵌套在这个lambda
函数中,然后我就搞不定了。。。
多谢大牛现身~
我也在stack-overflow上提问了:
1 个赞
Stack Overflow有人答了,用;; -*- lexical-binding:t -*-
可以简单搞定。如果一定要用dyanmic binding的话,我试了试它对一个问题的“等价”方案:
但不行,也许因为after-make-frame-functions
特殊性,也许我用错了。
lexical-binding
=> nil
(defun foo (x)
(lambda () x))
(foo 123)
=> (lambda nil x)
(defun bar (x)
`(lambda () ,x))
(bar 123)
=> (lambda nil 123)
至于 Dynamic v.s. Lexical binding,我的感觉是你应该总是用 Lexical binding,无论是写 Package 还是写自己的配置 init.el
。
1 个赞
(defun foo (y)
(add-hook 'after-make-frame-functions
`(lambda (frame)
(select-frame frame)
(when (display-graphic-p frame)
(load-theme ,y t)))))
这样?
不是 after-make-frame-functions
有什么特殊,也不是 hook 带参数的问题,是 lambda 的问题。
当你 (my-load-theme 'solarized)
的时候,theme 变量是有效的,但是这个时候只是定义了 lambda,并没有执行。等到 lambda 真正执行的时候,变量 theme 已经不存在了。
所以这个时候,你需要 -*- lexical-binding:t -*-
来维持 theme 变量的有效性:(请在 --batch
模式下执行示范代码)
-*- lexical-binding:t -*-
(defvar foo-hook nil)
(defun set-hook (s)
(add-hook 'foo-hook
(lambda ()
(princ s))))
(set-hook "foo")
(run-hooks 'foo-hook)
如果不想 lexical-binding 作用于整个文件, 可以在局部使用:
(require 'cl)
(defvar foo-hook nil)
(defun set-hook (s)
(lexical-let ((ss s))
(add-hook 'foo-hook
(lambda ()
(princ ss)))))
(set-hook "foo")
(run-hooks 'foo-hook)
如果根本不想使用 lexical-binding,就把 theme 定义成全局变量。总之就是要想办法,让 theme 变量在回调的时候仍然有效。
楼上的方法也是可以的,在 (my-load-theme 'solarized)
的时候立即把 theme 变量展开:
...
(load-theme ,theme t) ;; => (load-theme 'solarized t)
...
就不存在变量是否有效的问题了。
2 个赞
这种情况还是用全局变量好,可以很方便地更换theme。否则的话,第二次调用时,如何卸载之前的? 这样的话这个函数调用两次就会加载两个theme。
如果不需要换theme,也就不需要函数了,直接写死就行了。
1 个赞
LdBeth
10
那麼 after-make-frame-functions
值是啥?
大概明白你的问題在哪了
(defun foo (y)
(add-hook 'after-make-frame-functions
`(lambda (frame)
(select-frame frame)
(when (display-graphic-p frame)
(load-theme ,y t)))))
;; => foo
(foo '(quote spacemacs-light)) ;; (quote 'spacemacs-light), ''spacemacs-light 皆可
;; => ((lambda (frame) (select-frame frame) (when (display-graphic-p frame) (load-theme (quote spacemacs-light) t))))
2 个赞
and @netjune 多谢啊!
恩,我没有真正读过elisp的文档,都是用多少看多少;去仔细了解下lambda
哦,我同时开多个emacs server(平时使用两个,给daemon不同名字),对每个只加载一个theme的。只不过配置里,配了大概4个server,所以想写个函数(除了加载theme,还有modeline修改,字体什么的)。我用Alfred方便的打开不同的emacs client,这样我就可以文档(大量latex)用light theme,码代码用dark theme了:slight_smile:
多谢多谢!有估计是变量传递的问题,实在基础知识不够啊。你的解释解决了很多问题那。
不过 @LdBeth 的那个方案,我试过,不知道为什么不工作。(目前我用的是-*- lexical-binding:t -*-
).
更新:那个替代方案已解决,是我调用时的错误,应该传参数'(quote solarized)
。
是的!谢谢啊!
原来是调用问题。好吧,我还是把elisp, an introduction打出来都看一遍吧,elisp基础几乎没有啊。碰到语法问题没基础知识帮助解决啊。
恩,我一直以来都是用C/C++的概念处理elisp的,但lisp中的新玩意儿好多啊,得从基础抽空看看了。多谢啊!有解决了一个心腹大患
也可以定义为
(defun foo (y)
(add-hook 'after-make-frame-functions
`(lambda (frame)
(select-frame frame)
(when (display-graphic-p frame)
(load-theme ',y t)))))
这样就可以依然直接调用 (foo 'solaried)
。说白了,都是我基础知识缺乏整出来的问题,得补补基础了。
2 个赞
搜帖子时顺带发现: @ReimuXMX 你的主页竟然有背景图!
1 个赞