Emacs如何记住文本选择

4
我决定尝试学习使用Emacs,因为在几年中我大部分编码需求一直使用gEdit,希望尝试新的东西。虽然我知道这可能很困难,因为我听说过Emacs可能很复杂,但是我被它的强大吸引了。最难的事情是习惯在.emacs文件中编写ELisp以更改编辑器的一些设置。我目前还无法自己完成,但我在网上找到了一些有用的代码片段来更改一些选项。
我遇到的一个问题是,当执行某个命令后,Emacs无法记住我已经选择的文本,导致我经常遇到问题。例如,我通常会突出显示一段代码以进行批量缩进。但是,如果我在Emacs中这样做,它将在移动所选文本一次后取消选择所有文本。是否有人知道解决方法?
不好意思,这对我来说似乎是一个简单的问题,但经过一小时的谷歌搜索和在SO上查找后,我认为值得问一下。我还有关于Emacs的几个问题,但在解决这个问题之后,我会单独提出它们并询问。谢谢!
更新:
有几个人询问我正在使用的模式以及输入的文本类型。虽然我不太了解Emacs模式,但我目前正在编辑一个纯文本文件。就像这样:
Hello, I am a simple text file
that is made up of three separate 
lines.

如果我选中这三行并按下TAB键,会得到以下结果:
    Hello, I am a simple text file
    that is made up of three separate 
    lines.

这很好,但是如果我像下面一些人建议的那样使用 C-x C-x 来重新选择文本并再次按 TAB 键,我会得到以下结果:

        Hello, I am a simple text file
            that is made up of three separate 
                lines.

我希望这能够帮到你!

请参见 https://dev59.com/j3RA5IYBdhLWcg3wzhbZ。 - Yktula
5个回答

9
FWIW,这是您新增示例行为的原因。 (我在此处没有“解决”问题,但我会将其发布以消除您所看到的内容。)
这是使用禁用我的自定义的emacs -q 确定的,因此以下是emacs 23.2的默认行为。
  1. 您正在文本模式下。 您应该在屏幕底部的模式行中看到(Text)或类似信息,并且C-h m会告诉您(在小模式列表下):“文本模式:编辑写给人阅读的文本的主要模式。” Emacs通过auto-mode-alist变量决定(例如匹配某些扩展名,例如.txt ),它应该切换到文本模式。
  2. 在文本模式下,选定区域按TAB键会按顺序对区域中的每一行调用indent-according-to-mode。 找到这个函数的稍微复杂的路径从C-h k TAB开始,告诉我们TAB绑定到indent-for-tab-command,在这种情况下调用indent-region--该函数名称在帮助中没有明确说明,但可以在代码中看到--检查缓冲区局部的indent-region-function变量,其值为nil,并且:“值为nil表示在每行上真正运行indent-according-to-mode。”
  3. indent-according-to-mode 检查indent-line-function变量,其缓冲区本地值为indent-relative
  4. 使用C-h f indent-relative RET 查看此函数的帮助。 (阅读此内容)。
尽管您可能还没有经验来知道如何检查所有这些(甚至不一定想要!),并完全理解它告诉您的所有内容,但这是Emacs自我记录方面的一个示例,使用户能够弄清发生了什么(然后使更改变得可行)。 我实际上只是使用了C-h k (describe-key),C-h f (describe-function)和C-h v (describe-variable)以遵循文档。 查看indent-for-tab-command 的源代码就像点击其帮助页面中显示的文件名一样简单。
我建议执行以下操作以帮助查看每行运行indent-relative 时正在发生什么: M-x set-variable x-stretch-cursor t
M-x set-variable ruler-mode-show-tab-stops t
M-x ruler-mode 现在,对于每一行,将光标放在行的开头并按下TAB键。您将得到所有三行缩进到第一个制表位(标尺上的“T”)的结果。
现在重复此操作 - 再次确保您在每行的开头,位于现有缩进之前。
第一行的第一个字符(当前为制表符)再次缩进到第一个制表位,因为没有先前的行可以检查它。
接下来,第二行的第一个字符缩进以匹配前一行的第一个非空格字符的位置。由于第二行的第一个字符也是制表符,第二行的实际文本被向右推了一个制表符距离。
第三行也是如此。它的第一个制表符字符与第二行的第一个非空格字符对齐,具有与以前相同的相对效果,从而给出您示例中的最终状态。
强调一下,如果您现在在现有行上方输入“a b c”,然后返回到下一行的开头(以前的第一行)并按TAB键,则第一个制表符字符将与“b”对齐。只要indent-tabs-mode变量为true(表示您有实际的制表符字符),那么这对行中单词的位置不会产生实际影响,因为使用空格进行制表符缩进直到空格数量超过制表符宽度才会产生影响(但这是另一回事了!)
所有这些都意味着,Emacs中的text-mode在这种情况下的行为不符合您的期望。当然,在按下TAB键时,其他主要模式可能会执行完全不同的操作。
正如通常在Emacs中一样,您不喜欢的东西可以通过elisp进行更改或规避。一些搜索(尤其是在Emacs Wiki上)经常会找到有用的解决方案来解决您遇到的问题。

