~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to hunk_selector.py

  • Committer: Michael Ellerman
  • Date: 2005-11-29 01:41:52 UTC
  • mto: (0.3.1 shelf-dev) (325.1.2 bzrtools)
  • mto: This revision was merged to the branch mainline in revision 334.
  • Revision ID: michael@ellerman.id.au-20051129014152-f5ede8888bcebc48
HunkSelector was broken if you did a "done" followed by "status/invert" etc.
Fixup to make pychecker happy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
2
2
 
3
 
import sys
 
3
from userinteractor import UserInteractor, UserOption
4
4
 
5
5
class HunkSelector:
6
 
    class Option:
7
 
        def __init__(self, char, action, help, default=False):
8
 
            self.char = char
9
 
            self.action = action
10
 
            self.default = default
11
 
            self.help = help
12
 
 
13
 
    standard_options = [
14
 
        Option('n', 'shelve', 'shelve this change for the moment.',
15
 
            default=True),
16
 
        Option('y', 'keep', 'keep this change in your tree.'),
17
 
        Option('d', 'done', 'done, skip to the end.'),
18
 
        Option('i', 'invert', 'invert the current selection of all hunks.'),
19
 
        Option('s', 'status', 'show status of hunks.'),
20
 
        Option('q', 'quit', 'quit')
21
 
    ]
22
 
 
23
 
    end_options = [
24
 
        Option('y', 'continue', 'proceed to shelve selected changes.',
25
 
            default=True),
26
 
        Option('r', 'restart', 'restart the hunk selection loop.'),
27
 
        Option('s', 'status', 'show status of hunks.'),
28
 
        Option('i', 'invert', 'invert the current selection of all hunks.'),
29
 
        Option('q', 'quit', 'quit')
30
 
    ]
 
6
    strings = {}
31
7
 
32
8
    def __init__(self, patches):
 
9
        self.standard_options = [
 
10
            UserOption('y', self._selected, self.strings['select_desc'],
 
11
                default=True),
 
12
            UserOption('n', self._unselected, self.strings['unselect_desc']),
 
13
            UserOption('d', UserInteractor.FINISH, 'done, skip to the end.'),
 
14
            UserOption('i', self._invert,
 
15
                'invert the current selection status of all hunks.'),
 
16
            UserOption('s', self._status,
 
17
                'show selection status of all hunks.'),
 
18
            UserOption('q', UserInteractor.QUIT, 'quit')
 
19
        ]
 
20
 
 
21
        self.end_options = [
 
22
            UserOption('y', UserInteractor.FINISH, self.strings['finish_desc'],
 
23
                default=True),
 
24
            UserOption('r', UserInteractor.RESTART,
 
25
                'restart the hunk selection loop.'),
 
26
            UserOption('s', self._status,
 
27
                'show selection status of all hunks.'),
 
28
            UserOption('i', self._invert,
 
29
                'invert the current selection status of all hunks.'),
 
30
            UserOption('q', UserInteractor.QUIT, 'quit')
 
31
        ]
 
32
 
33
33
        self.patches = patches
34
34
        self.total_hunks = 0
 
35
 
 
36
        self.interactor = UserInteractor()
 
37
        self.interactor.set_item_callback(self._hunk_callback)
 
38
        self.interactor.set_start_callback(self._start_callback)
 
39
        self.interactor.set_end_callback(self._end_callback)
 
40
 
35
41
        for patch in patches:
36
42
            for hunk in patch.hunks:
37
 
                # everything's shelved by default
 
43
                # everything's selected by default
38
44
                hunk.selected = True
39
45
                self.total_hunks += 1
40
 
 
41
 
    def __get_option(self, char):
42
 
        for opt in self.standard_options:
43
 
            if opt.char == char:
44
 
                return opt
45
 
        raise Exception('Option "%s" not found!' % char)
46
 
 
47
 
    def __select_loop(self):
48
 
        j = 0
49
 
        for patch in self.patches:
50
 
            i = 0
51
 
            lasti = -1
52
 
            while i < len(patch.hunks):
53
 
                hunk = patch.hunks[i]
54
 
                if lasti != i:
55
 
                    print patch.get_header(), hunk
56
 
                    j += 1
57
 
                lasti = i
58
 
 
59
 
                prompt = 'Keep this change? (%d of %d)' \
