《elisp每日一练》——行定位与光标移动

《elisp每日一练》——行定位与光标移动

Masimaro
2026-08-02 / 0 评论 / 1 阅读 / 正在检测是否收录...

在第一天,我们知道buffer实际上就是一个存储文本信息的缓冲区,而光标所在位置就是缓冲区中当前字符的索引。并且这个缓冲区有一个最大索引和最小索引。

除非我们要对整个缓冲区进行清空、全选、移动到开头或者结尾位置等操作,一般来讲我们用到全缓冲区的操作并不多,更多的是快速移动光标然后插入字符或者在行间进行跳转。所以今天我们主要介绍行操作和光标移动

背景知识铺垫

依靠光标所在位置可以定位当前行所在的索引区间,通过函数 line-beginning-positionline-end-position 来获取前行行首或行尾的 Point 位置。

但是和它们第一天介绍的 point 等函数类似,只是获取对应的索引位置,并不会改变光标位置。如果要改变光标位置,通过 goto-char 来实现

依靠这些知识,我们实现一个移动到下一行或者上一行的函数

(defun my/goto-next-line()
  (interactive)
  (let* ((next-start (+ 1 (line-end-position)))
     (next-start (min next-start (point-max))))
    (goto-char next-start)))

上述实现的思路就是通过 line-end-position 定位到当前行尾的下一个位置。但是需要考虑是否是最后一行了。最后再通过 goto-char 移动光标到对应位置。

如果我们通过循环或者递归的方式调用该函数就可以实现连续向下移动N行。

但是这个功能Emacs也提供了,它的函数名为 forward-line。如果传入的参数N为正数则往下移动N行,为负数则表示向上移动N行。

练习

在vim中,我们常用的操作是 yy 拷贝当前行然后 p/P 粘贴到下一行或者上一行。今天的练习我们来尝试实现这么一个功能,为了简单我们就不支持拷贝多行了。

我们可能用到的API函数有:

  • line-beginning-positionline-end-position 用来定位范围
  • buffer-substring 用来拷贝字符串
  • goto-char 移动光标位置
  • newline 插入新行
  • insert 用来在光标所在位置插入字符

有了这些铺垫,我们可以实现这个函数了

(defun my/duplicate-current-line()
  (interactive)
  (let ((line-next (buffer-substring (line-beginning-position) (line-end-position))) ;拷贝当前行所在字符
    )
    (goto-char (line-end-position))
    (newline) ;;  插入新行
    (insert line-next)))

总结

本篇介绍了行操作有关的api函数。并且实现了一个简单的复制当前行到下一行的函数。

但是这个例子不太完美,因为我们发现执行玩之后光标停留在下一行的行尾位置,如果我们不希望改变光标位置,让它停留在当期行该怎么办呢?

下一篇我们将解决这个问题,来讨论如何恢复现场

0

评论 (0)

取消