Sublime Forum

How to highlight text and send to embedded terminus termial

#1

I am new to sublime and am liking more the more I use it. What I am struggling with is a usage pattern I used in Atom where I have an embedded terminal in the editor. I would highlight text in an edit panel, hit ctl-enter and have the text automatically sent to the terminal, which then executes.

I’ve been attempting to use sendText and Terminus packages. The combination works fine if I have a separate native (mac OSX) terminal window already open. What I’d like to do is send the text to a Terminus window. Seems you could do this through keybindings, but it’s beyond what I can figure out and not sure it’s really possible.

Would be very instructive to figure out how to do this.

Thank you!

0 Likes

#2

The Terminus package includes its own integrated terminus_send_string command that can be used to send a string to a Terminus view, though it can only transmit predefined strings unless you were to use a bit of glue plugin code.

The idea of the command is demonstrated in the README as the last item before the FAQ at the bottom, showing an example of simple plugin code to trigger the command:

window.run_command(
    "terminus_send_string", 
    {
        "string": "ls\n",
        "tag": "<YOUR_TAG>"        # ignore this or set it to None to send text to the first terminal found
        "visible_only": False      # send to visible panels only, default is `False`. Only relevent when `tag` is None
    }
)

So if you only ever want to trigger static text being sent, you could bind the terminus_send_string command to a key to do it. That doesn’t help you with the selection angle, though.

For that, you need a bit of plugin code that pulls the selection out of the buffer first. A simple example of that is the following (see this video if you’re not sure how to use plugins):

import sublime
import sublime_plugin


class SendSelectionToTerminusCommand(sublime_plugin.TextCommand):
    """
    Extract the contents of the first selection and send it to Terminus.
    """
    def run(self, edit, tag=None, visible_only=False):
        self.view.window().run_command("terminus_send_string", {
            "string": self.view.substr(self.view.sel()[0]),
            "tag": tag,
            "visible_only": visible_only
            })

This grabs whatever text is currently selected in the buffer (only the first selection, assuming you have more than one selection) and then uses the above command to send it to Terminus.

The command is set up to take the same tag and visible_only arguments as the Terminus command takes, and just passes them through.

To use it, you want a keybinding something like the following (though of course the key you use is up to you):

    {
        "keys": ["ctrl+enter"],
        "command": "send_selection_to_terminus",
        "context": [
            { "key": "selection_empty", "operator": "equal", "operand": false },
            { "key": "num_selections", "operator": "equal", "operand": 1 },
        ],
    },

You can add in an "args" key if you want to specify the other two arguments, which determine which Terminus view the output should be sent to (if you have more than one) or if it should only happen when the Terminus view is already visible.

As outlined above, it sends the selection directly, so in order to select code to execute you need to select the whole line (i.e. the cursor needs to be at the start of the following line); otherwise it just sends the text and you have to manually press enter.

The plugin could be modified to append a newline if there isn’t one if you always want this to execute the selection even if it’s not a full line though.

5 Likes

Capturing output from Terminus
#3

Way cul! This is what I am looking for and gives me a lot simpler way to implement what I want to build out in the end.

I am assuming that if you can append and send eol, then i can send any control character. If so, I am golden :wink:

Thank you!

0 Likes

#4

Yeah I imagine that would work as well.

0 Likes

#5

no problems appending -> python. yeah!

"string": self.view.substr(self.view.sel()[0]) + '\n\x04',

I think I’ve found my new favorite general editor. Any pointers on where to look for content to control which window (panel?) is active? After running the above, I want to make the terminus panel active.

0 Likes

#6

Terminus uses standard Sublime panels; the command show_panel can open and close panels (this is the command used to open the find panel, the console, etc if you check the default key bindings).

That command would let you open the panel if it wasn’t already open, though you need to know the name of the panel in question in order to do it. However it doesn’t necessarily give the panel the focus for you.

You should be able to augment the plugin above by adding this as the last line of the method, though:

self.view.window().run_command("toggle_terminus_panel")

That executes the command that Terminus provides for toggling it’s own panels, which also takes care of giving it the focus. When you don’t tell toggle_terminus_panel what panel to toggle, it defaults to the most recently used one, which should always be the one that just got a string sent to it I would think.

0 Likes

#7

Is it possible to send the current line (where the cursor is) to the terminal without first selecting the line?

0 Likes

#8

Of course. Just add self.view.line().

Here’s the modified command.

class SendLineToTerminusCommand(sublime_plugin.TextCommand):
    """
    Extract the contents of the first selection and send it to Terminus.
    """
    def run(self, edit, tag=None, visible_only=False):
        self.view.window().run_command("terminus_send_string", {
            "string": self.view.substr(self.view.line(self.view.sel()[0])),
            "tag": tag,
            "visible_only": visible_only
            })
1 Like

#9

I replaced the previous code with your code, but it doesn’t do anything. Can it be that there is a fault in the code?

0 Likes

#10

As you want it to run without selecting text, you might want to change key binding context as well.

    {
        "keys": ["ctrl+enter"],
        "command": "send_line_to_terminus",
        "context": [
            { "key": "selection_empty", "operand": true },
            { "key": "num_selections", "operator": "equal", "operand": 1 },
        ],
    },
1 Like

#11

@deathaxe yes, now it works! Thank you for taking helping me out!

0 Likes

#12

Hello, I’m from China. Sublime is being used now. Sublime is so easy to use. I know very little English. Now, I will talk to you through network translation and ask for your help.

0 Likes

#13

I replaced the previous code with your code, but it doesn’t do anything. ?.

0 Likes

#14

Where do you put this? You assume so much prerequisite knowledge about a proprietary system. Do I make a new package? Do I modify terminus? No clue…

0 Likes

#15

You probably want to study https://docs.sublimetext.io/guide/extensibility/plugins/ to learn about the very basic about writing open-source plugins for Sublime Text.

A list of all API end-points can be found https://www.sublimetext.com/docs/api_reference.html

Skimming though some of the available open-source plugins on packagecontrol.io may also provide some inspiration.

Last but not least @OdatNurd provides a rich set of super-useful information about all sorts of customization possibilities at https://www.youtube.com/c/OdatNurd

0 Likes