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
|
from types import NoneType
import sys
import os
import re
import plistlib
to_plist = plistlib.writePlistToString
from_plist = plistlib.readPlistFromString
def escape(s):
return re.sub(r"(?=[^a-zA-Z0-9_.\/\-\x7F-\xFF\n])", r'\\', s).replace("\n", "'\n'")
support = os.environ["TM_SUPPORT_PATH"]
dialog = os.path.join(support, 'bin/tm_dialog')
if not sys.version.startswith("2.5"):
def all(it):
return not bool(len([truth for truth in it if truth is False]))
def item(val):
if isinstance(val, str):
return {"title": val}
if isinstance(val, tuple):
return {"title": val[0]}
elif val is None:
return {"separator": 1}
def sh(cmd):
result = ""
pipe = None
try:
pipe = os.popen(cmd)
result = pipe.read()
finally:
if pipe: pipe.close()
return result
def all_are_instance(it, typ):
return all([(isinstance(i, typ)) for i in it])
def menu(options):
""" Accepts a list and causes TextMate to show an inline menu.
If options is a list of strings, will return the selected index.
If options is a list of (key, value) tuples, will return value of the
selected key. Note that we don't use dicts, so that key-value options
can be ordered. If you want to use a dict, try dict.items().
"""
hashed_options = False
if not options:
return None
if all_are_instance(options, (str, NoneType)):
menu = dict(menuItems=[item(val) for val in options])
elif all_are_instance(options, (tuple, NoneType)):
hashed_options = True
menu = dict(menuItems=[item(pair) for pair in options])
plist = to_plist(menu)
cmd = 'bash -c "%s -up %s"' % (escape(dialog), escape(plist))
result = from_plist(sh(cmd))
if not 'selectedIndex' in result:
return None
index = int(result['selectedIndex'])
if hashed_options:
return options[index][1]
return options[index]None
|