~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to shell.py

  • Committer: Aaron Bentley
  • Date: 2006-03-18 23:29:32 UTC
  • Revision ID: aaron.bentley@utoronto.ca-20060318232932-4981a8efa6e028c9
Fixed patch on checkouts

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
import terminal
21
21
import readline
22
22
import string
 
23
from itertools import chain
23
24
from bzrlib.errors import BzrError
24
 
from bzrlib.commands import get_cmd_object
 
25
from bzrlib.commands import get_cmd_object, get_all_cmds, get_alias
 
26
from bzrlib.branch import Branch
 
27
 
 
28
SHELL_BLACKLIST = set(['rm', 'ls'])
 
29
COMPLETION_BLACKLIST = set(['shell'])
 
30
 
 
31
class BlackListedCommand(BzrError):
 
32
    def __init__(self, command):
 
33
        BzrError.__init__(self, "The command %s is blacklisted for shell use" %
 
34
                          command)
 
35
 
 
36
class CompletionContext(object):
 
37
    def __init__(self, text, command=None, prev_opt=None, arg_pos=None):
 
38
        self.text = text
 
39
        self.command = command
 
40
        self.prev_opt = prev_opt
 
41
        self.arg_pos = None
 
42
 
 
43
    def get_completions(self):
 
44
        try:
 
45
            return self.get_completions_or_raise()
 
46
        except Exception, e:
 
47
            print e, type(e)
 
48
            return []
 
49
 
 
50
    def get_option_completions(self):
 
51
        try:
 
52
            command_obj = get_cmd_object(self.command)
 
53
        except BzrError:
 
54
            return []
 
55
        opts = [o+" " for o in iter_opt_completions(command_obj)]
 
56
        return list(filter_completions(opts, self.text))
 
57
 
 
58
    def get_completions_or_raise(self):
 
59
        if self.command is None:
 
60
            iter = (c+" " for c in iter_command_names() if
 
61
                    c not in COMPLETION_BLACKLIST)
 
62
            return list(filter_completions(iter, self.text))
 
63
        if self.prev_opt is None:
 
64
            completions = self.get_option_completions()
 
65
            if self.command == "cd":
 
66
                iter = iter_dir_completions(self.text)
 
67
                completions.extend(list(filter_completions(iter, self.text)))
 
68
            else:
 
69
                iter = iter_file_completions(self.text)
 
70
                completions.extend([f+" " for f in 
 
71
                                    filter_completions(iter, self.text)])
 
72
            return completions 
 
73
 
25
74
 
26
75
class PromptCmd(cmd.Cmd):
27
76
    def __init__(self):
28
77
        cmd.Cmd.__init__(self)
29
78
        self.prompt = "bzr> "
30
79
        try:
31
 
            self.tree = arch.tree_root(".")
 
80
            self.tree = WorkingTree.open_containing('.')[0]
32
81
        except:
33
82
            self.tree = None
34
83
        self.set_title()
46
95
 
47
96
    def do_quit(self, args):
48
97
        self.write_history()
49
 
        sys.exit(0)
 
98
        raise StopIteration
50
99
 
51
100
    def do_exit(self, args):
52
101
        self.do_quit(args)
62
111
    def set_prompt(self):
63
112
        if self.tree is not None:
64
113
            try:
65
 
                prompt = pylon.alias_or_version(self.tree.tree_version, 
66
 
                                                self.tree, 
67
 
                                                full=False)
68
 
                if prompt is not None:
69
 
                    prompt = " " + prompt +":"+ pylon.tree_cwd(self.tree)
 
114
                prompt_data = (self.tree.branch.nick, self.tree.branch.revno(), 
 
115
                               self.tree.branch.relpath('.'))
 
116
                prompt = " %s:%d/%s" % prompt_data
70
117
            except:
71
118
                prompt = ""
72
119
        else:
75
122
 
76
123
    def set_title(self, command=None):
77
124
        try:
78
 
            version = pylon.alias_or_version(self.tree.tree_version, self.tree, 
79
 
                                             full=False)
 
125
            b = Branch.open_containing('.')[0]
 
126
            version = "%s:%d" % (b.nick, b.revno())
80
127
        except:
81
128
            version = "[no version]"
82
129
        if command is None:
98
145
        except Exception, e:
99
146
            print e
100
147
        try:
101
 
            self.tree = arch.tree_root(".")
 
148
            self.tree = WorkingTree.open_containing(".")[0]
102
149
        except:
103
150
            self.tree = None
104
151
 
105
152
    def do_help(self, line):
106
 
        Help()(line)
 
153
        self.default("help "+line)
107
154
 
108
155
    def default(self, line):
109
156
        args = line.split()
 
157
        alias_args = get_alias(args[0])
 
158
        if alias_args is not None:
 
159
            args[0] = alias_args.pop(0)
 
160
            
110
161
        commandname = args.pop(0)
 
162
        for char in ('|', '<', '>'):
 
163
            commandname = commandname.split(char)[0]
 
164
        if commandname[-1] in ('|', '<', '>'):
 
165
            commandname = commandname[:-1]
111
166
        try:
 
167
            if commandname in SHELL_BLACKLIST:
 
168
                raise BlackListedCommand(commandname)
112
169
            cmd_obj = get_cmd_object(commandname)
113
 
        except BzrError:
 
