1
1
# Copyright (C) 2004, 2005 Aaron Bentley
2
# <aaron@aaronbentley.com>
2
# <aaron.bentley@utoronto.ca>
4
4
# This program is free software; you can redistribute it and/or modify
5
5
# it under the terms of the GNU General Public License as published by
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
from itertools import chain
27
from bzrlib import osutils
28
from bzrlib.branch import Branch
29
from bzrlib.config import config_dir, ensure_config_dir_exists
30
from bzrlib.commands import get_cmd_object, all_command_names, get_alias
23
from itertools import chain
31
24
from bzrlib.errors import BzrError
32
from bzrlib.workingtree import WorkingTree
25
from bzrlib.commands import get_cmd_object, get_all_cmds
37
27
SHELL_BLACKLIST = set(['rm', 'ls'])
38
28
COMPLETION_BLACKLIST = set(['shell'])
41
30
class BlackListedCommand(BzrError):
42
31
def __init__(self, command):
43
32
BzrError.__init__(self, "The command %s is blacklisted for shell use" %
47
35
class CompletionContext(object):
48
36
def __init__(self, text, command=None, prev_opt=None, arg_pos=None):
52
40
self.arg_pos = None
54
42
def get_completions(self):
56
return self.get_completions_or_raise()
61
def get_option_completions(self):
63
command_obj = get_cmd_object(self.command)
66
opts = [o+" " for o in iter_opt_completions(command_obj)]
67
return list(filter_completions(opts, self.text))
69
def get_completions_or_raise(self):
70
if self.command is None:
72
iter = iter_executables(self.text)
74
iter = (c+" " for c in iter_command_names() if
75
c not in COMPLETION_BLACKLIST)
76
return list(filter_completions(iter, self.text))
77
if self.prev_opt is None:
78
completions = self.get_option_completions()
79
if self.command == "cd":
80
iter = iter_dir_completions(self.text)
81
completions.extend(list(filter_completions(iter, self.text)))
83
iter = iter_file_completions(self.text)
84
completions.extend(filter_completions(iter, self.text))
44
iter = (c for c in iter_command_names() if
45
c not in COMPLETION_BLACKLIST)
47
iter = list(filter_completions(iter, text))
88
53
class PromptCmd(cmd.Cmd):
90
54
def __init__(self):
91
55
cmd.Cmd.__init__(self)
92
56
self.prompt = "bzr> "
94
self.tree = WorkingTree.open_containing('.')[0]
58
self.tree = arch.tree_root(".")
99
63
self.identchars += '-'
100
ensure_config_dir_exists()
101
self.history_file = osutils.pathjoin(config_dir(), 'shell-history')
102
whitespace = ''.join(c for c in string.whitespace if c < chr(127))
103
readline.set_completer_delims(whitespace)
64
self.history_file = os.path.expanduser("~/.bazaar/shell-history")
65
readline.set_completer_delims(string.whitespace)
104
66
if os.access(self.history_file, os.R_OK) and \
105
67
os.path.isfile(self.history_file):
106
68
readline.read_history_file(self.history_file)
127
89
def set_prompt(self):
128
90
if self.tree is not None:
130
prompt_data = (self.tree.branch.nick, self.tree.branch.revno(),
131
self.tree.relpath('.'))
132
prompt = " %s:%d/%s" % prompt_data
92
prompt = pylon.alias_or_version(self.tree.tree_version,
95
if prompt is not None:
96
prompt = " " + prompt +":"+ pylon.tree_cwd(self.tree)
139
103
def set_title(self, command=None):
141
b = Branch.open_containing('.')[0]
142
version = "%s:%d" % (b.nick, b.revno())
105
version = pylon.alias_or_version(self.tree.tree_version, self.tree,
144
108
version = "[no version]"
145
109
if command is None:
169
133
self.default("help "+line)
171
135
def default(self, line):
173
args = shlex.split(line)
174
except ValueError, e:
175
print 'Parse error:', e
178
alias_args = get_alias(args[0])
179
if alias_args is not None:
180
args[0] = alias_args.pop(0)
182
137
commandname = args.pop(0)
183
138
for char in ('|', '<', '>'):
184
139
commandname = commandname.split(char)[0]
192
147
return os.system(line)
195
is_qbzr = cmd_obj.__module__.startswith('bzrlib.plugins.qbzr.')
196
if too_complicated(line) or is_qbzr:
150
if too_complicated(line):
197
151
return os.system("bzr "+line)
199
return (cmd_obj.run_argv_aliases(args, alias_args) or 0)
153
return (cmd_obj.run_argv(args) or 0)
200
154
except BzrError, e:
202
156
except KeyboardInterrupt, e:
209
163
def completenames(self, text, line, begidx, endidx):
210
return CompletionContext(text).get_completions()
164
from bzrlib.trace import mutter
166
iter = (c for c in iter_command_names() if
167
c not in COMPLETION_BLACKLIST)
170
arg = line.split()[-1]
173
iter = filter_completions(iter, arg)
212
178
def completedefault(self, text, line, begidx, endidx):
213
179
"""Perform completion for native commands.
215
181
:param text: The text to complete
217
183
:param line: The entire line to complete
224
190
(cmd, args, foo) = self.parseline(line)
227
return CompletionContext(text, command=cmd).get_completions()
230
def run_shell(directory=None):
193
return self.completenames(text, line, begidx, endidx)
197
command_obj = get_cmd_object(cmd)
201
if command_obj is not None:
202
opts = list(iter_opt_completions(command_obj))
203
files = list(iter_file_completions(text))
204
return list(filter_completions(opts+files, text))
207
arg = args.split()[-1]
210
iter = iter_dir_completions(text)
211
iter = filter_completions(iter, text)
214
arg = args.split()[-1]
215
iter = iter_file_completions(arg)
216
return list(iter_munged_completions(iter, arg, text))
218
return self.completenames(text, line, begidx, endidx)
232
if not directory is None:
234
224
prompt = PromptCmd()
239
except KeyboardInterrupt:
242
prompt.write_history()
228
prompt.write_history()
243
229
except StopIteration:
247
232
def iter_opt_completions(command_obj):
248
233
for option_name, option in command_obj.options().items():
249
234
yield "--" + option_name
292
276
return iter_file_completions(arg, True)
295
278
def iter_command_names(hidden=False):
296
for real_cmd_name in all_command_names():
297
cmd_obj = get_cmd_object(real_cmd_name)
298
if not hidden and cmd_obj.hidden:
279
for real_cmd_name, cmd_class in get_all_cmds():
280
if not hidden and cmd_class.hidden:
300
for name in [real_cmd_name] + cmd_obj.aliases:
282
for name in [real_cmd_name] + cmd_class.aliases:
301
283
# Don't complete on aliases that are prefixes of the canonical name
302
284
if name == real_cmd_name or not real_cmd_name.startswith(name):
306
def iter_executables(path):
307
dirname, partial = os.path.split(path)
308
for filename in os.listdir(dirname):
309
if not filename.startswith(partial):
311
fullpath = os.path.join(dirname, filename)
312
mode=os.lstat(fullpath)[stat.ST_MODE]
313
if stat.S_ISREG(mode) and 0111 & mode:
317
287
def filter_completions(iter, arg):
318
288
return (c for c in iter if c.startswith(arg))
321
290
def iter_munged_completions(iter, arg, text):
322
291
for completion in iter:
323
292
completion = str(completion)
324
293
if completion.startswith(arg):
325
294
yield completion[len(arg)-len(text):]+" "
328
296
def too_complicated(line):
297
for char in '|<>"\"*?':