forked from dahlia/iterfzf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
__init__.py
137 lines (131 loc) · 3.85 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
from __future__ import print_function
import errno
from os import fspath, PathLike
from pathlib import Path
import subprocess
import sys
from typing import AnyStr, Iterable, Literal, Optional
__all__ = '__fzf_version__', '__version__', 'BUNDLED_EXECUTABLE', 'iterfzf'
__fzf_version__ = '0.44.0'
__version__ = '1.1.' + __fzf_version__
POSIX_EXECUTABLE_NAME: Literal['fzf'] = 'fzf'
WINDOWS_EXECUTABLE_NAME: Literal['fzf.exe'] = 'fzf.exe'
EXECUTABLE_NAME: Literal['fzf', 'fzf.exe'] = \
WINDOWS_EXECUTABLE_NAME \
if sys.platform == 'win32' \
else POSIX_EXECUTABLE_NAME
BUNDLED_EXECUTABLE: Optional[Path] = \
Path(__file__).parent / EXECUTABLE_NAME
def iterfzf(
iterable: Iterable[AnyStr],
*,
# Search mode:
extended: bool = True,
exact: bool = False,
case_sensitive: bool = None,
# Interface:
multi: bool = False,
mouse: bool = True,
print_query: bool = False,
# Layout:
prompt: str = '> ',
ansi: bool = False,
preview: Optional[str] = None,
# Misc:
query: str = '',
cycle: bool = False,
__extra__: Iterable[str] = (),
encoding: Optional[str] = None,
executable: PathLike = BUNDLED_EXECUTABLE or EXECUTABLE_NAME
):
cmd = [fspath(executable), '--no-sort', '--prompt=' + prompt]
if not extended:
cmd.append('--no-extended')
if case_sensitive is not None:
cmd.append('+i' if case_sensitive else '-i')
if exact:
cmd.append('--exact')
if multi:
cmd.append('--multi')
if not mouse:
cmd.append('--no-mouse')
if print_query:
cmd.append('--print-query')
if query:
cmd.append('--query=' + query)
if preview:
cmd.append('--preview=' + preview)
if ansi:
cmd.append('--ansi')
if cycle:
cmd.append('--cycle')
if __extra__:
cmd.extend(__extra__)
encoding = encoding or sys.getdefaultencoding()
proc = None
stdin = None
byte = None
lf = u'\n'
cr = u'\r'
for line in iterable:
if byte is None:
byte = isinstance(line, bytes)
if byte:
lf = b'\n'
cr = b'\r'
elif isinstance(line, bytes) is not byte:
raise ValueError(
'element values must be all byte strings or all '
'unicode strings, not mixed of them: ' + repr(line)
)
if lf in line or cr in line:
raise ValueError(
r"element values must not contain CR({1!r})/"
r"LF({2!r}): {0!r}".format(line, cr, lf)
)
if proc is None:
proc = subprocess.Popen(
cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=None
)
stdin = proc.stdin
if not byte:
line = line.encode(encoding)
try:
stdin.write(line + b'\n')
stdin.flush()
except IOError as e:
if e.errno != errno.EPIPE and errno.EPIPE != 32:
raise
break
try:
stdin.close()
except IOError as e:
if e.errno != errno.EPIPE and errno.EPIPE != 32:
raise
if proc is None or proc.wait() not in [0, 1]:
if print_query:
return None, None
else:
return None
stdout = proc.stdout
decode = (lambda b: b) if byte else (lambda t: t.decode(encoding))
output = [decode(ln.strip(b'\r\n\0')) for ln in iter(stdout.readline, b'')]
if print_query:
try:
if multi:
return output[0], output[1:]
else:
return output[0], output[1]
except IndexError:
return output[0], None
else:
if multi:
return output
else:
try:
return output[0]
except IndexError:
return None