forked from Swoffa/SublimeKickAssemblerC64
-
Notifications
You must be signed in to change notification settings - Fork 0
/
KickassTooltips.py
172 lines (135 loc) · 5.44 KB
/
KickassTooltips.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
"""
Sublime Text plugin for KickAssembler development for displaying information
about certain addresses (VIC/SID registers for example)
"""
import json
import logging
import os
import sublime
import sublime_plugin
TOOLTIP = """<style>%(css)s</style>
<b><u>%(title)s</u></b><br>
<b>%(name)s</b><br>
%(desc)s"""
NUMBER_TOOLTIP = """<style>{css}</style>
<b>${value:02X}</b><br>
<b>%{value:08b}</b><br>
<b>{value}</b><br>"""
def setup_logging(level):
"""Set up logger level"""
level_map = {'debug': logging.DEBUG,
'info': logging.INFO,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL}
logging.basicConfig(format='%(levelname)s: %(message)s')
log = logging.getLogger()
# set level on previously created root logger, otherwise calling
# basicConfig again with new level will have no effect.
log.setLevel(level_map.get(level, logging.INFO))
class KickAssTooltip:
"""
Name space/utility class for reading settings/definitions
"""
help_map = {}
css_file = ''
scopes = []
def __init__(self):
self.log_level = 'info'
self.settings = None
self.help_directories = []
self._register_settings()
def _register_settings(self):
"""
Set the settings object and register callback for settings/plugin
changes.
"""
self.settings = sublime.load_settings("KickassTooltips.sublime-settings")
self.settings.add_on_change('reload', self.load)
def load(self):
"""Load settings and refresh cache table (help_map)"""
self.log_level = self.settings.get('log_level')
setup_logging(self.log_level)
plug_path = sublime.packages_path()
default_css = os.path.join(plug_path, 'SublimeKickAssemblerC64/css/default.css')
KickAssTooltip.css_file = self.settings.get('css_file', default_css)
KickAssTooltip.scopes = self.settings.get('scopes', [])
self.help_directories = self.settings.get('help_directories', [])
self._load_definition()
def _load_definition(self):
"""
Read definition from json files and place them in class variable
help_map
"""
for dirname in self.help_directories:
if not os.path.isabs(dirname):
dirname = os.path.join(sublime.packages_path(), dirname)
for fname in os.listdir(dirname):
logging.debug('Loading %s', fname)
try:
with open(os.path.join(dirname, fname),
encoding='utf8') as fileobject:
try:
data = json.load(fileobject)
except ValueError as exc:
logging.error('Error in JSON file: %s, %s',
fname, exc.message)
continue
KickAssTooltip.help_map.update(data)
except EnvironmentError:
logging.error('Cannot access file: %s', fname)
logging.debug('Help map:\n%s', KickAssTooltip.help_map)
class KickassTooltipsCommand(sublime_plugin.ViewEventListener):
"""
Event listener class for specific view
"""
def on_hover(self, point, hover_zone):
"""
Mouse over text object. Check, if there is appropriate data to be
displayed about the object.
"""
if hover_zone != sublime.HOVER_TEXT:
return
selection = self.view.scope_name(self.view.sel()[0].begin())
if KickAssTooltip.scopes[0] not in selection:
return
text = self.view.substr(self.view.word(point))
logging.debug('Text under mouse pointer: %s', text)
if text.lower() in KickAssTooltip.help_map:
help_message = KickAssTooltip.help_map[text.lower()]
logging.debug('Help message: %s', help_message)
html_message = TOOLTIP % {'css': KickAssTooltip.css_file,
'title': text,
'name': help_message['name'],
'desc': help_message['descr']}
self.show_tooltip(html_message, point)
return
val = None
if "constant.numeric.hex" in selection:
val = int(text, 16)
if "constant.numeric.bin" in selection:
val = int(text, 2)
if "constant.numeric.decimal" in selection:
val = int(text)
if val is not None:
self.show_numeric_tooltip(val, point)
def show_numeric_tooltip(self, val, point):
html_message = NUMBER_TOOLTIP.format(css=KickAssTooltip.css_file,
value=val)
self.show_tooltip(html_message, point)
def show_tooltip(self, html_message, point):
logging.debug('HTML tooltip:\n%s', html_message)
self.view.show_popup(''.join(html_message),
flags=sublime.HIDE_ON_MOUSE_MOVE_AWAY,
location=point,
max_width=600,
on_navigate=self.on_navigate)
def on_navigate(self):
"""Hide popup on click/escape"""
self.view.hide_popup()
logging.debug('on_navigate')
def plugin_loaded():
"""Plugin entry point"""
tooltip = KickAssTooltip()
tooltip.load()
logging.info('KickAssTooltips loaded.')