TkTurf Plugin API : version 3.23+
Document version : 1.35
Author: Chris Allen <fastjack@fastjack.turf.org>

The TkTurf plugin API is constantly evolving as overlooked requirements are found. The API may change in such a way that older plugins no longer function, although this shall be avoided as much as possible. It is also possible that certain features may exist but remain undocumented. This file shall be maintained as time allows. The file is laid out in two sections. First, there is a style/procedure guide and introduction to hidden API features and aspects of the API which are not function based. This is followed by an index of functions included in the API for plugins, and the TkTurf program API.

The first thing a TkTurf plugin should do is register itself with the plugin registry. While not strictly needed, this provides a convenient means for users to identify which plugins are installed correctly, and which versions of said plugins they are currently using. This is done by calling the register function, which takes three arguments. register "name" version "description", where the name and description are relevant descriptive strings, and the version number is a floating point number. TkTurf now has a plugin manager plugin which downloads upgraders based on registration information, making this standard registration vital.

TkTurf plugins are executed immediately after all core TkTurf is loaded and immediately before the interface is created. This allows plugins to (in theory) over write any function they need to modify. Since multiple plugins may alter the same function it is recommended that plugins modify any functions in a non-destructive manner. This can be done through use of the info command, specifically, info args, and info body. Code can be appended to the end of the function, which will allow other plugins to also modify the same function. This can also be impossible on certain functions, such as the function for saving preferences, which has a buffer flush at the end of it. More sophisticated methods can be employed for non-destructive function editing in this case, such as use of the regsub command and code known to be in the function. In many (file|window) event binding cases functions can be stacked by a plugin. This can be done by getting the current binding and adding to the front or back of the stack, and having the function possibly alter the operating of following functions. For example, if a plugin wishes to filter through the input from the main prompt area, it could call bind that widget to "MyFunction;[bind .promptline.mainent <Return>]". If that function wished to prevent any other stack function (such as the originally bound STDre) from working in this case it could just set .promptline.mainent to "", and if it wishes to have those functions work normally it could not reset the widget text.

For removal of bindings for Plugin Reload compatability the unbind command, detailed below, is available.

Plugin scripts are not run in the global scope. Any loaded functions enter the root namespace, as expected. Variables, on the other hand, are *not* put in the global scope. Any variable which is expected to be global must be declared global even at the main script level.

Plugins may load and save variables through the PREFS global array. Any variable which the plugin wishes to have loaded from the preferences file must be set to a reasonable default in the PREFS array at script execution time, not to be confused with script installation time (discussed later). Variables in the prefs array, such as PREFS(LCKCMD) will be loaded from the preferences file, and any default will be overwritten. Variables in the PREFS array are automatically saved with the rest of the preferences, which requires the user to do something which will invoke the function which saves the preferences... this can be forced by the plugin if it wishes, with the command "::Preferences::save".

Array saving is not possible. If a plugin needs more complex data management than single variables, the plugin should use its own data file, for easy data management and uninstallation.

TkTurf provides a Misc ButtonNotebook preferences frame for one or two preferences from a plugin. If more need be added the plugin should create its own page. To either add an entry or a page simply use ::Preferences::addHook to add a function which will add to the preferences widget to this list and the commands from it will be run when the preferences window is created. Said commands are executed in the scope of the main preferences window function, so you may use variables therein stored if you wish.

Any special preference application can be done by using ::Preferences::addApply. Preference application is done before destruction of the preferences window, and before saving of the preferences, so it is possible to grab text from any widget in the text window. Function bodies are executed directly inside the apply function's scope with [info body].

Preferences window and apply hooks can be removed with the ::Preferences::removeHook and ::Preferences::removeApply functions, as detailed below. This should be done at the appropriate time for Plugin Reload compatability.

Since most any plugin will need to affect the interface to be used, TkTurf's plugin API provides a system for installing the plugin after it has been initially loaded. To have itself installed a plugin should create a procedure in the root namespace which begins with "install", such as "install_historybox". And underscore is not needed, but any name should be unique enough that it does not conflict with other plugins (the name of the plugin is generally a good trailer, for clarity). This special reserved function will be run immediately after interface creation, and immediately before creation of the socket connection to Turf. Plugins are not required to have an uninstall function, and providing one should probably be viewed as a pollution of the namespace, rather than a feature. This is because a runtime manager of plugins is not likely to be added. (Personally, I'd like it, just so I can edit plugins without restarting every time I edit a function, but I'm generally content to just use the Plugins::load function, since most changes are not direct changes to the interface management code.)

