~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to shell.py

  • Committer: Aaron Bentley
  • Date: 2006-03-22 15:19:16 UTC
  • Revision ID: abentley@panoramicfeedback.com-20060322151916-75711de1522d1f68
Tagged BZRTOOLS commands to reduce confusion

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2004, 2005 Aaron Bentley
2
 
# <aaron@aaronbentley.com>
 
2
# <aaron.bentley@utoronto.ca>
3
3
#
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
17
 
 
18
17
import cmd
19
 
from itertools import chain
 
18
import sys
20
19
import os
 
20
import terminal
21
21
import readline
22
 
import shlex
23
 
import stat
24
22
import string
25
 
import sys
26
 
 
27
 
from bzrlib import osutils
 
23
from itertools import chain
 
24
from bzrlib.errors import BzrError
 
25
from bzrlib.commands import get_cmd_object, get_all_cmds, get_alias
28
26
from bzrlib.branch import Branch
29
 
from bzrlib.config import config_dir, ensure_config_dir_exists
30
 
from bzrlib.commands import get_cmd_object, get_all_cmds, get_alias
31
 
from bzrlib.errors import BzrError
32
 
from bzrlib.workingtree import WorkingTree
33
 
 
34
 
import terminal
35
 
 
36
27
 
37
28
SHELL_BLACKLIST = set(['rm', 'ls'])
38
29
COMPLETION_BLACKLIST = set(['shell'])
39
30
 
40
 
 
41
31
class BlackListedCommand(BzrError):
42
32
    def __init__(self, command):
43
33
        BzrError.__init__(self, "The command %s is blacklisted for shell use" %
44
34
                          command)
45
35
 
46
 
 
47
36
class CompletionContext(object):
48
37
    def __init__(self, text, command=None, prev_opt=None, arg_pos=None):
49
38
        self.text = text
68
57
 
69
58
    def get_completions_or_raise(self):
70
59
        if self.command is None:
71
 
            if '/' in self.text:
72
 
                iter = iter_executables(self.text)
73
 
            else:
74
 
                iter = (c+" " for c in iter_command_names() if
75
 
                        c not in COMPLETION_BLACKLIST)
 
60
            iter = (c+" " for c in iter_command_names() if
 
61
                    c not in COMPLETION_BLACKLIST)
76
62
            return list(filter_completions(iter, self.text))
77
63
        if self.prev_opt is None:
78
64
            completions = self.get_option_completions()
81
67
                completions.extend(list(filter_completions(iter, self.text)))
82
68
            else:
83
69
                iter = iter_file_completions(self.text)
84
 
                completions.extend(filter_completions(iter, self.text))
85
 
            return completions
 
70
                completions.extend([f+" " for f in 
 
71
                                    filter_completions(iter, self.text)])
 
72
            return completions 
86
73
 
87
74
 
88
75
class PromptCmd(cmd.Cmd):
89
 
 
90
76
    def __init__(self):
91
77
        cmd.Cmd.__init__(self)
92
78
        self.prompt = "bzr> "
97
83
        self.set_title()
98
84
        self.set_prompt()
99
85
        self.identchars += '-'
100
 
        ensure_config_dir_exists()
101
 
        self.history_file = osutils.pathjoin(config_dir(), 'shell-history')
 
86
        self.history_file = os.path.expanduser("~/.bazaar/shell-history")
102
87
        readline.set_completer_delims(string.whitespace)
103
88
        if os.access(self.history_file, os.R_OK) and \
104
89
            os.path.isfile(self.history_file):
126
111
    def set_prompt(self):
127
112
        if self.tree is not None:
128
113
            try:
129
 
                prompt_data = (self.tree.branch.nick, self.tree.branch.revno(),
130
 
                               self.tree.relpath('.'))
 
114
                prompt_data = (self.tree.branch.nick, self.tree.branch.revno(), 
 
115
                               self.tree.branch.relpath('.'))
131
116
                prompt = " %s:%d/%s" % prompt_data
132
117
            except:
133
118
                prompt = ""
168
153
        self.default("help "+line)
169
154
 
170
155
    def default(self, line):
171
 
        args = shlex.split(line)
 
156
        args = line.split()
172
157
        alias_args = get_alias(args[0])
173
158
        if alias_args is not None:
174
159
            args[0] = alias_args.pop(0)
175
 
 
 
160
            
176
161
        commandname = args.pop(0)
177
162
        for char in ('|', '<', '>'):
178
163
            commandname = commandname.split(char)[0]
204
189
 
205
190
    def completedefault(self, text, line, begidx, endidx):
206
191
        """Perform completion for native commands.
207
 
 
 
192
        
208
193
        :param text: The text to complete
209
194
        :type text: str
210
195
        :param line: The entire line to complete
219
204
            cmd = None
220
205
        return CompletionContext(text, command=cmd).get_completions()
221
206
 
222
 
 
223
207
def run_shell():
224
208
    try:
225
209
        prompt = PromptCmd()
230
214
    except StopIteration:
231
215
        pass
232
216
 
233
 
 
234
217
def iter_opt_completions(command_obj):
235
218
    for option_name, option in command_obj.options().items():
236
219
        yield "--" + option_name
238
221
        if short_name:
239
222
            yield "-" + short_name
240
223
 
241
 
 
242
224
def iter_file_completions(arg, only_dirs = False):
243
225
    """Generate an iterator that iterates through filename completions.
244
226
 
267
249
                userfile+='/'
268
250
                yield userfile
269
251
            elif not only_dirs:
270
 
                yield userfile + ' '
 
252
                yield userfile
271
253
 
272
254
 
273
255
def iter_dir_completions(arg):
278
260
    """
279
261
    return iter_file_completions(arg, True)
280
262
 
281
 
 
282
263
def iter_command_names(hidden=False):
283
264
    for real_cmd_name, cmd_class in get_all_cmds():
284
265
        if not hidden and cmd_class.hidden:
288
269
            if name == real_cmd_name or not real_cmd_name.startswith(name):
289
270
                yield name
290
271
 
291
 
 
292
 
def iter_executables(path):
293
 
    dirname, partial = os.path.split(path)
294
 
    for filename in os.listdir(dirname):
295
 
        if not filename.startswith(partial):
296
 
            continue
297
 
        fullpath = os.path.join(dirname, filename)
298
 
        mode=os.lstat(fullpath)[stat.ST_MODE]
299
 
        if stat.S_ISREG(mode) and 0111 & mode:
300
 
            yield fullpath + ' '
301
 
 
302
 
 
303
272
def filter_completions(iter, arg):
304
273
    return (c for c in iter if c.startswith(arg))
305
274
 
306
 
 
307
275
def iter_munged_completions(iter, arg, text):
308
276
    for completion in iter:
309
277
        completion = str(completion)
310
278
        if completion.startswith(arg):
311
279
            yield completion[len(arg)-len(text):]+" "
312
280
 
313
 
 
314
281
def too_complicated(line):
315
 
    for char in '|<>*?':
 
282
    for char in '|<>"\"*?':
316
283
        if char in line:
317
284
            return True
318
285
    return False