进行文本替换后如何准确设置新的光标位置
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
命令来执行粘贴。
最后一部分将原始剪贴板文本放回剪贴板上,您可能需要也可能不需要。
我正在尝试
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
命令来执行粘贴。
最后一部分将原始剪贴板文本放回剪贴板上,您可能需要也可能不需要。