【问题标题】:First elisp attempt - minor mode for tab key not being invoked on tab?第一次 elisp 尝试 - 选项卡上未调用选项卡键的次要模式?
【发布时间】:2011-09-28 14:39:27
【问题描述】:

我决定用一点口齿不清来弄湿我的脚趾,因为我想让 emacs 在我点击 TAB 时表现得更好一些。我的命令工作正常。它只是执行indent-for-tab-command,如果什么也没发生,它执行tab-to-tab-stop,假设我不太可能点击 TAB 只是为了让我在一个多用途中拒绝让步线串或类似的东西。在第一次按 TAB 之后,它会继续执行tab-to-tab-stop,直到继续编辑,或者将点移到其他位置。 AFAIK,我的逻辑没问题,虽然我的 lisp 代码可能不是!

最初我只是通过(local-set-key (kbd "TAB") 'tab-dwim) 将它侵入到我的 emacs 点文件中,用于我想要这种行为的主要模式。这按预期工作。

然后我决定我所做的基本上是次要模式,所以我尝试将键绑定移动到次要模式。出于某种原因,即使启用了次要模式(如模式行中所示,并且只是通过打开和关闭它),当我点击 TAB时,我的 tab-dwim 函数没有被调用> 键。我仍然可以按预期使用 M-x 调用它。

我的次要模式的:keymap 做错了什么?

;;;
;; TAB DWIM

; buffer-local before/after point tracking
(setq point-before-tab nil)
(setq point-after-tab nil)
(make-local-variable 'point-before-tab)
(make-local-variable 'point-after-tab)

(defun tab-dwim ()
  "Indents normally once, then switches to tab-to-tab-stop if invoked again.

tab-dwim will always perform tab-to-tab-stop if the first TAB press does not
cause the point to move."

  (interactive)

  (print "in tab-dwim now") ; THIS LINE IS NEVER INVOKED ON TAB?

  (setq point-before-tab (point))

  (if (eq point-before-tab point-after-tab) ; pressed TAB again
      (tab-to-tab-stop)
    (indent-for-tab-command))

  (if (eq (point) point-before-tab) ; point didn't move
      (tab-to-tab-stop))
  (setq point-after-tab (point)))

(define-minor-mode tab-dwim-mode
  "Toggle tab-dwim-mode.
With a non-nil argument, turns on tab-dwim-mode. With a nil argument, turns it
off.

When tab-dwim-mode is enabled, pressing the TAB key once will behave as normal,
but pressing it subsequent times, will continue to indent, using
tab-to-tab-stop.

If tab-dwim determines that the first TAB key press resulted in no movement of
the point, it will indent according to tab-to-tab-stop instead."

  :init-value nil
  :lighter " DWIM"
  :keymap
  '(([TAB] . tab-dwim)))

(provide 'tab-dwim)

干杯,

克里斯

【问题讨论】:

    标签: emacs elisp


    【解决方案1】:

    我认为你很亲密。

    为您的键盘映射试试这个:

    '(("\t" . tab-dwim)))
    

    【讨论】:

    • 哇哦!就这么简单:) 在旁注中,我准备的setqmake-local-variable 电话的位置感觉有点不正确。应该将它们隐藏在次要模式中,还是可以像这样全局配置它们?
    • 我会把“make-local-variable”调用放在外面(因为它是一个全局设置),把“setq”调用放在里面。我还会选择一个前缀(如“dwim-tab”)并使用该前缀命名所有内容(函数和变量)。 ELisp 缺少命名空间,因此通常使用前缀。
    【解决方案2】:

    是的,使用“\t”或矢量格式“[(tab)]”。

    为您的 elisp 开发添加一些注意事项:

    1. 尽可能避免使用全局变量。在这种情况下,我认为与 let 动态绑定是合适的。也看看 let*。
    2. 了解make-local-variablemake-variable-buffer-local 之间的区别。按照您编写代码的方式,缓冲区局部变量仅存在于加载您的包的缓冲区中。
    3. 正如 Nemo 所提到的,极力建议您为与每个包相关的所有变量/函数使用一个通用前缀。 Emacs 只有一个命名空间,这是保持它有条理的“hacky”方式。

    【讨论】:

    • 谢谢,我刚刚重新命名了所有内容并移动了一些东西。现在只需阅读let 的手册。我同意,这似乎是一个更清洁的解决方案。
    • 我不明白你那里的逻辑,让你当前的逻辑不起作用。但是,您根本不需要跟踪点位置。您可以检查 last-command 变量,看看这是否是第二次+调用。
    • 这将适用于多个制表符(这是我要解决的问题的 90%),但在第一次制表符没有移动点的情况下它无济于事(例如,在按回车后,然后在多行字符串中使用 TAB)。感觉应该有更干净的方式,只是觉得检查最后一条命令还不够?
    • 嗯。我第一次做对了,你可以使用 let。发布有关如何将变量移入的问题,我将在那里发布代码。您的原始问题已解决,因此我不希望将代码埋在这里。
    • FWIW、"\t"[(tab)]是一回事。第一个是 TAB 字符,对于键绑定表示 ASCII 控制字符 TAB,与 C-i 相同。第二个是功能键tab——它表示键盘上的Tab 键发送的任何内容。如果您希望您的代码同时处理这两种 TAB 键,请绑定它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-13
    • 2019-02-28
    相关资源
    最近更新 更多