Skip to content
Newer
Older
100644 170 lines (129 sloc) 5.61 KB
7878dd3 @baverman predictable spots
authored Oct 24, 2011
1 import weakref
2 import gtk
3
4 def init(injector):
5 injector.add_context('spot-manager', 'window', lambda w: w.manager.spot_manager)
6 #injector.add_context('edit-spot', 'editor-active', spot_context('edit'))
7 #injector.add_context('master-spot', 'editor-active', spot_context('master'))
8 injector.add_context('regular-spot', 'editor-active', spot_context('regular'))
9
cc6df07 @baverman fix uxie API calls
authored Jan 6, 2012
10 injector.bind(('spot-manager', 'editor-active', 'regular-spot'), 'goto-last-spot',
11 'Edit/Goto last spot#70', Manager.goto_last).to('<Alt>q')
7878dd3 @baverman predictable spots
authored Oct 24, 2011
12
13 #injector.bind_accel(('spot-manager', 'editor-active', 'edit-spot'), 'goto-last-spot',
14 # '_Edit/Goto last edit spot', '<Alt>q', Manager.goto_last, 5)
15
cc6df07 @baverman fix uxie API calls
authored Jan 6, 2012
16 injector.bind(('spot-manager', 'editor-active'), 'goto-next-spot',
17 'Edit/Goto next spot', Manager.goto_next_prev, True).to('<ctrl>bracketright')
7878dd3 @baverman predictable spots
authored Oct 24, 2011
18
cc6df07 @baverman fix uxie API calls
authored Jan 6, 2012
19 injector.bind(('spot-manager', 'editor-active'), 'goto-prev-spot',
20 'Edit/Goto prev spot', Manager.goto_next_prev, False).to('<ctrl>bracketleft')
7878dd3 @baverman predictable spots
authored Oct 24, 2011
21
22 #injector.bind_accel(('spot-manager', 'editor-active', 'master-spot'), 'goto-last-spot',
23 # '_Edit/Goto last master spot', '<Alt>q', Manager.goto_last, 10)
24
25 #injector.bind_accel(('spot-manager', 'editor-active'), 'add-master-spot',
26 # '_Edit/Add master spot', '<Alt>s', Manager.add_master_spot)
27
28
29 injector.on_ready('buffer-created', buffer_created)
30 injector.on_ready('editor', editor_opened)
31 injector.on_done('editor', editor_closed)
32
33 def spot_context(spot_type):
34 def inner(editor):
35 new_spot = EditorSpot(editor, spot_type)
36 spot = editor.window.manager.spot_manager.get_last(new_spot, None, spot_type)
37 if spot:
38 return spot, new_spot
39 else:
40 return None
41
42 return inner
43
44 def buffer_created(buf):
45 buf.connect('changed', on_buffer_changed)
46 buf.is_changed = False
47
48 def on_buffer_changed(buf):
49 buf.is_changed = True
50
51 def editor_opened(editor):
52 editor.view.connect('move-cursor', on_textview_move_cursor)
53
54 def editor_closed(editor):
55 editor.window.manager.spot_manager.remove_invalid_spots(editor=editor)
56
57 SAFE_MOVEMENTS = set((gtk.MOVEMENT_VISUAL_POSITIONS, gtk.MOVEMENT_WORDS,
58 gtk.MOVEMENT_LOGICAL_POSITIONS, gtk.MOVEMENT_DISPLAY_LINE_ENDS))
59
60 def on_textview_move_cursor(view, step_size, count, extend_selection):
61 if view.get_buffer().is_changed and step_size not in SAFE_MOVEMENTS:
62 editor = view.editor_ref()
63 editor.window.manager.spot_manager.add(editor)
64
65 class Manager(object):
66 def __init__(self):
67 self.history = []
68
69 def add_master_spot(self, editor):
70 self.add(editor, 'master')
71 editor.message('Master spot added', 'done')
72
73 def add(self, editor, spot_type=None):
74 #if not spot_type and editor.buffer.is_changed:
75 # spot_type = 'edit'
76
77 editor.buffer.is_changed = False
78 self.add_to_history(EditorSpot(editor, spot_type))
79
80 def remove_invalid_spots(self, spot=None, editor=None):
81 result = []
82 for i, s in enumerate(self.history):
83 if i > 30 or (editor and s.editor() is editor) or not s.is_valid() or s.similar_to(spot):
84 s.remove()
85 else:
86 result.append(s)
87
88 self.history[:] = result
89
90 def add_to_history(self, spot):
91 self.remove_invalid_spots(spot=spot)
92 self.history.insert(0, spot)
93
94 def goto_last(self, editor, spots):
95 if spots:
96 spot, new_spot = spots
97 spot.goto(editor)
98 self.add_to_history(new_spot)
99 else:
100 editor.message('Spot history is empty', 'warn')
101
102 def get_last(self, exclude_spot=None, exclude_editor=None, spot_type=None):
103 spot_type = spot_type or 'regular'
104 for s in self.history:
105 if s.is_valid() and not s.similar_to(exclude_spot) \
106 and s.editor() is not exclude_editor and s.type == spot_type:
107 return s
108
109 return None
110
111 def goto_next_prev(self, editor, is_next):
112 current_spot = EditorSpot(editor)
113 if is_next:
114 seq = self.history
115 else:
116 seq = reversed(self.history)
117
118 prev_spot = None
119 for s in (s for s in seq if s.is_valid()):
120 if s.similar_to(current_spot):
121 if prev_spot:
122 prev_spot.goto(editor)
123 else:
124 editor.message('No more spots to go', 'warn')
125 return
126
127 prev_spot = s
128
129 spot = self.get_last(current_spot)
130 if spot:
131 self.goto_last(editor, (spot, current_spot))
132 else:
133 self.goto_last(editor, None)
134
135
136 class EditorSpot(object):
137 def __init__(self, editor, spot_type=None):
138 self.editor = weakref.ref(editor)
139 self.mark = editor.buffer.create_mark(None, editor.cursor)
140 self.type = spot_type or 'regular'
141
142 @property
143 def iter(self):
144 return self.mark.get_buffer().get_iter_at_mark(self.mark)
145
146 def is_valid(self):
147 return self.editor() and not self.mark.get_deleted()
148
149 def similar_to(self, spot):
150 return spot and self.mark.get_buffer() is spot.mark.get_buffer() \
151 and abs(self.iter.get_line() - spot.iter.get_line()) < 7
152
153 def remove(self):
154 editor = self.editor()
155 if editor:
156 editor.buffer.delete_mark(self.mark)
157 del self.mark
158
159 def goto(self, back_to=None):
160 editor = self.editor()
161 editor.buffer.place_cursor(self.iter)
162 editor.clear_cursor()
163
164 if editor is back_to:
165 editor.scroll_to_cursor()
166 else:
167 editor.view.scroll_mark_onscreen(editor.buffer.get_insert())
168 editor.focus()
169
Something went wrong with that request. Please try again.