Skip to content

Commit 4eadb63

Browse files
committed
Merge PR #74 'UI prototypes'
2 parents 5a8713a + 135362d commit 4eadb63

File tree

11 files changed

+1397
-5
lines changed

11 files changed

+1397
-5
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
*.egg-info/
2+
__pycache__
3+
neovim/ui/screen.c
4+
neovim/ui/screen.so

neovim/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def attach(session_type, address=None, port=None, path=None, argv=None):
8585
session = (tcp_session(address, port) if session_type == 'tcp' else
8686
socket_session(path) if session_type == 'socket' else
8787
stdio_session() if session_type == 'stdio' else
88-
child_session(argv) if session_type == 'child'else
88+
child_session(argv) if session_type == 'child' else
8989
None)
9090

9191
if not session:

neovim/api/nvim.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,25 @@ def session(self):
8686
"""Return the Session or SessionFilter for a Nvim instance."""
8787
return self._session
8888

89+
def ui_attach(self, width, height, rgb):
90+
"""Register as a remote UI.
91+
92+
After this method is called, the client will receive redraw
93+
notifications.
94+
"""
95+
return self._session.request('ui_attach', width, height, rgb)
96+
97+
def ui_detach(self):
98+
"""Unregister as a remote UI."""
99+
return self._session.request('ui_detach')
100+
101+
def ui_try_resize(self, width, height):
102+
"""Notify nvim that the client window has resized.
103+
104+
If possible, nvim will send a redraw request to resize.
105+
"""
106+
return self._session.request('ui_try_resize', width, height)
107+
89108
def subscribe(self, event):
90109
"""Subscribe to a Nvim event."""
91110
return self._session.request('vim_subscribe', event)

neovim/msgpack_rpc/event_loop/base.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Common code for event loop implementations."""
22
import logging
33
import signal
4+
import threading
45

56

67
logger = logging.getLogger(__name__)
@@ -11,6 +12,7 @@
1112
# which exits the program. To be able to restore the python interpreter to it's
1213
# default state, we keep a reference to the default handler
1314
default_int_handler = signal.getsignal(signal.SIGINT)
15+
main_thread = threading.current_thread()
1416

1517

1618
class BaseEventLoop(object):
@@ -131,12 +133,14 @@ def run(self, data_cb):
131133
self._error = None
132134
raise err
133135
self._on_data = data_cb
134-
self._setup_signals([signal.SIGINT, signal.SIGTERM])
136+
if threading.current_thread() == main_thread:
137+
self._setup_signals([signal.SIGINT, signal.SIGTERM])
135138
debug('Entering event loop')
136139
self._run()
137140
debug('Exited event loop')
138-
self._teardown_signals()
139-
signal.signal(signal.SIGINT, default_int_handler)
141+
if threading.current_thread() == main_thread:
142+
self._teardown_signals()
143+
signal.signal(signal.SIGINT, default_int_handler)
140144
self._on_data = None
141145

142146
def stop(self):

neovim/ui/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Neovim remote UI prototypes."""

neovim/ui/cli.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""CLI for accessing the gtk/tickit UIs implemented by this package."""
2+
import shlex
3+
4+
import click
5+
6+
from .ui_bridge import UIBridge
7+
from .. import attach
8+
9+
10+
@click.command(context_settings=dict(allow_extra_args=True))
11+
@click.option('--prog')
12+
@click.option('--notify', '-n', default=False, is_flag=True)
13+
@click.option('--gui', '-g', default=False, is_flag=True)
14+
@click.option('--listen', '-l')
15+
@click.option('--connect', '-c')
16+
@click.option('--profile',
17+
default='disable',
18+
type=click.Choice(['ncalls', 'tottime', 'percall', 'cumtime',
19+
'name', 'disable']))
20+
@click.pass_context
21+
def main(ctx, prog, notify, gui, listen, connect, profile):
22+
"""Entry point."""
23+
address = connect or listen
24+
25+
if address:
26+
import re
27+
p = re.compile(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?:\:\d{1,5})?$')
28+
29+
if p.match(address):
30+
args = ('tcp',)
31+
kwargs = {'address': address}
32+
else:
33+
args = ('socket',)
34+
kwargs = {'path': address}
35+
36+
if connect:
37+
# connect to existing instance listening on address
38+
nvim = attach(*args, **kwargs)
39+
elif listen:
40+
# spawn detached instance listening on address and connect to it
41+
import os
42+
import time
43+
from subprocess import Popen
44+
os.environ['NVIM_LISTEN_ADDRESS'] = address
45+
nvim_argv = shlex.split(prog or 'nvim -T abstract_ui') + ctx.args
46+
# spawn the nvim with stdio redirected to /dev/null.
47+
dnull = open(os.devnull)
48+
p = Popen(nvim_argv, stdin=dnull, stdout=dnull, stderr=dnull)
49+
dnull.close()
50+
while p.poll() or p.returncode is None:
51+
try:
52+
nvim = attach(*args, **kwargs)
53+
break
54+
except IOError:
55+
# socket not ready yet
56+
time.sleep(0.050)
57+
else:
58+
# spawn embedded instance
59+
nvim_argv = shlex.split(prog or 'nvim --embed') + ctx.args
60+
nvim = attach('child', argv=nvim_argv)
61+
62+
if gui:
63+
from .gtk_ui import GtkUI
64+
ui = GtkUI()
65+
else:
66+
from .tickit_ui import TickitUI
67+
ui = TickitUI()
68+
bridge = UIBridge()
69+
bridge.connect(nvim, ui, profile if profile != 'disable' else None, notify)
70+
71+
72+
if __name__ == '__main__':
73+
main()

0 commit comments

Comments
 (0)