进行文本替换后如何准确设置新的光标位置

How can I accurately set the new cursor positions after text replacements have been made

我正在尝试 在 Sublime Text 3 插件中进行自动文本替换。我想要它做的是从剪贴板粘贴文本并进行一些自动文本替换

import sublime
import sublime_plugin
import re

class PasteAndEscapeCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        # Position of cursor for all selections
        before_selections = [sel for sel in self.view.sel()]
        # Paste from clipboard
        self.view.run_command('paste')
        # Postion of cursor for all selections after paste
        after_selections = [sel for sel in self.view.sel()]
        # Define a new region based on pre and post paste cursor positions
        new_selections = list()
        delta = 0
        for before, after in zip(before_selections, after_selections):
            new = sublime.Region(before.begin() + delta, after.end()) 
            delta = after.end() - before.end()
            new_selections.append(new)
        # Clear any existing selections
        self.view.sel().clear()
        # Select the saved region
        self.view.sel().add_all(new_selections)
        # Replace text accordingly
        for region in self.view.sel():
            # Get the text from the selected region
            text = self.view.substr(region)
            # Make the required edits on the text
            text = text.replace("\","\\")
            text = text.replace("_","\_")
            text = text.replace("*","\*")
            # Paste the text back to the saved region
            self.view.replace(edit, region, text)
        # Clear selections and set cursor position
        self.view.sel().clear()
        self.view.sel().add_all(after_selections)

除了我需要为编辑的文本获取新区域外,这在大多数情况下都有效。光标将放置在粘贴文本末尾的位置。但是,由于我进行的替换总是使文本变大,因此最终位置将不准确。

我对 Sublime 的 Python 知之甚少,和大多数其他插件一样,这是我的第一个插件。

如何设置光标位置以适应文本中的大小变化。我知道我需要对 after_selections 列表做一些事情,因为我不确定如何创建新区域,因为它们是根据前面步骤中清除的选择创建的。

我觉得我和

越来越亲近了
# Add the updated region to the selection
self.view.sel().subtract(region)
self.view.sel().add(sublime.Region(region.begin()+len(text)))

由于某些我还不知道的原因,这会将光标置于替换文本的开头 结尾。一个猜测是我正在一个一个地删除区域,但忘记了一些 "initial" 也存在的区域。

备注

我很确定这里问题的代码中的双循环是多余的。但这超出了问题的范围。

因此,一种方法是创建新区域,因为替换文本是使用它们各自的长度作为起始位置创建的。然后一旦循环完成,清除所有现有选择并设置我们在替换循环中创建的新选择。

# Replace text accordingly
new_replacedselections = list()
for region in self.view.sel():
    # Get the text from the selected region
    text = self.view.substr(region)
    # Make the required edits on the text
    text = text.replace("\","\\") # Double up slashes
    text = text.replace("*","\*")   # Escape * 
    text = text.replace("_","\_")   # Escape _ 
    # Paste the text back to the saved region
    self.view.replace(edit, region, text)
    # Add the updated region to the collection
    new_replacedselections.append(sublime.Region(region.begin()+len(text)))

# Set the selection positions after the new insertions.
self.view.sel().clear()
self.view.sel().add_all(new_replacedselections)

我认为你自己对你的问题的回答很好,如果我以这种方式做这样的事情,我可能会采用这种方式。

特别是,由于插件会即时修改文本并使其变长,因此除了您自己的答案之外,第一种立即将其自身呈现为解决方案的方法是跟踪替换后的文本,以便您可以相应地调整选择。

由于我无法为您的问题提供比您已经提出的更好的答案,因此这里有一个替代解决方案:

import sublime
import sublime_plugin

class PasteAndEscapeCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        org_text = sublime.get_clipboard()
        text = org_text.replace("\","\\")
        text = text.replace("_","\_")
        text = text.replace("*","\*")

        sublime.set_clipboard(text)
        self.view.run_command("paste")

        sublime.set_clipboard(org_text)

这会修改剪贴板上的文本,使其按照您希望的方式被引用,这样它就可以使用内置的 paste 命令来执行粘贴。

最后一部分将原始剪贴板文本放回剪贴板上,您可能需要也可能不需要。