170
        except (BlackListedCommand, BzrError):
114
171
            return os.system(line)
115
172
 
116
 
 
117
173
        try:
118
 
            return (cmd_obj.run_argv(args) or 0)
 
174
            if too_complicated(line):
 
175
                return os.system("bzr "+line)
 
176
            else:
 
177
                return (cmd_obj.run_argv_aliases(args, alias_args) or 0)
119
178
        except BzrError, e:
120
179
            print e
121
180
        except KeyboardInterrupt, e:
126
185
 
127
186
 
128
187
    def completenames(self, text, line, begidx, endidx):
129
 
        completions = []
130
 
        iter = iter_command_names(self.fake_aba)
131
 
        try:
132
 
            if len(line) > 0:
133
 
                arg = line.split()[-1]
134
 
            else:
135
 
                arg = ""
136
 
            iter = cmdutil.iter_munged_completions(iter, arg, text)
137
 
        except Exception, e:
138
 
            print e
139
 
        return list(iter)
 
188
        return CompletionContext(text).get_completions()
140
189
 
141
190
    def completedefault(self, text, line, begidx, endidx):
142
191
        """Perform completion for native commands.
150
199
        :param endidx: The end of the text in the line
151
200
        :type endidx: int
152
201
        """
153
 
        try:
154
 
            (cmd, args, foo) = self.parseline(line)
155
 
            command_obj=find_command(cmd)
156
 
            if command_obj is not None:
157
 
                return command_obj.complete(args.split(), text)
158
 
            elif not self.fake_aba.is_command(cmd) and \
159
 
                cmdutil.is_tla_command(cmd):
160
 
                iter = cmdutil.iter_supported_switches(cmd)
161
 
                if len(args) > 0:
162
 
                    arg = args.split()[-1]
163
 
                else:
164
 
                    arg = ""
165
 
                if arg.startswith("-"):
166
 
                    return list(cmdutil.iter_munged_completions(iter, arg, 
167
 
                                                                text))
168
 
                else:
169
 
                    return list(cmdutil.iter_munged_completions(
170
 
                        cmdutil.iter_file_completions(arg), arg, text))
171
 
 
172
 
 
173
 
            elif cmd == "cd":
174
 
                if len(args) > 0:
175
 
                    arg = args.split()[-1]
176
 
                else:
177
 
                    arg = ""
178
 
                iter = cmdutil.iter_dir_completions(arg)
179
 
                iter = cmdutil.iter_munged_completions(iter, arg, text)
180
 
                return list(iter)
181
 
            elif len(args)>0:
182
 
                arg = args.split()[-1]
183
 
                iter = cmdutil.iter_file_completions(arg)
184
 
                return list(cmdutil.iter_munged_completions(iter, arg, text))
185
 
            else:
186
 
                return self.completenames(text, line, begidx, endidx)
187
 
        except Exception, e:
188
 
            print e
 
202
        (cmd, args, foo) = self.parseline(line)
 
203
        if cmd == "bzr":
 
204
            cmd = None
 
205
        return CompletionContext(text, command=cmd).get_completions()
189
206
 
190
207
def run_shell():
191
 
    prompt = PromptCmd()
192
208
    try:
193
 
        prompt.cmdloop()
194
 
    finally:
195
 
        prompt.write_history()
 
209
        prompt = PromptCmd()
 
210
        try:
 
211
            prompt.cmdloop()
 
212
        finally:
 
213
            prompt.write_history()
 
214
    except StopIteration:
 
215
        pass
 
216
 
 
217
def iter_opt_completions(command_obj):
 
218
    for option_name, option in command_obj.options().items():
 
219
        yield "--" + option_name
 
220
        short_name = option.short_name()
 
221
        if short_name:
 
222
            yield "-" + short_name
196
223
 
197
224
def iter_file_completions(arg, only_dirs = False):
198
225
    """Generate an iterator that iterates through filename completions.
212
239
        listingdir = os.path.expanduser(dir)
213
240
    else:
214
241
        listingdir = cwd
215
 
    for file in iter_combine([os.listdir(listingdir), extras]):
 
242
    for file in chain(os.listdir(listingdir), extras):
216
243
        if dir != "":
217
244
            userfile = dir+'/'+file
218
245
        else:
232
259
    :type arg: str
233
260
    """
234
261
    return iter_file_completions(arg, True)
 
262
 
 
263
def iter_command_names(hidden=False):
 
264
    for real_cmd_name, cmd_class in get_all_cmds():
 
265
        if not hidden and cmd_class.hidden:
 
266
            continue
 
267
        for name in [real_cmd_name] + cmd_class.aliases:
 
268
            # Don't complete on aliases that are prefixes of the canonical name
 
269
            if name == real_cmd_name or not real_cmd_name.startswith(name):
 
270
                yield name
 
271
 
 
272
def filter_completions(iter, arg):
 
273
    return (c for c in iter if c.startswith(arg))
 
274
 
 
275
def iter_munged_completions(iter, arg, text):
 
276
    for completion in iter:
 
277
        completion = str(completion)
 
278
        if completion.startswith(arg):
 
279
            yield completion[len(arg)-len(text):]+" "
 
280
 
 
281
def too_complicated(line):
 
282
    for char in '|<>"\"*?':
 
283
        if char in line:
 
284
            return True
 
285
    return False