2
尝试在Emacs取消选择后键入C-x C-x。然后,不要按下“tab”键(我以前从未知道“tab”键会做你说的事情!那完全是疯了),而是按下M-8 C-x C-i。可惜需要按这么多键,但它应该能够实现你想要的——即将所有内容推到8列之外。如果您想要其他列数,请将M-8替换为其他内容。

1
我尝试了一下,它有点起作用。Emacs确实重新选择了我的文本,我可以再次按Tab键,但是,它会在每行选择上方的行的基础上增加一个额外的制表符空格。例如,如果我突出显示三行并按Tab键,则所有行都缩进1个制表符空格。接下来,我按C-x C-x重新选择文本。然后我再次按Tab键,第1行缩进了1个额外的制表符空格,第2行缩进了2个额外的制表符空格,第3行缩进了3个制表符空格。现在我的文档看起来像一个楼梯!还有其他想法吗? - Jason Watkins
1
虽然需要敲击更多的键,但这确实有效,也是我想要的。我从未想到Emacs会如此困难,但我猜随着时间的推移,它会变得更容易。谢谢! - Jason Watkins

1
你可以使用以下代码来实现这个功能:

(add-hook 'text-mode-hook (lambda ()
                            (set (make-local-variable 'indent-region-function)
                                 (lambda (s e)
                                   (indent-rigidly s e tab-width)))))

然后选择一个区域,按下TAB键即可将该区域缩进一个制表符宽度。你可以使用C-x C-x交换光标和标记,再次按下TAB键以重复操作。
不过,我同意之前的答案建议直接使用indent-rigidly

1

你是如何缩进的,使用的是哪种模式?

在任何编程模式中,缩进规则通常应该是正确的。(如果不是,那可能更表明您想要为该模式配置不同的规则,但我怀疑这是一个已经被问过的不同问题)。

如果您处于文本模式或类似模式,并且只是使用TAB,则我可以看到问题所在。

请注意,如果您使用indent-rigidlyC-x C-i或相同的C-x TAB),则即使高亮显示已消失,您也可以通过重复命令来重复缩进相同的区域。

您还可以使用前缀参数indent-rigidly来使其缩进多次。例如,C-u C-u C-x C-i(比看起来更容易输入)将缩进16个空格(4 x 4,因为前缀参数默认为4,并且每次重复都会乘以它)。同样,M-8 C-x C-i缩进8个空格。这在某些情况下很好用,在其他情况下则太麻烦了。

个人建议将(cua-selection-mode 1)放入您的.emacs文件中,并使用它进行严格的缩进。Trey Jackson制作了一个方便的博客。有了这个,您可以使用C-RET开始矩形选择,向下移动需要的行数,重复使用TAB来缩进行,然后使用C-RET退出模式。

当矩形处于活动状态时,RET会循环遍历角落。对于左侧角落,键入会插入在前面。对于右侧角落,键入会插入在后面。对于单列矩形,底部计为“左”,顶部计为“右”。

Trey的博客列出了所有可用功能(或查看源文件:cua-base.el)

请注意,Emacs中的缩进通常是一个意外复杂的主题


1
哇,这似乎比我想象的要复杂得多。我会尝试你的建议,但我可以肯定地说,只需要在gEdit中突出显示文本并按Tab键即可,这样做会很难适应。我不确定你所说的“哪种模式”是什么意思?对于Emacs语言学,我还是很新手。我目前正在编辑一个纯文本文件,但我将经常使用Emacs来编辑Java文件。希望这有所帮助!感谢您的建议! - Jason Watkins
模式对于Emacs来说非常基础;它们使其能够针对不同类型的内容以不同/适当的方式运行。每个缓冲区都有一个单独的“主模式”,并且在任何给定的缓冲区中可能有许多“次要模式”处于活动状态。模式行至少指示了主模式。您还可以键入C-h m以查看您输入该命令的缓冲区中所有活动模式的信息。 - phils
1
考虑到这对你来说很新,我建议你跟随一些教程和其他帮助设施。它们将极大地提高你的起始学习曲线。Emacs有一个内置的教程('C-h t')。它不短,但是Emacs也不小 :)以下是另外几个起点链接:http://stackoverflow.com/questions/210791/good-resources-for-emacs https://dev59.com/Z3RB5IYBdhLWcg3wz6ad - phils

1
通常我所做的是在取消选区命令后,简单地输入C-x C-xexchange-point-and-mark)。

1
我尝试了你的命令(与offby1给出的相同),并在我的评论中列出了结果。有什么想法为什么会这样? - Jason Watkins
你目前处于哪种主要模式?你正在编辑什么样的文本?你能将其缩小到最小的文本片段,以展示该行为,并将其添加到原始问题中吗? - Sean

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