更改Emacs的前进单词行为

21

正如标题所说,如何改变emacs前进一个单词函数的行为?例如,假设[]是光标。那么:

my $abs_target_path[]= abs_path($target);
<M-f>
my $abs_target_path = abs[_]path($target);

我知道我可以使用 M-f M-b,但在我看来,这不应该是必要的,我想要改变它。特别是,我希望实现以下两点:

  1. 当我按下M-f时,无论光标是否在单词内部、一组空格内或其他位置,我都希望移动到下一个单词的第一个字符。
  2. 根据每种模式自定义单词字符。毕竟,在CPerl模式和TeX模式下移动的方式是不同的。

因此,在上面的示例中,项目1将使光标移动到“a”(并将点移到其左侧),然后再按下M-f。项目2将允许我将下划线和符号设置为单词字符。


请参考https://dev59.com/AnI_5IYBdhLWcg3wDOrW#1545934,了解下划线部分的内容。 - Bahbar
4个回答

34

尝试:

(require 'misc)

然后使用M-x forward-to-word,看看它是否达到您的要求。然后您可以重新绑定M-f等。

要使_在C和C++模式下不成为单词分隔符(即使其成为单词组成部分),您需要执行以下操作:

(modify-syntax-entry ?_ "w" c-mode-syntax-table)
(modify-syntax-entry ?_ "w" c++-mode-syntax-table)

有关语法表的更多信息,请阅读这个维基页面。 语法表通常被命名为tex-mode-syntax-tablecperl-mode-syntax-table之类的名称。


有没有特定版本的(x)Emacs,其中(require 'misc)会将_字符移动到语法表中的空格?我不得不执行(modify-syntax-entry ?_ "-")才能使其正常工作。 - sameers
我现在在OSX上使用GNU Emacs 24.5,不知道以前是否尝试过,但是将modify-syntax-entry调用添加到我的.emacs文件中并没有设置表项。当我在小缓冲区中输入时可以正常工作。有什么办法可以使它在所有模式下都起作用吗? (modify-syntax-entry? _“w”standard-syntax-table) 表示 standard-syntax-table 是一个未定义的符号。 - sameers
这可能会导致24.5.1版本出现严重的延迟问题。 - Zelphir Kaltstahl

3
请参考 forward-same-syntax 函数。也许这是你需要基于的内容。

非常感谢!我之前不知道这个,它运行得很好!我找到了这个将所有东西捆绑在一起的项目——前进/后退移动/删除:https://github.com/nixme/.emacs.d/blob/master/core/init-keybindings.el - fikovnik

2

我有一个小模式,它可以将基于单词的命令更改为操作语法更改(以及CamelCaseSubwords)。对于某些人来说,它可能过于细粒度,但我发现我基本上不再使用单个字符移动。

https://bitbucket.org/jpkotta/syntax-subword


0

我想复制我的上一个编辑器的行为,因此需要更多的控制,以下是我的方法:

(defun my-syntax-class (char)
  "Return ?s, ?w or ?p depending or whether CHAR is a white-space, word or punctuation character."
  (pcase (char-syntax char)
      (`?\s ?s)
      (`?w ?w)
      (`?_ ?w)
      (_ ?p)))

(defun my-forward-word (&optional arg)
  "Move point forward a word (simulate behavior of Far Manager's editor).
With prefix argument ARG, do it ARG times if positive, or move backwards ARG times if negative."
  (interactive "^p")
  (or arg (setq arg 1))
  (let* ((backward (< arg 0))
         (count (abs arg))
         (char-next
          (if backward 'char-before 'char-after))
         (skip-syntax
          (if backward 'skip-syntax-backward 'skip-syntax-forward))
         (skip-char
          (if backward 'backward-char 'forward-char))
         prev-char next-char)
    (while (> count 0)
      (setq next-char (funcall char-next))
      (loop
       (if (or                          ; skip one char at a time for whitespace,
            (eql next-char ?\n)         ; in order to stop on newlines
            (eql (char-syntax next-char) ?\s))
           (funcall skip-char)
         (funcall skip-syntax (char-to-string (char-syntax next-char))))
       (setq prev-char next-char)
       (setq next-char (funcall char-next))
       ;; (message (format "Prev: %c %c %c Next: %c %c %c"
       ;;                   prev-char (char-syntax prev-char) (my-syntax-class prev-char)
       ;;                   next-char (char-syntax next-char) (my-syntax-class next-char)))
       (when
           (or
            (eql prev-char ?\n)         ; stop on newlines
            (eql next-char ?\n)
            (and                        ; stop on word -> punctuation
             (eql (my-syntax-class prev-char) ?w)
             (eql (my-syntax-class next-char) ?p))
            (and                        ; stop on word -> whitespace
             this-command-keys-shift-translated ; when selecting
             (eql (my-syntax-class prev-char) ?w)
             (eql (my-syntax-class next-char) ?s))
            (and                        ; stop on whitespace -> non-whitespace
             (not backward)             ; when going forward
             (not this-command-keys-shift-translated) ; and not selecting
             (eql (my-syntax-class prev-char) ?s)
             (not (eql (my-syntax-class next-char) ?s)))
            (and                        ; stop on non-whitespace -> whitespace
             backward                   ; when going backward
             (not this-command-keys-shift-translated) ; and not selecting
             (not (eql (my-syntax-class prev-char) ?s))
             (eql (my-syntax-class next-char) ?s))
            )
         (return))
       )
      (setq count (1- count)))))

(defun delete-word (&optional arg)
  "Delete characters forward until encountering the end of a word.
With argument ARG, do this that many times."
  (interactive "p")
  (delete-region (point) (progn (my-forward-word arg) (point))))

(defun backward-delete-word (arg)
  "Delete characters backward until encountering the beginning of a word.
With argument ARG, do this that many times."
  (interactive "p")
  (delete-word (- arg)))

(defun my-backward-word (&optional arg)
  (interactive "^p")
  (or arg (setq arg 1))
  (my-forward-word (- arg)))

(global-set-key (kbd "C-<left>") 'my-backward-word)
(global-set-key (kbd "C-<right>") 'my-forward-word)
(global-set-key (kbd "C-<delete>") 'delete-word)
(global-set-key (kbd "C-<backspace>") 'backward-delete-word)

当我尝试运行时,出现了“while: Symbol's function definition is void: loop”的错误提示。 - Arch Stanton
2
(require 'cl) - Vladimir Panteleev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接