Sublime Forum

Split/iterate [regions]

#6

[quote=“castles_made_of_sand”]Except someone else patched Region.iter to return an xrange(r.begin(), r.end()) and all was hell in the world :confused:

IMO, you wanna avoid monkey patches unless really needed[/quote]

:smile: yeah, yeah. It is the same argument made with not prototyping things like array etc in javascript (which is a completely valid argument). It all depends how isolated your code will be, but yeah, if you are going to be communicating with other plugins, then you might have a problem. If you are only talking directly with the API, then you are probably okay. But the same logic could just be contained in a regular function totuplelist that you feed a RegionSet or list of Regions.

[quote=“agibsonsw”]Thank you @facelessuser

[code]Except someone else patched Region.iter to return an xrange(r.begin(), r.end()) and all was hell in the world :confused:

IMO, you wanna avoid monkey patches unless really needed[/code]
I agree, and it turns out I may not need to - but it’s nice to know that I can if necessary :smile:.

Continuing this topic slightly, how can I create a RegionSet? It seems it is only possible via sel() or add_regions?[/quote]

You pretty much answered your own question. It cannot be instantiated from Python. It is Jon’s custom class which he hasen’t really given access to. The easiest way is to bug Jon…or not use it except when accessing set() and add_regions().

0 Likes

#7

[quote]Yeah, monkey patching is seductively cool and there are legitimate uses for it, however that doesn’t seem to be one. I’ve written heaps of plugins I can’t share cause I used a heap of monkey patches.

You can’t actually instantiate a RegionSet, only get a reference to one via view.sel(). You can make a crappy implementation in Python though.[/quote]

There is that too. As long as the API functions don’t really check the types of what you send in, you could use something like that, but if they do, you would then have to convert your PyRegionSet back to a list of of Regions…unless you are only using it for convenience in your code.

0 Likes

#8

not prototyping things like array

Are you talking about JavaScript extending of prototypes?

if you are going to be communicating with other plugins, then you might have a problem

?

0 Likes

#9

As long as the API functions don’t really check the types of what you send in, you could use something like that

[code]>>> rs = PyRegionSet(list(view.sel()))

view.add_regions(‘derpa’, rs, ‘’)
view.get_regions(‘derpa’)
(2131, 2131)]
[/code]

0 Likes

#10

Are you talking about JavaScript extending of prototypes?

NM, I missed the part where you said JavaScript.

0 Likes

#11

[quote=“castles_made_of_sand”]>>> not prototyping things like array

Are you talking about JavaScript extending of prototypes?
[/quote]

Yeah, I meant Javascript. Post corrected.

[quote=“castles_made_of_sand”]

if you are going to be communicating with other plugins, then you might have a problem

?[/quote]

Edit: wrong quote, but this was referring to other people mucking with the same kind of monkey patches.

0 Likes

#12

[quote=“castles_made_of_sand”]>>> As long as the API functions don’t really check the types of what you send in, you could use something like that

[code]>>> rs = PyRegionSet(list(view.sel()))

view.add_regions(‘derpa’, rs, ‘’)
view.get_regions(‘derpa’)
(2131, 2131)]
[/code][/quote]

Good to know.

0 Likes

#13

For the record, I do wish things like iter/hash were defined and indeed, boost::python is designed explicitly for the classes to be re opened. You can’t patch normal C extension builtin objects.

0 Likes

#14

Ahh. You are correct. I had not tested that. I have not used said monkey patch, and was only showing it as a concept, but it appears to be greatly flawed if communicating with the API. C is not so forgiving of class types as python is.

0 Likes

#15

Thanks for the code @castles. I don’t need this yet but shall bear it in mind :sunglasses:

edited = self.view.get_regions("edited_rgns") or ]

I just need two things now:
I want to select from “edited_rgns” based on its index number(s) - facelessuser’s code could do this but I’m not sure I need it just yet.

How would you converge my regions in “edited_rgns”. That is, if two regions are touching (or overlap) how can I convert them into one region please? Although ST seems to occasionally do this of its own accord if one region is contained within another.

0 Likes

#16

Don’t use mine if you intend to modify the Region class. Only use it as its own function that simply converts the regionset. Boost will not like you tampering with the base class.

0 Likes

#17

