#pragma section-numbers on
<>
Throughout Conkeror, hooks are provided for a variety of events. Basically, a hook is a set of functions to run when a given event occurs. Hooks promote neatness and modularity of source code because new features can be added to an existing system by ''hooking'' functions into the system at strategic points---that is, the existing system itself need not be modified.
= Hook Components =
A hook can be made of any number of components. Broadly, the three component-types of hooks used by Cokeror are ''global'', ''simple-local'', and ''local''.
Global hooks::
:: Global hooks have only one component, a hook in application context.
Simple-local hooks::
:: Simple-local hooks have two components: a local component for the specific object in question and a global hook which will be run for any object. For example, the `window_*` hooks are all simple-local. You can add a hook function to the global component, which will be run when the given event happens ''in any window'', or you can add a hook function to the local component of a ''specific window'' so your function will only get run when the given event happens ''in that window''.
Local hooks::
:: Local hooks have more components than simple-local (limited by current implementation to three). These components represent the levels of a hierarchy. For instance, the `buffer_*` hooks are local hooks with three components: you can put a hook function on the component local to ''a specific buffer'', so that the function will run for the event ''only in that buffer''; you can put a hook function on the component of ''a specific window'', so that it will run when the event happens in any buffer in that window; or you can put a hook function on the global component, meaning it will run when the event happens ''in any buffer''.
= Hook Types =
Most hooks in Conkeror are of the normal type: every hooked function gets run, and the return values of those functions are ignored. But some hooks exist for special purposes. There are two special types:
RUN_HOOK_UNTIL_SUCCESS::
:: The hook functions are run until one returns a logically true value, at which point that value is returned as the overall value of the run.
RUN_HOOK_UNTIL_FAILURE::
:: The hook functions are run until one returns a logically false value, at which point that value is returned as the overall value of the run. If no hook functions returned a logically false value, then the overall value of the run will be `true`.
For multi-component hooks, local components are run in order hierarchical specificity, and the global component runs last. For example, In a buffer-local hook, the buffer component will run first, then the window component, and finally the global.
= Adding and Removing Hook Functions =
To add a function to the global component of any hook, use the following call form:
{{{
add_hook(String hook_name, Function func, Bool prepend, Bool avoid_duplicates)
}}}
To remove a function from the global component of any hook, use the following call form:
{{{
remove_hook(String hook_name, Function func)
}}}
To add a function to a local component of any hook, use the following call form:
{{{
add_hook.call(Object context, String hook_name, Function func, Bool prepend, Bool avoid_duplicates)
}}}
To remove a function from a local component of any hook, use the following call form:
{{{
remove_hook.call(Object context, String hook_name, Function func)
}}}
= Defining Hooks =
In the code below, `hook_type` can be one of the following constants:
* RUN_HOOK
* RUN_HOOK_UNTIL_SUCCESS
* RUN_HOOK_UNTIL_FAILURE
If `hook_type` is null or omitted, the type will be `RUN_HOOK`.
To define a global hook:
{{{
define_hook(String hook_name, &optional Const hook_type, &optional String docstring);
}}}
To define a window-local hook:
{{{
define_window_local_hook(String hook_name, &optional Const hook_type, &optional String docstring);
}}}
To define a buffer-local hook:
{{{
define_buffer_local_hook(String hook_name, &optional Const hook_type, &optional String docstring);
}}}
To define a current-buffer-local hook:
{{{
define_current_buffer_hook(String hook_name, String existing_buffer_local_hook);
}}}
To define a download-local hook:
{{{
define_download_local_hook(String hook_name, &optional Const hook_type, &optional String docstring);
}}}
== Defining Coroutine Hooks ==
Coroutine hooks are a type of hook which can call coroutines as well as functions. These can be used to have asynchronous procedures like minibuffer prompts in a hook. They are defined by an alternative set of functions from normal hooks, but not all equivalents are provided. They will be added as they are deemed relevant.
To define a global coroutine hook:
{{{
define_coroutine_hook(String hook_name, &optional Const hook_type, &optional String docstring);
}}}
= Running Hooks =
To run a global hook:
{{{
some_hook.run(&rest args);
}}}
To run a hook with local components:
{{{
some_hook.run(Object context, &rest args)
}}}
For multiple-component hooks, the `context` will be the first argument passed to each hook function, followed by any additional arguments.
== Running Coroutine Hooks ==
The way to run a coroutine hook depends on whether the calling context is already in a coroutine or not.
Run a global coroutine hook from within a coroutine:
{{{
yield some_hook.run(&rest args);
}}}
Run a global coroutine hook, starting a new coroutine:
{{{
co_call(some_hook.run(&rest args));
}}}
Run a multi-component coroutine hook from within a coroutine:
{{{
yield some_hook.run(Object context, &rest args);
}}}
Run a multi-component coroutine hook, starting a new coroutine:
{{{
co_call(some_hook.run(Object context, &rest args));
}}}
= List of Hooks =
== Global ==
Global hooks are made by `define_hook`. They are only called in the global context.
make_window_hook::
:: Called with one argument: the window being created. The window is not yet initialized.
before_quit_hook::
:: '''type:''' RUN_HOOK_UNTIL_FAILURE
:: '''coroutine hook'''
:: This hook can be used to prompt for confirmation of the `quit` command.
quit_hook::
:: Called with no arguments by the `quit` command, after it is determined that the program is definitely quitting.
Additionally, every global mode has a pair of global hooks, one `MODE-enable-hook` and one `MODE-disable-hook`.
== Window-local ==
Window-local hooks are ''simple-local'' hooks, so they have two components: a local component for the window, and a global component.
window_initialize_early_hook::
:: '''noteworthy events:''' buffer_container and first buffer initialized.
window_initialize_hook::
:: '''noteworthy events:''' keyboard handling is initialized for the window.
window_initialize_late_hook::
:: '''noteworthy events:''' `set_window_title`
window_before_close_hook::
:: '''type:''' RUN_HOOK_UNTIL_FAILURE
:: '''coroutine hook'''
:: This hook can be used to prompt for confirmation of window closings. It does not run when windows are being closed because the application was quit with the `quit` command.
window_close_hook::
mode_line_hook::
keypress_hook::
:: '''type:''' RUN_HOOK_UNTIL_SUCCESS
== Buffer-local ==
Buffer-local hooks are ''local'' hooks with three components: buffer, window, and global.
=== all buffers ===
buffer_title_change_hook::
buffer_description_change_hook::
buffer_icon_change_hook::
select_buffer_hook::
:: '''noteworthy events:''' `set_window_title`
create_buffer_early_hook::
:: Run during buffer construction, after the buffer base class has finished setup, but before child classes are initialized.
:: '''noteworthy events:''' `tab_bar_add_buffer`
create_buffer_hook::
create_buffer_late_hook::
:: Run by a zero timeout after buffer construction. Can be used to hide scrollbars.
kill_buffer_hook::
buffer_scroll_hook::
buffer_dom_content_loaded_hook::
buffer_loaded_hook::
:: Called when the top-level document of a buffer is done loading, not counting any embedded content.
buffer_kill_before_hook::
:: '''type:''' RUN_HOOK_UNTIL_FAILURE
buffer_mode_change_hook::
:: Run whenever a buffer-mode is enabled or disabled.
Additionally, every buffer mode has a set of buffer-local hooks: a `MODE_enable_hook`, a `MODE_disable_hook`. And every buffer ''mode-class'' has a `MODECLASS_change_hook`.
=== content-buffers ===
content_buffer_finished_loading_hook::
content_buffer_started_loading_hook::
content_buffer_progress_change_hook::
content_buffer_location_change_hook::
:: '''noteworthy events:''' `set_window_title`
content_buffer_status_change_hook::
content_buffer_focus_change_hook::
content_buffer_dom_link_added_hook::
input_mode_change_hook::
:: fixme: doublecheck that this is in the right category. (do input-modes work for non-content-buffers?)
== Current-buffer-local ==
A current-buffer hook is a buffer-local hook which only runs for those buffers which are current in their window. Every current-buffer hook is chained onto a corresponding buffer-local hook. In other words, if we have a buffer-local hook `foo`, then `foo` will in turn call `current-buffer-foo` when the buffer in question is current in its window.
=== all buffers ===
current_buffer_title_change_hook::
:: '''noteworthy events:''' `set_window_title`
current_buffer_description_change_hook::
current_buffer_icon_change_hook::
current_buffer_scroll_hook::
current_buffer_dom_content_loaded_hook::
current_buffer_mode_change_hook::
=== content-buffers ===
current_content_buffer_finished_loading_hook::
current_content_buffer_progress_change_hook::
current_content_buffer_location_change_hook::
current_content_buffer_status_change_hook::
current_content_buffer_focus_change_hook::
current_buffer_input_mode_change_hook::
:: fixme: doublecheck that this is in the right category. (do input-modes work for non-content-buffers?)
== Download-local ==
The download hooks are all simple-local hooks. They have a local component for the download and a global component.
download_added_hook::
:: '''noteworthy events:''' `open_download_buffer_automatically`
download_removed_hook::
download_finished_hook::
download_progress_change_hook::
download_state_change_hook::
download_shell_command_change_hook::