60
 
                            % (j, self.total_hunks)
61
 
 
 
46
                # we need a back pointer in the callbacks
 
47
                hunk.patch = patch
 
48
                self.interactor.add_item(hunk)
 
49
 
 
50
    # Called at the start of the main loop
 
51
    def _start_callback(self):
 
52
        self.last_printed = -1
 
53
        self.interactor.set_prompt(self.strings['prompt'])
 
54
        self.interactor.set_options(self.standard_options)
 
55
 
 
56
    # Called at the end of the item loop, return False to indicate that the
 
57
    # interaction isn't finished and the confirmation prompt should be displayed
 
58
    def _end_callback(self):
 
59
        self._status()
 
60
        self.interactor.set_prompt(self.strings['end_prompt'])
 
61
        self.interactor.set_options(self.end_options)
 
62
        return False
 
63
 
 
64
    # Called once for each hunk
 
65
    def _hunk_callback(self, hunk, count):
 
66
        if self.last_printed != count:
 
67
            print hunk.patch.get_header(), hunk
 
68
            self.last_printed = count
 
69
 
 
70
        if hunk.selected:
 
71
            self.interactor.get_option('y').default = True
 
72
            self.interactor.get_option('n').default = False
 
73
        else:
 
74
            self.interactor.get_option('y').default = False
 
75
            self.interactor.get_option('n').default = True
 
76
 
 
77
    # The user chooses to (un)shelve a hunk
 
78
    def _selected(self, hunk):
 
79
        hunk.selected = True
 
80
        return True
 
81
 
 
82
    # The user chooses to keep a hunk
 
83
    def _unselected(self, hunk):
 
84
        hunk.selected = False
 
85
        return True
 
86
 
 
87
    # The user chooses to invert the selection
 
88
    def _invert(self, hunk):
 
89
        for patch in self.patches:
 
90
            for hunk in patch.hunks:
 
91
                if hunk.__dict__.has_key('selected'):
 
92
                    hunk.selected = not hunk.selected
 
93
                else:
 
94
                    hunk.selected = True
 
95
        self._status()
 
96
        return False
 
97
 
 
98
    # The user wants to see the status
 
99
    def _status(self, hunk=None):
 
100
        print '\nStatus:'
 
101
        for patch in self.patches:
 
102
            print '  %s' % patch.oldname
 
103
            selected = 0
 
104
            unselected = 0
 
105
            for hunk in patch.hunks:
62
106
                if hunk.selected:
63
 
                    self.__get_option('n').default = True
64
 
                    self.__get_option('y').default = False
 
107
                    selected += 1
65
108
                else:
66
 
                    self.__get_option('n').default = False
67
 
                    self.__get_option('y').default = True
68
 
 
69
 
                action = self.__ask_user(prompt, self.standard_options)
70
 
 
71
 
                if action == 'keep':
72
 
                    hunk.selected = False
73
 
                elif action == 'shelve':
74
 
                    hunk.selected = True
75
 
                elif action == 'done':
76
 
                    return True
77
 
                elif action == 'invert':
78
 
                    self.__invert_selection()
79
 
                    self.__show_status()
80
 
                    continue
81
 
                elif action == 'status':
82
 
                    self.__show_status()
83
 
                    continue
84
 
                elif action == 'quit':
85
 
                    return False
86
 
 
87
 
                i += 1
88
 
        return True
 
109
                    unselected += 1
 
110
 
 
111
            print '  ', self.strings['status_selected'] % selected
 
112
            print '  ', self.strings['status_unselected'] % unselected
 
113
            print
 
114
 
 
115
        # Tell the interactor we're not done with this item
 
116
        return False
89
117
 
90
118
    def select(self):
91
119
        if self.total_hunks == 0:
92
120
            return []
93
121
 
94
 
        done = False
95
 
        while not done:
96
 
            if not self.__select_loop():
97
 
                return []
98
 
 
99
 
            while True:
100
 
                self.__show_status()
101
 
                prompt = "Shelve these changes, or restart?"
102
 
                action = self.__ask_user(prompt, self.end_options)
103
 
 
104
 
                if action == 'continue':
105
 
                    done = True
106
 
                    break
107
 
                elif action == 'quit':
108
 
                    return []
109
 
                elif action == 'status':
