Skip to content

Commit

Permalink
propose: class Panel
Browse files Browse the repository at this point in the history
remove ensure_*_panel and ensure_panel and create_panel functions
with a class Panel that abstracts all the interaction with the panels
  • Loading branch information
predrag-codetribe committed Dec 12, 2020
1 parent f6e17d3 commit 2a962e0
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 130 deletions.
7 changes: 0 additions & 7 deletions plugin/core/diagnostics.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
from .panels import ensure_panel
from .protocol import Diagnostic
from .protocol import Point
from .sessions import SessionBufferProtocol
from .types import PANEL_FILE_REGEX, PANEL_LINE_REGEX
from .typing import List, Tuple, Callable, Optional, Iterable
import sublime


def ensure_diagnostics_panel(window: sublime.Window) -> Optional[sublime.View]:
return ensure_panel(window, "diagnostics", PANEL_FILE_REGEX, PANEL_LINE_REGEX,
"Packages/LSP/Syntaxes/Diagnostics.sublime-syntax")


class DiagnosticsUpdateWalk(object):

def begin(self) -> None:
Expand Down
149 changes: 104 additions & 45 deletions plugin/core/panels.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from re import sub
from .typing import Dict, Optional, List, Generator, Tuple
from .types import debounced
from contextlib import contextmanager
import sublime
import sublime_plugin

PANEL_FILE_REGEX = r"^(?!\s+\d+:\d+)(.*)(:)$"
PANEL_LINE_REGEX = r"^\s+(\d+):(\d+)"

# about 80 chars per line implies maintaining a buffer of about 40kb per window
SERVER_PANEL_MAX_LINES = 500
Expand Down Expand Up @@ -32,11 +35,99 @@
}


class PanelName:
Diagnostics = "diagnostics"
References = "references"
Rename = "rename"
LanguageServers = "language servers"
class Panel:
def __init__(self, name: str, syntax="", file_regex="", line_regex=""):
self.name = name
self._panel = None # type: Optional[sublime.View]
self._syntax = syntax
self._file_regex = file_regex
self._line_regex = line_regex

def view(self, w: sublime.Window) -> sublime.View:
""" Returns the view contained within the panel. """
return self._ensure_panel(w)

def is_open(self, w: sublime.Window) -> bool:
return w.active_panel() == "output.{}".format(self.name)

def open(self, w: sublime.Window) -> None:
self._panel = self._ensure_panel(w)
w.run_command("show_panel", {"panel": "output.{}".format(self.name)})

# HACK: Focus the panel to make the next_result prev_result commands work,
# than focus back to the currently open view
current_view = w.active_view()
w.focus_view(self._panel)
w.focus_view(current_view)

def close(self, w: sublime.Window) -> None:
self._panel = self._ensure_panel(w)
w.run_command("hide_panel", {"panel": "output.{}".format(self.name)})

def toggle(self, w: sublime.Window) -> None:
if self.is_open(w):
self.close(w)
else:
self.open(w)

def update(self, w: sublime.Window, content: str) -> None:
self._panel = self._ensure_panel(w)
self._panel.run_command("lsp_update_panel", {"characters": content})

def clear(self, w: sublime.Window) -> None:
self._panel = self._ensure_panel(w)
self._panel.run_command("lsp_clear_panel")

def destroy(self, w: sublime.Window) -> None:
self._panel = self._ensure_panel(w)
self._panel.settings().set("syntax", "Packages/Text/Plain text.tmLanguage")
w.destroy_output_panel(self.name)

def _ensure_panel(self, w: sublime.Window) -> sublime.View:
panel = w.find_output_panel(self.name);
if panel:
return panel
panel = create_output_panel(w, self.name)

if self._file_regex:
panel.settings().set("result_file_regex", self._file_regex)
if self._line_regex:
panel.settings().set("result_line_regex", self._line_regex)
if self._syntax:
panel.assign_syntax(self._syntax)

# All our panels are read-only
panel.set_read_only(True)
return panel


diagnostics_panel = Panel(
"diagnostics",
syntax="Packages/LSP/Syntaxes/Diagnostics.sublime-syntax",
file_regex=PANEL_FILE_REGEX,
line_regex=PANEL_LINE_REGEX
)

reference_panel = Panel(
"references",
syntax="Packages/LSP/Syntaxes/References.sublime-syntax",
file_regex=PANEL_FILE_REGEX,
line_regex=PANEL_LINE_REGEX
)

language_servers_panel = Panel(
"language servers",
syntax="Packages/LSP/Syntaxes/ServerLog.sublime-syntax",
)

rename_panel = Panel(
"rename",
syntax="Packages/LSP/Syntaxes/References.sublime-syntax",
file_regex=PANEL_FILE_REGEX,
line_regex=PANEL_LINE_REGEX
)

lsp_panels = [diagnostics_panel, reference_panel, language_servers_panel, rename_panel]


@contextmanager
Expand All @@ -46,7 +137,7 @@ def mutable(view: sublime.View) -> Generator:
view.set_read_only(True)


