Sublime Forum

Goto Last Edit

#1

I used this feature from Netbeans alot. A shortcut to go with you cursor to the code line/column, where you did your last edit. If you press the shortcut again, you get to the position before that … and so on.

Very handy every time you look up something in the code and want to get back to work afterwards.

0 Likes

#2

+1 from me.

0 Likes

#3

+1 from me. This feature is really good.

Even better if it is project based instead of just file based.

0 Likes

#4

+1 here. Is there perhaps a plugin for this?

0 Likes

#5

+1

0 Likes

#6

Hi,

I’ve developed a plugin with this functionality you can find it here: https://github.com/khrizt/GotoLastEdit… this is my first plugin so please any advice, comment or fix would be appreciated

0 Likes

#7

I’ve not looked at your version in detail, mainly because I’ve been playing/studying this myself :smile:. You should be able to add CE = CaptureEditing within the TextCommand as well, which will make the code easier to read. I would prefer not to maintain five separate dictionaries… but, hey!, “if it works…” :sunglasses:. And, like myself (and most others) it lacks commentary :wink:

From previous posts it seems that people are keen that the edit positions should jump between files. Personally, I prefer the navigation to occur within each file separately.

I’ll post my current version out of interest/ for comparison. It ignores the Enter key as an edit position; if you are currently on an edited line it should, instead, move to a different edited line. And, most significantly, it should still highlight the *correct *edited line, even if you’ve deleted, copied, duplicated, etc., text.

[code]import sublime, sublime_plugin

POSNS = {} # Based on each view’s id, store edited positions.
# The first element stores the most recently edited line
# number, so that the same line is not saved repeatedly.

class LastEditLineCommand(sublime_plugin.TextCommand):
posn = -1 # always add 1 to this, which indexes the first
# edited position (for the current view)
def run(self, edit):
vid = self.view.id()
# if there are no edited positions stored, just return
if not POSNS.has_key(vid): return
# identify the previously edited position
self.posn = (self.posn + 1) % (len(POSNS[vid]) - 1)
# if already on the next edited line, go to the previous edit
if self.view.full_line(self.view.sel()[0]).contains(POSNS[vid]-(self.posn + 1)]):
self.posn = (self.posn + 1) % (len(POSNS[vid]) - 1)
self.view.sel().clear()
# bring the edited position into view and select the line
self.view.show(POSNS[vid]-(self.posn + 1)])
self.view.sel().add(self.view.line(POSNS[vid]-(self.posn + 1)]))

class CaptureEditing(sublime_plugin.EventListener):
def on_modified(self, view):
vid = view.id()
sel = view.sel()[0]
curr_pos = sel.end()
curr_line, _ = view.rowcol(curr_pos)
if not POSNS.has_key(vid): # if a dictionary entry doesn’t already
# exist for this view…
POSNS[vid] = [curr_line, curr_pos]
self.prev_size = view.size() # store the initial size
return
self.curr_size = view.size()
self.diff = self.curr_size - self.prev_size # has the file grown/shrunk?
for index, value in enumerate(POSNS[vid]):
if index > 0 and value > curr_pos:
# for every saved position, increase or reduce it by the
# difference in file size (but only if it’s beyond the cursor)
if self.diff > 0:
POSNS[vid][index] = min(value + self.diff, self.curr_size - 1)
# min is used in case the edited position has been deleted
elif self.diff < 0:
POSNS[vid][index] = max(value + self.diff, curr_pos)
# max is used so that we don’t go beyond the end of the file
self.prev_size = self.curr_size
# if they haven’t pressed Enter, and they are not on the same line…
if view.substr(sublime.Region(0,curr_pos))-1] != ‘\n’
and POSNS[vid][0] != curr_line:
POSNS[vid].append(curr_pos) # … store the edited position,
POSNS[vid][0] = curr_line # and update the current line
if len(POSNS[vid]) > 6: POSNS[vid].pop(1)[/code]
I need to test it a lot more, and there’s tweaks I’d like to implement. For example, because the event always runs once, the first line of the view is treated as an edit position. This doesn’t concern me too much. But I’d like it to behave a bit better in terms of deciding which edit position should be jumped too on different occasions.

I could edit it such that it wouldn’t store edit positions for the same line more than once; that is, if you edit a line, a different line, and then edit the original line again, it currently treats these as an additional edit. But I’m not sure that this should be an issue. After all, I did edit the line more than once ?!

0 Likes

#8

Actually, I think it’s worth considering the following edit:

