Sublime Forum

Pipe command

#1

I’m looking at adding a pipe command and need references on what code needs to be added to handle it. All I’m trying to do is select a section of text and pipe (|) it to a command of my choosing. The output of the command would replace the selected text.

Doing so makes it much easier to {select} | sort -k 2 and have something sorted the way I want it instead of the default. It becomes even more expressive when piping through awk or custom applications come into play. This isn’t a new concept and would really improve the core functionality of Sublime Text.

0 Likes

#2

It looks like there are probably at least a couple of packages that already do this, based on this search on packagecontrol.io. You’re probably better off using one of those and/or creating a PR on the existing package if it doesn’t meet your needs than you are trying to recreate something similar.

That said, for reference here is a simple example of a command named shell that does this. This is for illustration only, it’s missing a lot of parts that would make it more robust, such as error handling and not blocking Sublime while the external command is running, among other things. Still, it should give you an idea on how you would capture the text out of the file, run it through a command, and replace it with the output.

import sublime
import sublime_plugin

import subprocess


class ShellCommand(sublime_plugin.TextCommand):
    def run(self, edit, cmd=None):
        if cmd is None:
            return self.view.window().show_input_panel("Command:", "sort -n",
                    lambda cmd: self.view.run_command("shell", {"cmd": cmd}),
                    None, None)

        for region in self.get_selected_regions():
            text = self.view.substr(region)
            result = self.run_shell_command(cmd, text)
            if result is not None:
                self.view.replace(edit, region, result)

    def run_shell_command(self, command, input_text):
        proc = subprocess.Popen(command,
                                shell=True,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        try:
            stdout, stderr = proc.communicate(input_text.encode("utf-8"), 5)
            if proc.returncode == 0:
                return stdout.decode("utf-8")
        except:
            proc.kill()

        return None


    def get_selected_regions(self):
        result = [region for region in self.view.sel() if not region.empty()]
        if not result:
            result = [sublime.Region(0, self.view.size())]

        return reversed(result)
1 Like