代码之家  ›  专栏  ›  技术社区  ›  Cheeso

emacs/emacs-lisp:我可以在交互表单之前插入建议吗?或者如何智能地预先设置编译命令?

  •  6
  • Cheeso  · 技术社区  · 13 年前

    我要做的是智能地为字符串参数预先设置缓冲区本地默认值 compile 功能。

    现在compile.el默认使用“make”作为命令。我可以通过设置来设置这个 compile-command . 我甚至可以将该变量缓冲区设置为本地。如果我想要相同的静态值,总是可以的。

    但我想明智地选择 编译命令 取决于缓冲区的内容、缓冲区的名称、文件的包含目录(如果有)的内容以及月球的相位。基本上,我希望控制默认值,然后允许交互用户覆盖该预设值。

    我本来想在事先的建议下做这件事。但这并不像我预期的那样有效。

    我看了Advice.el文件

    假设一个函数/macro/subr/special form有n个before advice、m个around advice和k个after advice。假设所有通知都不受保护,则其建议定义如下(身体形式索引对应于该通知类中各个通知的位置):

    ([macro] lambda <arglist>
       [ [<advised-docstring>] [(interactive ...)] ]
       (let (ad-return-value)
     {<before-0-body-form>}*
           ....
     {<before-N-1-body-form>}*
     {<around-0-body-form>}*
        {<around-1-body-form>}*
          ....
           {<around-M-1-body-form>}*
          (setq ad-return-value
            <apply original definition to <arglist>>)
           {<other-around-M-1-body-form>}*
          ....
        {<other-around-1-body-form>}*
     {<other-around-0-body-form>}*
     {<after-0-body-form>}*
           ....
     {<after-K-1-body-form>}*
     ad-return-value))
    

    这告诉我的是,当advised函数是交互式的时,“以交互方式调用”在调用before通知或任何通知之前调用交互式窗体。

    当我给 编译 我观察到的行为证实了这一点。通知被调用 之后 处理交互窗体。交互式表单建议用于编译的字符串, 之前 我的建议有机会猜测它应该是什么,并预先设定它。

    所以…

    • 如何在交互窗体之前运行我的代码?建议能做到这一点吗?如果不是建议,还有别的吗?或
    • 如何动态预设 编译命令 对于任何缓冲区?

    欣赏想法。

    5 回复  |  直到 9 年前
        1
  •  5
  •   Trey Jackson    13 年前

    一种选择是设置变量 compile-command 在模式挂钩中,类似于

    (add-hook 'c++-mode-hook 'my-c++-set-compile-command)
    (defun my-c++-set-compile-command ()
       (setq (make-local-variable 'compile-command) (format "gmake %s" (buffer-file-name))))
    

    我有时会添加专门的命令来调整当前的编译行(打开/关闭调试标志、优化标志等),然后将这些命令绑定到迷你缓冲区中方便的击键。

    关于在 interactive 形式上,你需要提出建议(无论是在前面还是周围),其中 您需要的交互式表单。来自advice.el库的示例:

    ;;(defadvice switch-to-buffer (around confirm-non-existing-buffers activate)
    ;;  "Switch to non-existing buffers only upon confirmation."
    ;;  (interactive "BSwitch to buffer: ")
    ;;  (if (or (get-buffer (ad-get-arg 0))
    ;;          (y-or-n-p (format "`%s' does not exist, create? " (ad-get-arg 0))))
    ;;      ad-do-it))
    
        2
  •  5
  •   Joseph    11 年前

    编译命令不必是字符串。compile函数会对其进行求值,因此它可以是返回特定于缓冲区或取决于一天中的时间的字符串的函数,等等:

    (setq compile-command (lambda () (if (eq phase-of-moon 'waning) 
                                         "make -DWANING=1" 
                                        "make -DWANING=0")))
    

    此外,尽管可能对您的特定需求不太有用,但您始终可以在文件变量部分定义compile命令:

    /* -*- compile-command: "make -DFOO"; -*- */
    

    // Local Variables:
    // compile-command: "make -DSOMETHING_SPECIAL"
    // End:
    

    编译命令实际上用作 the manual .

        3
  •  4
  •   Cheeso    13 年前

    啊,你知道我做了什么吗?我使用了一种倾斜的策略。

    我已将C-XC-E全局设置为 compile . 我定义了一个函数来包装 编译 ,然后将c-xc-e绑定到 那个 . 在包装器中,我对compile命令进行了猜测。

    (defun cheeso-invoke-compile-interactively ()
      "fn to wrap the `compile' function.  This simply
    checks to see if `compile-command' has been previously guessed, and
    if not, invokes `cheeso-guess-compile-command' to set the value.
    Then it invokes the `compile' function, interactively."
      (interactive)
      (cond
       ((not (boundp 'cheeso-local-compile-command-has-been-set))
    (cheeso-guess-compile-command)
    (set (make-local-variable 'cheeso-local-compile-command-has-been-set) t)))
      ;; local compile command has now been set
      (call-interactively 'compile))
    

    猜测函数是这样的:

    (defun cheeso-guess-compile-command ()
      "set `compile-command' intelligently depending on the
    current buffer, or the contents of the current directory."
      (interactive)
      (set (make-local-variable 'compile-command)
       (cond
        ((or (file-expand-wildcards "*.csproj" t)
         (file-expand-wildcards "*.vcproj" t)
         (file-expand-wildcards "*.vbproj" t)
         (file-expand-wildcards "*.shfbproj" t)
         (file-expand-wildcards "*.sln" t))
         "msbuild ")
    
        ;; sometimes, not sure why, the buffer-file-name is
        ;; not set.  Can use it only if set.
        (buffer-file-name
         (let ((filename (file-name-nondirectory buffer-file-name)))
           (cond
    
        ;; editing a .wxs (WIX Soluition) file
        ((string-equal (substring buffer-file-name -4) ".wxs")
         (concat "nmake "
             ;; (substring buffer-file-name 0 -4) ;; includes full path
             (file-name-sans-extension filename)
             ".msi" ))
    
        ;; a javascript file - run jslint
        ((string-equal (substring buffer-file-name -3) ".js")
         (concat (getenv "windir")
             "\\system32\\cscript.exe c:\\cheeso\\bin\\jslint-for-wsh.js "
             filename))
    
        ;; something else - do a typical .exe build
        (t
         (concat "nmake "
             (file-name-sans-extension filename)
             ".exe")))))
    
        (t
         "nmake "))))
    
        4
  •  1
  •   dustin    9 年前

    下面是我使用的一些代码,它智能地选择了 University of Wyoming . 我目前已经为 C, C++ Fortran . 您可以添加更多以满足您的需求。如果我打开一个程序 C++ 扩展和我执行 M—X 编译 ,我的编译命令发出 g++ -Wall currentfilename.cpp -o currentfilename -std=c++14 . 我就得打了 进入 .

    ;; M-x compile smarter in order to guess language
    (require 'compile)
    (defvar compile-guess-command-table
      '((c-mode       . "gcc -Wall -g %s -o %s -lm")
        (c++-mode     . "g++ -Wall %s -o %s -std=c++14")
        (fortran-mode . "gfortran -C %s -o %s")
        ))
    
    (defun compile-guess-command ()
      (let ((command-for-mode (cdr (assq major-mode
                                         compile-guess-command-table))))
        (if (and command-for-mode
                 (stringp buffer-file-name))
            (let* ((file-name (file-name-nondirectory buffer-file-name))
                   (file-name-sans-suffix (if (and (string-match "\\.[^.]*\\'"
                                                                 file-name)
                                                   (> (match-beginning 0) 0))
                                              (substring file-name
                                                         0 (match-beginning 0))
                                            nil)))
              (if file-name-sans-suffix
                  (progn
                    (make-local-variable 'compile-command)
                    (setq compile-command
                          (if (stringp command-for-mode)
                              ;; Optimize the common case.
                              (format command-for-mode
                                      file-name file-name-sans-suffix)
                            (funcall command-for-mode
                                     file-name file-name-sans-suffix)))
                    compile-command)
                nil))
          nil)))
    
    
    ;; Add the appropriate mode hooks.
    (add-hook 'c-mode-hook       (function compile-guess-command))
    (add-hook 'c++-mode-hook     (function compile-guess-command))
    (add-hook 'fortran-mode-hook (function compile-guess-command))
    
        5
  •  0
  •   Ryan C. Thompson    10 年前

    根据手册,您只需在建议中包含一个交互式表单,就可以用自己的表单覆盖函数的交互式表单。我认为您不能修改或包装现有的交互表单,只能完全覆盖它。

    http://www.gnu.org/software/emacs/manual/html_node/elisp/Defining-Advice.html