Sublime Forum

ST2/3 Edit Abstraction

#1

While porting some of my plugins to ST3, I was annoyed enough with the edit changes (view.insert, replace, erase can only be used in a TextCommand now) to make an edit abstraction with easy syntax that works with both ST2 and ST3.

https://github.com/lunixbochs/SublimeXiki/blob/st3/edit.py

This module allows use of insert, replace, and erase. It also batches all edits made inside the “with” block so they appear as one “edit” to Sublime.

Hopefully this makes your life easier if you enjoy writing text manipulation plugins as much as me :wink:

Example (should work in both ST2 and ST3):

with Edit(view) as edit: edit.insert(0, 'hi\n') edit.insert(0, 'more stuff\n')


Compare to:

ST2 edit:

edit = view.begin_edit() view.insert(edit, 0, 'hi\n') view.insert(edit, 0, 'more stuff\n') view.end_edit(edit)
ST3 edit (repeat for erase, replace? or roll your own / use callbacks if you want multiple operations in a single edit):

[code]class InsertCommand(sublime_plugin.TextCommand):
def run(self, edit, pos, text):
self.view.insert(edit, pos, text)

view.run_command(‘insert’, {‘pos’: 0, ‘text’: ‘hi\n’})
view.run_command(‘insert’, {‘pos’: 0, ‘text’: ‘more stuff\n’})[/code]

1 Like

How to insert text to View?
Porting begin_edit() ... end_edit() code
Porting begin_edit() ... end_edit() code
#2

Awesome. Would be great to publish more of these abstractions.

0 Likes

#3

Thanks!

0 Likes

#4

This is awesome. Thank you.

0 Likes

#5

Really like it, can’t think of any way to improve it right now.

I found this in this commit and since we already have something “similar” for ST2 in sublime_lib I’d like to add this too when migrating to ST3.

Hopefully, Package Control will, at some point, get a decent dependency and python-only packages so other packages/pugins can use sublime_lib without requiring AAAPackageDev (which could then finally be renamed to “PackageDev”). Really excited about that.

Edit: Well, there is a way to improve it, imo. Instead of monkeypatching “sublime.edit_storage” you could use a global (in that module) or just pass “self.run” as is, because command arguments are preserved even if they are non-linear types (like a function/method here). Should not be unsafe because the Edit instance will be unreferenced anyway at the execution of exit, as long as the programmer uses it sanely.

0 Likes

#6

This wasn’t my experience. I had bad results when I put persistent data anywhere but in an imported Python module. I picked sublime.edit_storage because I could guarantee a working import (sublime) in both ST2/3. When I tried storing it in other places (like the current module) or passing the callback directly, I had issues with edits failing.

0 Likes

#7

[quote=“FichteFoll”]Hopefully, Package Control will, at some point, get a decent dependency and python-only packages so other packages/pugins can use sublime_lib without requiring AAAPackageDev (which could then finally be renamed to “PackageDev”). Really excited about that.
[/quote]

The load order is still controlled by ST, so I wouldn’t get your hopes up.

Dependency management and things like it are on my mind, but unlikely to happen in the near term just dealing with what I have on my plate for now. More than happy to have contributions to the discussion github.com/wbond/sublime_packag … issues/166. Mostly someone needs to come up with a good plan for dealing with dependencies. Probably not going to be able to pin dependencies to specific versions since everything is loaded into a single process. But yeah, install-time dependency resolution would be great.

0 Likes

#8

Yes, this is true. However, in ST3 (mainly) you can also directly import modules that are not exactly a plugin because the packages directory is added to sys.path. At least this is what I think, so you should be able to load required modules if you need them without relying on ST’s load order. And if that doesn’t work you can also import in “plugin_loaded()”.

[quote=“wbond”]
Dependency management and things like it are on my mind, but unlikely to happen in the near term just dealing with what I have on my plate for now. More than happy to have contributions to the discussion github.com/wbond/sublime_packag … issues/166. Mostly someone needs to come up with a good plan for dealing with dependencies. Probably not going to be able to pin dependencies to specific versions since everything is loaded into a single process. But yeah, install-time dependency resolution would be great.[/quote]

I am monitoring that issue and plan to step onto the discussion 1) when PC2.0 is ready and 2) when I have a decent (implementation) idea. I’m perfectly fine with no version dependencies because that introcudes a bunch of complexity for both, the dependency and the depedency-using packages (even a simple thing). But well, this does not really belong here but in #166.

Edit: While I think about this, it could lead to terrible name clashes (e.g. “YAML” package and “yaml” Python module)…

0 Likes

#9

So toss them in a package folder - you can import somethingunique.yaml instead of just yaml if you don’t want name collisions

0 Likes

#10

[quote=“lunixbochs”]

So toss them in a package folder - you can import somethingunique.yaml instead of just yaml if you don’t want name collisions[/quote]

Yes, I could do that. I could just as well just name it “pyyaml” instead but that is out of the purpose because in real world Python you use “import yaml” and not “import pyyaml” or “import somepackage.yaml”. So I currently see one main with two sub options:

  1. Let the package manager wrap all these packages into their own dictionary. Probably preceded by some characters that are guaranteed to be the first in Sublime Text’s loading precedence or at least show visually that there’s not a package in this folder.
    1.1. Let packages include these using “import _pc.yaml” for example. (ST3 only but no name clashes)
    1.2. Have a “plugin” that adds the above directory to “sys.path” and thus enables plugins to write “import yaml”. While this would work for both ST2 and ST3 it also reintroduces name clashes because “Packages/yaml” and “Packages/_pc/yaml” would again both map to “yaml” (example, the real YAML packages is written in caps which I think makes a difference).

Either way, this is not the right place to discuss this even though this small snippet would certainly be useful when distributable.

0 Likes

Elastic tabs
#11

github.com/FichteFoll/AAAPackag … ib/edit.py

I changed it a bit:

  • Added some documentation.
  • Removed sel method, because I have no idea what it is supposed to do.
  • Removed FutureEdit stuff that you added recently and instead check if a parameter is “callable”. Reduced the required amount of code.
  • Added classmethod Edit.call(func) which is basically with Edit(edit) as edit: edit.callback(func). With this you just need to write a function like TextCommand.run and pass it.
0 Likes

#12

FYI, my latest incarnation of it is in ActualVim: github.com/lunixbochs/actualvim … er/edit.py

I have defer vs call. I use Edit for selection, because sometimes you need a command to kick through a proper buffer refresh.

0 Likes