Skip to content

Commit

Permalink
Uses css to display linting messages on hover for DamnWidget#862
Browse files Browse the repository at this point in the history
    * Created new files: templates/tooltops/error_warning.tpl and templates/tooltips/error_warning_helper.tpl
    * Created new Class TooltipHelper in anaconda_lib/tooltips.py
    * Created new function get_specific_lineo_msgs in anaconda_lib/linting/sublime.py
    * Modified css/popup.css to add linting message color codes.
    * Modified Tooltip.show_tooltip in anaconda_lib/tooltips.py to add optional **kwargs for popup
    * Cleaned up listeners/linting.py, added css viewing using tooltips.py
  • Loading branch information
Kyu committed May 28, 2020
1 parent 1f28d53 commit e31b2fa
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 29 deletions.
29 changes: 29 additions & 0 deletions anaconda_lib/linting/sublime.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,35 @@ def get_lineno_msgs(view, lineno):
return errors_msg


def get_specific_lineno_msgs(view, lineno):
"""Get lineno error messages and return them by message type
"""

ERRORS = ANACONDA.get('ERRORS')
WARNINGS = ANACONDA.get('WARNINGS')
VIOLATIONS = ANACONDA.get('VIOLATIONS')

specific_errors_msg = {}

if lineno is not None:
def check_and_delete_if_empty(dct: dict, key: str):
if not dct.get(key):
del dct[key]

vid = view.id()
if vid in ERRORS:
specific_errors_msg['ERRORS'] = ERRORS[vid].get(lineno, [])
check_and_delete_if_empty(specific_errors_msg, 'ERRORS')
if vid in WARNINGS:
specific_errors_msg['WARNINGS'] = WARNINGS[vid].get(lineno, [])
check_and_delete_if_empty(specific_errors_msg, 'WARNINGS')
if vid in VIOLATIONS:
specific_errors_msg['VIOLATIONS'] = VIOLATIONS[vid].get(lineno, [])
check_and_delete_if_empty(specific_errors_msg, 'VIOLATIONS')

return specific_errors_msg


def run_linter(view=None, hook=None):
"""Run the linter for the given view
"""
Expand Down
47 changes: 44 additions & 3 deletions anaconda_lib/tooltips.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def __init__(self, theme: str) -> None:
self._load_tooltips()
Tooltip.loaded = True

def show_tooltip(self, view: sublime.View, tooltip: str, content: Dict[str, str], fallback: Callable) -> None: # noqa
def show_tooltip(self, view: sublime.View, tooltip: str, content: Dict[str, str], fallback: Callable, **kwargs: dict) -> None: # noqa
"""Generates and display a tooltip or pass execution to fallback
"""

