~abentley/bzrtools/bzrtools.dev

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/python

import sys

class UserOption:
    def __init__(self, char, action, help, default=False):
        self.char = char
        self.action = action
        self.default = default
        self.help = help

class UserInteractor(object):
    # Special actions
    RESTART = 0
    QUIT = 1
    FINISH = 2

    def __init__(self):
        self.items = []

    def add_item(self, item):
        self.items.append(item)
        self.__total_items = len(self.items)

    def set_items(self, item_list):
        self.items = item_list
        self.__total_items = len(self.items)

    def set_item_callback(self, cb):
        self.item_callback = cb

    def set_start_callback(self, cb):
        self.start_callback = cb

    def set_end_callback(self, cb):
        self.end_callback = cb

    def set_prompt(self, prompt):
        self.prompt = prompt

    def set_options(self, opt_list):
        self._options = []
        self._option_dict = {}
        for option in opt_list:
            self.add_option(option)

    def add_option(self, option):
        self._options.append(option)
        self._option_dict[option.char] = option

    def get_option(self, char):
        return self._option_dict[char]

    def __do_action(self, action, item):
        if type(action) is int:
            if action == self.QUIT:
                self.__quit = True
                self.__finished = True
            elif action == self.RESTART:
                self.__restart = True
                self.__finished = False
            elif action == self.FINISH:
                self.__finished = True
            return True
        else:
            return action(item)

    def __select_loop(self):
        i = 0
        self.start_callback()
        while i < len(self.items):
                item = self.items[i]

                self.item_callback(item, i + 1)

                if self.__ask_once(item, i + 1):
                    i += 1

                if self.__quit or self.__finished:
                    break

    def interact(self):
        self.__quit = False
        self.__finished = False

        while not self.__quit and not self.__finished:
            self.__restart = False

            self.__select_loop()
            if self.__quit:
                break

            if self.end_callback():
                break

            self.__finished = False

            self.__ask_once(None, self.__total_items)
            while not self.__finished and not self.__restart:
                self.__ask_once(None, -1)

        return not self.__quit

    def __ask_once(self, item, count):
        args = {'count': count, 'total' : self.__total_items}

        while True:
            sys.stdout.write(self.prompt % args)
            sys.stdout.write(' [')
            for opt in self._options:
                if opt.default:
                    default = opt
                sys.stdout.write(opt.char)
            sys.stdout.write('?] (%s): ' % default.char)

            response = self.__getchar()

            # default, which we see as newline, is 'n'
            if response in ['\n', '\r', '\r\n']:
                response = default.char

            print response # because echo is off

            for opt in self._options:
                if opt.char == response:
                    return self.__do_action(opt.action, item)

            self.__show_help()

        return False # keep pychecker happy

    def __show_help(self):
        for opt in self._options:
            print '  %s - %s' % (opt.char, opt.help)

    if sys.platform == "win32":
        def __getchar(self):
            import msvcrt
            return msvcrt.getch()
    else:
        def __getchar(self):
            import tty
            import termios
            fd = sys.stdin.fileno()
            settings = termios.tcgetattr(fd)
            try:
                tty.setraw(fd)
                ch = sys.stdin.read(1)
            finally:
                termios.tcsetattr(fd, termios.TCSADRAIN, settings)
            return ch