Search code examples
pythonsublimetext3sublimetextsublime-text-plugin

Print text in new view (unsaved buffer), not in console


1. Briefly

I don't find, how I can get output in new view, not in Sublime Text console.


2. Expected behavior

For example, I have countdown timer:

import time

seconds = 10

while seconds >= 0:
    time.sleep(1)
    if seconds == 5:
        print("5 seconds")
    elif seconds == 0:
        print("Time over!")
        time.sleep(5)
    else:
        print(seconds)
    seconds -= 1

Ctrl+Shift+P (⌘⇧p for Mac) → SublimeREPL: Python RUN current file → I get expected behavior:

Countdown timer


3. Actual behavior

Same countdown timer in Sublime Text plugin:

import time

import sublime_plugin

seconds = 10


class LovernaStandardCommand(sublime_plugin.TextCommand):

    def run(self, edit):
        current_id = self.view.id()
        if current_id:
            global seconds
            while seconds >= 0:
                time.sleep(1)
                if seconds == 5:
                    print("5 seconds")
                elif seconds == 0:
                    print("Time over!")
                    time.sleep(5)
                else:
                    print(seconds)
                seconds -= 1

I run command loverna_standard → I see output in Sublime Text console, not in new view.


4. Not helped

  1. Python write() method works with files, not with unsaved buffers.
  2. I find in Sublime Text 3 API documentation, how I can open new view — sublime.active_window().new_file() — but I don't find, how I can print text in this view.

Solution

  • You can append text to a Sublime Text view by using the append command. For example, if you want the view to automatically scroll to the bottom when new text is added:

    view.run_command('append', { 'characters': str(seconds) + '\n', 'scroll_to_end': True })
    

    However, it is best to set up a callback every second than to sleep, otherwise ST will be unresponsive while the command is running.

    import sublime
    import sublime_plugin
    
    class LovernaStandardCommand(sublime_plugin.TextCommand):
    
        def run(self, edit, seconds=10):
            self.print_seconds(sublime.active_window().new_file(), seconds)
    
        def print_seconds(self, view, seconds):
            text = ''
            if seconds > 0:
                text = str(seconds)
                if seconds == 5:
                    text += ' seconds'
                sublime.set_timeout_async(lambda: self.print_seconds(view, seconds - 1), 1000) 
            else:
                text = 'Time over!'
            view.run_command('append', { 'characters': text + '\n', 'scroll_to_end': True })