几乎总是启用某些emacs模式或功能

几乎总是启用某些emacs模式或功能,emacs,Emacs,还有一些emacs功能,例如flyspell模式, 突出显示超出填充列,或自动填充模式,我发现非常有用 希望它们几乎一直处于启用状态。然而,总有一点是肯定的 它们没有多大意义的条件 突出显示填充列之外的内容,例如,我倾向于 我自己编辑的所有东西,除了阅读别人写的东西,比如Gnus或 当阅读内置文档时,它实际上相当烦人 类似地,自动填充模式在只编写文本时非常方便。然而, 这在编程时完全没有帮助 出于这些原因,我不能在全球范围内启用这样的功能。总是 手动启用它们也不太实际,但必须编写它们也是如此 显

还有一些emacs功能,例如
flyspell模式
突出显示超出填充列
,或
自动填充模式
,我发现非常有用 希望它们几乎一直处于启用状态。然而,总有一点是肯定的 它们没有多大意义的条件

突出显示填充列之外的内容
,例如,我倾向于 我自己编辑的所有东西,除了阅读别人写的东西,比如Gnus或 当阅读内置文档时,它实际上相当烦人

类似地,
自动填充模式
在只编写文本时非常方便。然而, 这在编程时完全没有帮助

出于这些原因,我不能在全球范围内启用这样的功能。总是 手动启用它们也不太实际,但必须编写它们也是如此 显然,我在emacs中使用的每个模式或应用程序都有挂钩 无法涵盖所有这些功能,但最终仍然启用了这些功能 手动

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

我这样做

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

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

;; 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)

通过这段代码,您可以进行所需的细粒度定制。这只是一个例子,您可以根据自己的需要对其进行调整。

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

基于主模式启用/禁用事物的常用方法是通过
主模式挂钩
变量。这是您粘贴内容以自定义模式的地方:

(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)
我通常在主模式加载钩子中执行所有这些操作,因此只有在加载主模式的代码时才会发生:

(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
变量(我通常通过查看模式的源代码来了解)。如果它没有
负载挂钩
,您可以使用
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))
如果在
加载挂钩中不执行此操作
,则必须确保
模式挂钩
可自定义,然后通过自定义添加
我的模式挂钩
;我宁愿把所有的东西都放在.emacs中的一个地方,所以我通常不会这样定制我的挂钩

如果您发现一个主模式没有
主模式挂钩
,您可以使用
定义派生模式
根据它创建自己的主模式。然后,无论何时调用旧模式,都必须调用新定义的模式

(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))))

如果次要模式无法全局启用,或者您不希望它全局启用,只需为特定模式启用它,如上图所示。

因此,我在阅读[Jérôme Radix][1]后得出了以下结论 回复尤其是在更改主模式挂钩后指向
的指针有助于
很多

现在,我在如下列表中定义了特定于缓冲区的设置:

  ;; 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)))
当主模式更改时,我会迭代所有这些设置,然后计算 缓冲区中定义的条件,如果 条件匹配:

(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:

有趣的想法。我建议使用
扩展名自。

这似乎只对编辑文件有用。但是,并非所有缓冲区都有与之关联的文件,我还想启用或禁用这些缓冲区中的某些行为。不过,你确实回答了我部分问题。谢谢大家!@rafl我很确定这个钩子总是被调用的。恐怕不是。正如名字所示,它只被
find file
调用,这绝不是创建缓冲区的唯一方法。指向
after change mair mode hook
的指针非常有用。非常感谢。这个问题的目的是不必为我正在使用的每一种模式维护主模式挂钩,而是更普遍地在不同的主模式之间维护特定于缓冲区的设置。不,不,不要误解我的意思。这很有帮助,也很有趣。它只是没有真正解决问题所描述的问题。