Well got it working - seems to be behaving :sunglasses:. I’ve re-written my LastEditLine (overnight…) code so that it maintains hidden regions that coincide with the edited content. I can now invoke a quick panel to list and jump to the edited lines :smiley:. It would be really nice if someone gave it a quick test run (please).

{ "keys": "ctrl+alt+j"], "command": "quick_edits" }, { "keys": "ctrl+alt+k"], "command": "prev_edit_line" }, { "keys": "ctrl+alt+l"], "command": "next_edit_line" }

[code]import sublime, sublime_plugin

class PrevEditLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
vid = self.view.id()
sel = self.view.sel()[0]
currA = sel.begin()
currB = sel.end()
curr_line, _ = self.view.rowcol(currA)
edited = self.view.get_regions(“edited_rgns”) or ]
edited_last = self.view.get_regions(“edited_rgn”) or ]
if not edited and not edited_last:
return
edited.extend(edited_last)
self.view.add_regions(“edited_rgns”, edited, “edits”, sublime.HIDDEN)
self.view.erase_regions(“edited_rgn”)
edited = self.view.get_regions(“edited_rgns”) or ]

    for reg in [r for r in reversed(edited) if r.begin() < currA]:
        self.view.sel().clear()
        self.view.show(reg)
        self.view.sel().add(reg)
        break

class NextEditLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
vid = self.view.id()
sel = self.view.sel()[0]
currA = sel.begin()
currB = sel.end()
curr_line, _ = self.view.rowcol(currA)
edited = self.view.get_regions(“edited_rgns”) or ]
edited_last = self.view.get_regions(“edited_rgn”) or ]
if not edited and not edited_last:
return
edited.extend(edited_last)
self.view.add_regions(“edited_rgns”, edited, “edits”, sublime.HIDDEN)
self.view.erase_regions(“edited_rgn”)
edited = self.view.get_regions(“edited_rgns”) or ]

    for reg in [r for r in edited if r.begin() > currA]:
        self.view.sel().clear()
        self.view.show(reg)
        self.view.sel().add(reg)
        break

class QuickEditsCommand(sublime_plugin.TextCommand):
def run(self, edit):
window = sublime.active_window()
view = window.active_view() if window != None else None
if view is None or view.id() != self.view.id():
sublime.status_message(‘Click into the view/tab first.’)
return
edited = self.view.get_regions(“edited_rgns”) or ]
edited_last = self.view.get_regions(“edited_rgn”) or ]
if not edited and not edited_last:
sublime.status_message(‘No edits to list.’)
return
edited.extend(edited_last)
self.view.add_regions(“edited_rgns”, edited, “edits”, sublime.HIDDEN)
self.view.erase_regions(“edited_rgn”)
edited = self.view.get_regions(“edited_rgns”) or ]
the_edits = ]
for i, r in enumerate(edited):
curr_line, _ = self.view.rowcol(r.begin())
curr_text = self.view.substr®
the_edits.append(“Line: %03d %s” % ( curr_line, curr_text ))
window.show_quick_panel(the_edits, self.on_chosen)

def on_chosen(self, index):
    if index == -1: return
    edited = self.view.get_regions("edited_rgns") or ]
    for reg in [r for i, r in enumerate(edited) if i == index]:
        self.view.sel().clear()
        self.view.show(reg)
        self.view.sel().add(reg)
        break

class CaptureEditing(sublime_plugin.EventListener):
def on_modified(self, view):
# create hidden regions that mirror the edited regions
vid = view.id()
sel = view.sel()[0]
currA = sel.begin()
currB = sel.end()
self.curr_line, _ = view.rowcol(currA)
if not hasattr(self, ‘prev_line’):
self.prev_line = self.curr_line
self.lastx = currA
self.lasty = currB
self.curr_edit = sublime.Region(self.lastx, self.lasty)
view.add_regions(“edited_rgn”,[self.curr_edit], “edits”, sublime.HIDDEN)
return
if self.curr_line == self.prev_line:
self.lastx = min(currA, self.lastx)
self.lasty = max(currB, self.lasty)
self.curr_edit = sublime.Region(self.lastx, self.lasty)
view.add_regions(“edited_rgn”,[self.curr_edit], “edits”, sublime.HIDDEN)
else:
self.prev_line = self.curr_line
self.lastx = currA
self.lasty = currB
edited = view.get_regions(“edited_rgns”) or ]
edited_last = view.get_regions(“edited_rgn”) or ]
if not edited and not edited_last:
return
edited.extend(edited_last)
view.add_regions(“edited_rgns”, edited, “edits”, sublime.HIDDEN)
view.erase_regions(“edited_rgn”)
[/code]
It occasionally drops the first letter of the edited text(?) and, as mentioned, I would like to collapse two adjacent regions. Regards, Andy.
LastEditLine.zip (993 Bytes)

