Skip to content
cantora edited this page Feb 4, 2014 · 15 revisions

##overview An aug plugin is a shared object which at least exports the following symbols:
name: a null terminated string.
aug_plugin_init: a function which takes a plugin struct pointer and an api struct pointer as arguments and initializes the plugin's resources.
aug_plugin_free: a function which takes no arguments and frees the plugin's resources.
See ./include/aug_plugin.h for the details of the function prototypes.

When aug starts it will find the plugin objects in its plugin search path and initialize each plugin in the order they are defined in the aug configuration file. A plugin will only be loaded if it is defined in the configuration file; in other words there must exist a [<plugin name>] section (the section may be empty).

When a plugin is initialized, aug will call the aug_plugin_init function wherein the plugin can initialize resources and/or create threads. If the aug_plugin_init function returns non-zero, aug will free resources for the plugin and initialization for that plugin will be logged as a failure. If aug_plugin_init returns zero, then initialization for that plugin is considered successful and when aug eventually exits it will call aug_plugin_free wherein the plugin can free resources and join/cancel threads.

##examples
Some very simple examples can be found in the ./plugin directory of the source tree. The plugin API unit test in ./test/plugin/api_test/ attempts to exercise every component of the API, so it may be useful as an example (though the code is kind of ugly). Finally, the aug-db plugin is a good example of a more in depth plugin.

##API files
Plugins only need the files found in the ./include directory of the source tree for compilation and they should only need to actually include the aug_plugin.h and aug_api.h files.
aug.h: the primary API definition file, it contains prototypes of the API calls, macro definitions and struct definitions.
aug_api.h: the API interface include file.
aug_plugin.h: defines prototypes for the plugin symbols.
aug_api_macros.h: defines macros to make API calls more convenient.
ncurses.h: includes the ncurses library headers in a platform independent way.

##aug_api.h
The recommended way of interfacing with the aug API is to include the aug_api.h file. In only one .c file of your project you should also use the AUG_GLOBAL_API_OBJECTS macro to define some necessary global objects needed by the API. Finally, in the aug_plugin_init function you must call AUG_API_INIT(plugin, api) to initialize the global objects. In other source files of your project you now need only include aug_api.h in order to make API calls.

##structs, definitions and constants

  • AUG_ACT_CANCEL: return this value from an API callback when you want to "cancel" the API callback action. The meaning of this varies across API callbacks. For example, when this value is returned in an input_char callback, the input character will be filtered.
  • AUG_ACT_OK: return this value from an API callback when you don't want to cancel the current callback action. The meaning of this varies across API callbacks.
  • The aug_on_key_fn type is a prototype for a function pointer that should be passed to the aug_key_bind API call. It is defined as follows:
    typedef void (*aug_on_key_fn)(uint32_t chr, void *user);
  • The aug_inject struct is for use with the input_char callback and is defined as follows:
    struct aug_inject {
        /* the characters to inject into the terminal input.
         * aug does not take 'ownership' of the memory pointed to
         * by @chars (it wont free it or anything like that),
         * but the plugin must assure that the memory remains
         * valid until the next callback to 'input_char'. */
        const uint32_t *chars;
        /* the number of characters to inject */
        size_t len;
    };
  • The callback struct is a collection of function pointers which should be passed to the aug_callbacks API call.
    struct aug_plugin_cb {
        /* called when a character of input is received from stdin. the
         * plugin can update the ch variable and set action to
         * AUG_ACT_OK in order to change the data being sent to the
         * terminal. or the plugin can set action to AUG_ACT_CANCEL to
         * cause the input to be filtered from the terminal.
         *
         * if the plugin would like to replace the current character
         * with multiple characters, it can set action to AUG_ACT_CANCEL
         * and set inject->chars to an array of characters to send to
         * the terminal input (inject->len must also be set accordingly,
         * see the aug_inject struct definition). the plugin must ensure
         * that the data pointed to by inject->chars remains valid until
         * the next invocation of this callback, at which point the plugin
         * may free the array or reuse/overwrite it as it sees fit. */
        void (*input_char)(uint32_t *ch, aug_action *action, struct aug_inject *inject, void *user);

        /* called when a cell in the terminal window is
         * about to be updated. the plugin can
         * alter (or not) any of the output 
         * variables and then
         * set action to AUG_ACTION_OK to modify
         * the cell getting updated. or it can
         * set action to AUG_ACTION_CANCEL and 
         * and prevent the cell from being 
         * updated. */
        void (*cell_update)(
                int rows, int cols,
                int *row, int *col, 
                wchar_t *wch, attr_t *attr,
                int *color_pair, 
                aug_action *action, 
                void *user
        );

        /* called when the terminal lines are about to
         * be scrolled. if @direction is positive,
         * the screen is being scrolled up by that amount; 
         * that is, the lines are moving up the screen by
         * @direction lines. setting @*action to AUG_ACT_CANCEL
         * will prevent the use of ncurses scrolling functions
         * and the parts of the screen which would be scrolled
         * will instead be re-rendered (thus, the cell_update
         * callback will be invoked for each cell in the scrolled
         * area of the screen). */
        void (*pre_scroll)(
                int rows, int cols, int direction,
                aug_action *action, 
                void *user
        );

        /* called after terminal lines have been scrolled.
         * @direction follows the same behaviour as in the
         * pre_scroll callback. if @action is set to AUG_ACT_CANCEL
         * the post_scroll callback will not be invoked for
         * plugins after this one. */
        void (*post_scroll)(
                int rows, int cols, int direction,
                aug_action *action, 
                void *user
        );

        /* called when the cursor is about to be
         * moved to some location in the terminal window.
         * the plugin can change (or not) the 
         * new_row, new_col output parameters
         * and set action to AUG_ACT_OK to modify
         * where the cursor is moved to. */
        void (*cursor_move)(
                int rows, int cols, 
                int old_row, int old_col, 
                int *new_row, int *new_col,
                aug_action *action, void *user
        );

        /* called when the screen dimensions change.
         * note that the dimensions are for the entire screen, not
         * the size of the main window. */
        void (*screen_dims_change)(int rows, int cols, void *user);

        /* called when the primary terminal dimensions change. */
        void (*primary_term_dims_change)(int rows, int cols, void *user);

        void *user;
    };    
  • A plugin should initialize an aug_plugin_cb struct with a call to the aug_callbacks_init function. The prototype is shown below:
void aug_callbacks_init(struct aug_plugin_cb *cbs)

##screen windows/panels There are two types of screen real estate a plugin can request the aug to allocate: panels and windows. Panels correspond to the ncurses panels library and will stack on top of the main terminal window in the order they are allocated (like a popup window for some sort of transient interaction with the user). Windows correspond to ncurses windows and will not overlap the main terminal, but will only be allocated in ways such that they occupy a number of lines at the top, bottom, left or right of the screen (this is for peristent existence of plugin output on the screen, like a status bar or something).

A note on concurrency: generally these windows/panels will probably be accessed by a thread created by the plugin and any window or panel allocated to the plugin can be accessed directly with ncurses functions because these windows and panels are "owned" by the plugin and are not accessed by any other threads. However, since ncurses is not thread safe, all ncurses calls must be protected by API calls to aug_lock_screen and aug_unlock_screen which serialize access to the library.

Clone this wiki locally