if view.substr(sublime.Region(0,curr_pos))-1] != '\n' \ and abs(POSNS[vid][0] - curr_line) > 2:
That is, don’t register an edit position if it is within two lines of the existing (current) edit position. Otherwise, typing a few lines of code will remove previous (more useful) edit positions. :question:

0 Likes

#9

Hi,

I’ve added your suggestion as a Issue in github… https://github.com/khrizt/GotoLastEdit/issues/3 I’ll do that as soon as possible.

Thanks

0 Likes

#10

I’m liking this version - it’s beginning to take shape :smile:. It highlights not just the edited line, but the actual text that was edited, and this text is still highlighted even after deleting, copying, etc., other text. (But it needs a bit more testing… :wink: )

[code]import sublime, sublime_plugin, re

POSNS = {} # Based on each view’s id, store edited positions.
# The first element stores the most recently edited line
# number, so that the same line is not saved repeatedly.

class LastEditLineCommand(sublime_plugin.TextCommand):
posn = -1 # always add 2 to this, which indexes the first
# edited position (for the current view)
def run(self, edit):
vid = self.view.id()
# if there are no edited positions stored, just return
if not POSNS.has_key(vid): return
# identify the previously edited position
self.posn = (self.posn + 2) % (len(POSNS[vid]) - 1)
edited_region = sublime.Region(POSNS[vid]-(self.posn + 1)], POSNS[vid]-self.posn])
self.view.sel().clear()
# bring the edited position into view and select the region
self.view.show(edited_region)
self.view.sel().add(edited_region)

class CaptureEditing(sublime_plugin.EventListener):
# def init(self): POSNS = {}
def on_modified(self, view):
vid = view.id()
sel = view.sel()[0]
currA = sel.begin()
currB = sel.end()
curr_line, _ = view.rowcol(currB)
if not POSNS.has_key(vid): # if a dictionary entry doesn’t already
# exist for this view…
POSNS[vid] = [curr_line, currA - sel.empty(), currB]
self.prev_size = view.size() # store the initial size
return
self.curr_size = view.size()
self.diff = self.curr_size - self.prev_size # has the file grown/shrunk?
self.prev_size = self.curr_size
for index, value in enumerate(POSNS[vid]):
if index > 0 and value >= currB:
# for every saved position, increase or reduce it by the
# difference in file size (but only if it’s beyond the cursor)
if self.diff > 0:
POSNS[vid][index] = min(value + self.diff, self.curr_size - 1)
# min is used so that we don’t go beyond the end of the file
elif self.diff < 0:
POSNS[vid][index] = max(value + self.diff, currA)
# max is used in case the edited position has been deleted
if POSNS[vid][0] == curr_line or abs(POSNS[vid]-2] - currA) == 1
or abs(POSNS[vid]-1] - currB) == 1:
POSNS[vid]-2] = min(POSNS[vid]-2], currA)
POSNS[vid]-1] = max(POSNS[vid]-1], currB)
else:
POSNS[vid].extend([currA - sel.empty(), currB]) # add the edited position
if len(POSNS[vid]) > 11: POSNS[vid][1:] = POSNS[vid][3:]
POSNS[vid][0] = curr_line # update the current line[/code]
@khrizt My apologies :smile:. I’m not trying to compete in any way, it’s just that I’m studying as well, and this has been a very useful exercise. Andy.

0 Likes

#11

[quote=“khrizt”]Hi,

I’ve added your suggestion as a Issue in github… https://github.com/khrizt/GotoLastEdit/issues/3 I’ll do that as soon as possible.

Thanks[/quote]

My latest version kinda gets round this issue, as it remembers the edited region. Andy.

**PS **I want to leave this alone now (as it’s working perfectly :smiley: ) but I’ll correct it if anyone spots a bugget. https://gist.github.com/1993147

0 Likes

#12

Hey khrizt and Andy, just to post that I started using this in Windows Vista, however, the default keymap has ctrl+q assigned to recording macros. That needs to be disabled for this to work. But no big problem :smile:

0 Likes

#13

Hi Arin,

I didn’t know that… what key binding do you suggest for Windows, I’ll change that in the next version

0 Likes

#14

[quote=“khrizt”]Hi Arin,

I didn’t know that… what key binding do you suggest for Windows, I’ll change that in the next version[/quote]

Hey, really sorry about the late reply. I just disabled recording macros… I am not really that well informed about the key bindings, I would leave it to other users here.

0 Likes