0 Likes

#18

I will use

if not len(curr_text.strip()): curr_text = self.view.substr(self.view.line(r)) + " (line)"
so that, if the edit is just whitespace, it will instead display the full line in the quick panel.

It does seem to connect adjoining regions (sometimes…) but I’ll need to test this a bit more. But I still need to resolve it dropping the first edit-character…

0 Likes

#19

This version is working perfectly now!

[code]import sublime, sublime_plugin

def AdjustEdits(view):
edited = view.get_regions(“edited_rgns”) or ]
edited_last = view.get_regions(“edited_rgn”) or ]
if not edited and not edited_last:
return False
edited.extend(edited_last)
view.add_regions(“edited_rgns”, edited, “edits”, sublime.HIDDEN)
view.erase_regions(“edited_rgn”)
return view.get_regions(“edited_rgns”) or ]

class PrevEditLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
vid = self.view.id()
currA = self.view.sel()[0].begin()
edited = AdjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to go to.’)
return
for reg in [r for r in reversed(edited) if r.begin() < currA]:
self.view.sel().clear()
self.view.show(reg)
self.view.sel().add(reg)
break
else:
sublime.status_message(‘No edits further up.’)

class NextEditLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
vid = self.view.id()
currA = self.view.sel()[0].begin()
edited = AdjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to go to.’)
return
for reg in [r for r in edited if r.begin() > currA]:
self.view.sel().clear()
self.view.show(reg)
self.view.sel().add(reg)
break
else:
sublime.status_message(‘No edits further down.’)

class QuickEditsCommand(sublime_plugin.TextCommand):
def run(self, edit):
window = sublime.active_window()
view = window.active_view() if window != None else None
if view is None or view.id() != self.view.id():
sublime.status_message(‘Click into the view/tab first.’)
return
self.vid = self.view.id()
edited = AdjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to list.’)
return
the_edits = ]
for i, r in enumerate(edited):
curr_line, _ = self.view.rowcol(r.begin())
curr_text = self.view.substr®.strip()
if not len(curr_text):
curr_text = self.view.substr(self.view.line®).strip():40]
+ " (line)"
the_edits.append(“Line: %03d %s” % ( curr_line + 1, curr_text ))
window.show_quick_panel(the_edits, self.on_chosen)

def on_chosen(self, index):
    if index == -1: return
    window = sublime.active_window()
    view = window.active_view() if window != None else None
    if view is None or view.id() != self.vid:
        sublime.status_message('You are in a different view.')
        return
    edited = self.view.get_regions("edited_rgns") or ]
    for reg in [r for i, r in enumerate(edited) if i == index]:
        self.view.sel().clear()
        self.view.show(reg)
        self.view.sel().add(reg)
        break

class CaptureEditing(sublime_plugin.EventListener):
def on_modified(self, view):
# create hidden regions that mirror the edited regions
vid = view.id()
sel = view.sel()[0]
currA, currB = (sel.begin(), sel.end())
self.curr_line, _ = view.rowcol(currA)
if not hasattr(self, ‘prev_line’):
self.prev_line = self.curr_line
if currA > 0 and sel.empty():
currA -= 1
self.lastx, self.lasty = (currA, currB)
self.curr_edit = sublime.Region(self.lastx, self.lasty)
view.add_regions(“edited_rgn”,[self.curr_edit], “edits”, sublime.HIDDEN)
return
if self.curr_line == self.prev_line:
self.lastx = min(currA, self.lastx)
self.lasty = max(currB, self.lasty)
self.curr_edit = sublime.Region(self.lastx, self.lasty)
view.add_regions(“edited_rgn”,[self.curr_edit], “edits”, sublime.HIDDEN)
else:
self.prev_line = self.curr_line
if currA > 0 and sel.empty():
currA -= 1
self.lastx, self.lasty = (currA, currB)
_ = AdjustEdits(view)[/code]
I’m not really interested in jumping between views (as some others have done) nor in ordering them by edit-time, or storing the information between sessions. However, I retain an open mind so wont ignore requests :wink: .

