~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to shell.py

  • Committer: Aaron Bentley
  • Date: 2008-11-05 00:11:09 UTC
  • mto: This revision was merged to the branch mainline in revision 678.
  • Revision ID: aaron@aaronbentley.com-20081105001109-yt2dp0h5h3ssb7xt
Restore runtime ignore for .shelf

Show diffs side-by-side

added added

removed removed

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