Skip to content

Commit

Permalink
Merge pull request #1912 from SublimeLinter/rewrite-message-view
Browse files Browse the repository at this point in the history
  • Loading branch information
kaste committed Jun 19, 2023
2 parents c383ea9 + 07050dd commit c2ea1f1
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 65 deletions.
6 changes: 3 additions & 3 deletions lint/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def validate_settings(filename_settings_pairs, flat=False):
window.status_message(status_msg)

if good:
util.clear_message()
util.close_error_panel()

return good

Expand All @@ -145,7 +145,7 @@ def validate_project_settings(filename):

settings = obj.get('settings', {})
if not settings:
util.clear_message()
util.close_error_panel()
return True

sl_settings = {
Expand All @@ -154,7 +154,7 @@ def validate_project_settings(filename):
if key.startswith('SublimeLinter.') and key != IS_ENABLED_SWITCH
}
if not sl_settings:
util.clear_message()
util.close_error_panel()
return True

invalid_top_level_keys = [
Expand Down
75 changes: 70 additions & 5 deletions lint/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@
if MYPY:
from typing import (
Callable, Iterator, List, MutableMapping, Optional, TypeVar, Union)
from typing_extensions import ParamSpec
from typing_extensions import Concatenate as Con, ParamSpec
P = ParamSpec('P')
T = TypeVar('T')
Q = TypeVar('Q', bound=Union[sublime.Window, sublime.View])


logger = logging.getLogger(__name__)
Expand All @@ -34,6 +35,8 @@
STREAM_BOTH = STREAM_STDOUT + STREAM_STDERR
UI_THREAD_NAME = None # type: Optional[str]
ANSI_COLOR_RE = re.compile(r'\033\[[0-9;]*m')
ERROR_PANEL_NAME = "SublimeLinter Messages"
ERROR_OUTPUT_PANEL = "output." + ERROR_PANEL_NAME


@events.on('settings_changed')
Expand Down Expand Up @@ -95,6 +98,33 @@ def enqueue_on_ui(fn, *args, **kwargs):
sublime.set_timeout(partial(fn, *args, **kwargs))


def ui_block(fn):
# type: (Callable[Con[Q, P], T]) -> Callable[Con[Q, P], None]
"""Mark a function as UI block and mimic `run_command` behavior.
Annotates a function that takes as its first argument either a `View`
or a `Window`. Calling that function will then ensure it will run
on the UI thread and with a valid subject, t.i. we call `is_valid()`
on the first argument. The function will be a no-op if the subject
is not valid anymore. The function will run sync and blocking if
called from the UI thread, otherwise a task will be enqueud on the
UI. In this case the function will return immediately before it has
run.
"""
return ensure_on_ui_thread(skip_if_invalid_subject(fn))


def skip_if_invalid_subject(fn):
# type: (Callable[Con[Q, P], T]) -> Callable[Con[Q, P], None]
@wraps(fn)
def wrapped(__view_or_window, *args, **kwargs):
# type: (Q, P.args, P.kwargs) -> None
if __view_or_window.is_valid():
fn(__view_or_window, *args, **kwargs)

return wrapped


@contextmanager
def print_runtime(message):
start_time = time.perf_counter()
Expand All @@ -106,14 +136,49 @@ def print_runtime(message):


def show_message(message, window=None):
# type: (str, Optional[sublime.Window]) -> None
if window is None:
window = sublime.active_window()
window.run_command("sublime_linter_display_panel", {"msg": message})
_show_message(window, message)


@ui_block
def _show_message(window, message):
# type: (sublime.Window, str) -> None
if window.active_panel() == ERROR_OUTPUT_PANEL:
panel = window.find_output_panel(ERROR_PANEL_NAME)
assert panel
else:
panel = window.create_output_panel(ERROR_PANEL_NAME)
syntax_path = "Packages/SublimeLinter/panel/message_view.sublime-syntax"
try: # Try the resource first, in case we're in the middle of an upgrade
sublime.load_resource(syntax_path)
except Exception:
return

panel.assign_syntax(syntax_path)

scroll_to = panel.size()
msg = message.rstrip() + '\n\n\n'

panel.set_read_only(False)
panel.run_command('append', {'characters': msg})
panel.set_read_only(True)
panel.show(scroll_to)
window.run_command("show_panel", {"panel": ERROR_OUTPUT_PANEL})

def clear_message():
window = sublime.active_window()
window.run_command("sublime_linter_remove_panel")

def close_all_error_panels():
# type: () -> None
for window in sublime.windows():
close_error_panel(window)


def close_error_panel(window=None):
# type: (Optional[sublime.Window]) -> None
if window is None:
window = sublime.active_window()
window.destroy_output_panel(ERROR_PANEL_NAME)


def flash(view, msg):
Expand Down
46 changes: 0 additions & 46 deletions message_view.py

This file was deleted.

16 changes: 5 additions & 11 deletions sublime_linter.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ def plugin_unloaded():

queue.unload()
persist.settings.unobserve()
util.close_all_error_panels()
events.off(on_settings_changed)


Expand Down Expand Up @@ -129,7 +130,10 @@ def run(self):
try:
reloader.reload_everything()
except Exception:
show_restart_message()
util.show_message(
'Reloading SublimeLinter failed. :-(\n'
'Please restart Sublime Text.'
)
raise # Still write the traceback to the console!
finally:
log_handler.install()
Expand All @@ -140,16 +144,6 @@ def reload_sublime_linter():
window.run_command("sublime_linter_reload")


def show_restart_message():
window = sublime.active_window()
window.run_command("sublime_linter_display_panel", {
'msg': (
'Reloading SublimeLinter failed. :-(\n'
'Please restart Sublime Text.'
)
})


def other_visible_views():
"""Yield all visible views of the active window except the active_view."""
window = sublime.active_window()
Expand Down

0 comments on commit c2ea1f1

Please sign in to comment.