The original plugin above is a quite dump straight forward wrapper for the view.replace()
API function. It can be improved by several means, of course.
According to your description I came up with the following proposal:
The start_pt
argument is removed as the command uses selections to look for regions to replace tokens within. If all selections are empty, view.replace()
is performed within the whole document. Otherwise only tokens within a non-empty selection are replaced.
It provides a selector
argument which can be used to replace tokens only if they match certain scopes. A "selector": "text.html.markdown - markup.raw - source"
for instance would replace a token in a Markdown file but leave all fenced codeblocks untouched.
class FindReplaceSelectedCommand(sublime_plugin.TextCommand):
"""The implementation of 'find_replace_selected' text command.
Example:
view.run_command(
"find_replace", {
"pattern": "the",
"replace_by": "THE",
"selector": "text - source",
"flags": ["LITERAL"]
}
)
"""
FLAGS = {
"LITERAL": sublime.LITERAL,
"IGNORECASE": sublime.IGNORECASE
}
def run(self, edit, pattern, replace_by, selector=None, flags=[]):
"""Find and replace all patterns.
Arguments:
edit (sublime.Edit):
The edit token used to undo this command.
pattern (string):
The regex pattern to use for finding.
replace_by (string):
The text to replace all found words by.
selector (string):
The selector to match a found token against.
Can be used to replace tokens of certain scope only.
flags (list):
The flags to pass to view.find()
["LITERAL", "IGNORECASE"]
"""
view = self.view
selections = view.sel()
selection_empty = all(len(sel) == 0 for sel in selections)
for found in reversed(view.find_all(pattern, self._flags(flags))):
# skip all tokens which don't match the selector
if selector and not view.match_selector(found.begin(), selector):
continue
# skip all tokens not within any selection if non-empty selections exist
if selection_empty or any(sel.contains(found) for sel in selections):
view.replace(edit, found, replace_by)
def _flags(self, flags):
"""Translate list of flags."""
result = 0
for flag in flags:
result |= self.FLAGS.get(flag, 0)
return result