Skip to content

Commit fe832b0

Browse files
Merge pull request #9 from hkupty/add-acid-support
Add initial support for acid
2 parents a8a8402 + 15066bc commit fe832b0

File tree

1 file changed

+152
-0
lines changed
  • rplugin/python3/deoplete/sources

1 file changed

+152
-0
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import uuid
2+
import threading
3+
# Adds a git submodule to the import path
4+
import sys
5+
import os
6+
basedir = os.path.dirname(os.path.realpath(__file__))
7+
sys.path.append(os.path.join(basedir, "vim_nrepl_python_client/"))
8+
sys.path.append(os.path.join(basedir, "../../acid"))
9+
10+
try:
11+
from acid.nvim import localhost, path_to_ns
12+
from acid.session import SessionHandler, send
13+
loaded = True
14+
except:
15+
loaded = False
16+
17+
from .base import Base # NOQA
18+
import nrepl # NOQA
19+
20+
21+
short_types = {
22+
"function": "f",
23+
"macro": "m",
24+
"var": "v",
25+
"special-form": "s",
26+
"class": "c",
27+
"keyword": "k",
28+
"local": "l",
29+
"namespace": "n",
30+
"field": "i",
31+
"method": "f",
32+
"static-field": "i",
33+
"static-method": "f",
34+
"resource": "r"
35+
}
36+
37+
38+
def candidate(val):
39+
arglists = val.get("arglists")
40+
type = val.get("type")
41+
return {
42+
"word": val.get("candidate"),
43+
"kind": short_types.get(type, type),
44+
"info": val.get("doc", ""),
45+
"menu": " ".join(arglists) if arglists else ""
46+
}
47+
48+
49+
def completion_callback(event):
50+
def handlecompletion(msg, wc, key):
51+
pass
52+
return handlecompletion
53+
54+
55+
class Source(Base):
56+
def __init__(self, vim):
57+
Base.__init__(self, vim)
58+
self.name = "acid"
59+
self.mark = "[acid]"
60+
self.filetypes = ['clojure']
61+
self.rank = 200
62+
self.__conns = {}
63+
64+
def on_init(self, context):
65+
if loaded:
66+
self.acid_sessions = SessionHandler()
67+
else:
68+
self.vim.call('echom "Acid.nvim not found. Please install it."')
69+
self.sessions = {}
70+
71+
def get_wc(self, url):
72+
return self.acid_sessions.get_or_create(url)
73+
74+
def get_session(self, url, wc):
75+
if url in self.sessions:
76+
return self.sessions[url]
77+
78+
session_event = threading.Event()
79+
80+
def clone_handler(msg, wc, key):
81+
wc.unwatch(key)
82+
self.sessions[url] = msg['new-session']
83+
session_event.set()
84+
85+
wc.watch('dyn-session', {'new-session': None}, clone_handler)
86+
wc.send({'op': 'clone'})
87+
session_event.wait(0.5)
88+
89+
return self.sessions[url]
90+
91+
def gather_candidates(self, context):
92+
if not loaded:
93+
return []
94+
95+
address = localhost(self.vim)
96+
if address is None:
97+
return []
98+
url = "nrepl://{}:{}".format(*address)
99+
wc = self.get_wc(url)
100+
session = self.get_session(url, wc)
101+
ns = path_to_ns(self.vim)
102+
103+
def global_watch(cmsg, cwc, ckey):
104+
self.debug("Received message for {}".format(url))
105+
self.debug(cmsg)
106+
107+
wc.watch('global_watch', {}, global_watch)
108+
109+
# Should be unique for EVERY message
110+
msgid = uuid.uuid4().hex
111+
112+
# Perform completion
113+
completion_event = threading.Event()
114+
response = None
115+
116+
def completion_callback(cmsg, cwc, ckey):
117+
nonlocal response
118+
response = cmsg
119+
self.debug("Got response {}".format(str(cmsg)))
120+
completion_event.set()
121+
122+
self.debug("Adding completion watch")
123+
watcher_key = "{}-completion".format(msgid),
124+
wc.watch(watcher_key, {"id": msgid}, completion_callback)
125+
126+
# TODO: context for context aware completions
127+
self.debug("Sending completion op")
128+
try:
129+
payload = {"id": msgid,
130+
"op": "complete",
131+
"symbol": context["complete_str"],
132+
"session": session,
133+
"extra-metadata": ["arglists", "doc"],
134+
"ns": ns}
135+
self.debug('Sending payload {}'.format(str(payload)))
136+
wc.send(payload)
137+
except BrokenPipeError:
138+
self.debug("Connection died. Removing the connection.")
139+
wc.close() # Try and cancel the hanging connection
140+
del self.acid_sessions.sessions[url]
141+
142+
self.debug("Waiting for completion")
143+
completion_event.wait(0.5)
144+
self.debug("Completion event is done!")
145+
wc.unwatch(watcher_key)
146+
# Bencode read can return None, e.g. when and empty byte is read
147+
# from connection.
148+
if response:
149+
return [candidate(x) for x in response.get("completions", [])]
150+
151+
self.debug('No answer.')
152+
return []

0 commit comments

Comments
 (0)