如何在完成文本替换后准确设置新光标位置

时间:2018-01-16 16:28:25

标签: python sublimetext3 sublimetext sublime-text-plugin

我正在尝试adapt a plugin在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)))

对于某些我未知的原因,将光标放在替换文本的开头末尾。一个猜测是,我将逐个删除这些区域,但忘记了一些同样存在的“初始”区域。

注意

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

2 个答案:

答案 0 :(得分:1)

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

# 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)

答案 1 :(得分:1)

我认为你自己对问题的回答是好的,如果我以这种方式做这样的事情,可能就是我要去的方式。

特别是,由于插件正在动态修改文本并使其更长,因此第一种立即将其作为解决方案而不是您自己的答案所做的解决方案的方法是跟踪文本的长度变化。替换,以便您可以相应地调整选择。

由于我无法真正为您的问题提供比您已经提出的问题更好的答案,所以这里有另一种解决方案:

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命令来执行粘贴。

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