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__.py
files in your module folders. Make sure that you place one file in each sub-folder.