《elisp每日一练》——行定位与光标移动
在第一天我们知道buffer实际上就是一个存储文本信息的缓冲区而光标所在位置就是缓冲区中当前字符的索引。并且这个缓冲区有一个最大索引和最小索引。除非我们要对整个缓冲区进行清空、全选、移动到开头或者结尾位置等操作一般来讲我们用到全缓冲区的操作并不多更多的是快速移动光标然后插入字符或者在行间进行跳转。所以今天我们主要介绍行操作和光标移动背景知识铺垫依靠光标所在位置可以定位当前行所在的索引区间通过函数line-beginning-position和line-end-position来获取前行行首或行尾的 Point 位置。但是和它们第一天介绍的point等函数类似只是获取对应的索引位置并不会改变光标位置。如果要改变光标位置通过goto-char来实现依靠这些知识我们实现一个移动到下一行或者上一行的函数(defunmy/goto-next-line()(interactive)(let*((next-start(1(line-end-position)))(next-start(minnext-start(point-max))))(goto-charnext-start)))上述实现的思路就是通过line-end-position定位到当前行尾的下一个位置。但是需要考虑是否是最后一行了。最后再通过goto-char移动光标到对应位置。如果我们通过循环或者递归的方式调用该函数就可以实现连续向下移动N行。但是这个功能Emacs也提供了它的函数名为forward-line。如果传入的参数N为正数则往下移动N行为负数则表示向上移动N行。练习在vim中我们常用的操作是yy拷贝当前行然后p/P粘贴到下一行或者上一行。今天的练习我们来尝试实现这么一个功能为了简单我们就不支持拷贝多行了。我们可能用到的API函数有:line-beginning-position和line-end-position用来定位范围buffer-substring用来拷贝字符串goto-char移动光标位置newline插入新行insert用来在光标所在位置插入字符有了这些铺垫我们可以实现这个函数了(defunmy/duplicate-current-line()(interactive)(let((line-next(buffer-substring(line-beginning-position)(line-end-position)));拷贝当前行所在字符)(goto-char(line-end-position))(newline);; 插入新行(insertline-next)))总结本篇介绍了行操作有关的api函数。并且实现了一个简单的复制当前行到下一行的函数。但是这个例子不太完美因为我们发现执行玩之后光标停留在下一行的行尾位置如果我们不希望改变光标位置让它停留在当期行该怎么办呢下一篇我们将解决这个问题来讨论如何恢复现场