Sublime Forum

How to track if an output panel is closed/hidden?

#1

Output panels are hidden when I bring out the console with CTRL+` or trigger some other output panel to be shown… How can I track that the output panel I have is “closed” or hidden?

My panel is created with this code

panel = window.get_output_panel(self.PANEL_NAME)

1 Like

Why do I call 'show_panel' with 'output.exec', but need to call window.find_output_panel("exec") instead of window.find_output_panel("output.exec")?
How to detect whether some quick panel is open as the Command Palette is open?
#2

Edit: After thinking about this only a bit I realize that the thing I wanted to use only works for “context managers” added by plugins, not for internals.

I don’t know of a way to track the visibility of output panels but re-running the show_panel command does not break anything and would be the desired way to make the panel appear “always”. If you only want to “check” if a panel is visible/focused, I can’t really help you. I tried a few things, though.

In the key bindings I found this (extracts):

"command": "show_panel", "args": {"panel": "console", "toggle": true}

"context": {"key": "panel", "operand": "find"}, {"key": "panel_has_focus"}]

	{ "keys": "escape"], "command": "hide_panel", "args": {"cancel": true},
		"context":
		
			{ "key": "panel_visible", "operator": "equal", "operand": true }
		]
	},

However, triggering these context events did not really help and always returned “False” for my tests. (sublime_lib.WindowAndTextCommand)

class TestCommandCommand(sublime_lib.WindowAndTextCommand):
    def is_checked(self):
        return False

    def run(self, param):
        print(self.view, self._window_command)
        self.window.run_command("show_panel", {"panel": "output.aaa_package_dev"})
        visible = sublime_plugin.on_query_context(self.view, key="panel_visible", operator=sublime.OP_EQUAL, operand=True, match_all=False)
        focus = sublime_plugin.on_query_context(self.view, key="panel_has_focus", operator=sublime.OP_EQUAL, operand="output.aaa_package_dev", match_all=False)
        print("is visible", visible, "has focus", focus)

So, not really helpful but maybe you can find something out of this.

1 Like

#3

I found:

view = window.get_output_panel(self.PANEL_NAME) if view.window(): #visible is true else: #visible is false

2 Likes

#4

That’s interesting and indeed seems to work (well). There are probably some edge cases like when there is no window created yet, but I’m not even sure if you can actually get an output panel in that case. I should add that to the docs.

I used this (for the default output panel):

class TestCommandCommand(sublime_plugin.WindowCommand):
    def run(self):
        out = self.window.get_output_panel("exec")
        print "visible:", bool(out.window())
2 Likes

#5

This view.window() does not seem to be working on Sublime Text build 3157 to determine whether the output.exec panel is visible or not.

try:
    defaultExec = importlib.import_module("Better Build System").BetterBuidSystem
except:
    defaultExec = importlib.import_module("Default.exec")

class ExecCommand(defaultExec.ExecCommand):

    def on_finished(self, proc):
        """It is the entry point after the process is finished."""
        super(ExecCommand, self).on_finished(proc)

        if g_settings.get("force_show_build_panel", False):
            exit_code = proc.exit_code()
            output_view = self.output_view
            errors_len = len(output_view.find_all_results())

            if ( exit_code \
                    or errors_len ) \
                    and output_view.window():

                self.window.run_command("show_panel", {"panel": "output.exec"})
                output_view.show(0)

Correction

It still working, I forgot to invert the boolean:

                    and output_view.window():

–>

                    and not output_view.window():
0 Likes

#6

New hack into the panel visibility:

class HackListener(sublime_plugin.EventListener):

    def on_selection_modified(self, view):
        active_window = sublime.active_window()
        panel_has_focus = not view.file_name()

        is_widget = view.settings().get('is_widget')
        active_panel = active_window.active_panel()

        print( "is_widget:", is_widget )
        print( "panel_has_focus:", panel_has_focus )
        if active_panel and panel_has_focus or is_widget:
            correct_view = view
        
        else:
            correct_view = active_window.active_view()

This has a flaw, it will not work, if the current view is a new file not saved on the file system, as they will also not report a file name when calling view.file_name(). So, this will also report the panel has focus when you have focus on this new file view.

The correct_view result is a fix for this bug on the core of Sublime Text when working with cloned views:

  1. $Core/289 Multiple event hooks don’t work with clones
0 Likes

#7

New example code. This also has the same flaw as the other before. It will not work if the current view is a new file not saved on the file system, as they will also not report a file name when calling view.file_name() . So, this will also report the panel has focus when you have focus on this new file view.

import sublime
import sublime_plugin

import datetime
g_is_panel_focused = False

# https://forum.sublimetext.com/t/how-to-set-focus-to-exec-output-panel/26689/5
class ExecOutputFocusCancelBuildCommand(sublime_plugin.WindowCommand):

    def run(self):
        window = self.window
        active_panel = window.active_panel()

        # if the panel is not visible in the current window, active_panel will be None
        if active_panel:
            # https://forum.sublimetext.com/t/why-do-i-call-show-panel-with-output-exec-but-need-to-call-window-find-output-panel-exec-instead-of-window-find-output-panel-output-exec/45739
            panel_view = self.window.find_output_panel( active_panel ) or \
                    self.window.find_output_panel( active_panel.lstrip("output.") )

            # this global variable will be True when the panel has focus
            if g_is_panel_focused:
                user_notice = "Cancelling the build for '%s'..." % active_panel
                print( str(datetime.datetime.now())[:-4], user_notice )

                sublime.status_message( user_notice )
                self.window.run_command( 'cancel_build' )

            else:
                self.window.focus_view( panel_view )

        else:
            self.window.run_command('show_panel', args={'panel': 'output.exec'})


class HackListener(sublime_plugin.EventListener):

    def on_activated(self, view):
        global g_is_panel_focused

        # Multiple event hooks don’t work with clones
        # https://github.com/SublimeTextIssues/Core/issues/289
        active_window = sublime.active_window()
        view_has_name = not not view.file_name()

        is_widget = view.settings().get('is_widget')
        active_panel = active_window.active_panel()
        g_is_panel_focused = active_panel and not view_has_name and not is_widget

        # print( "is_widget:", is_widget )
        # print( "view_has_name:", view_has_name )
        # print( "g_is_panel_focused:", g_is_panel_focused )

Keybind:

[
    { "keys": ["f8"], "command": "exec_output_focus_cancel_build", "context": [{ "key": "panel", "operand": "output.exec" }] },
]
  1. On the first time pressed, it will show the output panel. (if not already shown)
  2. On the second time pressed, it will focus the cursor/caret on the output panel. (if not already focused)
  3. On the third time and so on pressed, it will cancel the build. (even if it already cancelled)
0 Likes

#8

Does window.active_panel() == panel_name by itself not suffice to determine whether a panel is open?

0 Likes

#9

Yes, but what my last code does with the variable g_is_panel_focused is tell whether it has focus, not whether the panel is opened/showing up on the screen, i.e., on this screencast the panel is opened but it does not has focus:
has_focus

However, on the next screencast the panel is opened and it has focus:
hasfocus

0 Likes

#10

I just figured out a fix for this problem. By registring the event on_new, I can register a view setting called is_new_file and later on I can check for that, and now the hack works on 100% of the situations!

g_widget_view = None
g_is_panel_focused = False
g_is_widget_focused = False

class HackListener(sublime_plugin.EventListener):

    def on_new(self, view):
        # The Window event on_new(view) is not called when opening a file
        # https://github.com/SublimeTextIssues/Core/issues/2906
        if not view.file_name():
            view.settings().set('is_new_file', True)

    def on_activated(self, view):
        global g_widget_view
        global g_is_panel_focused
        global g_is_widget_focused

        # Multiple event hooks don’t work with clones
        # https://github.com/SublimeTextIssues/Core/issues/289
        g_widget_view = view
        active_window = sublime.active_window()
        view_has_name = not not view.file_name() or view.settings().get('is_new_file')

        g_is_widget_focused = view.settings().get('is_widget')
        active_panel = active_window.active_panel()
        g_is_panel_focused = active_panel and not view_has_name and not g_is_widget_focused
0 Likes