Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 185 lines (142 sloc) 5.7 kB
353fd58 @optilude First attempt at navigation history plugin - mostly works, but back/f…
optilude authored
1 import sublime, sublime_plugin
2 from collections import deque
3
4 MAX_SIZE = 64
5 LINE_THRESHOLD = 2
6
7 class History(object):
8 """Keep track of the history for a single window
9 """
10
11 def __init__(self, max_size=MAX_SIZE):
12 self._back = deque([], max_size)
13 self._forward = deque([], max_size)
14 self._last_location = ("", -100,)
15
16 def push(self, path, line):
17 """Push the given path and line number to indicate the
18 location has changed. Clear the forward history.
19 """
20
21 self._back.append((path, line,))
22 self._forward.clear()
23
24 def mark_location(self, path, line):
25 """Remember the current location, for the purposes of being able
26 to do a has_changed() check.
27 """
28 self._last_location = (path, line,)
29
30 def has_changed(self, path, line):
31 """Determine if the given path/line combination
32 represents a significant enough change to warrant
33 pushing history.
34 """
35
36 old_path, old_line = self._last_location
37
38 if old_path != path:
39 return True
40
41 if abs(line - old_line) > LINE_THRESHOLD:
42 return True
43
44 return False
45
46 def record_movement(self, path, line):
47 """Record movement to the given location, pushing history if
48 applicable
49 """
50
51 if path and line:
52 if self.has_changed(path, line):
53 self.push(path, line)
54 print "pushed", path, line, self._back, self._forward
55 self.mark_location(path, line)
56
57 def back(self, path, line):
58 """Move backward in history, returning the (path, line) tuple to
59 jump to, or (None, None) if the history is empty. Should be passed
60 the current path and line, which will be added to the forward deque.
61 """
62
63 if not self._back:
64 return (None, None,)
65
66 self._forward.appendleft((path, line,))
67 new_path, new_line = self._back.pop()
68
69 # We may still be within the same area as the last recorded jump,
70 # in which case we really want to jump back one more
71 if new_path == path and new_line == line:
72 if self._back:
73 new_path, new_line = self._back.pop()
74
75 self.mark_location(new_path, new_line)
76 return new_path, new_line
77
78 def forward(self, path, line):
79 """Move forward in history, returning the (path, line) tuple to
80 jump to, or (None, None) if the history is empty. Should be passed
81 the current path and line, which will be added to the back deque.
82 """
83
84 if not self._forward:
85 return (None, None,)
86
87 self._back.append((path, line))
88 new_path, new_line = self._forward.popleft()
89
90 # if new_path == path and new_line == line:
91 # if self._forward:
92 # new_path, new_line = self._forward.popleft()
93
94 self.mark_location(new_path, new_line)
95 return new_path, new_line
96
97 _histories = {} # window id -> History
98
99 def get_history():
100 """Get a History object for the current window,
101 creating a new one if required
102 """
103
104 window = sublime.active_window()
105 if window is None:
106 return None
107
108 window_id = window.id()
109 history = _histories.get(window_id, None)
110 if history is None:
111 _histories[window_id] = history = History()
112 return history
113
114 class NavigationHistoryRecorder(sublime_plugin.EventListener):
115 """Keep track of history
116 """
117
118 def on_selection_modified(self, view):
119 """When the selection is changed, possibly record movement in the
120 history
121 """
122 history = get_history()
123 if history is None:
124 return
125
126 path = view.file_name()
127 row, col = view.rowcol(view.sel()[0].a)
128 line = row + 1
129
130 # TODO: This mustn't happen when we move due to back() or
131 # forward()
132 history.record_movement(path, line)
133
134 # def on_close(self, view):
135 # """When a view is closed, check to see if the window was closed too
136 # and clean up orphan histories
137 # """
138 #
139 # # XXX: This doesn't work - event runs before window is removed
140 # # from sublime.windows()
141 #
142 # windows_with_history = set(_histories.keys())
143 # window_ids = set([w.id() for w in sublime.windows()])
144 # closed_windows = windows_with_history.difference(window_ids)
145 # for window_id in closed_windows:
146 # del _histories[window_id]
147
148 class NavigationHistoryBack(sublime_plugin.TextCommand):
149 """Go back in history
150 """
151
152 def run(self, edit):
153 history = get_history()
154 if history is None:
155 return
156
157 old_path = self.view.file_name()
158 row, col = self.view.rowcol(self.view.sel()[0].a)
159 old_line = row + 1
160
161 path, line = history.back(old_path, old_line)
162
163 if path is not None and line is not None:
164 window = sublime.active_window()
165 window.open_file("%s:%d" % (path, line,), sublime.ENCODED_POSITION)
166
167 class NavigationHistoryForward(sublime_plugin.TextCommand):
168 """Go forward in history
169 """
170
171 def run(self, edit):
172 history = get_history()
173 if history is None:
174 return
175
176 old_path = self.view.file_name()
177 row, col = self.view.rowcol(self.view.sel()[0].a)
178 old_line = row + 1
179
180 path, line = history.forward(old_path, old_line)
181
182 if path is not None and line is not None:
183 window = sublime.active_window()
184 window.open_file("%s:%d" % (path, line,), sublime.ENCODED_POSITION)
Something went wrong with that request. Please try again.