TkTurf provides a nice tray space for icon button interfaces to plugins. The path for this is .promptline.tray, which is a frame any button may be packed into. For stylistic consistency icons should be roughly 12x12, and all buttons should have flat relief, and standard colors (unless a good reason precludes this, such as the errorlog plugin, which changes to a red icon to indicate a fault).

Sound events may be automatically loaded and saved to the preferences file by setting an element in the SOUNDSTUB global array (at load time). This sound event's value sound may be added to the preferences window sound editor by setting a human-readable name for this sound in soundnames array. Any sound not listed in this array will be left to the plugin to customize. Self entry and customization in either the Misc frame or a unique frame is the preferred method for plugin soud customization, to keep the page a reasonable size.

TkTurf includes a system for hiding "system" triggers, so that plugins may automatically add a trigger which will not appear in the trigger edit window. To specify a trigger as a system trigger, make the first line of the trigger execution code "#TkTurf System Trigger".

Triggers in TkTurf 3.02+ can destroy whatever text triggered them. To do so a trigger should use upvar on the line variable in the next level up of the stack, and set it to null. Example: "upvar line line" sets local variable line to refer to line in the executing scope, so line is the line that triggered the match. As of 3.02+ lines should be spooled line at a time to triggers, however this is not fully tested.

Aliases may also be made "system" aliases which are hidden from view. In the same manner as triggers the first line of their function should be "#TkTurf System Alias". (Although, with aliases it is not required that it by the first line.) Setting an alias manually in TkTurf can be done by creating the proper function in ::Aliases::. If an alias is not created at load time you must call ::Alias::makelist to refresh the alias listing.

Turf assumes that if a socket is blocked when Turf attempts to write to it that it is link-dead, but this can also happen when the socket is flooded. If a client will be sending large numbers of messages to remote clients it is necessary to slow the flow of messages, or one or both parties may lose their links. To accomplish this a message spooling system has been added. See details in the Spool namespace below. Spool::enqueue should not be used in high-performance situations.

TkTurf includes an Event system for easier session management. Several events are pre-defined and called by TkTurf, including: CONNECT, LOGIN and DISCONNECT, and SHUTDOWN. The system is open to the definition and calling of other events. Typically this system should be used for plugins such as biff, which must reset for every connection. This event system is in no way connected with the eventsound system for sounds.

Turf now includes a system for capturing output from commands with c15 h. Programmers interested in using this should consult the Turf Protocol documentation. TkTurf includes a system for gathering and distributing commands received under this new protocol with the Capture::addID command (see below). This allows the programmer to specify a function to be called which must take one argument. Data from a command should be sent in single-line chunks.
A unique identifier should be used for c15 h commands, and it is advisable to use the API "new" function. In the case that a unique window is also needed to go with this unique command it is advised that the same identifier be used for both, and the data reading command for the id can use the $::CMD_ID variable to get the current identifier. However, should additional data be needed for the capture function, ::Capture::addID uses scripts rather than functions for execution, however any script should be capable of taking the data argument as a final argument to the call.
When the output from the command is finished the read function for Capture will be called one more time with a null data argument. This is the only time it will be called with no data, and can be used to determine when the command is done returning information.

TkTurf now includes a system for plugin cooperation in areas where many plugins want jurisdiction, such as prompts and text output filters. See the Plugins::addFilter, Plugins::addPrompt, Plugins::addCommand, Plugins::removeFilter, Plugins::removePrompt, and Plugins::removeCommand functions below. The core of this system is not destroying anything already present, and returning unused data.

Function index (dictionary sort):

addhandler prefix handler

audiobell ButtonNotebook::create frame args ButtonNotebook::getpage frame num ButtonNotebook::getnextpage frame ButtonNotebook::newpage frame name Capture::addID id script ChalWin game cmd dcmd eventsound event Event::call event Event::on event script Event::remove event script MakePlayerListing win title cmd makereg string MakeRelay win new playsound file register name version description Plugins::addCommand filterfunction Plugins::addFilter filterfunction Plugins::addPrompt promptfunction Plugins::removeCommand filterfunction Plugins::removeFilter filterfunction Plugins::removePrompt promptfunction Preferences::addApply function Preferences::addHook function Preferences::removeApply function Preferences::removeHook function Preferences::save Prompt::addMarker msym description Prompt::removeMarker msym ScrolledListWidget frame args ScrolledTextWidget frame args send message Spool::enqueue args unbind tag sequence script wintalk win message flags