110
 
                    self.__show_status()
111
 
                elif action == 'invert':
112
 
                    self.__invert_selection()
113
 
                elif action == 'restart':
114
 
                    break
115
 
 
 
122
        if not self.interactor.interact():
 
123
            # False from interact means they quit
 
124
            return []
116
125
 
117
126
        for patch in self.patches:
118
127
            tmp = []
129
138
 
130
139
        return self.patches
131
140
 
132
 
    def __invert_selection(self):
133
 
        for patch in self.patches:
134
 
            for hunk in patch.hunks:
135
 
                if hunk.__dict__.has_key('selected'):
136
 
                    hunk.selected = not hunk.selected
137
 
                else:
138
 
                    hunk.selected = True
139
 
 
140
 
    def __show_status(self):
141
 
        print '\nStatus:'
142
 
        for patch in self.patches:
143
 
            print '  %s' % patch.oldname
144
 
            shelve = 0
145
 
            keep = 0
146
 
            for hunk in patch.hunks:
147
 
                if hunk.selected:
148
 
                    shelve += 1
149
 
                else:
150
 
                    keep += 1
151
 
 
152
 
            print '    %d hunks to be shelved' % shelve
153
 
            print '    %d hunks to be kept' % keep
154
 
            print
155
 
 
156
 
    if sys.platform == "win32":
157
 
        import msvcrt
158
 
        def __getchar(self):
159
 
            return msvcrt.getche()
160
 
    else:
161
 
        def __getchar(self):
162
 
            import tty
163
 
            import termios
164
 
            fd = sys.stdin.fileno()
165
 
            settings = termios.tcgetattr(fd)
166
 
            try:
167
 
                tty.setraw(fd)
168
 
                ch = sys.stdin.read(1)
169
 
            finally:
170
 
                termios.tcsetattr(fd, termios.TCSADRAIN, settings)
171
 
            return ch
172
 
 
173
 
    def __ask_user(self, prompt, options):
174
 
        while True:
175
 
            sys.stdout.write(prompt)
176
 
            sys.stdout.write(' [')
177
 
            for opt in options:
178
 
                if opt.default:
179
 
                    default = opt
180
 
                sys.stdout.write(opt.char)
181
 
            sys.stdout.write('?] (%s): ' % default.char)
182
 
 
183
 
            response = self.__getchar()
184
 
 
185
 
            # default, which we see as newline, is 'n'
186
 
            if response in ['\n', '\r', '\r\n']:
187
 
                response = default.char
188
 
 
189
 
            print response # because echo is off
190
 
 
191
 
            for opt in options:
192
 
                if opt.char == response:
193
 
                    return opt.action
194
 
 
195
 
            for opt in options:
196
 
                print '  %s - %s' % (opt.char, opt.help)
 
141
class ShelveHunkSelector(HunkSelector):
 
142
    def __init__(self, patches):
 
143
        self.strings = {}
 
144
        self.strings['status_selected'] = '%d hunks to be shelved'
 
145
        self.strings['status_unselected'] = '%d hunks to be kept'
 
146
        self.strings['select_desc'] = 'shelve this change.'
 
147
        self.strings['unselect_desc'] = 'keep this change in your tree.'
 
148
        self.strings['finish_desc'] = 'shelve selected changes.'
 
149
        self.strings['prompt'] = 'Shelve this change? (%(count)d of %(total)d)'
 
150
        self.strings['end_prompt'] = 'Shelve these changes?'
 
151
        HunkSelector.__init__(self, patches)
 
152
 
 
153
class UnshelveHunkSelector(HunkSelector):
 
154
    def __init__(self, patches):
 
155
        self.strings = {}
 
156
        self.strings['status_selected'] = '%d hunks to be unshelved'
 
157
        self.strings['status_unselected'] = '%d hunks left on shelf'
 
158
        self.strings['select_desc'] = 'unshelve this change.'
 
159
        self.strings['unselect_desc'] = 'leave this change on the shelf.'
 
160
        self.strings['finish_desc'] = 'unshelve selected changes.'
 
161
        self.strings['prompt'] = 'Unshelve this change? ' \
 
162
            '(%(count)d of %(total)d)'
 
163
        self.strings['end_prompt'] = 'Unshelve these changes?'
 
164
        HunkSelector.__init__(self, patches)