【问题标题】:Emacs metaprogramming, dynamically define methodsEmacs 元编程,动态定义方法
【发布时间】:2013-11-17 21:25:34
【问题描述】:

我正在尝试定义一些辅助函数以从 emacs 中快速跳转到不同的项目。我首先定义了一个宏,如下所示

(defmacro project-alias (name path)
  `(defun ,name ()
     (interactive)
     (cd ,path)))

这很好用,我可以(project-alias foo "~/bar") 没问题。当我尝试将此宏应用于元组列表时,问题就出现了。

(setq projects '((foo . "~/foo")
                 (bar . "~/bar")))

(dolist (p projects)
  (project-alias (car p) (cdr p)))

上面的代码错误与

Debugger entered--Lisp error: (wrong-type-argument symbolp (car p))
  defalias((car p) (lambda nil (interactive) (cd (cdr p))))

我尝试将第一个参数作为字符串传递并调用intern 以毫无乐趣地获取符号表示,并且我还尝试定义我的宏以接受字符串形式,但这也不起作用

我做错了什么?

【问题讨论】:

    标签: emacs macros elisp metaprogramming


    【解决方案1】:

    如果您对宏的使用涉及 评估 sexps 以生成名称和路径,那么它需要评估 sexps:

    (defmacro project-alias (name path)
      `(defun ,(eval name) () (interactive) (cd ,(eval path))))
    

    或者,使用函数:

    (defun project-alias (name path)
      (eval `(defun ,name () (interactive) (cd ,path))))
    

    【讨论】:

      【解决方案2】:

      你也可以

      (defun project-alias-f (name path)
        (eval `(defun ,name ()
             (interactive)
             (cd ,path))))
      
      
      
      (dolist (p projects)
        (project-alias-f (car p) (cdr p)))
      

      (dolist (p projects)
        (eval `(project-alias ,(car p) ,(cdr p))))
      

      【讨论】:

        【解决方案3】:

        宏参数被传递未评估。 (宏不能做他们能做的事情。)

        所以你的论点实际上是 (car p)(cdr p) 的形式(而不是,例如,foo"~/foo")。

        【讨论】:

          【解决方案4】:

          这是另一个版本,没有宏也没有 eval:

          ;; -*- lexical-binding:t -*-
          
          (defun project-alias-f (name filename)
            (defalias name (lambda () (interactive) (cd filename)))
          
          (dolist (p projects)
            (project-alias-f (car p) (cdr p)))
          

          【讨论】:

          • 似乎没有评估filename
          • 是什么让它“看起来”如此?如果您收到void-variable: filename 类型的错误,可能是因为;; -*- lexical-binding:t -*- 存在问题(它需要位于文件的第一行,并且如果您使用C-x C-eM-C-x,它仅在以下情况下有效当您打开文件时,该行已经存在)。
          • 哦,是的。但似乎不能在 emacs23 但 emacs24 上工作。
          • 哦,确实,词法绑定是 Emacs-24.1 中引入的一个特性
          【解决方案5】:

          这不是解决您的宏观问题,而是您希望在项目之间跳转的替代解决方案。

          在我的 init.el 文件中,我有(除其他外)

          (set-register ?A '(file . "~/.aliases"))
          (set-register ?E '(file . "~/.emacs.d/init.el"))
          (set-register ?H '(file . "~/.hgrc"))
          (set-register ?T '(file . "~/.TODO.org"))
          

          然后我可以使用jump-to-register (C-x r j) 在我希望编辑文件(或对未列出的项目之一进行操作)时跳转到其中一个文件。因为文件/文件夹存储在寄存器中(而不是窗口配置),emacs 将打开它在寄存器中找到的文件或文件夹。

          【讨论】:

          • 谢谢。这看起来很有用,但并不是我真正想要的——我的用例是我大量使用 Projectile 模式来打开项目中的文件,正确设置上下文的最简单方法是将 emacs 告诉 cd在打开 Projectile 之前进入项目。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-01
          • 2012-11-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多