Configuring Howl
Init files
Howl looks for a startup file in one of these locations:
~/.howl/
$XDG_CONFIG_HOME/howl/
, usually~/.config/howl/
(see XDG specification)
Inside this user directory, it searches for either:
init.moon
, written in Moonscriptinit.lua
, written in Lua
Which flavor to pick depends on your preference with regards to these languages.
Should a startup file be found, it is loaded after Howl is initialized which includes loading all available bundles. Howl does not have any special configuration format for use with the startup file, instead it’s just plain Lua or Moonscript.
The startup file is typically used for various types of configuration, but
there’s no restriction to what you can do in it - you have access to the entire
Howl API. However, some parts of the API, such as running
commands, can only be accessed after the application has fully initialized, and
needs be run within an 'app-ready'
signal handler, rather than at the top
level. For instance, this code launches the file selection command on startup:
howl.signal.connect 'app-ready', -> howl.command.run 'open'
You can split up your startup code in multiple files if you like. Your local
user files will be not found by an ordinary require
, since the user directory
is not part of the search path. However, there is a user_load
helper available
from your startup files that works the same way. For example, given
init.moon
and other.moon
in the Howl user directory, you could load
‘other’ from init like so:
other = user_load 'other'
Just as with require
, paths are given without any extension. Files are
loaded only once, with subsequent loads returning the same value. The path
passed to user_load
can contain dots, which are translated to the directory
separator before loading the file.
It is not allowed for the startup files to implicitly clobber the global environment, and Howl will raise an error upon startup if this is detected. Consider for instance this incorrect Lua startup file:
-- Oops, forgot the local keyword here my_internal_var = 2
This would cause Howl to abort with an error upon startup. Should you for any reason want to set a global variable, you can do so by being explicit:
_G.my_explicit_global = 2
(Note: the user_load
helper is only available when loading startup files.)
Configuration variables
Overview
Things that are meant to be configurable in Howl are exposed as “configuration
variables”. Configuration variables can be set either interactively from within
Howl, using the set
command, or programmatically from code. The set
command
shows a list of avaliable variables. Press alt_x
to invoke the command line,
then type set
and press the spacebar:
Here you can select a configuration variable by typing and selecting from the
list. For example, to change the current theme interactively you can select
theme
and press enter. This then presents you with a list of available themes
- after choosing one you can press enter again to switch to the specified theme.
See the sections below,
Setting variables upon startup and
Automatic persistence, for information on how to
change a setting so that it persists across restarts.
Scopes and layers
The value for each configuration variable can be set at multiple levels, called scopes, and at multiple layers for each scope. The scope is the path for which the configuration value applies. For instance, a configuration value set at the global scope applies across all of Howl and includes all buffers. A configuration value at a file scope applies to a specific file only, overriding any global value for the same variable. A folder scope (similar to file scope, but referencing a folder) applies a value to all files under a specific folder.
Scopes work well when the same configuration value applies to all types of files
within a scope. To use different values depending on the
mode, configuration layers are used. A layer is
a string such as 'mode:moonscript'
and can by specified in addition to the
scope for a variable. So a value set at global scope for layer
'mode:moonscript'
is applied to all moonscript buffers. A value set for scope
'file/path/to/project'
and layer 'mode:python'
is applied to all python
files under the path/to/project
folder.
Interactive configuration
As seen above, the set
command is used to specify values for configuration
variables. When setting the theme
, you did not have a choice for scope because
the theme can only be specified for the global
scope. For other variables, the
set
command allows you to specify the scope, and optionally, the layer.
The syntax for the set
command is:
set name@scope_name[layer]=value
While you can type out the entire command by hand, a selection list for the
scope_name and another for the value (if applicable) is displayed to make
command entry easier. Let’s see a few examples of using this command to set the
indent
configuration variable for different scopes and layers. The indent
variable specifies the number of characters to use for each level of
indentation.
Global scope: To set the global value of indent to ‘3’, use the command
set indent@global=3
. Note that after you typeset indent@
, the command shows an auto complete list containing different options for scope and the current effective value at each scope.For current buffer: To set the configuration for the current buffer only to 4, use the command
set indent@buffer=4
. This applies to the currently active buffer only, and no other buffers.For current mode: Another available option applies to the global scope and mode layer for the current mode. This command looks something like
set indent@global[mode:moonscript]=2
(assuming the current mode is moonscript). This applies indent=2 to all buffers that are in moonscript mode.
Once you type the full command, pressing enter
makes it effective and pressing
escape
cancels, making no changes. You can also press backspace
to go back
and change the selected scope, or the originally selected variable.
Programmatic access
The Howl API can be used to update the configuration values as well. An easy way
to set (and access) variables is using config
objects. For the global scope,
you can use the main config object in the howl
namespace. For a specific mode,
you access variables using the config object on a particular mode instance, and
similarily for buffer variables you use the config object for a particular
buffer.
The following code snippet illustrates the various ways of setting variables on different levels:
howl.config.my_var = 'foo' howl.mode.by_name('ruby').config.my_var = 'foo' howl.app:new_buffer().config.my_var = 'foo'
For more fine grained access to configuration variables, see the config API.
Setting variables upon startup
Let’s have a look at configuring the indent
variable as discussed in
Interactive configuration earlier, using the below
example Moonscript init file (init.moon):
import config, mode from howl import File from howl.io -- Set indent globally to two spaces config.indent = 2 -- Use four spaces for C files mode.configure 'c', { indent: 4 } -- Set it to three for this weird project config.for_file('/home/nino/code/some_project').indent = 3
A few notes on the above example:
There’s no need to
require
any class/module/etc. that comes with Howl. They’re all available upon access. You can still require them explicitly if you want to however. One exception to this is the modulehowl
however. Requiring it will lead to an error preventing the editor to start.We use
mode.configure
for specifying the mode variable rather than setting it using the config object of an existing mode instance. This is because we don’t want to load the mode unnecessarily just to set a variable. Using configure() instead means that it will be set once the mode is loaded (or straight away should the mode already be loaded).We use config.for_file to add access a config proxy object that sets and gets variables for the file scope.
Automatic persistence
Howl does not automatically save any configuration variables updated via the
command line or the API. One way to save the modified configuration is to run
the save-config
command. This saves the modified variables in
~/.howl/system/config.lua
from where they are automatically reloaded on
startup. To automatically save all modified variables every time you close Howl,
you can use the save_config_on_exit
configuration variable. If set to true,
any changes made to the config using set
will automatically be saved on exit.
A simple way to enable automatic persistence is to add the following line to
your init.moon
:
config.save_config_on_exit = true
Note: The save_config_on_exit
configuration and save-config
command only
save the settings for global scope. Any file or buffer level configuration is
not currently saved.
Another way to persist your settings is to manually update the init.moon
file
as described in the previous section. Any
variables set via init.moon
override the variables automatically loaded from
config.lua
.
Key bindings
Key bindings map keyboard presses to different actions within Howl. The nitty-gritty details on how this is handled is outlined in the documentation for the bindings module, and won’t be repeated here. Rather, the below Lua example illustrates how to add different kind of binding customizations from within your init file (init.lua).
howl.bindings.push { -- editor specific bindings editor = { -- bind ctrl_k to a named command ctrl_k = 'editor-cut-to-end-of-line', -- bind ctrl_shift_x to a closure ctrl_shift_x = function(editor) -- replace the active chunk with a reversed bracked enclosed version editor.active_chunk.text = "<" .. editor.active_chunk.text.ureverse .. ">" end }, -- Bind the Emacs find-file binding (C-x C-f) to the open command ctrl_x = { ctrl_f = 'open' } }
Running commands
You’ve seen how to invoke commands from a key binding (simply specify the command name as a string), but sometimes you’ll want to invoke commands programmatically from within your startup file. As an example, to enter VI mode automatically upon startup:
howl.signal.connect 'app-ready', -> howl.command.vi_on!
While it’s possible in some cases to run commands directly in the init file, we
run this when the app-ready
signal fires since the application needs to be
ready before activating the VI mode.
Consult the documentation for the command module for more information on commands.
Next: Using Howl completions