【问题标题】:Enabling certain emacs modes or features *almost* always*几乎*总是启用某些 emacs 模式或功能
【发布时间】:2010-09-09 07:39:43
【问题描述】:

有几个 emacs 功能,例如flyspell-modehighlight-beyond-fill-columnauto-fill-mode,我觉得很有用,我 希望它们几乎一直启用。然而,总有确定的 在没有多大意义的情况下。

highlight-beyond-fill-column,例如,我很想要 我自己编辑的所有东西,但为了阅读其他人写的东西,比如在 Gnus 或 看内置文档的时候,其实挺烦的。

同样,auto-fill-mode 在只写文本时非常方便。然而, 编程时完全没有帮助。

由于这些原因,我不能只在全球范围内启用类似的功能。总是 手动启用它们也不是很实用,但是必须编写 显然,我在 emacs 中使用的每种模式或应用程序的挂钩 无法涵盖所有​​这些功能,但最终仍启用了这些功能 手动。

我相信我正在寻找的是一种全局启用某些功能的方法,但是 根据各种条件(例如哪个专业),有选择地再次关闭它们 或次要模式正在使用,如果缓冲区是只读或可写的,或者 取决于包含文本或源代码的缓冲区。我确实意识到 至少最后一件事对于 emacs 来说可能不容易回答,但至少对于 我相信我会很好地使用我使用的“编程模式”的硬编码列表 定期。

