~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to shell.py

Merge from Aaron.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
from itertools import chain
24
24
from bzrlib.errors import BzrError
25
25
from bzrlib.commands import get_cmd_object, get_all_cmds
 
26
from bzrlib.branch import Branch
26
27
 
27
28
SHELL_BLACKLIST = set(['rm', 'ls'])
 
29
COMPLETION_BLACKLIST = set(['shell'])
28
30
 
29
31
class BlackListedCommand(BzrError):
30
32
    def __init__(self, command):
31
33
        BzrError.__init__(self, "The command %s is blacklisted for shell use" %
32
34
                          command)
33
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
 
 
74
 
34
75
class PromptCmd(cmd.Cmd):
35
76
    def __init__(self):
36
77
        cmd.Cmd.__init__(self)
37
78
        self.prompt = "bzr> "
38
79
        try:
39
 
            self.tree = arch.tree_root(".")
 
80
            self.branch = Branch.open_containing('.')[0]
40
81
        except:
41
 
            self.tree = None
 
82
            self.branch = None
42
83
        self.set_title()
43
84
        self.set_prompt()
44
85
        self.identchars += '-'
68
109
        self.set_prompt()
69
110
 
70
111
    def set_prompt(self):
71
 
        if self.tree is not None:
 
112
        if self.branch is not None:
72
113
            try:
73
 
                prompt = pylon.alias_or_version(self.tree.tree_version, 
74
 
                                                self.tree, 
75
 
                                                full=False)
76
 
                if prompt is not None:
77
 
                    prompt = " " + prompt +":"+ pylon.tree_cwd(self.tree)
 
114
                prompt_data = (self.branch.nick, self.branch.revno(), 
 
115
                               self.branch.working_tree().relpath('.'))
 
116
                prompt = " %s:%d/%s" % prompt_data
78
117
            except:
79
118
                prompt = ""
80
119
        else:
83
122
 
84
123
    def set_title(self, command=None):
85
124
        try:
86
 
            version = pylon.alias_or_version(self.tree.tree_version, self.tree, 
87
 
                                             full=False)
 
125
            b = Branch.open_containing('.')[0]
 
126
            version = "%s:%d" % (b.nick, b.revno())
88
127
        except:
89
128
            version = "[no version]"
90
129
        if command is None:
106
145
        except Exception, e:
107
146
            print e
108
147
        try:
109
 
            self.tree = arch.tree_root(".")
 
148
            self.branch = Branch.open_containing(".")[0]
110
149
        except:
111
 
            self.tree = None
 
150
            self.branch = None
112
151
 
113
152
    def do_help(self, line):
114
153
        self.default("help "+line)
142
181
 
143
182
 
144
183
    def completenames(self, text, line, begidx, endidx):
145
 
        completions = []
146
 
        iter = iter_command_names()
147
 
        try:
148
 
            if len(line) > 0:
149
 
                arg = line.split()[-1]
150
 
            else:
151
 
                arg = ""
152
 
            iter = list(iter_munged_completions(iter, arg, text))
153
 
        except Exception, e:
154
 
            print e, type(e)
155
 
        return list(iter)
 
184
        return CompletionContext(text).get_completions()
156
185
 
157
186
    def completedefault(self, text, line, begidx, endidx):
158
187
        """Perform completion for native commands.
168
197
        """
169
198
        (cmd, args, foo) = self.parseline(line)
170
199
        if cmd == "bzr":
171
 
            try:
172
 
                return self.completenames(text, line, begidx, endidx)
173
 
            except Exception, e:
174
 
                print e
175
 
        try:
176
 
            command_obj = get_cmd_object(cmd)
177
 
        except BzrError:
178
 
            command_obj = None
179
 
        try:
180
 
            if command_obj is not None:
181
 
                opts = []
182
 
                for option_name, option in command_obj.options().items():
183
 
                    opts.append("--" + option_name)
184
 
                    short_name = option.short_name()
185
 
                    if short_name:
186
 
                        opts.append("-" + short_name)
187
 
                q = list(iter_munged_completions(opts, args, text))
188
 
                return list(iter_munged_completions(opts, args, text))
189
 
            elif cmd == "cd":
190
 
                if len(args) > 0:
191
 
                    arg = args.split()[-1]
192
 
                else:
193
 
                    arg = ""
194
 
                iter = iter_dir_completions(arg)
195
 
                iter = iter_munged_completions(iter, arg, text)
196
 
                return list(iter)
197
 
            elif len(args)>0:
198
 
                arg = args.split()[-1]
199
 
                iter = iter_file_completions(arg)
200
 
                return list(iter_munged_completions(iter, arg, text))
201
 
            else:
202
 
                return self.completenames(text, line, begidx, endidx)
203
 
        except Exception, e:
204
 
            print e
 
200
            cmd = None
 
201
        return CompletionContext(text, command=cmd).get_completions()
205
202
 
206
203
def run_shell():
207
204
    try:
213
210
    except StopIteration:
214
211
        pass
215
212
 
 
213
def iter_opt_completions(command_obj):
 
214
    for option_name, option in command_obj.options().items():
 
215
        yield "--" + option_name
 
216
        short_name = option.short_name()
 
217
        if short_name:
 
218
            yield "-" + short_name
 
219
 
216
220
def iter_file_completions(arg, only_dirs = False):
217
221
    """Generate an iterator that iterates through filename completions.
218
222
 
261
265
            if name == real_cmd_name or not real_cmd_name.startswith(name):
262
266
                yield name
263
267
 
 
268
def filter_completions(iter, arg):
 
269
    return (c for c in iter if c.startswith(arg))
 
270
 
264
271
def iter_munged_completions(iter, arg, text):
265
272
    for completion in iter:
266
273
        completion = str(completion)
268
275
            yield completion[len(arg)-len(text):]+" "
269
276
 
270
277
def too_complicated(line):
271
 
    for char in '|<>"\"':
 
278
    for char in '|<>"\"*?':
272
279
        if char in line:
273
280
            return True
274
281
    return False