The only other thing I’m considering at the moment is to, perhaps, toggle highlighting of edited text.

BTW There are already alternative versions of this available on PackageControl - but not as good as mine, he, he! Andy.

Added: I might try a combine consecutive edited lines though…
AndyEdits.zip (1.1 KB)

0 Likes

#20

Wow, that didn’t take long! Consecutive edited-lines will be treated as one edit:

[code]import sublime, sublime_plugin

def AdjustEdits(view):
edited = view.get_regions(“edited_rgns”) or ]
edited_last = view.get_regions(“edited_rgn”) or ]
if not edited and not edited_last:
return False
new_edits = ]
edited.extend(edited_last)
for i, r in enumerate(edited):
if i > 0 and r.begin() == prev_end:
new_edits.append(sublime.Region(prev_begin, r.end()))
else:
new_edits.append®
prev_begin, prev_end = (r.begin(), r.end())

view.add_regions("edited_rgns", new_edits, "edits", sublime.HIDDEN)
view.erase_regions("edited_rgn")
return view.get_regions("edited_rgns") or ]

class PrevEditLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
vid = self.view.id()
currA = self.view.sel()[0].begin()
edited = AdjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to go to.’)
return
for reg in [r for r in reversed(edited) if r.begin() < currA]:
self.view.sel().clear()
self.view.show(reg)
self.view.sel().add(reg)
break
else:
sublime.status_message(‘No edits further up.’)

class NextEditLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
vid = self.view.id()
currA = self.view.sel()[0].begin()
edited = AdjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to go to.’)
return
for reg in [r for r in edited if r.begin() > currA]:
self.view.sel().clear()
self.view.show(reg)
self.view.sel().add(reg)
break
else:
sublime.status_message(‘No edits further down.’)

class QuickEditsCommand(sublime_plugin.TextCommand):
def run(self, edit):
window = sublime.active_window()
view = window.active_view() if window != None else None
if view is None or view.id() != self.view.id():
sublime.status_message(‘Click into the view/tab first.’)
return
self.vid = self.view.id()
edited = AdjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to list.’)
return
the_edits = ]
for i, r in enumerate(edited):
curr_line, _ = self.view.rowcol(r.begin())
curr_text = self.view.substr®.strip()
if not len(curr_text):
curr_text = self.view.substr(self.view.line®).strip():40]
+ " (line)"
the_edits.append(“Line: %03d %s” % ( curr_line + 1, curr_text ))
window.show_quick_panel(the_edits, self.on_chosen)

def on_chosen(self, index):
    if index == -1: return
    window = sublime.active_window()
    view = window.active_view() if window != None else None
    if view is None or view.id() != self.vid:
        sublime.status_message('You are in a different view.')
        return
    edited = self.view.get_regions("edited_rgns") or ]
    for reg in [r for i, r in enumerate(edited) if i == index]:
        self.view.sel().clear()
        self.view.show(reg)
        self.view.sel().add(reg)
        break

class CaptureEditing(sublime_plugin.EventListener):
def on_modified(self, view):
# create hidden regions that mirror the edited regions
vid = view.id()
sel = view.sel()[0]
currA, currB = (sel.begin(), sel.end())
self.curr_line, _ = view.rowcol(currA)
if not hasattr(self, ‘prev_line’):
self.prev_line = self.curr_line
if currA > 0 and sel.empty():
currA -= 1
self.lastx, self.lasty = (currA, currB)
self.curr_edit = sublime.Region(self.lastx, self.lasty)
view.add_regions(“edited_rgn”,[self.curr_edit], “edits”, sublime.HIDDEN)
return
if self.curr_line == self.prev_line:
self.lastx = min(currA, self.lastx)
self.lasty = max(currB, self.lasty)
self.curr_edit = sublime.Region(self.lastx, self.lasty)
view.add_regions(“edited_rgn”,[self.curr_edit], “edits”, sublime.HIDDEN)
else:
self.prev_line = self.curr_line
if currA > 0 and sel.empty():
currA -= 1
self.lastx, self.lasty = (currA, currB)
_ = AdjustEdits(view)[/code]

