Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Anaconda.sublime-settings
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,11 @@
*/
"anaconda_linter_phantoms_template": "default",

/*
This determines whether error messages are show when hovering over a line.
*/
"anaconda_linter_hover_message": false,

/*
If anaconda_linter_show_errors_on_save is set to true, anaconda
will show a list of errors when you save the file.
Expand Down
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;
}
32 changes: 31 additions & 1 deletion listeners/linting.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
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,
ONLY_CODE, NOT_SCRATCH, LINTING_ENABLED, is_code
)
from ..anaconda_lib.linting.sublime import (
ANACONDA, erase_lint_marks, run_linter,
last_selected_lineno, update_statusbar
last_selected_lineno, update_statusbar,
get_specific_lineno_msgs
)


Expand Down Expand Up @@ -152,3 +154,31 @@ def _erase_marks(self, view: sublime.View) -> None:
"""

erase_lint_marks(view)

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>