Emacs 第一次elisp尝试-未在tab上调用tab键的次要模式?

Emacs 第一次elisp尝试-未在tab上调用tab键的次要模式?,emacs,elisp,Emacs,Elisp,我决定用一点口齿不清的口齿不清让我的脚趾湿透,因为我想让emacs在我点击TAB时表现得更好一点。我的命令行得通。它只是对tab命令执行缩进,如果什么也没发生,它会执行tab-to-tab-stop,假设我在多行字符串或类似的字符串中点击tab不太可能只是为了让点拒绝移动。第一次按TAB键后,它将继续执行逐页停止操作,直到编辑恢复,或该点移到其他位置。好吧,我的逻辑是正确的,尽管我的lisp代码可能不是 最初,我只是通过对我想要这种行为的主要模式执行(localset key(kbd“TAB”)

我决定用一点口齿不清的口齿不清让我的脚趾湿透,因为我想让emacs在我点击TAB时表现得更好一点。我的命令行得通。它只是对tab命令执行缩进,如果什么也没发生,它会执行tab-to-tab-stop,假设我在多行字符串或类似的字符串中点击tab不太可能只是为了让点拒绝移动。第一次按TAB键后,它将继续执行
逐页停止操作
,直到编辑恢复,或该点移到其他位置。好吧,我的逻辑是正确的,尽管我的lisp代码可能不是

最初,我只是通过对我想要这种行为的主要模式执行
(localset 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)
干杯


克里斯

我觉得你很接近

为您的密钥映射尝试以下操作:

'(("\t" . tab-dwim)))
可以,使用“\t”或矢量格式“[(制表)]”

有关elisp开发的其他注意事项:

  • 尽量避免使用全局变量。在这种情况下,我认为使用let动态绑定是合适的。还可以看看let*
  • 了解
    make local variable
    make variable buffer local
    之间的区别。按照编写代码的方式,缓冲区局部变量将只存在于加载包的缓冲区中
  • 正如Nemo所提到的,非常建议您对与每个包相关的所有变量/函数使用一个通用前缀。Emacs只有一个名称空间,这是一种“黑客式”的方法来保持它的有序性

  • 呜呼!这很简单:)顺便说一句,我的
    setq
    makelocalvariable
    调用的位置感觉有点不正确。它们应该放在次要模式中,还是可以这样全局配置它们?我会将“makelocalvariable”调用放在外部(因为这是一个全局设置),将“setq”调用放在内部。我还将选择一个前缀(如“dwim tab”),并用该前缀命名所有内容(函数和变量)。ELisp没有名称空间,所以前缀是通常的惯例。谢谢,我刚刚重新命名了所有内容并移动了一些内容。只需阅读
    手册,现在就让
    开始。这似乎是一个更干净的解决方案,我同意。我不理解你的逻辑,让我们不工作在你目前的逻辑。但是,您根本不需要跟踪点的位置。您只需检查最后一个命令变量,看看这是否是第二次+调用。这将适用于多次按tab键(这是我试图解决的问题的90%),但在第一次按tab键没有移动点的情况下(例如,在按enter键后,然后在多行字符串中按tab键),这将没有帮助。感觉应该有一个更干净的方法,我只是不认为检查最后一个命令就足够了?嗯,我第一次就做对了,你可以使用let。发布一个关于如何移入变量的问题,我将在那里发布代码。您原来的问题已经解决,所以我不希望代码被隐藏在这里。FWIW、
    “\t”
    [(tab)]
    不是一回事。第一个是制表符,它对于键绑定意味着ASCII控制字符制表符,它与
    C-i
    相同。第二个是功能键
    tab
    ——它表示键盘的
    tab
    键发送的任何信息。如果您希望您的代码处理这两种制表键,那么绑定它们。