#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::