Sublime Forum

[SOLVED] issue using "edit" objects recursively

#2

The code sample doesn’t really help me much, but I can suggest the following:

Always use the edit object you get handed in the TextCommand’s run method and then forward that explicitly to synchronous function calls if necessary.

The reason is that edit objects are opened and closed internally before and after your run method is called and behavior will be unpredictable if you use the edit object after it has been closed already. Furthermore, you can nest TextCommands (i.e. call a text command within a text command) and every change made during the existance of the outer edit object will get grouped into it for undoing purposes, which means there is an implicit hierarchy between edit objects. I do not know what happens when you use the outer edit object while an inner object still exists.

Maybe this can help you spot the actual problem because there is no real error description included in your post (besides “doesn’t work”).

2 Likes

#3

From the error message I think FichterFoll is correct about edit object, your edit.edit_token is gone.
Without the complete code it’s difficult to tell why but from your sample I can tell you that storing the edit object (especially in a global variable) is a bad idea.

0 Likes

#4

I tried to be as detailed as possible between the code sample & error log. I figured the Traceback & raise ValueError in the error log would provide context of the actual error. How can I provide a more informative error description?

The issue I’m running into, now that I’ve removed the manual edit handling, is:
error: plugin_host has exited unexpectedly, plugin functionality won't be available until Sublime Text has been restarted

I’m going to post some functional code when I get a chance to prep some working & non-working examples.

0 Likes

#5

Oh, never mind, I didn’t realize that your code block contained the traceback. Good thing I was on the right track regardless.

0 Likes

#6

@FichteFoll @bizoo



I’ve reduced the code from around 1500 lines to 200.
The plugin now contains only the core functionality required to reproduce the error.

#@ GitHub



The demo GIF below shows the plugin_host crash.

The demo macro does the following:

    [1] initialize MacroScript ( reset view object )
    [2] copy text from the original document to a new document
    [3] delete all text outside of the target region
    [4] replace all instances of the word “def” with “__REPLACED__”

I can’t figure out the issue, because command section [4] is actually executing successfully (as you can see in the GIF). I’m unsure why the plugin is crashing AFTER running the command.

0 Likes

[Proof Of Concept] Visual Progress Bar
#7

I think you replied to yourself, basically you using the edit object of a view into other view. Is that causing the error? Im not sure if that should work or not, but looks to me that should not work.
At first I tried to look into the error when you first reported it but I found all the fancy comments very distracting :stuck_out_tongue:

Suggestion, use this file https://github.com/titoBouzout/Open-Include/blob/master/Edit.py as

try:
    from .Edit import Edit as Edit
except:
    from Edit import Edit as Edit

then, use it like this:

        with Edit(view) as edit:
            edit.insert(0, 'asdadasd') # tada!  an edit object

Ill not explain, I guess you will find a way to use it when the edit object is obsolete or something, or maybe use it always

credits to user lunixbochs for this handy thing

2 Likes

How to run part of my plugin in the second thread properly?
[SOLVED] [st3] Edit object, outside run method has return: How to?
#8

 

Thanks man, this works great on the error-demo code!   :grin: :+1:

I’m going to try it on the full code now.

 



 

Is there any reason you have to use:

with Edit(view) as edit:

?

 

I tried using

edit = Edit(view)

but it didn’t work.

0 Likes

#9

looks like edit.py use the magic methods

 __enter__ and __exit__ that automatically run 

when entering and exiting “With” statement https://github.com/titoBouzout/Open-Include/blob/master/Edit.py#L59-L71

1 Like

#10

Just tried it on the full code. Works perfectly!
 

Thanks again for your help! :beers:

0 Likes

#11

I didn’t have the time to lok into your code and try to reproduce/debug, but I made some adjustments to the script from linuxbochs that @tito linked: https://github.com/FichteFoll/CSScheme/blob/master/my_sublime_lib/edit.py, most notably a classmethod that accepts a single callable (a callback) and just runs that in a textcommand.

It will be available as a dependency eventually … when I find the time.

2 Likes

#12

 

Cool, I tried it out in place of my modified version, and it worked without requiring any adjustments of my implementation.

I’ll use it since I’ll be able to swap it out for the dependency @ some point :+1:

 

##Edit:

 

Turns out your version is actually causing an error that I didn’t notice initially:

Traceback (most recent call last):
  File "C:\Program Files\Sublime Text 3\sublime_plugin.py", line 568, in run_
    return self.run(edit, **args)
