vim-fireplace/python/nrepl_fireplace.py

127 lines
3.1 KiB
Python

import os
import re
import select
import socket
import sys
from StringIO import StringIO
def noop():
pass
def vim_encode(data):
if isinstance(data, list):
return "[" + ",".join([vim_encode(x) for x in data]) + "]"
elif isinstance(data, dict):
return "{" + ",".join([vim_encode(x)+":"+vim_encode(y) for x,y in data.items()]) + "}"
elif isinstance(data, str):
str_list = []
for c in data:
if (000 <= ord(c) and ord(c) <= 037) or c == '"' or c == "\\":
str_list.append("\\%03o" % ord(c))
else:
str_list.append(c)
return '"' + ''.join(str_list) + '"'
elif isinstance(data, int):
return str(data)
else:
raise TypeError("can't encode a " + type(data).__name__)
def bdecode(f, char=None):
if char == None:
char = f.read(1)
if char == 'l':
l = []
while True:
char = f.read(1)
if char == 'e':
return l
l.append(bdecode(f, char))
elif char == 'd':
d = {}
while True:
char = f.read(1)
if char == 'e':
return d
key = bdecode(f, char)
d[key] = bdecode(f)
elif char == 'i':
i = 0
while True:
char = f.read(1)
if char == 'e':
return i
i = 10 * i + int(char)
elif char.isdigit():
i = int(char)
while True:
char = f.read(1)
if char == ':':
return f.read(i)
i = 10 * i + int(char)
elif char == '':
raise EOFError("unexpected end of bencode data")
else:
raise TypeError("unexpected type "+char+"in bencode data")
class Connection:
def __init__(self, host, port, custom_poll=noop, keepalive_file=None):
self.custom_poll = custom_poll
self.keepalive_file = keepalive_file
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(8)
s.connect((host, int(port)))
s.setblocking(1)
self.socket = s
def poll(self):
self.custom_poll()
if self.keepalive_file and not os.path.exists(self.keepalive_file):
exit(0)
def close(self):
return self.socket.close()
def send(self, payload):
self.socket.sendall(payload)
return ''
def receive(self, char=None):
while len(select.select([self.socket], [], [], 0.1)[0]) == 0:
self.poll()
f = self.socket.makefile()
try:
return bdecode(f)
finally:
f.close()
def call(self, payload, terminators, selectors):
self.send(payload)
responses = []
while True:
response = self.receive()
for key in selectors:
if response[key] != selectors[key]:
continue
responses.append(response)
if 'status' in response and set(terminators) & set(response['status']):
return responses
def dispatch(host, port, poll, keepalive, command, *args):
conn = Connection(host, port, poll, keepalive)
try:
return getattr(conn, command)(*args)
finally:
conn.close()
def main(host, port, keepalive, command, *args):
try:
sys.stdout.write(vim_encode(dispatch(host, port, noop, keepalive, command, *[bdecode(StringIO(arg)) for arg in args])))
except Exception, e:
print(e)
exit(1)
if __name__ == "__main__":
main(*sys.argv[1:])