|
1
|
|
|
"""CLI for accessing the gtk/tickit UIs implemented by this package.""" |
|
2
|
|
|
import os |
|
3
|
|
|
import resource |
|
4
|
|
|
import sys |
|
5
|
|
|
import shlex |
|
6
|
|
|
|
|
7
|
|
|
import click |
|
|
|
|
|
|
8
|
|
|
import yaml |
|
|
|
|
|
|
9
|
|
|
|
|
10
|
|
|
from .ui_bridge import UIBridge |
|
11
|
|
|
from neovim import attach |
|
|
|
|
|
|
12
|
|
|
from neovim.compat import IS_PYTHON3 |
|
|
|
|
|
|
13
|
|
|
|
|
14
|
|
|
|
|
15
|
|
|
CONFIG_FILES = ( |
|
16
|
|
|
'.pynvim.yaml', |
|
17
|
|
|
'~/.pynvim.yaml', |
|
18
|
|
|
'~/.config/pynvim/config.yaml' |
|
19
|
|
|
) |
|
20
|
|
|
|
|
21
|
|
|
|
|
22
|
|
|
def load_config(config_file): |
|
23
|
|
|
"""Load config values from yaml.""" |
|
24
|
|
|
|
|
25
|
|
|
if config_file: |
|
26
|
|
|
with open(config_file) as f: |
|
27
|
|
|
return yaml.load(f) |
|
28
|
|
|
|
|
29
|
|
|
else: |
|
30
|
|
|
for config_file in CONFIG_FILES: |
|
31
|
|
|
try: |
|
32
|
|
|
with open(os.path.expanduser(config_file)) as f: |
|
33
|
|
|
return yaml.load(f) |
|
34
|
|
|
|
|
35
|
|
|
except IOError: |
|
|
|
|
|
|
36
|
|
|
pass |
|
37
|
|
|
|
|
38
|
|
|
return {} |
|
39
|
|
|
|
|
40
|
|
|
|
|
41
|
|
|
# http://code.activestate.com/recipes/278731-creating-a-daemon-the-python-way/ |
|
42
|
|
|
def detach_proc(workdir='.', umask=0): |
|
43
|
|
|
"""Detach a process from the controlling terminal and run it in the |
|
44
|
|
|
background as a daemon. |
|
45
|
|
|
""" |
|
46
|
|
|
|
|
47
|
|
|
# Default maximum for the number of available file descriptors. |
|
48
|
|
|
MAXFD = 1024 |
|
49
|
|
|
|
|
50
|
|
|
# The standard I/O file descriptors are redirected to /dev/null by default. |
|
51
|
|
|
if (hasattr(os, "devnull")): |
|
|
|
|
|
|
52
|
|
|
REDIRECT_TO = os.devnull |
|
53
|
|
|
else: |
|
54
|
|
|
REDIRECT_TO = "/dev/null" |
|
55
|
|
|
|
|
56
|
|
|
pid = os.fork() |
|
57
|
|
|
if (pid == 0): |
|
|
|
|
|
|
58
|
|
|
os.setsid() |
|
59
|
|
|
|
|
60
|
|
|
pid = os.fork() |
|
61
|
|
|
if (pid == 0): |
|
|
|
|
|
|
62
|
|
|
os.chdir(workdir) |
|
63
|
|
|
os.umask(umask) |
|
64
|
|
|
else: |
|
65
|
|
|
os._exit(0) |
|
|
|
|
|
|
66
|
|
|
else: |
|
67
|
|
|
os._exit(0) |
|
|
|
|
|
|
68
|
|
|
|
|
69
|
|
|
maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] |
|
70
|
|
|
if (maxfd == resource.RLIM_INFINITY): |
|
|
|
|
|
|
71
|
|
|
maxfd = MAXFD |
|
72
|
|
|
|
|
73
|
|
|
# Iterate through and close all file descriptors. |
|
74
|
|
|
for fd in range(0, maxfd): |
|
75
|
|
|
try: |
|
76
|
|
|
os.close(fd) |
|
77
|
|
|
except OSError: |
|
|
|
|
|
|
78
|
|
|
pass |
|
79
|
|
|
|
|
80
|
|
|
os.open(REDIRECT_TO, os.O_RDWR) |
|
81
|
|
|
|
|
82
|
|
|
os.dup2(0, 1) |
|
83
|
|
|
os.dup2(0, 2) |
|
84
|
|
|
|
|
85
|
|
|
return(0) |
|
|
|
|
|
|
86
|
|
|
|
|
87
|
|
|
|
|
88
|
|
|
@click.command(context_settings=dict(allow_extra_args=True)) |
|
89
|
|
|
@click.option('--prog') |
|
90
|
|
|
@click.option('--notify', '-n', default=False, is_flag=True) |
|
91
|
|
|
@click.option('--listen', '-l') |
|
92
|
|
|
@click.option('--connect', '-c') |
|
93
|
|
|
@click.option('--profile', |
|
94
|
|
|
default='disable', |
|
95
|
|
|
type=click.Choice(['ncalls', 'tottime', 'percall', 'cumtime', |
|
96
|
|
|
'name', 'disable'])) |
|
97
|
|
|
@click.option('config_file', '--config', type=click.Path(exists=True)) |
|
98
|
|
|
@click.option('--detach/--no-detach', default=True, is_flag=True) |
|
99
|
|
|
@click.pass_context |
|
100
|
|
|
def main(ctx, prog, notify, listen, connect, profile, config_file, detach): |
|
101
|
|
|
"""Entry point.""" |
|
102
|
|
|
|
|
103
|
|
|
if detach: |
|
104
|
|
|
exit_code = detach_proc() |
|
105
|
|
|
|
|
106
|
|
|
address = connect or listen |
|
107
|
|
|
|
|
108
|
|
|
if address: |
|
109
|
|
|
import re |
|
110
|
|
|
p = re.compile(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?:\:\d{1,5})?$') |
|
111
|
|
|
|
|
112
|
|
|
if p.match(address): |
|
113
|
|
|
args = ('tcp',) |
|
114
|
|
|
kwargs = {'address': address} |
|
115
|
|
|
else: |
|
116
|
|
|
args = ('socket',) |
|
117
|
|
|
kwargs = {'path': address} |
|
118
|
|
|
|
|
119
|
|
|
if connect: |
|
120
|
|
|
# connect to existing instance listening on address |
|
121
|
|
|
nvim = attach(*args, **kwargs) |
|
122
|
|
|
elif listen: |
|
123
|
|
|
# spawn detached instance listening on address and connect to it |
|
124
|
|
|
import os |
|
|
|
|
|
|
125
|
|
|
import time |
|
126
|
|
|
from subprocess import Popen |
|
127
|
|
|
os.environ['NVIM_LISTEN_ADDRESS'] = address |
|
128
|
|
|
nvim_argv = shlex.split(prog or 'nvim --headless') + ctx.args |
|
129
|
|
|
# spawn the nvim with stdio redirected to /dev/null. |
|
130
|
|
|
dnull = open(os.devnull) |
|
131
|
|
|
p = Popen(nvim_argv, stdin=dnull, stdout=dnull, stderr=dnull) |
|
132
|
|
|
dnull.close() |
|
133
|
|
|
while p.poll() or p.returncode is None: |
|
134
|
|
|
try: |
|
135
|
|
|
nvim = attach(*args, **kwargs) |
|
136
|
|
|
break |
|
137
|
|
|
except IOError: |
|
138
|
|
|
# socket not ready yet |
|
139
|
|
|
time.sleep(0.050) |
|
140
|
|
|
else: |
|
141
|
|
|
# spawn embedded instance |
|
142
|
|
|
nvim_argv = shlex.split(prog or 'nvim --embed') + ctx.args |
|
143
|
|
|
nvim = attach('child', argv=nvim_argv) |
|
144
|
|
|
|
|
145
|
|
|
from .gtk_ui import GtkUI |
|
146
|
|
|
config = load_config(config_file) |
|
147
|
|
|
ui = GtkUI(config) |
|
148
|
|
|
bridge = UIBridge() |
|
149
|
|
|
bridge.connect(nvim, ui, profile if profile != 'disable' else None, notify) |
|
150
|
|
|
|
|
151
|
|
|
if detach: |
|
152
|
|
|
sys.exit(exit_code) |
|
153
|
|
|
|
|
154
|
|
|
|
|
155
|
|
|
if __name__ == '__main__': |
|
156
|
|
|
main() |
|
|
|
|
|
|
157
|
|
|
|
This can be caused by one of the following:
1. Missing Dependencies
This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.
2. Missing __init__.py files
This error could also result from missing
__init__.pyfiles in your module folders. Make sure that you place one file in each sub-folder.