如何编写Emacs Lisp函数以替换光标处的单词?

11

我尝试了两种不同的方式来编写我的函数。我决定编写一个小型函数,使用这个elisp字符串库将文本转换为驼峰式并进行反向操作。一开始通过搜索发现了这篇教程,学会了在点位替换字符,并编写出这个函数:

; use string manipulation library to switch between camel and snake (s.el)
(defun my_test ()
  "test"
  (interactive)
  ;; get current selection or word
  (let (bds p1 p2 inputStr resultStr)
    ;; get boundary
    (if (use-region-p)
        (setq bds (cons (region-beginning) (region-end) ))
      (setq bds (bounds-of-thing-at-point 'word)) )
    (setq p1 (car bds) )
    (setq p2 (cdr bds) )
    ;; grab the string
    (setq inputStr (buffer-substring-no-properties p1 p2)  )
    (setq resultStr (s-lower-camel-case inputStr))
    (message inputStr)

    (delete-region p1 p2 ) ; delete the region
    (insert resultStr) ; insert new string
    )
)

这并没有按预期修改resultStr,而只是把inputStr复制粘贴到了那里。

我不理解的是,当我使用M-: eval (setq resultStr (s-lower-camel-case "other_string"))时,我得到了预期的结果("otherString")

我甚至尝试了另一种(对我的目的来说更好的)编写该函数的方式,灵感来自于这个SO问题:

(defun change-word-at-point (fun)
  (cl-destructuring-bind (beg . end)
      (bounds-of-thing-at-point 'word)
    (let ((str (buffer-substring-no-properties beg end)))
      (delete-region beg end)
      (insert (funcall fun str)))))

(defun my_test_camel ()
  (interactive)
  (change-word-at-point 's-lower-camel-case))

它受到相同问题的困扰。这让我认为 s-lower-camel-case 函数存在问题(或者我调用它的方式有问题),但是当从上面提到的 eval 调用时它能正常运行。

编辑:修改第一个函数以包含 let 语法,详见注释。

编辑 #2:这两个函数都能够正确工作,已经接受了答案,因为它提供了一个带有 symbol 信息和正确书写方式的更好的替代方案。我的问题出在测试上,这是由于 haskell-mode 引起的。新问题在这里


注意,如之前所提到的s-lower-camel-case函数来自于位于这里s.el库。 - Mike H-R
我认为delete-region不会移动光标,而insert会将其参数插入到光标处。这可能是问题的一部分吗? - user725091
1
此外,在您的函数的第一个版本中,您应该使用(let* ((bds …) (p1 …) (p2 …)) …)来绑定局部变量,而不是使用setq(当没有周围的let绑定时,它将操作该名称的全局变量)。 - user725091
我认为你是正确的,该区域被删除,然后插入文本,所以点会跳到新文本的末尾。但是插入的文本仍然是错误的,对我来说并不是很重要。 - Mike H-R
@JonO。另外,你是对的,我在调试时删除了它,我会编辑以重新插入它并修复这个问题,谢谢。 - Mike H-R
你可能会感兴趣的是:https://github.com/akicho8/string-inflection - Ehvince
1个回答

14

这里有一个替代定义。评论中提到需要通过let进行本地绑定是正确的。请注意,如果区域处于活动状态,则此版本将使用该区域,否则将使用bounds-of-thing-at-point来获取指针所在位置的单词(如果没有活动区域):

(defun word-or-region-to-lcc ()
  "Convert word at point (or selected region) to lower camel case."
  (interactive)
  (let* ((bounds (if (use-region-p)
                     (cons (region-beginning) (region-end))
                   (bounds-of-thing-at-point 'symbol)))
         (text   (buffer-substring-no-properties (car bounds) (cdr bounds))))
    (when bounds
      (delete-region (car bounds) (cdr bounds))
      (insert (s-lower-camel-case text)))))
如果您不关心使用区域选项,可以将text局部绑定到(thing-at-point 'symbol),而不是调用buffer-substring-no-properties函数。
更新。事实证明,您可以使用(thing-at-point 'symbol)而不是(thing-at-point 'word)来获取蛇形命名的完整符号。

这与我的实现有相同的问题,它只是用自身替换文本(而不是修改它)。如果我使用eval(使用M-:)调用函数时可以正常工作,但从交互式函数调用时却无法正常工作,是否有什么原因呢? - Mike H-R
只是想确认一下,这对你有效吗?还是我有一些奇怪的配置问题导致出现了问题? - Mike H-R
它对我有用:将光标放在 MyVariableHere 中的某个位置并调用函数会得到 myVariableHere。您是否试图从 my_variable_here 转换为 myVariableHere?如果是这样,您可能需要使用区域选择整个内容,因为 _ 可能是单词边界。 - Dan
嗯...在Scratch中它可以工作,但在我一直在测试的haskell-mode中却无法工作(所有其他函数也是如此),因为缓冲区是打开的。这非常奇怪。我不认为你有任何想法,这可能是怎么发生的? - Mike H-R
我不使用 haskell-mode,所以除了想知道什么算单词边界之外,无法发表评论。请参见更新的答案,它允许您在蛇形命名法上使用它,而无需选择区域。 - Dan
我会将这个问题标记为已回答,因为我认为它已经得到了解决(感谢您提供的有关符号的提示,我很感激)。我可能会提出另一个问题来解决与Haskell模式不兼容的问题。谢谢! - Mike H-R

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