Configuration
Klunok can be configured with the Lua programming language. Settings are global Lua variables assigned in a file. If the file is within directories that are monitored by Klunok, the settings are automatically reloaded when the file is written to. Here is an example of the content of the configuration file:
debounce_seconds = 5
editors['emacs-28.2'] = true
The file is passed to Klunok via the -c
command-line option,
like this:
klunok -c ~/.config/klunok.lua
This page documents the available settings, their types, and default values.
Configuration parsing code is extracted from this page
to ensure that the documentation is always up to date.
This imposes a certain structure on this page.
Lua code blocks titled pre-config
are executed before the passed configuration file.
This blocks assign static default values to some settings.
You can use this values in your configuration file, like this:
debounce_seconds = debounce_seconds * 2
prefix_var = prefix .. '/volatile'
Lua code blocks titled post-config
are executed after the passed configuration file.
This blocks invoke the declare
function.
The invocations specify the name of a setting,
its dynamically computed default value and its type.
Here is a sample invocation:
declare('prefix_var', prefix .. '/var', is_string)
This invocation means that a setting called prefix_var
must be a string,
and if it's not set in the configuration file,
its value is dynamically computed as string /var
concatenated to
the value of the prefix
setting.
The declare
function is defined below:
function declare(name, default, assertion)
if _G[name] == nil and default ~= nil then
_G[name] = default
else
assertion(name)
end
end
Setting types
The functions below check that a setting is of the right type.
They are used as the third argument to the declare
function.
is_string
accepts only strings.
Strings in Lua are enclosed in double or single quotes, like "this"
or 'this'
.
function is_string(name)
assert(type(_G[name]) == 'string', name .. ' must be a string')
end
is_nil_or_string
accepts nil
and strings.
nil
in Lua is a representation of absence of value.
nil
is not the same as an empty string ''
.
The description of a setting of this type will specify what exactly nil
represents in the
context of the setting.
function is_nil_or_string(name)
assert(_G[name] == nil or type(_G[name]) == 'string', name .. ' must be nil or a string')
end
is_positive
accepts integers greater than or equal to zero.
function is_positive(name)
local value = _G[name]
assert(
type(value) == 'number' and math.floor(value) == value and value >= 0,
name .. ' must be a positive integer'
)
end
is_set_of_strings
accepts Lua tables with string keys.
Working with settings of this type usually means setting individual keys to true
or nil
.
For example, to add string 'abc'
to set xyz
, you can write xyz.abc = true
.
To remove 'abc'
from xyz
, you can write xyz.abc = nil
.
If the key contains characters that are not letters, for example string '/@'
,
you can add the key as xyz['/@'] = true
and remove it as xyz['/@'] = nil
.
function is_set_of_strings(name)
local value = _G[name]
assert(type(value) == 'table', name .. ' must be a table')
for key, _ in pairs(value) do
assert(type(key) == 'string', name .. ' must contain only string keys')
end
end
Changing the paths that Klunok writes to
prefix
Prefix used by default for all of the paths that Klunok writes to.
prefix = '/var/klunok'
prefix = 'klunok'
declare('prefix', nil, is_string)
prefix_var
Prefix used by default for non-store paths that Klunok writes to.
declare('prefix_var', prefix .. '/var', is_string)
store_root
Root of the store. This is where the backed up versions of files that you edit are placed.
declare('store_root', prefix .. '/store', is_string)
queue_path
Path to the queue. The queue is a directory that contains symbolic links to files that you edit. Klunok uses the queue for debouncing.
declare('queue_path', prefix_var .. '/queue', is_string)
journal_path
Path to the journal.
The journal is a file where Klunok records various events,
for example a file being backed up.
See the other events here.
If nil
, Klunok does not write journal events anywhere.
Specifying nil
is more efficient than '/dev/null'
.
journal_path = '/dev/stderr' -- write the events to the terminal
declare('journal_path', prefix_var .. '/journal', is_nil_or_string)
offset_store_root
Root of an auxiliary store used for keeping track of offsets of
history_paths
.
declare('offset_store_root', prefix_var .. '/offsets', is_string)
Debouncing
Debouncing means delaying copying until some time passes without any further modifications.
debounce_seconds
The delay in seconds of copying a file to the store after the last modification.
debounce_seconds = 60
declare('debounce_seconds', nil, is_positive)
Timestamps and versions
These settings use
the strftime
special characters.
journal_timestamp_pattern
Pattern of timestamps in the journal.
journal_timestamp_pattern = '%Y-%m-%d-%H-%M'
declare('journal_timestamp_pattern', nil, is_string)
version_pattern
Pattern of file versions in the store.
declare('version_pattern', 'v' .. journal_timestamp_pattern, is_string)
Controlling which files are copied to the store and how
By default, a file is copied to the store only if it's written to by
an editor application and it's not hidden.
A file is hidden if its name or name of one of its ancestor directories begins with a dot,
for example .config
.
Relative paths are interpreted relative to the common parent of directories
monitored via
the -w
command line option.
For example, if Klunok is invoked as
klunok -w /home/nazar/src -w /home/nazar/.config/nvim -w /home/nazar/.config/klunok
,
relatives paths are interpreted relative to /home/nazar
.
history_paths
, excluded_paths
, included_paths
and cluded_paths
can be paths not only to files, but also to directories.
If a path is a directory,
the setting applies to each file in the directory and its descendants.
More specific paths override less specific ones.
For example, let's consider this configuration:
excluded_paths['/home/nazar'] = true
included_paths['/home/nazar/src'] = true
excluded_paths['/home/nazar/src/secret.txt'] = true
included_paths['/home/nazar/.config/klunok'] = true
With this configuration:
/home/nazar/file.txt
is excluded;/home/nazar/src/file.txt
is included;/home/nazar/src/project/file.txt
is included;/home/nazar/src/secret.txt
is excluded;/home/nazar/.config/file.txt
is excluded because the.config
directory is hidden;/home/nazar/.config/klunok/file.txt
is included;/home/nazar/.config/klunok/.file.txt
is excluded.
editors
Filenames of executables that are considered editors. By default, only files edited by this applications are copied to the store. If you have problems registering an application as an editor, please read the editors section.
editors.ed = true
editors['emacs-28.3'] = true
editors.code = nil -- do not treat "code" as an editor
editors = {
atom = true,
code = true,
codium = true,
gedit = true,
howl = true,
hx = true,
inkscape = true,
kak = true,
kate = true,
kwrite = true,
micro = true,
nano = true,
nvim = true,
pluma = true,
rsession = true,
sublime_text = true,
vi = true,
vim = true,
xed = true,
['gnome-text-editor'] = true,
['notepadqq-bin'] = true,
['soffice.bin'] = true,
['vim.basic'] = true,
['vim.tiny'] = true,
['.gedit-wrapped'] = true,
['.gnome-text-editor-wrapped'] = true,
['.howl-wrapped'] = true,
['.hx-wrapped'] = true,
['.inkscape-wrapped'] = true,
['.kate-wrapped'] = true,
['.kwrite-wrapped'] = true,
['.pluma-wrapped'] = true,
['.xed-wrapped'] = true,
}
declare('editors', nil, is_set_of_strings)
history_paths
Paths that are assumed to be always appended to.
Only changes will be stored as new versions.
These paths are copied to the store regardless of the application that writes to them
and hence regardless of the editors
setting.
history_paths['/home/nazar/.bash_history'] = true
history_paths = {}
declare('history_paths', nil, is_set_of_strings)
excluded_paths
Paths that are never copied to the store.
excluded_paths = {}
declare('excluded_paths', nil, is_set_of_strings)
included_paths
Paths that are copied to the store regardless of the application that writes to them,
and hence regardless of the editors
setting.
included_paths = {}
declare('included_paths', nil, is_set_of_strings)
cluded_paths
Paths that are copied to the store only if they are written to by an editor application.
Editor applications are defined in the editors
setting.
This is the default, so this setting is mainly useful to:
- override
history_paths
,excluded_paths
andincluded_paths
; - include files in hidden directories if the files themselves are not hidden, for example
specifying
cluded_paths['/home/nazar/.config'] = true
will allow/home/nazar/.config/klunok.lua
to be copied when written to by an editor application, but/home/nazar/.config/.klunok.lua
and/home/nazar/.config/.klunok/config.lua
will not be copied.
cluded_paths = {}
declare('cluded_paths', nil, is_set_of_strings)
Projects
See the projects section.
project_roots
Roots of projects.
project_roots['/home/nazar/src/klunok'] = true
project_roots = {}
declare('project_roots', nil, is_set_of_strings)
project_parents
Directories that contain roots of projects.
project_parents['/home/nazar/src/'] = true
project_parents = {}
declare('project_parents', nil, is_set_of_strings)
project_store_root
Root of the project store.
declare('project_store_root', prefix .. '/projects', is_string)
unstable_project_store_root
Root of the unstable project store.
declare('unstable_project_store_root', prefix_var .. '/projects', is_string)
Performance tuning
These settings control the trade-off between RAM usage and performance. Tinkering with these settings cannot impact Klunok in any other way.
queue_size_guess
Guess of the maximum queue size.
declare('queue_size_guess', debounce_seconds * 2, is_positive)
path_length_guess
Guess of the maximum length of the majority of the paths in the system.
path_length_guess = 1024
declare('path_length_guess', nil, is_positive)
max_pid_guess
Guess of the maximum PID (process ID) in the system while Klunok is running.
max_pid_guess = 2^15
declare('max_pid_guess', nil, is_positive)
elf_interpreter_count_guess
Guess of how many ELF iterpreters are there in the system.
elf_interpreter_count_guess = 1
declare('elf_interpreter_count_guess', nil, is_positive)
Events
If a setting from this section is nil
, the corresponding event is not logged to
the journal.
Otherwise, the corresponding event is logged to the journal with
the provided prefix.
If prefix is not an empty string, it is separated from the
rest of the logged line by a tab.
event_queue_head_stored = ''
declare('event_open_exec_not_editor', nil, is_nil_or_string)
declare('event_open_exec_editor', nil, is_nil_or_string)
declare('event_close_write_not_by_editor', nil, is_nil_or_string)
declare('event_close_write_by_editor', nil, is_nil_or_string)
declare('event_queue_head_deleted', nil, is_nil_or_string)
declare('event_queue_head_forbidden', nil, is_nil_or_string)
declare('event_queue_head_stored', nil, is_nil_or_string)