【问题标题】:How can I accurately set the new cursor positions after text replacements have been made进行文本替换后如何准确设置新光标位置
【发布时间】:2018-01-16 16:28:25
【问题描述】:

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

出于某些我不知道的原因,这会将光标置于替换文本的开头 结尾。猜测是我正在逐个删除这些区域,但忘记了一些也存在的“初始”区域。

注意

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

【问题讨论】:

  • 我猜这里的python标签可能不适用,因为它可能不是真正的python,但你们肯定知道。
  • 视图的选择 (view.sel()) 是一个区域列表,其中每个区域都是一个光标,这就是为什么添加第二个会使第二个添加第二个光标。我会尝试使用view.sel().clear() 而不是subtract,看看会得到什么。
  • @OdatNurd 我无法在循环中添加清除,因为我需要维护多个选择的列表,而不仅仅是最后一个。这就是为什么我认为减法是个好主意。减法可能没有像我想象的那样做。我曾假设初始光标已被删除,但它看起来除了其他 sel()s 之外还在那里。在我收集了所有我想要的区域后,我仍然以与粘贴相同的方式完成了清理工作。可能我可以将两者结合为一个循环,但我没有这样做足以确定。

标签: python sublimetext3 sublimetext sublime-text-plugin


【解决方案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 命令来执行粘贴。

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

【讨论】:

  • 谢谢。我刚刚看到API页面上有与剪贴板交互的方法,并回到这里发表评论。如果我做得对,我根本不需要粘贴。接下来我要做的就是弄清楚如何将密钥对作为参数传递,以便插件可以是动态的! It's my first day
  • 我想说你到目前为止做得很好。 :)
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    • 1970-01-01
    相关资源
    最近更新 更多