~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to shell.py

  • Committer: Aaron Bentley
  • Date: 2006-07-17 13:29:34 UTC
  • Revision ID: abentley@panoramicfeedback.com-20060717132934-6dd09eca40796769
Nicer directory completion for bzr shell

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
20
20
import os
21
21
import readline
22
22
import shlex
23
 
import stat
24
23
import string
25
24
import sys
26
25
 
27
 
from bzrlib import osutils
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, all_command_names, get_alias
 
27
from bzrlib.commands import get_cmd_object, get_all_cmds, get_alias
31
28
from bzrlib.errors import BzrError
32
 
from bzrlib.workingtree import WorkingTree
33
29
 
34
30
import terminal
35
31
 
68
64
 
69
65
    def get_completions_or_raise(self):
70
66
        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)
 
67
            iter = (c+" " for c in iter_command_names() if
 
68
                    c not in COMPLETION_BLACKLIST)
76
69
            return list(filter_completions(iter, self.text))
77
70
        if self.prev_opt is None:
78
71
            completions = self.get_option_completions()
82
75
            else:
83
76
                iter = iter_file_completions(self.text)
84
77
                completions.extend(filter_completions(iter, self.text))
85
 
            return completions
 
78
            return completions 
86
79
 
87
80
 
88
81
class PromptCmd(cmd.Cmd):
89
 
 
90
82
    def __init__(self):
91
83
        cmd.Cmd.__init__(self)
92
84
        self.prompt = "bzr> "
97
89
        self.set_title()
98
90
        self.set_prompt()
99
91
        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)
 
92
        self.history_file = os.path.expanduser("~/.bazaar/shell-history")
 
93
        readline.set_completer_delims(string.whitespace)
104
94
        if os.access(self.history_file, os.R_OK) and \
105
95
            os.path.isfile(self.history_file):
106
96
            readline.read_history_file(self.history_file)
127
117
    def set_prompt(self):
128
118
        if self.tree is not None:
129
119
            try:
130
 
                prompt_data = (self.tree.branch.nick, self.tree.branch.revno(),
131
 
                               self.tree.relpath('.'))
 
120
                prompt_data = (self.tree.branch.nick, self.tree.branch.revno(), 
 
121
                               self.tree.branch.relpath('.'))
132
122
                prompt = " %s:%d/%s" % prompt_data
133
123
            except:
134
124
                prompt = ""
169
159
        self.default("help "+line)
170
160
 
171
161
    def default(self, line):
172
 
        try:
173
 
            args = shlex.split(line)
174
 
        except ValueError, e:
175
 
            print 'Parse error:', e
176
 
            return
177
 
 
 
162
        args = shlex.split(line)
178
163
        alias_args = get_alias(args[0])
179
164
        if alias_args is not None:
180
165
            args[0] = alias_args.pop(0)
181
 
 
 
166
            
182
167
        commandname = args.pop(0)
183
168
        for char in ('|', '<', '>'):
184
169
            commandname = commandname.split(char)[0]
192
177
            return os.system(line)
193
178
 
194
179
        try:
195
 
            is_qbzr = cmd_obj.__module__.startswith('bzrlib.plugins.qbzr.')
196
 
            if too_complicated(line) or is_qbzr:
 
180
            if too_complicated(line):
197
181
                return os.system("bzr "+line)
198
182
            else:
199
183
                return (cmd_obj.run_argv_aliases(args, alias_args) or 0)
211
195
 
212
196
    def completedefault(self, text, line, begidx, endidx):
213
197
        """Perform completion for native commands.
214
 
 
 
198
        
215
199
        :param text: The text to complete
216
200
        :type text: str
217
201
        :param line: The entire line to complete
227
211
        return CompletionContext(text, command=cmd).get_completions()
228
212
 
229
213
 
230
 
def run_shell(directory=None):
 
214
def run_shell():
231
215
    try:
232
 
        if not directory is None:
233
 
            os.chdir(directory)
234
216
        prompt = PromptCmd()
235
 
        while True:
236
 
            try:
237
 
                try:
238
 
                    prompt.cmdloop()
239
 
                except KeyboardInterrupt:
240
 
                    print
241
 
            finally:
242
 
                prompt.write_history()
 
217
        try:
 
218
            prompt.cmdloop()
 
219
        finally:
 
220
            prompt.write_history()
243
221
    except StopIteration:
244
222
        pass
245
223
 
293
271
 
294
272
 
295
273
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:
 
274
    for real_cmd_name, cmd_class in get_all_cmds():
 
275
        if not hidden and cmd_class.hidden:
299
276
            continue
300
 
        for name in [real_cmd_name] + cmd_obj.aliases:
 
277
        for name in [real_cmd_name] + cmd_class.aliases:
301
278
            # Don't complete on aliases that are prefixes of the canonical name
302
279
            if name == real_cmd_name or not real_cmd_name.startswith(name):
303
280
                yield name
304
281
 
305
282
 
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):
310
 
            continue
311
 
        fullpath = os.path.join(dirname, filename)
312
 
        mode=os.lstat(fullpath)[stat.ST_MODE]
313
 
        if stat.S_ISREG(mode) and 0111 & mode:
314
 
            yield fullpath + ' '
315
 
 
316
 
 
317
283
def filter_completions(iter, arg):
318
284
    return (c for c in iter if c.startswith(arg))
319
285