0 Likes

#21

Finished! I can toggle the display of the edited regions (Ctrl+Alt+H) and they are persistent. That is, if you close the application then they will persist, but not if you close the file/view (this is how persistence behaves by default in ST).

{ "keys": "ctrl+alt+h"], "command": "toggle_edits" }, { "keys": "ctrl+alt+j"], "command": "quick_edits" }, { "keys": "ctrl+alt+k"], "command": "prev_edit_line" }, { "keys": "ctrl+alt+l"], "command": "next_edit_line" }

[code]import sublime, sublime_plugin

def AdjustEdits(view):
edited = view.get_regions(“edited_rgns”) or ]
edited_last = view.get_regions(“edited_rgn”) or ]
if not edited and not edited_last:
return False
new_edits = ]
edited.extend(edited_last)
for i, r in enumerate(edited):
if i > 0 and r.begin() == prev_end:
new_edits.append(sublime.Region(prev_begin, r.end()))
else:
new_edits.append®
prev_begin, prev_end = (r.begin(), r.end())

view.add_regions("edited_rgns", new_edits, "edits", \
    sublime.HIDDEN | sublime.PERSISTENT)
view.erase_regions("edited_rgn")
return view.get_regions("edited_rgns") or ]

class ToggleEditsCommand(sublime_plugin.TextCommand):
def run(self, edit):
edited = AdjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to show or hide.’)
return
toggled = self.view.get_regions(“toggled_edits”) or ]
if toggled:
self.view.erase_regions(“toggled_edits”)
else:
self.view.add_regions(“toggled_edits”, edited, “keyword”,
sublime.DRAW_OUTLINED)

class PrevEditLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
vid = self.view.id()
currA = self.view.sel()[0].begin()
edited = AdjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to go to.’)
return
for reg in [r for r in reversed(edited) if r.begin() < currA]:
self.view.sel().clear()
self.view.show(reg)
self.view.sel().add(reg)
break
else:
sublime.status_message(‘No edits further up.’)

class NextEditLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
vid = self.view.id()
currA = self.view.sel()[0].begin()
edited = AdjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to go to.’)
return
for reg in [r for r in edited if r.begin() > currA]:
self.view.sel().clear()
self.view.show(reg)
self.view.sel().add(reg)
break
else:
sublime.status_message(‘No edits further down.’)

class QuickEditsCommand(sublime_plugin.TextCommand):
def run(self, edit):
window = sublime.active_window()
view = window.active_view() if window != None else None
if view is None or view.id() != self.view.id():
sublime.status_message(‘Click into the view/tab first.’)
return
self.vid = self.view.id()
edited = AdjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to list.’)
return
the_edits = ]
for i, r in enumerate(edited):
curr_line, _ = self.view.rowcol(r.begin())
curr_text = self.view.substr®.strip():40]
if not len(curr_text):
curr_text = self.view.substr(self.view.line®).strip():40]
+ " (line)"
the_edits.append(“Line: %03d %s” % ( curr_line + 1, curr_text ))
window.show_quick_panel(the_edits, self.on_chosen)

def on_chosen(self, index):
    if index == -1: return
    window = sublime.active_window()
    view = window.active_view() if window != None else None
    if view is None or view.id() != self.vid:
        sublime.status_message('You are in a different view.')
        return
    edited = self.view.get_regions("edited_rgns") or ]
    for reg in [r for i, r in enumerate(edited) if i == index]:
        self.view.sel().clear()
        self.view.show(reg)
        self.view.sel().add(reg)
        break