Expand All @@ -42,14 +42,15 @@ def show_tooltip(self, view: sublime.View, tooltip: str, content: Dict[str, str]
return fallback()

width = get_settings(view, 'font_size', 8) * 75
kwargs = {'location': -1, 'max_width': width if width < 900 else 900}
popup_kwargs = {'location': kwargs.get('location', -1),
'max_width': kwargs.get('max_width', width if width < 900 else 900)}
if st_ver >= 3071:
kwargs['flags'] = sublime.COOPERATE_WITH_AUTO_COMPLETE
text = self._generate(tooltip, content)
if text is None:
return fallback()

return view.show_popup(text, **kwargs)
return view.show_popup(text, **popup_kwargs)

def _generate(self, tooltip: str, content: Dict[str, str]) -> Union[Dict[str, str], None]: # noqa
"""Generate a tooltip with the given text
Expand Down Expand Up @@ -114,3 +115,43 @@ def _load_css(self, css_file: str) -> str:
self.themes[theme_name] = resource.read()

return theme_name


class TooltipHelper(Tooltip):
loaded = False
themes = {} # type: Dict[str, bytes]
tooltips = {} # type: Dict[str, str]

def __init__(self, theme: str) -> None:
self.theme = theme

if int(sublime.version()) < 3070:
return

if TooltipHelper.loaded is False:
self._load_css_themes()
self._load_tooltips()
TooltipHelper.loaded = True

def _load_tooltips(self) -> None:
"""Load tooltips templates from anaconda tooltips templates
"""

template_files_pattern = os.path.join(
os.path.dirname(__file__), os.pardir,
'templates', 'tooltips', '*.tpl')
for template_file in glob.glob(template_files_pattern):
with open(template_file, 'r', encoding='utf8') as tplfile:
tplname = os.path.basename(template_file).split('.tpl')[0]
self.tooltips[tplname] = Template(tplfile.read())

def generate_no_css(self, tooltip: str, content: Dict[str, str]) -> Union[Dict[str, str], None]:
try:
data = self.tooltips[tooltip].safe_substitute(content)
return data
except KeyError as err:
logging.error(
'while generating tooltip without css: tooltip {} don\'t exists'.format(
str(err))
)
return None
12 changes: 12 additions & 0 deletions css/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,15 @@ div.anaconda {
font-weight: bold;
font-size: 1.05em;
}

.anaconda .error_warning .errors {
color: red;
}

.anaconda .error_warning .warnings {
color: orange;
}

.anaconda .error_warning .violations {
color: blue;
}
55 changes: 29 additions & 26 deletions listeners/linting.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import sublime
import sublime_plugin

from ..anaconda_lib.tooltips import Tooltip, TooltipHelper
from ..anaconda_lib._typing import Callable, Dict, Any
from ..anaconda_lib.helpers import (
check_linting, get_settings, check_linting_behaviour,
Expand All @@ -15,7 +16,7 @@
from ..anaconda_lib.linting.sublime import (
ANACONDA, erase_lint_marks, run_linter,
last_selected_lineno, update_statusbar,
get_lineno_msgs
get_specific_lineno_msgs
)


Expand Down Expand Up @@ -154,28 +155,30 @@ def _erase_marks(self, view: sublime.View) -> None:

erase_lint_marks(view)

def on_hover(self, view: sublime.View, point: int, hover_zone: int):
# Planned to make my own listener class(sublime_plugin.ViewEventListener) for this function
# but couldn't figure out how to register them
# Tell me if I need to move this, or if it can piggyback under this listener

# from anaconda_lib.tooltips:show_tooltips
st_ver = int(sublime.version())
if st_ver < 3070:
return

if hover_zone == sublime.HOVER_TEXT:
if get_settings(view, 'anaconda_linter_hover_message', False):
rowcol = view.rowcol(point)
line = rowcol[0] # tuple (lineno, col)
messages = get_lineno_msgs(view, line)

if messages:
# Not sure how to properly choose the height & width values, but this works fine on my laptop
# Also unsure as to how to format it so its pretty and colorful (Tooltip._generate ?)
max_width = len(messages) * 840
max_height = len(max(messages))
message = "\n".join(messages)
# Newline is not rendered , errors all on one line :( help
view.show_popup(message, location=point, max_width=max_width, max_height=max_height)
# amount of time of popup?
def on_hover(self, view: sublime.View, point: int, hover_zone: int) -> None:
"""Called when user hovers cursor above a line
"""
if hover_zone == sublime.HOVER_TEXT and get_settings(view, 'anaconda_linter_hover_message', False):
rowcol = view.rowcol(point)
line = rowcol[0] # tuple (lineno, col)
messages_with_type = get_specific_lineno_msgs(view, line)

if messages_with_type:
css = get_settings(view, 'anaconda_tooltip_theme', 'popup')
main_tooltip = Tooltip(css)
tooltip_helper = TooltipHelper(css)
helper_content = []

for key in messages_with_type.keys():
for msg in messages_with_type.get(key):
tooltip_data = {'level': key.lower(), 'messages': msg}
helper_content.append(tooltip_helper.generate_no_css('error_warning_helper', tooltip_data))

def do_nothing():
return

messages = "<br>".join(helper_content)
tooltip_name = 'error_warning'
main_content = {'helper_content': messages}
kwargs = {'location': point}
main_tooltip.show_tooltip(view, tooltip_name, main_content, do_nothing, **kwargs)
5 changes: 5 additions & 0 deletions templates/tooltips/error_warning.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="anaconda">
<div class="error_warning">
${helper_content}
</div>
</div>
1 change: 1 addition & 0 deletions templates/tooltips/error_warning_helper.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<pre class="${level}">${messages}</pre>

0 comments on commit e31b2fa

Please sign in to comment.