Forum Archive

Suggestion: Formal Plugin API

Webmaster4o

Disclamer: This is a pretty major feature request. So hold on.

The Problem

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.

The solution

My proposal is that Pythonista implement such a system. A library called something like internals would do nicely. As I see it, this would be somewhere between the difficulties of objc_util and @omz having to implement things. The downsides of objc_util as I see them are:

  1. High level of technical Objective-C knowledge required. It's very unfriendly to native python-speakers.
  2. Users are kept too much in the dark. Trying to extend the editor with objc_util involves 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.View classes for views inside the editor. Now, I know you can add subviews to editor views with objc_util but this has several issues:

  1. The facts of which editor views are where and how to access them are completely undocumented.
  2. This is very prone to crashes.

A magical library that wraps all this functionality would certainly be very useful.

However, internals wouldn'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:

  1. Hooks and callbacks to common events (save, open file, swipe to console, open file browser to name a few)
  2. Easy methods for adding editor buttons
  3. 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.

dgelessus

Sounds like an interesting idea, but this would probably require a lot of work to implement. The reason why objc_util exists 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 console and editor already 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 editor module, 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 editor and console modules 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.

Webmaster4o

@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.

Although objc_util does a great job of bridging the gap, it's hard to use and doesn't really follow the principles of a Python library.

chibill

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.

dgelessus

@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 pythonista as the module name, which could be an issue if omz adds a pythonista module/package at some point.)

Webmaster4o

@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.

JonB

fwiw,

A few things I have found that really help with customizing the editor/app and such:
https://github.com/jsbain/objc_hacks/blob/master/print_objc.py
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(  )

Also, 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.