class CaptureEditing(sublime_plugin.EventListener):
def on_modified(self, view):
# create hidden regions that mirror the edited regions
vid = view.id()
sel = view.sel()[0]
currA, currB = (sel.begin(), sel.end())
self.curr_line, _ = view.rowcol(currA)
if not hasattr(self, ‘prev_line’):
self.prev_line = self.curr_line
if currA > 0 and sel.empty():
currA -= 1
self.lastx, self.lasty = (currA, currB)
self.curr_edit = sublime.Region(self.lastx, self.lasty)
view.add_regions(“edited_rgn”,[self.curr_edit], “edits”,
sublime.HIDDEN | sublime.PERSISTENT)
return
if self.curr_line == self.prev_line:
self.lastx = min(currA, self.lastx)
self.lasty = max(currB, self.lasty)
self.curr_edit = sublime.Region(self.lastx, self.lasty)
view.add_regions(“edited_rgn”,[self.curr_edit], “edits”,
sublime.HIDDEN | sublime.PERSISTENT)
else:
self.prev_line = self.curr_line
if currA > 0 and sel.empty():
currA -= 1
self.lastx, self.lasty = (currA, currB)
_ = AdjustEdits(view)[/code]
Not bad for a few hours work - I might actually use this :laughing:
AndyEdits.zip (1.28 KB)

0 Likes

#22

Talking of JavaScript prototypes…

Date.prototype.format = function (sFormat, twelve) { // Returns: A string version of the date. // Usage: date_instance.format("d mmm yy hh:nn:ss ap") or // date_instance.format("dddd dd mmmm hh:nn", true) // Defaults to YYYY/MM/DD. // twelve == true for a 12hr clock, or just AP or ap within // sFormat (for AM/PM or am/pm). // Use z or zzz for milliseconds and xx for suffixes (st, nd, etc.). var MonthNames = "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; var DayNames = "Sunday", "Monday", "Tueday", "Wednesday", "Thursday", "Friday", "Saturday" ]; var dDate = this || new Date(), D = dDate.getDate(), DDDD = DayNames[dDate.getDay()], DDD = DDDD.substr(0,3), M = dDate.getMonth()+1, MMMM = MonthNames[dDate.getMonth()], MMM = MMMM.substr(0,3), YYYY = dDate.getFullYear(), YY = ('' + YYYY).substr(2, 2), H = dDate.getHours(), N = dDate.getMinutes(), S = dDate.getSeconds(), Z = dDate.getMilliseconds(), ap = (H > 11) ? "pm" : "am", // pad with leading zeros, if required DD = ( D < 10 ? "0" : "" ) + D, MM = ( M < 10 ? "0" : "" ) + M, NN = ( N < 10 ? "0" : "" ) + N, SS = ( S < 10 ? "0" : "" ) + S, ZZZ = ( Z < 10 ? "00" : (Z < 100 ? "0" : "") ) + Z, XX; var AP = (sFormat && (sFormat.toUpperCase().indexOf('AP')+1)) ? ((sFormat.indexOf('ap')+1) ? ap : ap.toUpperCase()) : ''; if (twelve || AP) { H = (H < 12) ? (H || 12) : ((H - 12) || 12); } var HH = ( H < 10 ? "0" : "" ) + H; XX = (D == 1 || D == 21 || D == 31) ? "st" : ((D == 2 || D == 22) ? "nd" : ((D == 3 || D == 23) ? "rd" : "th")); sFormat = ( sFormat ) ? sFormat.toUpperCase() : 'YYYY/MM/DD'; var sParsed = sFormat.replace(/D{1,4}|M{1,4}|Y{2,4}|H{1,2}|N{1,2}|S{1,2}|Z{1,3}|XX|AP/g, function (m) { try { return eval(m); } catch (e) { return ''; } }); return sParsed; };

I appreciate the arguments about JS prototypes, but this is one exception I’m happy to use. I suppose it could be named **andyFormat ** :sunglasses:
[There are other versions than mine, but mine distinguishes between [b]AM and **am **and enables **suffixes **1st ,2nd etc…]

0 Likes

#23

Attached screenshot.


0 Likes

#24

Second/last screenshot.


0 Likes

#25

Sorry, but I should offer the following version which prevents anything happening if you are not in a View; that is, if you are in the Find dialog, or anywhere else.

[code]import sublime, sublime_plugin

def adjustEdits(view):
edited = view.get_regions(“edited_rgns”) or ]
edited_last = view.get_regions(“edited_rgn”) or ]
if not edited and not edited_last:
return False
new_edits = ]
edited.extend(edited_last)
for i, r in enumerate(edited):
if i > 0 and r.begin() == prev_end:
new_edits.append(sublime.Region(prev_begin, r.end()))
else:
new_edits.append®
prev_begin, prev_end = (r.begin(), r.end())

view.add_regions("edited_rgns", new_edits, "keyword", \
    sublime.HIDDEN | sublime.PERSISTENT)
