-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNakama.py
188 lines (143 loc) · 5.06 KB
/
Nakama.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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# Nakama-sublime
# Autocompletes all of nakama server functions from `require "nakama"`
# Presents documentation of nakama function on hover
import sublime
import sublime_plugin
import re
import urllib.request
import functools
# Popup template for on hover documentation
TEMPLATE = """
<p>Nakama Function</p>
<p><b>{func_name}</b> ({param_types})</p>
<h4>Description:</h4>
<p>{desc}</p>
<h4>Example:</h4>
{example}
"""
CONTEXT_TEMPLATE = """
<p>Nakama Context Var</p>
<p><b>{description}</b></p>
"""
class NakamaCompletionEvent(sublime_plugin.ViewEventListener):
# Setting for the current view
_is_lua = False
has_nakama = False
cur_nakama_var = ""
cur_nakama_line = -1
# Keep count for idle execution
timeout = 0
def handle_timeout(self):
self.timeout = self.timeout - 1
# Keep the loop running
if self.timeout > 0:
sublime.set_timeout_async(self.handle_timeout, 500)
else: self.on_idle()
# Start or reset the timer on document modification
def on_modified_async(self):
if not self.is_lua():
# Not Lua, don't do anything.
return
# If document was changed to Nakama after view focus, search for nakama
if not self._is_lua:
self.find_nakama_var()
self._is_lua = True
# Start idle timer loop if none is running
if self.timeout == 0:
sublime.set_timeout_async(self.handle_timeout, 500)
# Set timer to 1 seconds, 2 ticks of 500ms
self.timeout = 2
# Find Nakama var when idle times out
def on_idle(self):
self.find_nakama_var()
def is_lua(self):
# Some plugins modify scope name, check if 'source.lua' is in the scope name
return 'source.lua' in self.view.scope_name(0)
def get_setting(self, key, default=None):
settings = sublime.load_settings('nakama-completion.sublime-settings')
return settings.get(key, default)
def get_doc_entry(self, key, default=None):
settings = sublime.load_settings('nakama-doc.sublime-settings')
return settings.get(key, default)
def get_context_doc_entry(self, key, default=None):
settings = sublime.load_settings('nakama-context-doc.sublime-settings')
return settings.get(key, default)
def get_nakama_var(self):
return self.cur_nakama_var
def find_nakama_var(self):
var_region = self.view.find(r"""local [^\s]+ = require[\s\(]+['"]nakama['"]""", 0)
if var_region.a == -1:
self.has_nakama = False
return
match = re.search(r"""local ([^\s]+) = require[\s\(]+['"]nakama['"]""", self.view.substr(var_region))
self.cur_nakama_var = match.group(1)
self.cur_nakama_line = self.view.rowcol(var_region.a)[0]
self.has_nakama = True
def check_document(self):
self._is_lua = self.is_lua()
if self._is_lua:
self.find_nakama_var()
else:
self.has_nakama = False
# Search for nakama on load
def on_load_async(self):
self.check_document()
# Search for nakama on view focus
def on_activated_async(self):
self.check_document()
def on_query_completions(self, prefix, locations):
if not self._is_lua or not self.has_nakama:
# Not Lua or nakama present, don't do anything.
return
# Get where the current word begins and ends
word_location = self.view.word(locations[0])
start_location = word_location.a
end_location = word_location.b
# Check if we're autocompleting from a dot
if self.view.substr(sublime.Region(start_location-1, start_location)) != '.':
return
# Get the nakama variable name
nakama_var = self.get_nakama_var()
# Get the word before the dot
class_var = self.view.substr(self.view.word(start_location-2))
if class_var == nakama_var:
return (
self.get_setting('autocomplete'),
sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS
)
elif class_var == "context":
return (
self.get_setting('autocomplete-context')
)
def on_hover(self, point, hover_zone):
if hover_zone != sublime.HOVER_TEXT or not self.has_nakama:
return
# Get start and finish for current hovered word
word_location = self.view.word(point)
start_location = word_location.a
end_location = word_location.b
# Get the entire current hovered word
cur_word = self.view.substr(word_location)
# Check if we're autocompleting from a dot
if self.view.substr(sublime.Region(start_location-1, start_location)) != '.':
return
# Get the word before the dot
class_var = self.view.substr(self.view.word(start_location-2))
# Check for current hovered word in documentation function list
entry = self.get_doc_entry(cur_word, None)
# Get the nakama variable name
nakama_var = self.get_nakama_var()
if class_var == nakama_var:
# Check for current hovered word in documentation function list
entry = self.get_doc_entry(cur_word, None)
if entry is None:
return
self.view.show_popup(TEMPLATE.format(**entry),
sublime.HIDE_ON_MOUSE_MOVE_AWAY, point, *self.view.viewport_extent())
elif class_var == "context":
# Check for current hovered word in documentation context list
entry = self.get_context_doc_entry(cur_word, None)
if entry is None:
return
self.view.show_popup(CONTEXT_TEMPLATE.format(**entry),
sublime.HIDE_ON_MOUSE_MOVE_AWAY, point, *self.view.viewport_extent())