【问题讨论】:

    标签: emacs


    【解决方案1】:

    因此,您希望完全控制在打开特定模式或特定类型的文件时执行的操作...好吧,这就是您所需要的:

    ;; The function where you could put all your customization
    (defun my-func ()
      (turn-on-auto-fill))
    
    ;; This is an example, customize it like you need it.
    (defvar functions-to-call
      `(((c-mode c++-mode) ".h$" (my-func))
        ((cperl-mode perl-mode) nil (my-func)))
      "A list of triples, used for storing functions.
    A triplet is composed of a symbol for the major mode (or a list of symbols),
    a regular expression to match against the buffer's file name,
    and the functions to call when both the major mode and regular expr match.")
    
    (defun call-mode-functions ()
      "call functions, based on major mode and buffer name regexp matching"
      (interactive)
      (let ((l functions-to-call))
          (while l
            (let* ((elt (car l))
                   (modes (if (listp (car elt)) (car elt) (list (car elt))))
                   (re (cadr elt))
                   (fcts (caddr elt)))
              (when (and (member major-mode modes)
                         (or (null re)
                             (string-match re (buffer-file-name))))
                (while fcts
                  (funcall (car fcts))
                  (setq fcts (cdr fcts)))
                (setq l nil)))
            (setq l (cdr l)))))
    
    (add-hook 'after-change-major-mode-hook 'call-mode-functions)
    

    使用此代码,您可以进行所需的细粒度自定义。这只是一个示例,您可以根据自己的需要进行调整。

    【讨论】:

    • 指向after-change-major-mode-hook 的指针非常有用。谢谢!
    【解决方案2】:

    有趣的想法。我建议使用 espect 扩展自 your github

    【讨论】:

      【解决方案3】:

      听起来您基本上想为“特定缓冲区”打开或关闭特定的次要模式。通常,“特定缓冲区”可以通过它们的主要模式来区分,这就是我通常看待这类问题的方式。如何打开或关闭次要模式取决于您尝试打​​开/关闭的次要模式和您尝试打开/关闭的主要模式的实现。

      根据主要模式启用/禁用事物的常用方法是通过major-mode-hook 变量。这是您自定义模式的地方:

      (add-hook 'text-mode-hook 'auto-fill-mode)
      

      我通常编写自己的函数,即使它是一个简单的单行函数,因为我几乎总是会在以后添加东西:

      (defun my-text-mode-hook ()
        "Stuff to do when `text-mode' is invoked."
        (auto-fill-mode 1))
      
      (add-hook 'text-mode-hook 'my-text-mode-hook)
      

      你也可以在钩子中设置条件:

      (defun my-text-mode-hook ()
        "Stuff to do when `text-mode' is invoked."
        ;; skip modes based on text-mode
        (when (eq major-mode 'text-mode)
            (auto-fill-mode 1))
        )
      
      (add-hook 'text-mode-hook 'my-text-mode-hook)
      

      我通常在major-mode-load-hook 中完成所有这些操作,因此只有在加载主模式的代码时才会发生:

      (defun my-tnt-load-hook ()
        (defun my-tnt-im-mode-hook ()
          "Hook for TNT's im-mode hook."
          (flyspell-mode 1)
          (setq fill-column (- (frame-width) 5)))
      
        (add-hook 'tnt-im-mode-hook 'my-tnt-im-mode-hook)
        (add-hook 'tnt-chat-mode-hook 'my-tnt-im-mode-hook))
      
      (add-hook 'tnt-load-hook 'my-tnt-load-hook)
      

      编写良好的主模式将定义一个load-hook 变量(我通常查看该模式的源代码以找出答案)。如果它没有load-hook,你可以用eval-after-load函数模拟一个:

      (defun my-view-mode-after-load-hook ()
        "Stuff to do after view mode loads."
        (defun my-view-mode-hook ()
          "Stuff to run in `view-mode'."
          (flyspell-mode 0))
        (add-hook 'view-mode-hook 'my-view-mode-hook)
      
        (define-key view-mode-map "b" 'View-scroll-page-backward)
        (define-key view-mode-map [(delete)] 'View-scroll-page-backward)
        (define-key view-mode-map "q" 'View-kill-and-leave)
        (define-key view-mode-map "Q" 'View-quit))
      
      (eval-after-load 'view '(my-view-mode-after-load-hook))
      

      如果您不在load-hook 中执行此操作,那么您必须确保mode-hook 是可自定义的,然后通过自定义添加您的my-mode-hook;我宁愿把所有的东西都放在我的 .emacs 中的一个地方,所以我通常不会这样自定义我的钩子。

      如果您发现没有major-mode-hook 的主模式,您可以使用define-derived-mode 基于它创建自己的主模式。然后,您必须在旧模式出现时调用新定义的模式。

      (defun replace-alist-mode (alist oldmode newmode)
        (dolist (aitem alist)
          (if (eq (cdr aitem) oldmode)
              (setcdr aitem newmode))))
      
      (define-derived-mode hooked-foobar-mode foobar-mode "Foobar")
      (replace-alist-mode auto-mode-alist 'foobar-mode 'hooked-foobar-mode)
      (defun my-hooked-foobar-mode-hook ()
        "Hook to run when `hooked-foobar-mode' is called."
        (flyspell-mode 0))
      (add-hook 'hooked-foobar-mode-hook 'my-hooked-foobar-mode-hook)
      

      一些次要模式可以全局启用。如果您希望它们大部分时间都打开并且它支持它,您可以全局打开它,然后针对特定的主要模式将其关闭。

      (global-font-lock-mode 1)
      ;; example of how to do it without a defun
      (add-hook 'text-mode-hook (function
                                 (lambda () ""
                                   (interactive)
                                   (font-lock-mode 0))))
      

      如果无法全局启用次要模式,或者您不希望全局启用它,只需针对特定模式将其打开即可,如上所示。

      【讨论】:

      • 问题的目标是不必为我碰巧使用的每个模式维护主要模式挂钩,而是更普遍地维护不同主要模式的缓冲区特定设置。
      • 不,不。不要误会我的意思。这很有帮助,也很有趣。它只是没有真正解决问题所描述的问题。
      【解决方案4】:

      以下是我在阅读 [Jérôme Radix][1] 的优秀作品后得出的结论 回复。特别是指向after-change-major-mode-hook 的指针帮助了 很多。

      我现在在这样的列表中定义我的缓冲区特定设置:

        ;; no `highlight-beyond-fill-column' for w3m and gnus
      '((((:not ((:mode "^gnus") (:mode w3m-mode))))
         (lambda () (highlight-beyond-fill-column)))
        ;; `flyspell-mode` and `auto-fill-mode` for text-ish buffers
        (((:mode message-mode)
          (:mode org-mode)
          (:mode pod-mode)
          (:mode markdown-mode)
          (:name "\\.\\(txt\\|mkn\\)$"))
         (lambda ()
           (flyspell-mode)
           (auto-fill-mode)))
        ;; indenting with tabs for certain projects
        (((:name t :fun (lambda () (and (not eproject-root)
                                        (eproject-maybe-turn-on)))))
         (lambda () (setq indent-tabs-mode t)))
      

      当主要模式发生变化时,我会遍历所有这些设置,评估 缓冲区中定义的条件,如果 a 条件匹配:

      (add-hook 'after-change-major-mode-hook
                (lambda () (rafl:apply-buffer-settings rafl:buffer-settings)))
      
      (defun rafl:apply-buffer-settings (settings)
        (dolist (setting rafl:buffer-settings)
          (let ((condition (car setting))
                (action (cadr setting)))
            (when (rafl:evaluate-buffer-condition condition)
              (funcall action)))))
      

      评估这些条件有点混乱,但对我来说效果很好。

      (defun rafl:evaluate-buffer-condition (con)
        (cond
         ((functionp con)
          (funcall con))
         ((listp con)
          (cond
           ((listp (car con))
            (reduce
             (lambda (a b) (or a b))
             (cons nil (mapcar #'rafl:evaluate-buffer-condition con))))
           (t
            (reduce
             (lambda (a b) (and a b))
             (cons
              t
              (let (ret)
                (while con
                  (let ((k (pop con))
                        (v (pop con)))
                    (push (cond
                           ((eq k :fun)
                            (funcall v))
                           ((eq k :not)
                            (when (not (listp v))
                              (error ":not requires a list"))
                            (not (rafl:evaluate-buffer-condition v)))
                           ((eq k :mode)
                            (if (stringp v)
                                (string-match-p v (symbol-name major-mode))
                              (eq v major-mode)))
                           ((eq k :name)
                            (cond
                             ((and (buffer-file-name) (stringp v))
                              (string-match-p v (buffer-file-name)))
                             ((buffer-file-name)
                              v)
                             (t
                              (not v))))
                           (t
                            (error "unknown cond")))
                          ret)))
                ret))))))
         (t
          (error "invalid condition"))))
      

      事实证明,我可以完成所有的每个项目设置,我做得很好 以前不同,使用这种机制。我对此感到非常高兴。

      1:Enabling certain emacs modes or features *almost* always

      【讨论】:

        【解决方案5】:

        我这样做

        (require 'linum)
        ;(global-linum-mode t)
        (add-hook 'find-file-hook (lambda ()
                                    (if (not(equal major-mode 'term-mode))
                                        (linum-mode nil))))
        

        【讨论】:

        • 这似乎只对编辑文件有用。但是,并非所有缓冲区都有与之关联的文件,我也想启用或禁用其中的某些行为。但是,您确实回答了我的部分问题。谢谢!
        • @rafl 我很确定这个钩子总是被调用
        • 恐怕不会,不会。顾名思义,它只被find-file 调用过,这绝不是创建缓冲区的唯一方法。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-20
        • 2017-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多