def create_output_panel(window: sublime.Window, name: str) -> Optional[sublime.View]:
def create_output_panel(window: sublime.Window, name: str) -> sublime.View:
panel = window.create_output_panel(name)
settings = panel.settings()
for key, value in OUTPUT_PANEL_SETTINGS.items():
Expand All @@ -55,36 +146,8 @@ def create_output_panel(window: sublime.Window, name: str) -> Optional[sublime.V


def destroy_output_panels(window: sublime.Window) -> None:
for field in filter(lambda a: not a.startswith('__'), PanelName.__dict__.keys()):
panel_name = getattr(PanelName, field)
panel = window.find_output_panel(panel_name)
if panel and panel.is_valid():
panel.settings().set("syntax", "Packages/Text/Plain text.tmLanguage")
window.destroy_output_panel(panel_name)


def create_panel(window: sublime.Window, name: str, result_file_regex: str, result_line_regex: str,
syntax: str) -> Optional[sublime.View]:
panel = create_output_panel(window, name)
if not panel:
return None
if result_file_regex:
panel.settings().set("result_file_regex", result_file_regex)
if result_line_regex:
panel.settings().set("result_line_regex", result_line_regex)
panel.assign_syntax(syntax)
# Call create_output_panel a second time after assigning the above
# settings, so that it'll be picked up as a result buffer
# see: Packages/Default/exec.py#L228-L230
panel = window.create_output_panel(name)
# All our panels are read-only
panel.set_read_only(True)
return panel


def ensure_panel(window: sublime.Window, name: str, result_file_regex: str, result_line_regex: str,
syntax: str) -> Optional[sublime.View]:
return window.find_output_panel(name) or create_panel(window, name, result_file_regex, result_line_regex, syntax)
for panel in lsp_panels:
panel.destroy(window)


class LspClearPanelCommand(sublime_plugin.TextCommand):
Expand Down Expand Up @@ -114,24 +177,20 @@ def run(self, edit: sublime.Edit, characters: Optional[str] = "") -> None:
selection.clear()


def ensure_server_panel(window: sublime.Window) -> Optional[sublime.View]:
return ensure_panel(window, PanelName.LanguageServers, "", "", "Packages/LSP/Syntaxes/ServerLog.sublime-syntax")


def update_server_panel(window: sublime.Window, prefix: str, message: str) -> None:
if not window.is_valid():
return
window_id = window.id()
panel = ensure_server_panel(window)
if not panel:
panel_view = language_servers_panel.view(window)
if not panel_view.is_valid():
return
LspUpdateServerPanelCommand.to_be_processed.setdefault(window_id, []).append((prefix, message))
previous_length = len(LspUpdateServerPanelCommand.to_be_processed[window_id])

def condition() -> bool:
if not panel:
if not panel_view:
return False
if not panel.is_valid():
if not panel_view.is_valid():
return False
to_process = LspUpdateServerPanelCommand.to_be_processed.get(window_id)
if to_process is None:
Expand All @@ -144,7 +203,7 @@ def condition() -> bool:
return current_length == previous_length

debounced(
lambda: panel.run_command("lsp_update_server_panel", {"window_id": window_id}) if panel else None,
lambda: panel_view.run_command("lsp_update_server_panel", {"window_id": window_id}) if panel_view else None,
SERVER_PANEL_DEBOUNCE_TIME_MS,
condition
)
Expand Down
3 changes: 0 additions & 3 deletions plugin/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
TCP_CONNECT_TIMEOUT = 5 # seconds
FEATURES_TIMEOUT = 300 # milliseconds

PANEL_FILE_REGEX = r"^(?!\s+\d+:\d+)(.*)(:)$"
PANEL_LINE_REGEX = r"^\s+(\d+):(\d+)"


def basescope2languageid(base_scope: str) -> str:
# This the connection between Language IDs and ST selectors.
Expand Down
17 changes: 8 additions & 9 deletions plugin/core/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from .configurations import WindowConfigManager
from .diagnostics import DiagnosticsCursor
from .diagnostics import DiagnosticsWalker
from .diagnostics import ensure_diagnostics_panel
from .logging import debug
from .logging import exception_log
from .message_request_handler import MessageRequestHandler
from .panels import update_server_panel
from .panels import update_server_panel, diagnostics_panel
from .protocol import Diagnostic
from .protocol import Error
from .protocol import Point
Expand Down Expand Up @@ -440,19 +439,19 @@ def update_diagnostics_panel_async(self) -> None:
set_diagnostics_count(listener.view, self.total_error_count, self.total_warning_count)

def update() -> None:
panel = ensure_diagnostics_panel(self._window)
if not panel or not panel.is_valid():
panel_view = diagnostics_panel.view(self._window)
if not panel_view.is_valid():
return
if isinstance(base_dir, str):
panel.settings().set("result_base_dir", base_dir)
panel_view.settings().set("result_base_dir", base_dir)
else:
panel.settings().erase("result_base_dir")
panel.run_command("lsp_update_panel", {"characters": to_render})
panel_view.settings().erase("result_base_dir")
diagnostics_panel.update(self._window, to_render)
if self._panel_code_phantoms is None:
self._panel_code_phantoms = sublime.PhantomSet(panel, "hrefs")
self._panel_code_phantoms = sublime.PhantomSet(panel_view, "hrefs")
phantoms = [] # type: List[sublime.Phantom]
for row, col, code, href in prephantoms:
point = panel.text_point(row, col)
point = panel_view.text_point(row, col)
region = sublime.Region(point, point)
phantoms.append(sublime.Phantom(region, make_link(href, code), sublime.LAYOUT_INLINE))
self._panel_code_phantoms.update(phantoms)
Expand Down
23 changes: 6 additions & 17 deletions plugin/panels.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
from .core.diagnostics import ensure_diagnostics_panel
from .core.panels import ensure_server_panel
from .core.panels import PanelName
from sublime import Window
from sublime_plugin import WindowCommand
from .core.panels import diagnostics_panel, language_servers_panel
import sublime_plugin


def toggle_output_panel(window: Window, panel_type: str) -> None:
panel_name = "output.{}".format(panel_type)
command = "{}_panel".format("hide" if window.active_panel() == panel_name else "show")
window.run_command(command, {"panel": panel_name})


class LspToggleServerPanelCommand(WindowCommand):
class LspToggleServerPanelCommand(sublime_plugin.WindowCommand):
def run(self) -> None:
ensure_server_panel(self.window)
toggle_output_panel(self.window, PanelName.LanguageServers)
language_servers_panel.toggle(self.window)


class LspShowDiagnosticsPanelCommand(WindowCommand):
class LspShowDiagnosticsPanelCommand(sublime_plugin.WindowCommand):
def run(self) -> None:
ensure_diagnostics_panel(self.window)
toggle_output_panel(self.window, PanelName.Diagnostics)
diagnostics_panel.toggle(self.window)
29 changes: 9 additions & 20 deletions plugin/references.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,20 @@
import sublime
import linecache

from .core.panels import ensure_panel
from .core.panels import reference_panel
from .core.protocol import Request, Point
from .core.registry import get_position
from .core.registry import LspTextCommand
from .core.registry import windows
from .core.settings import PLUGIN_NAME
from .core.settings import userprefs
from .core.types import PANEL_FILE_REGEX, PANEL_LINE_REGEX
from .core.typing import List, Dict, Optional, Tuple, TypedDict
from .core.url import uri_to_filename
from .core.views import get_line, text_document_position_params

ReferenceDict = TypedDict('ReferenceDict', {'uri': str, 'range': dict})


def ensure_references_panel(window: sublime.Window) -> 'Optional[sublime.View]':
return ensure_panel(window, "references", PANEL_FILE_REGEX, PANEL_LINE_REGEX,
"Packages/" + PLUGIN_NAME + "/Syntaxes/References.sublime-syntax")


class LspSymbolReferencesCommand(LspTextCommand):

capability = 'referencesProvider'
Expand Down Expand Up @@ -117,11 +111,11 @@ def open_ref_index(self, index: int, transient: bool = False) -> None:
def show_references_panel(self, references_by_file: Dict[str, List[Tuple[Point, str]]]) -> None:
window = self.view.window()
if window:
panel = ensure_references_panel(window)
if not panel:
panel_view = reference_panel.view(window)
if not panel_view.is_valid():
return

text = ''
text = ""
references_count = 0
for file, references in references_by_file.items():
text += '{}:\n'.format(self.get_relative_path(file))
Expand All @@ -133,19 +127,14 @@ def show_references_panel(self, references_by_file: Dict[str, List[Tuple[Point,
text += '\n'

base_dir = windows.lookup(window).get_project_path(self.view.file_name() or "")
panel.settings().set("result_base_dir", base_dir)
panel_view.settings().set("result_base_dir", base_dir)

panel.run_command("lsp_clear_panel")
window.run_command("show_panel", {"panel": "output.references"})
panel.run_command('append', {
'characters': "{} references for '{}'\n\n{}".format(references_count, self.word, text),
'force': True,
'scroll_to_end': False
})
reference_panel.update(window, "{} references for '{}'\n\n{}".format(references_count, self.word, text))
reference_panel.open(window)

# highlight all word occurrences
regions = panel.find_all(r"\b{}\b".format(self.word))
panel.add_regions('ReferenceHighlight', regions, 'comment', flags=sublime.DRAW_OUTLINED)
regions = panel_view.find_all(r"\b{}\b".format(self.word))
panel_view.add_regions('ReferenceHighlight', regions, 'comment', flags=sublime.DRAW_OUTLINED)

def get_selected_file_path(self, index: int) -> str:
return self.get_full_path(self.reflist[index][0])
Expand Down
Loading

0 comments on commit 2a962e0

Please sign in to comment.