Dev Build 3118 is out now at https://www.sublimetext.com/3dev

3118 introduces Phantoms into the API, allowing computed data to be embedded within a text view. You can see it in action via compile errors, which are now shown inline.

Each phantom has HTML content, a region where it’s shown, and a layout: either LAYOUT_INLINE (phantom is drawn in the flow), LAYOUT_BLOCK (phantom is draw below the region, taking the full width when applicable) or LAYOUT_BELOW (phantom is drawn below the region, but not left-aligned).

Simple example:

view.add_phantom("test", view.sel()[0], "Hello, World!", sublime.LAYOUT_BLOCK)

To remove the added phantom, either delete the region it’s associated with, or call:

view.erase_phantoms("test")

In the common case where the phantoms are generated as a function of the buffer content, you can use a sublime.PhantomSet to make keeping track of them simpler: pass a list of sublime.Phantom objects (their ctor is the same as view.add_phantom, but without the initial string parameter) to a PhantomSet’s update() function, and it’ll take care of adding and erasing phantoms in the view to match.

Also in 3118 is the notion of a ViewEventListener: these are like an EventListener, but are created one per-view, to make keeping track of per-view state simpler. They receive view level events (e.g., on_modified), but not window level ones (e.g., on_new). If your ViewEventListener should only be created for some files, but not all, then you can override the is_applicable(cls, settings) class level method. An example is below.

I haven’t updated the docs yet, but will do so in the next few days. In the mean time, here is an example that shows Phantoms and ViewEventListeners. Save it as a new plugin, then start editing a plain text file with content along the lines of ```how many characters is this =>`