view.erase_regions("edited_rgn")
return view.get_regions("edited_rgns") or ]

def showRegion(view, reg):
view.sel().clear()
view.show(reg)
view.sel().add(reg)

class ToggleEditsCommand(sublime_plugin.TextCommand):
def run(self, edit):
window = sublime.active_window()
view = window.active_view() if window != None else None
if view is None or view.id() != self.view.id():
sublime.status_message(‘Click into the view/tab first.’)
return
edited = adjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to show or hide.’)
return
toggled = self.view.get_regions(“toggled_edits”) or ]
if toggled:
self.view.erase_regions(“toggled_edits”)
else:
self.view.add_regions(“toggled_edits”, edited,
“keyword”, sublime.DRAW_OUTLINED)

class PrevEditLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
window = sublime.active_window()
view = window.active_view() if window != None else None
if view is None or view.id() != self.view.id():
sublime.status_message(‘Click into the view/tab first.’)
return
currA = self.view.sel()[0].begin()
edited = adjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to go to.’)
return
for reg in [r for r in reversed(edited) if r.begin() < currA]:
showRegion(self.view, reg)
break
else:
sublime.status_message(‘No edits further up.’)

class NextEditLineCommand(sublime_plugin.TextCommand):
def run(self, edit):
window = sublime.active_window()
view = window.active_view() if window != None else None
if view is None or view.id() != self.view.id():
sublime.status_message(‘Click into the view/tab first.’)
return
currA = self.view.sel()[0].begin()
edited = adjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to go to.’)
return
for reg in [r for r in edited if r.begin() > currA]:
showRegion(self.view, reg)
break
else:
sublime.status_message(‘No edits further down.’)

class QuickEditsCommand(sublime_plugin.TextCommand):
def run(self, edit):
window = sublime.active_window()
view = window.active_view() if window != None else None
if view is None or view.id() != self.view.id():
sublime.status_message(‘Click into the view/tab first.’)
return
self.vid = self.view.id()
edited = adjustEdits(self.view)
if not edited:
sublime.status_message(‘No edits to list.’)
return
the_edits = ]
for i, r in enumerate(edited):
curr_line, _ = self.view.rowcol(r.begin())
curr_text = self.view.substr®.strip():40]
if not len(curr_text):
curr_text = self.view.substr(self.view.line®).strip():40]
+ " (line)"
the_edits.append(“Line: %03d %s” % ( curr_line + 1, curr_text ))
window.show_quick_panel(the_edits, self.on_chosen)

def on_chosen(self, index):
    if index == -1: return
    window = sublime.active_window()
    view = window.active_view() if window != None else None
    if view is None or view.id() != self.vid:
        sublime.status_message('You are in a different view.')
        return
    edited = self.view.get_regions("edited_rgns") or ]
    for reg in [r for i, r in enumerate(edited) if i == index]:
        showRegion(self.view, reg)
        break

class CaptureEditing(sublime_plugin.EventListener):
def on_modified(self, view):
# create hidden regions that mirror the edited regions
window = sublime.active_window()
curr_view = window.active_view() if window != None else None
if curr_view is None or curr_view.id() != view.id():
return
sel = view.sel()[0]
currA, currB = (sel.begin(), sel.end())
self.curr_line, _ = view.rowcol(currA)
if not hasattr(self, ‘prev_line’):
self.prev_line = self.curr_line
if currA > 0 and sel.empty():
currA -= 1
self.lastx, self.lasty = (currA, currB)
self.curr_edit = sublime.Region(self.lastx, self.lasty)
view.add_regions(“edited_rgn”,[self.curr_edit],
“keyword”, sublime.HIDDEN | sublime.PERSISTENT)
return
if self.curr_line == self.prev_line:
self.lastx = min(currA, self.lastx)
self.lasty = max(currB, self.lasty)
self.curr_edit = sublime.Region(self.lastx, self.lasty)
view.add_regions(“edited_rgn”,[self.curr_edit],
“keyword”, sublime.HIDDEN | sublime.PERSISTENT)
else:
self.prev_line = self.curr_line
if currA > 0 and sel.empty():
currA -= 1
self.lastx, self.lasty = (currA, currB)
_ = adjustEdits(view)[/code]

0 Likes