TypeError: run() missing 1 required positional argument: 'name'

 

My current implementation is:

edit = Edit(view)

edit.replace(region, text)

which seems like it should satisfy the requirements of the Edit class.

0 Likes

#13

I assume you mean that this traceback is caused by my version?

I’ll need to take a look at it when I’m back home in two weeks. Please open an issue on the CSScheme repo with reproduction steps, if you would be so kind, so I don’t forget it.

0 Likes

#14

Yes, I meant that the traceback is caused by your version.

CSScheme / Issue 12

1 Like

#15

What is the difference between .Edit & Edit ?   Is this required for ST2 compatibility or something python related?

0 Likes

#16

If you find out, you will be able to answer this question: http://stackoverflow.com/questions/34155553/python-import-module-check-needed-due-to-different-python-versions-or-the-way-s

1 Like

#17

Just found the answer @ Python Enhancement Proposals.

Seems like a single dot will import from the package directory; and each additional dot will seek further into parent directories, relative to the package.

If no dots are present, the import will be absolute and seek from sys.path.
 



 
That makes sense, but what I still don’t get is where the absolute import @ except points to.
What is sys.path in relation to SublimeText?
 



 
From that SO post you linked to, it seems like the plugin author he referenced implemented absolute paths as a workaround for ST2.   The PEP mentions implementation issues up to Python 2.6.

Looks like I’m good to drop the try block since I’ll be using relative directories & working with ST3+.

1 Like

#18

nice find :slightly_smiling:

In terms of ST, it seems that sys.path is the ST3 installation folder, the Python zip file in said folder, and all the relevant package folders.

You can see it by writing

import sys
print (sys.path)

in the ST console :slightly_smiling:

1 Like

#19

Awesome.   :+1:

Seems like dependencies are included in that list also so you can access their modules directly without a directory prefix.

C:\\Program Files\\Sublime Text 3
C:\\Program Files\\Sublime Text 3/python3.3.zip
C:\\Users\\Fico\\AppData\\Roaming\\Sublime Text 3\\Packages
C:\\Users\\Fico\\AppData\\Roaming\\SUBLIM~1\\Packages\\pygments\\all
C:\\Users\\Fico\\AppData\\Roaming\\SUBLIM~1\\Packages\\bz2\\ST3_WI~2
C:\\Users\\Fico\\AppData\\Roaming\\SUBLIM~1\\Packages\\backrefs\\st3
C:\\Users\\Fico\\AppData\\Roaming\\SUBLIM~1\\Packages\\MARKUP~1\\all
C:\\Users\\Fico\\AppData\\Roaming\\SUBLIM~1\\Packages\\PYTHON~1\\st3
C:\\Users\\Fico\\AppData\\Roaming\\SUBLIM~1\\Packages\\pyyaml\\st3
C:\\Users\\Fico\\AppData\\Roaming\\SUBLIM~1\\Packages\\PYTHON~2\\all
C:\\Users\\Fico\\AppData\\Roaming\\SUBLIM~1\\Packages\\mdpopups\\st3
0 Likes

#20

ST 2 does weird things when loading the modules of packages, most notably changing the working directory to the package’s and then letting python do most of the remaining work after manually importing or exec’ing the plugin files. As such, the plugins themselves are not actually recognized as being part of a package, meaning relative imports are not possible from these files. Due to the working directory hack, plugins are able to import other python files (or packages) next to them, but only at module load time and only with absolute imports. Python packages imported that way are different in that they are properly recognized as such a package and relative imports work again.
Another unfortunate side effect is that all plugin files share the same module namespace (the global one), causing some plugin files to not get loaded from the current directory because they are already in sys.modules from another package. You better not think about it too much and just focus on developing for st3.

ST3 handles this better by providing a Loader class and adding it to sys.meta_path (refer to the corresponding PEP for details) and wrapping it around st’s resource loader. Plugin files are then loaded with their correct __name__ relative to the package directory. It still has a few minor bugs such as __init__.py getting loaded twice if in a package folder (once by python’s package loading behavior and once by ST when looking for plugin code) or bad caching for files in package archives) but that is comparatively minor.

I investigated the code a few times while trying to reproduce (and fix) bugs, so feel free to hit me with more questions.

3 Likes

#21

##@FichteFoll

 

Nice explanation :slightly_smiling:

I kind of noticed some of those issues ( although not with as much understanding ) and ended up getting some help from @wbond with which I implemented my own solution to dynamically load modules.

0 Likes