Suggestion: Formal Plugin API
Disclamer: This is a pretty major feature request. So hold on.
The Pythonista forums are riddled with feature requests. Many of these are relatively minor, and could be implemented by @omz with minimal effort.
It's not practical for many editors to include a massive codebase packed with functionality, it would make the application huge and much of the functionality would go unused by the majority of users. This is why popular editors like Atom and Sublime Text have libraries exposing methods by which third-party developers can extend the editor's functionality.
My proposal is that Pythonista implement such a system. A library called something like
internalswould do nicely. As I see it, this would be somewhere between the difficulties of
objc_utiland @omz having to implement things. The downsides of
objc_utilas I see them are:
- High level of technical Objective-C knowledge required. It's very unfriendly to native python-speakers.
- Users are kept too much in the dark. Trying to extend the editor with
objc_utilinvolves a large amount of guesswork about the completely undocumented inner workings of Pythonista.
These could be overcome with a native Python library. As I envision it, its goal would be to allow for easy and powerful extension of the editor by someone who only knows Python. It would be thoroughly documented. Ideally, this could tie into existing libraries. For example, it could provide
ui.Viewclasses for views inside the editor. Now, I know you can add subviews to editor views with
objc_utilbut this has several issues:
- The facts of which editor views are where and how to access them are completely undocumented.
- This is very prone to crashes.
A magical library that wraps all this functionality would certainly be very useful.
internalswouldn't be a full plugin system with only the ability to add views. This module would also need much more functionality. A non-exhaustive list that names a few functions needed:
- Hooks and callbacks to common events (save, open file, swipe to console, open file browser to name a few)
- Easy methods for adding editor buttons
- Python methods wrapping many of the Pythonista's internal methods used to save files, present views, control the console, etc.
A plugin system could be modeled off of those found in Atom and Sublime Text, to provide a rough idea of the functionality needed to make a complete API.
With a full set of hooks and features, extending Pythonista could be trivial. This would take pressure off @omz to implement requested features, and would take Pythonista to the next level.
Sounds like an interesting idea, but this would probably require a lot of work to implement. The reason why
objc_utilexists is to allow access to any Objective-C API without omz wrapping them in a Python extension module. A more pythonic and user-friendly API would be nice, but each function would need to be written by hand, to convert between Python and Objective-C objects and perform error checking. This is what modules like
editoralready do. There isn't a lot of room "in between" - it's simply not possible to write an API that is low-level enough to automagically work with all functions, but high-level enough to not crash when given bad data. The error-checking part especially requires a lot of testing and handling of edge cases and cannot be written in a generic way for all available functions.
Another issue is the documentation part - currently we have the
editormodule, which has a stable and documented Python API, and whatever you can access through
objc_util, which is undocumented and could change at any time. Documenting the internal Objective-C APIs would be a bad idea, it would mean that when omz changes the editor internals he would need to worry about backwards compatibility on the Objective-C side, in addition to the Python modules.
The features you're suggesting would make good additions to the
consolemodules though. I would also like to see that kind of extensibility (especially with things like callbacks) but it sounds like something that would take a while to fully work out and implement.
@dgelessus I definitely see all your points. All the specifics in my proposal are flexible, it's not like a rigid plan. The basic idea is to have a module custom-built for extensions, modeled after the equivalent things in other editors.
If crash protection isn't possible, so be it, it's not that important. The main idea of the post was just the idea of a module for extensibility.
objc_utildoes a great job of bridging the gap, it's hard to use and doesn't really follow the principles of a Python library.
We could all work on a libaray that uses objc_utils and makes a pythonic libaray for objc classes. Like a warper around objc_utils to make it friendlier.
@chibill There is something like that called "Pythonista-Tweaks" on @Webmaster4o's GitHub. It never got very far though last I checked. (And it uses
pythonistaas the module name, which could be an issue if omz adds a
pythonistamodule/package at some point.)
@dgelessus @chibill Yeah, that's correct. I plan to get back to ut soon(ish); it's on my endless todo list. But developing that will be much harder without the knowledge @omz has, and also many things are liable to break between versions. That's why I've proposed this, if it's a core part of Pythonista @omz has more of an obligation to update it as he updates the rest of the app. Maybe he doesn't want that responsibility, though, which is also fine.
A few things I have found that really help with customizing the editor/app and such:
prints the Instance and Class methods of a class, but not of its ancestors. really helps identify what is unique about custom classes (vs dir() which shows instance and inherited methods)
A lot of good stuff is exposed in PA2UniversalTextEditorViewController, which is what editor._get_editor_tab() returns. For instance, saveData, which can be swizzled. Also, @dgelessus, I think you mentioned you wanted the ability to launch a script with another interpreter version, this class seems to have that capability.
void runScriptAtPath_withInterpreterVersion_arguments_( object, int, object ) void runScriptAtPath_withInterpreterVersion_scriptForShebang_arguments_( object, int, object, object ) void runScriptWithNonDefaultPythonVersion( )
editorView()on this object returns a view which you can
addSubview_to create your own overlays.
Also, I have experimented a bit with NSNotifications, which can be another interesting way to get callbacks for some things without swizzling. here is a class which captures all notifications types (by default excluding the various NS and UI notifications). For instance, changing from editor to console or vice versa posts a notification which can be observed and action taken.