每天学点elisp

我的visual-column-line开启了全局模式:

(global-visual-line-mode t)
(require 'visual-fill-column)
(setq visual-fill-column-width 80)
(add-hook 'visual-line-mode-hook #'visual-fill-column-mode)
(setq-default visual-fill-column-center-text t)

但在org-agenda-mode中,会把tag拖到第二行显示很难看,问kimi怎么对当前模式取消,给出的方案是:

(add-hook 'org-agenda-mode-hook
          (lambda ()
            (when (bound-and-true-p visual-fill-column-mode)
              (visual-fill-column-mode -1))))

额外多出来的这一行防御性的安全检查头一回遇到 bound-and-true-p

(bound-and-true-p VARIABLE)
相当于
(and (boundp 'VARIABLE) VARIABLE)

一是检查变量是否已定义(bound),只要变量或函数被 defvar / defun / setq … 过,它就“bound”或fbound了,否则访问它会报错 “void variable”。 二是检查变量的值是否为非nil(true)

Kimi举了一个🌰

你把 Emacs 想成一家图书馆:

  • bound=“这本书有没有编目入库?” 没编目就根本借不到,直接报错。

  • true-p=“这本书现在能不能借(不在架上)?” 编目了但被别人借走了,也算“不可用”。

bound-and-true-p 就是管理员帮你一次性回答: “书有没有编目?编了的话现在能不能借?” 只有两关都过,才给你“可以借”的答复。

elisp中的其他相关函数:

boundp :variable-bound-predicate只检查变量是否存在,

fboundp :function-bound-predicate 检查函数是否存在。

4 个赞

声明式编程

我的org-capture-templates中有很多自定义函数:

(setq org-capture-templates
      '(("f" "flash" plain ;; 闪念卡片
         (file+function flashcards-file goto-this-month)
         "** %?\n%U\n"          
         :empty-lines 1
         :kill-buffer t)

比如上面的goto-this-month, 配置中有十多个类似的自定义,而且都堆放在org-capture-templates的头顶上。

每次修改template都要下拉到最后才能看到templates。

我想把templates前置,所用到的函数的实现细节放到后面,这样看起来一目了然,想看具体函数实现就M-.

deepseek说这种“先what后how”的想法叫: 声明式编程 (Declarative Programming) 配置与实现分离 (Separation of Concerns)

Kimi说: 在elisp里,这种“先写接口/声明,后给实现”的做法通常叫做 forward-declaration(前向声明) 或者更口语化地说 “hoist the interface, delay the implementation”(把接口提上来,实现扔下去)。 这正应了SICP的那句名言: “Programs must be written for people to read, and only incidentally for machines to execute.”

配置org-download

今年年初将emacs升级到emacs30之后,发现org-download的配置不好用了。 在新的emacs中的org9.7有了自己的拖拽插入图片的功能,覆盖了org-download的拖拽调用。

插入图片会提示三个选项,但都不是很好用。

当时问AI怎么处理,给出很多重新写dnd的方案,但是都不好用。 那段时间全面转向了markdown半年多,orgmode用得少,心想等着emacs或者org的下一版本再碰碰运气吧。

这两个月又重新回到了orgmode,不仅PC上,而且还有移动端。

还是拖拽图片的问题,再一问,deepseek给出的方案好使。

(use-package org-download
  :ensure t
  :defer t
  :config
  (setq org-download-method 'directory)
  (setq org-download-image-dir "./images")
  (setq org-download-heading-lvl nil)
  (setq org-download-annotate-function (lambda (link) ""))

  ;; 可选:设置截图命令
  (setq org-download-screenshot-method 
        (cond ((eq system-type 'darwin) "screencapture -i %s")
              ((eq system-type 'gnu/linux) "import %s")
              (t nil)))
  )
(add-hook 'org-mode-hook 'org-download-enable)

犹记得年初的时候,各个AI给出的都是长篇大论的改写dnd的方案。

deepseek的方案,就多了一行 :defer t,解决问题。 AI的发展真是惊人呀。

另外,结合上篇笔记, use-package这个包完全是抽象层的声明式编程 (Declarative Programming)的风格。 defer与config是纯语言的字面含义,只有ensure稍微一丢丢晦涩。

: ensure
相当于
(unless (package-installed-p 'org-download)
  (package-install 'org-download))

想一想,当前的AI无非是这种声明式编程或者命令式编程的向前的一个发展阶段。

只需要说我要这个,我要那个,而不必去浪费精力去想底层的怎么去实现。AI让编程祛魅,命令者就是下命令者,执行者就是执行者,从来都不高级。

1 个赞