-
Notifications
You must be signed in to change notification settings - Fork 4
/
man.py
executable file
·153 lines (123 loc) · 4.3 KB
/
man.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
man.alfredworkflow, v3.0
Robin Breathe, 2013-2023
"""
import json
import os
import re
import subprocess
import sys
from fnmatch import fnmatch
from time import time
import alfred
DEFAULT_MAX_RESULTS = 36
DEFAULT_CACHE_TTL = 604800
WHATIS_COMMAND = '/usr/libexec/makewhatis -o /dev/fd/1 `/usr/bin/manpath`'
def cache_file(filename, volatile=True):
parent = os.path.expanduser(
(
os.getenv('alfred_workflow_data'),
os.getenv('alfred_workflow_cache')
)[bool(volatile)] or os.getenv('TMPDIR')
)
if not os.path.isdir(parent):
os.mkdir(parent)
if not os.access(parent, os.W_OK):
raise IOError('No write access: %s' % parent)
return os.path.join(parent, filename)
def fetch_whatis(max_age=DEFAULT_CACHE_TTL):
cache = cache_file('whatis.1.json')
if os.path.isfile(cache) and (time() - os.path.getmtime(cache) < max_age):
return json.load(open(cache, 'r'))
raw_pages = subprocess.check_output(WHATIS_COMMAND, shell=True).decode('utf-8')
pagelist = map(
lambda x: map(
lambda y: y.strip(),
x.split(' - ', 1)
),
raw_pages.splitlines()
)
whatis = {}
for (pages, description) in pagelist:
for page in pages.split(', '):
whatis[page] = description
json.dump(whatis, open(cache, 'w'))
return whatis
def fetch_sections(whatis, max_age=DEFAULT_CACHE_TTL):
cache = cache_file('sections.1.json')
if os.path.isfile(cache) and (time() - os.path.getmtime(cache) < max_age):
return set(json.load(open(cache, 'r')))
sections = set([])
pattern = re.compile(r'\(([^()]+)\)$')
for page in whatis.keys():
sre = pattern.search(page)
if sre:
sections.add(sre.group(1))
json.dump(list(sections), open(cache, 'w'))
return sections
def man_arg(manpage):
pattern = re.compile(r'(.*)\((.+)\)')
sre = pattern.match(manpage)
(title, section) = (sre.group(1), sre.group(2))
return '%s/%s' % (section, title)
def man_uri(manpage, protocol='x-man-page'):
return '%s://%s' % (protocol, man_arg(manpage))
def filter_whatis_name(_filter, whatis):
return {k: v for (k, v) in whatis.items() if _filter(k)}
def filter_whatis_description(_filter, whatis):
return {k: v for (k, v) in whatis.items() if _filter(v)}
def result_list(query, whatis):
return {
alfred.Item(attributes={'uid': man_uri(page), 'arg': man_arg(page)},
title=page, subtitle=description, icon='icon.png')
for (page, description) in whatis.items()
if fnmatch(page, '%s*' % query)
}
def complete():
query = sys.argv[1].strip()
maxresults = int(os.getenv('alfredman_max_results', DEFAULT_MAX_RESULTS))
cache_ttl = int(os.getenv('alfredman_cache_ttl', DEFAULT_CACHE_TTL))
whatis = fetch_whatis(cache_ttl)
sections = fetch_sections(whatis, cache_ttl)
results = []
if ' ' in query:
# section page
(_section, _title) = query.split()
pattern = re.compile(r'^.+\(%s\)$' % _section)
_whatis = filter_whatis_name(pattern.match, whatis)
results.extend(result_list(_title, _whatis))
else:
# section filtering
if query in sections:
_uri = man_uri('(%s)' % query)
results.append(alfred.Item(
attributes={'uid': _uri, 'arg': _uri, 'valid': 'no'},
title='Open man page',
subtitle='Scope restricted to section %s' % query,
icon='icon.png'
))
# direct hit
if query in whatis:
_arg = man_arg(query)
_uri = man_uri(query)
results.append(alfred.Item(
attributes={'uid': _uri, 'arg': _arg},
title=query,
subtitle=whatis[query],
icon='icon.png'
))
# standard filtering
results.extend(result_list(query, whatis))
# no matches
if not results:
results.append(alfred.Item(
attributes={'uid': 'x-man-page://404', 'valid': 'no'},
title='404 Page Not Found',
subtitle='',
icon='icon.png'
))
return alfred.xml(results, maxresults=maxresults)
if __name__ == '__main__':
print(complete())