Search code examples
pythonsublimetextsublimerepl

Display output from evaluating selection - Sublime Text Python REPL


I am using Sublime Text 3 and running OSX Mavericks. I am using the Sublime REPL package and I have adjusted the settings for that package such that I have "show_transferred_text" : true

When a Python REPL window is opened, I have the nice option to send a chunk of code from the editor to it using Ctrl + , , s . But, doing so doesn't display any of the output of my commands, unless I include a print command. E.g. If I write the following

x = 2.5

type(x)

and use the Ctrl +, , s to send it to be evaluated, then I do get a display of these commands, but I don't get a display of the output from type(x) as I would if I copy/pasted the commands into the Python interpreter in the Mac Terminal.

Is there any way to get this functionality within Sublime Text?


Solution

  • [UPDATE]

    The code below is now deprecated. For the newest, better working version, please visit the gist for this plugin at https://gist.github.com/dantonnoriega/46c40275a93bab74cff6.

    Feel free to fork and star. I will add any changes to the gist as the code evolves. However, to stay the most up-to-date, please following the following repo: https://github.com/dantonnoriega/sublime_text_plugins/blob/master/python_blocks_for_repl.py

    ***************

    I wanted the same functionality. What I came up with works and is a hodgepodge of the following posts:

    https://stackoverflow.com/a/14091739/3987905

    Is it possible to chain key binding commands in sublime text 2?

    How to pass a line to the console in sublime text 2 editor

    Creating the Plugin

    The following plugin requires that you open repl in the same window as your code but as a separate group. I learned how to do this using the 1st link above. In order to send the text you want and then execute the text, I used the idea from the 2nd link above and wrote the following plugin (Tools -> New Plugin...)

    class ReplViewAndExecute(sublime_plugin.TextCommand):
        def run(self, edit):
            v = self.view
            ex_id = v.scope_name(0).split(" ")[0].split(".", 1)[1]
            lines = v.lines(self.view.sel()[0]) # get the region, ordered
            last_point = v.line(self.view.sel()[0]).b # get last point (must use v.line)
            last_line = v.line(last_point) # get region of last line
    
            for line in lines:
                self.view.sel().clear() # clear selection
                self.view.sel().add(line) # add the first region/line
                text = v.substr(line)
                print('%s' % text) # prints in console (ctrl+`)
    
                if not line.empty() and text[0] != '#': # ignore empty lines or comments
                    v.window().run_command('focus_group', {"group": 1}) # focus REPL
                    v.window().active_view().run_command("insert",
                        {"characters": text})
                    v.window().run_command('repl_enter')
    
            # if the last line was empty, hit return
            # else, move the cursor down. check if empty, hit return once more
            if last_line.empty():
                self.view.sel().clear()
                self.view.sel().add(last_line)
                v.window().run_command('focus_group', {"group": 1}) # focus REPL
                v.window().run_command('repl_enter')
                v.window().run_command('focus_group', {"group": 0})
                v.window().run_command('move', {
                    "by": "lines",
                    "forward": True,
                    "extend": False
                })
            else:
                v.window().run_command('focus_group', {"group": 0})
                v.window().run_command('move', {
                    "by": "lines",
                    "forward": True,
                    "extend": False
                })
                if self.empty_space():
                    v.window().run_command('focus_group', {"group": 1}) # focus REPL
                    v.window().run_command('repl_enter')
    
            # move through empty space
            while self.empty_space() and self.eof():
                v.window().run_command('focus_group', {"group": 0})
                v.window().run_command('move', {
                    "by": "lines",
                    "forward": True,
                    "extend": False
                })
        def eof(self):
            v = self.view
            s = v.sel()
            return True if v.line(s[0]).b < v.size() else False
    
        def empty_space(self):
            v = self.view
            s = v.sel()
            return True if v.line(s[0]).empty() else False
    

    The code above sends the selected line(s) to REPL, focuses the group where REPL is contained, executes REPL (i.e. hits 'enter') then focuses back to the code window.

    The plugin now moves the cursor to the next line automatically so you can evaluate lines quickly. Also, if the next line happens to be empty, the plugin keeps hitting 'enter' for you automatically until it encounters a non-empty line. This, for me, was key, since if I selected a function block in python, I would still have to switch over to REPL and hit enter for the function to complete. The while loop part fixes that.

    Using the Plugin

    To run the following plugin, I put the following in my user key bindings (which I learned from the 3rd link above)...

        //REPL send and evaluate
        { "keys": ["super+enter"], "command": "repl_view_and_execute"}
    

    And that should work!

    Summary

    Remember, you need to

    1. Put sublimeREPL in the same window but in a separate group (follow the first link to do this quickly with the pydev plugin).
    2. Create the 'repl_view_and_execute' plugin then bind it.

    If anyone knows how to make a more elegant version that can switch between the active window and wherever the REPL view is contained (like another window), I welcome the advice. I worked through sublimerepl.py but could not figure out how to use all the active_window() etc. commands.