利用lazy-load.el按需加载Emacs插件

试用了你的 init-mode.el,有个问题,当直接 open -a Emacs xx.hs 的时候,打开的 xx.hs 没有触发 haskell mode,此时切换到另一个 hs 文件时,就可以正常高亮了,是不是直接 open -a Emacs xx.hs 的流程不一样?

我个人配置,你自己研究哈,我没这个问题

最近尝试用lazycat-emacs的架构,喜欢这种清晰可控的架构(use-package的那一套确实很重,而git-submodule和lazy-load都清晰),但因为我是meow使用者,因此遇到了lazy-load按键绑定的问题

meow绑定 leader的按键是这样的:

(meow-leader-define-key
 '("d" . dired)
 '("f" . find-file))

我的想法是利用 one-key.el生成后再绑定到meow-leader-define-key的定义里。

但同时lazy-load需要这样设置

;;; --- 星际译王命令行
(lazy-load-global-keys
 '(("p" . sdcv-search-pointer)          ;光标处的单词, buffer显示
   ("y" . sdcv-search-pointer+)         ;光标处的单词, tooltip显示
   ("i" . sdcv-search-input)            ;输入的单词, buffer显示
   (";" . sdcv-search-input+))
 "init-sdcv"
 "C-z")

但这样没办法设置leader按键。 能力有限捣鼓不出来,请问有没有办法把meow的 leader 嵌入到 lazy-load的按键绑定里面?

lazy-load的原理很简单,就是把按键和插件路径关联起来。

你可以研究lazy-load的源码,没几行,写一个函数把meow和插件路径产生关联就可以了

啊你说的对,我尝试写了一个关联调用的函数结果就能用了,归功于lazy-load的原理真的很清晰

@Lewisliu 能否分享一下你是怎么设置的啊?

唔,我现在不用这一套了。原理很简单你可以试试,meow接受的是一串按键序列,直接抄lazy-load的那个函数,然后在把命令绑定meow按键之后,传递给autoload就行了,

我现在没有用这种混合方法的原因是,我的按键绑定量比较大了,混合着需要lazy-load和自带的函数(不需要lazy),有一点乱。所以我换成了一个新的思路,就是meow只管按键绑定不区分lazy-load还是原生函数,一视同仁地统一管理所有按键,统一放在一起好维护。至于lazy-load我写了一个宏放到包各自的配置里去维护。这样就分开了

他的配置好像在这里,GitHub - nowislewis/nowisemacs: A full-blown emacs configuration framework with easy abstraction 参考他的配置,我也准备换到setup了,感谢

1 个赞

貌似setup的bind缺乏lazy-load这套机制,好像还缺少use-package的那个带星号的bind*

你说的对的,setup的功能相当少。不过因为setup的原理真的很简单,因此可以很方便的添加需要的功能,比如autoload

(setup-define :autoload
  (lambda (&rest funcs)
    (let ((body '())
          (feature-string (symbol-name (setup-get 'feature))))
      (dolist (single-func (nreverse funcs))
        (add-to-list 'body `(autoload ',single-func ,feature-string nil t))
        (add-to-list 'body 'progn))
      body))
  :documentation "Load the current feature after FEATURES.")

1 个赞

很高兴我的配置能给你一点点参考意义,我的核心想法是在满足实用需求的情况下,尽可能降低配置的抽象等级,方便理解自己的配置,容易维护,而且减少代码代码量。因此我放弃了use-package和leaf,他们的机制相对复杂,出了问题不好调试。

受懒猫的建议,我用过一段时间原生方式配置代码,很喜欢这种方式,清晰明确,我清楚我的每一行代码是什么,他们的在干什么,不存在黑盒子。

现在使用setup,他和原生配置在我看来近乎没有抽象层级的区别。setup其实就是一堆很简单的宏,套在代码上,expand后生成的代码和手动管理一摸一样。因此setup近乎具备手动管理的大部分优点

然后讲一讲我使用setup的理由,因为很多手动配置代码都是重复的,eval-after之类的,用的很多,写起来重复。我不喜欢大量重复的代码,这会增加出错风险,setup的作用仅仅是把这些重复的手动配置代码变成了一个个非常简单的call,相当于我定义一处,却能处处使用,如果有问题比如升级和修改我只一般需要更改定义的地方就好了。

1 个赞

还是你的动手能力强,这里有个配置我感觉很有用,如果方便可以加个宏:

;; http://endlessparentheses.com/define-context-aware-keys-in-emacs.html
(defmacro my-define-conditional-key (keymap condition &rest args)
  "In KEYMAP, define key sequences ARGS conditionally.
This is like `define-key', except the definition
\"disappears\" whenever CONDITION evaluates to nil."
  (declare (indent 3)
           (debug (form form form &rest sexp)))
  `(let (key def (bindings ',args))
     (while bindings
       (setq key (pop bindings)
             def (pop bindings))
       (define-key ,keymap key
         '(menu-item
           (format "maybe-%s" (or (car (cdr-safe def)) def))
           nil
           :filter (lambda (&optional _)
                     (when (macroexp-progn ,condition)
                       def)))))))

比如:

  (my-define-conditional-key org-mode-map (org-at-table-p)
                         "M-p" 'org-table-previous-field
                         "M-n" 'org-table-next-field)

bind-key* 好像就是改变 override-global-map,感觉可以对应搞一个 :global, :predicate

好像有个小错误:

(setup-define :autoload
  (lambda (&rest funcs)
    (let ((body '())
          (feature-string (symbol-name (setup-get 'feature))))
      (dolist (single-func (nreverse funcs))
        (add-to-list 'body `(autoload ',single-func ,feature-string nil t)))
      (add-to-list 'body 'progn)
      body))
  :documentation "Load the current feature after FEATURES.")

或者

(setup-define :autoload
  (lambda (function)
    `(autoload ',function (symbol-name ',(setup-get 'feature)) nil t))
  :documentation "autoload function"
  :repeatable t)

对,你下面的那个很短的其实就是我写的那个代码能实现的效果。我发的那个确实有些问题,不能做连续autoload,只能连着调用几次autoload。这个事情我好久之前写的了,后面因为很少用到多次autoload,也就忘记去继续优化了 :joy:

你这个确实挺有用的,看起来是针对一个断言判断后绑定?至于global之类的可能比较好做,可以直接利用setup的上下文绑定

我过几天试试看,这两天休假了哈哈