5
\$\begingroup\$

It's my first plugin and it's super simple but there could easily be some things worth knowing from this e.g. Python coding practices and potential bugs.

import sublime
import sublime_plugin

class EscapeAndPasteCommand(sublime_plugin.TextCommand):
    def run(self, edit, **kwargs):
        # Get the clipboard text
        originalText = textToPaste = sublime.get_clipboard() 
        # Loop through the arguments making changes where possible
        for replacement in kwargs:
            # print("replacing '" + replacement + "'' with '" + kwargs[replacement] + "'")
            textToPaste = textToPaste.replace(replacement,kwargs[replacement])
        # Place the text back into the clipboard and paste in place
        sublime.set_clipboard(textToPaste)
        self.view.run_command("paste")

        # Restore the original text to the clipboard
        sublime.set_clipboard(originalText)

The idea is you feed this a dictionary of matches and replacements that it will perform on the clipboard object. Once those changes are made it restores the untouched text to the clipboard.

I made a key binding for this so that when I am pasting text, in my markdown files, that has file paths it will autoescape it for me, such as underscores and slashes that are meant to be just that.

{ "keys": ["ctrl+shift+v"], 
    "command": "escape_and_paste", 
    "args": {
        "\\": "\\\\",
        "_" : "\\_",
        "*" : "\\*"
    }
}

It works well for me and I think I would be lost without it now as it makes my documentation processes easier.

\$\endgroup\$
5
\$\begingroup\$

If your intention is to escape certain characters by prefixing them with backslashes, you would be better off with a function that performs that specific task, rather than a generalized function that accepts a dictionary of replacements.

In general, performing multiple substitution passes over a string is a bad idea. Certain substitution dictionaries could result in non-deterministic behaviour, depending on the order in which the substitutions are performed. In fact, you have just that problem:

  • If the _ escape is performed before the \ escape, then _ would become \_, then \\_.
  • If the \ escape is performed before the _ escape, then _ would remain _, then become \_.

You could overcome that problem by specifying the substitutions using a collections.OrderedDict, but I still recommend against it on principle. Escaping / unescaping is always better done using a single left-to-right pass.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Yes. That would be a problem. And I thought this was going to be a silly post. I had initially made a specialized escaping function then thought I could design it so it would be useful in other places. Thanks \$\endgroup\$ – Matt Jan 19 '18 at 21:33
  • 1
    \$\begingroup\$ There is also str.translate, which avoids this problem. \$\endgroup\$ – Graipher Jan 19 '18 at 23:45
  • \$\begingroup\$ I plan on a refactor where you pass all characters you want to escape and the escape character itself. If I were to better this approach does left to right mean that I do all changes one character at a time and loop through the string \$\endgroup\$ – Matt Jan 21 '18 at 2:21
  • 1
    \$\begingroup\$ You could do that, or the regex substitution in the answer that I cited. The best solution is probably str.translate() as suggested by @Graipher. \$\endgroup\$ – 200_success Jan 21 '18 at 2:23
  • \$\begingroup\$ Sorry to bug you about this but this is what I ended up doing and its not worth another question textToPaste = textToPaste.translate(str.maketrans(kwargs)). Converted my arguments to a translation map outright. I think that should prevent any issues. \$\endgroup\$ – Matt Jan 22 '18 at 16:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.