diff --git a/site/source/blog/2017-06-30-howl-0-5-released.md b/site/source/blog/2017-06-30-howl-0-5-released.md
new file mode 100644
index 000000000..3120db084
--- /dev/null
+++ b/site/source/blog/2017-06-30-howl-0-5-released.md
@@ -0,0 +1,155 @@
+---
+title: Howl 0.5 released!
+location: Stockholm, Sweden
+---
+
+We are very happy to announce the release of [Howl](http://howl.io/) 0.5!
+Highlights of this release are below and the full changelog since 0.4 is
+included at the bottom of this blog post.
+
+READMORE
+
+### Code inspection support
+
+Code inspections integrates various types of annotations, typically from linters
+and similar checkers, directly into Howl:
+
+![Buffer inspections](/images/screenshots/monokai/buffer-inspect.png)
+
+The 0.5 release ships with built-in inspection support for
+
+- Lua (using [luacheck](https://github.com/mpeterv/luacheck))
+- Moonscript (using [moonpick](https://github.com/nilnor/moonpick))
+- Ruby (using the interpreter's built-in syntax checking)
+
+Support for more languages will likely come in the future. It's easy to add
+support for your own custom inspectors as well using the new inspect API.
+
+### Revamped configuration system
+
+Howl has always had a pretty flexible configuration system, allowing you to set
+configuration for different layers: globally, for a specific mode or a specific
+buffer. With 0.5 this is cranked up a notch, as it's now possible to set
+configuration not only for the aforementioned layers, but for different type of
+scopes as well. Having scopes allows you to specify configuration for a
+particular file for instance, or all files below a particular directory. Or
+files using a particular mode below a particular directory.. It makes for a very
+powerful and flexible configuration system, and is something that future
+releases is likely to build upon, e.g. to introduce project specific
+configuration, etc.
+
+You can read more about the new configuration system in the
+[manual](/doc/manual/configuration.html#configuration-variables).
+
+### New bundles
+
+- A new [Rust](http://www.rust-lang.org) bundle was added with lexing and
+indentation support.
+
+- A new Cython bundle provides syntax and structure support for
+[Cython](http://cython.org) code.
+
+- A new Dart bundle provides syntax and structure support for
+[Dart](https://www.dartlang.org) code.
+
+![New bundles](/images/blog/0-5-released/new-bundles.png)
+
+### New and improved commands
+
+- Added new commands `editor-move-text-left` and `editor-move-text-right`, bound
+to `alt_left` and `alt_right` by default. These move the current character or
+selected text left or right by one character while preserving the selection.
+
+- Added new commands `editor-move-lines-up` and `editor-move-lines-down`, bound
+to `alt_up` and `alt_down` by default. These move the current or selected lines
+up (or down) by one line while preserving the selection.
+
+- Added new command, `editor-replace-exec`, for replacing selection or buffer
+content with the result of piping it to an external command.
+
+## Full Changelog since 0.4
+
+### New and improved
+
+- New Dart bundle for [Dart](https://www.dartlang.org) code.
+
+- Make fixes to let OpenBSD build cleanly (thanks @oficial)
+
+- Various improvements for VI mode
+
+- Code inspection support for Lua using
+[luacheck](https://github.com/mpeterv/luacheck)
+
+- Code inspection support for Ruby using Ruby interpreter
+
+- Code inspection support for Moonscript using
+[moonpick](https://github.com/nilnor/moonpick)
+
+- Support for a new inspections framework (i.e. linting).
+
+- New Rust bundle provides syntax and structure support for
+[Rust](http://www.rust-lang.org) code.
+
+- Added `--version` command line flag.
+
+- Bundles can now declare dependencies on other modules using the
+`require_bundle` helper function.
+
+- Bundles can now expose modules using `provide_module` helper function.
+
+- LuaJIT was updated to LuaJIT-2.1.0-beta3
+
+- Theme compatibility fixes for newer Gtk versions
+
+- Quiet Gtk size allocation warnings in newer Gtk versions
+
+- Added support for X11 primary selection (e.g. copy & paste using middle
+button).
+
+- New Cython bundle provides syntax and structure support for
+[Cython](http://cython.org) code.
+
+- **breaking** - Default for `line-padding` setting has been changed to `0`. If
+you've relied on it: set it explicitly to its' previous value `1` in your Howl
+configuration.
+
+- **breaking** - Overhauled the configuration system to use a flexible *scope*
+and *layer* structure. Replaced all 'set*' commands with a new `set` command as
+part of this. See the documentation for more details.
+
+- Added `config.save_config_on_exit` variable to automatically save global
+configuration to `~/.howl/system/config.lua`.
+
+- Added the `save-config` command that saves the current global configuration to
+`~/.howl/system/config.lua`.
+
+- Changed undo coalescing to not be as greedy (e.g. coalescing pastes and
+ordinary edit revisions).
+
+- Added `custom_draw` flair type (`highlight.CUSTOM`).
+
+- Added command line help which is invoked by pressing `f1` while any
+interactive command is running. This displays a popup containing information
+about the command.
+
+- Added new commands `editor-move-text-left` and `editor-move-text-right`, bound
+to `alt_left` and `alt_right` by default. These move the current character or
+selected text left or right by one character while preserving the selection.
+
+- Added new commands `editor-move-lines-up` and `editor-move-lines-down`, bound
+to `alt_up` and `alt_down` by default. These move the current or selected lines
+up (or down) by one line while preserving the selection.
+
+- Bundled all required dependencies for running specs: `./bin/howl-spec` can now
+be run without any type of external dependecy.
+
+- Upgrade Moonscript to 0.5.0
+
+- Added new command, `editor-replace-exec`, for replacing selection or buffer
+content with the result of piping it to an external command.
+
+### Bugs fixed
+
+- Issues as seen on
+[Github](https://github.com/howl-editor/howl/issues?utf8=✓&q=closed%3A2016-05-30..2017-06-05%20is%3Aissue%20is%3Aclosed
+sort%3Acreated-asc)
diff --git a/site/source/doc/index.haml b/site/source/doc/index.haml
index ffb461d3e..5253520cb 100644
--- a/site/source/doc/index.haml
+++ b/site/source/doc/index.haml
@@ -7,12 +7,12 @@ title: Howl Documentation (master branch)
%p
This is the documentation for the master branch,
documentation for older releases can be found here:
- %a.alert-link(href = "/versions/0.4/doc/") [Version 0.4]
- ,
- %a.alert-link(href = "/versions/0.3/doc/") [Version 0.3]
+ %a.alert-link(href = "/versions/0.5/doc/") [Version 0.5]
,
+ %a.alert-link(href = "/versions/0.4/doc/") [Version 0.4]
+ \.
- Documentation is ever a ongoing work, and additional documentation
+ Documentation is ever ongoing work, and additional documentation
will appear here as it is written. However, don't hesitate to
%a.alert-link(href = "/contact.html") get in contact
if you have any questions.
diff --git a/site/source/getit.md b/site/source/getit.md
index 846d8fb61..ecdeb2501 100644
--- a/site/source/getit.md
+++ b/site/source/getit.md
@@ -5,26 +5,26 @@ title: Installation
# Installing Howl
Howl is developed on Linux, but it builds on other \*NIX platforms as well such
-as FreeBSD (with other \*BSDs presumably requiring only little work). It should
-be possible to port to OSX or Windows, should any brave soul be willing to put in
-the work.
+as FreeBSD and OpenBSD (with other \*BSDs presumably requiring only little
+work). It should be possible to port to OSX or Windows, should any brave soul be
+willing to put in the work.
You can install Howl by building it from source, either from a release or by
cloning the repository from Github.
## Latest release
-The latest release of Howl is 0.4.1. It was released at 2016-10-14, and is
+The latest release of Howl is 0.5. It was released at 2017-06-30, and is
available for download from:
-[https://github.com/howl-editor/howl/releases/download/0.4.1/howl-0.4.1.tgz](https://github.com/howl-editor/howl/releases/download/0.4.1/howl-0.4.1.tgz)
+[https://github.com/howl-editor/howl/releases/download/0.5/howl-0.5.tgz](https://github.com/howl-editor/howl/releases/download/0.5/howl-0.5.tgz)
-_MD5_: 9ef463f4d8b31e8954e70e507fbb1858
+_MD5_: 3bd902adb1fa8116053431f81b9a8b1f
-_SHA1_: 1434af03c5bc9f10d64ef93ca0ae68ccc7092fee
+_SHA1_: 905179ceb78f80ffd2612c5f22067d7b7b336bbc
__Release notes:__
-[Howl 0.4.1 Released](/blog/2016/10/14/howl-0-4-1-released.html)
+[Howl 0.5 Released](/blog/2017/06/30/howl-0-5-released.html)
## Building Howl from source
@@ -101,6 +101,14 @@ and confusion to arise.
## Older releases
+### Howl 0.4.1 released 2016-10-14
+
+_MD5_: 9ef463f4d8b31e8954e70e507fbb1858
+
+_SHA1_: 1434af03c5bc9f10d64ef93ca0ae68ccc7092fee
+
+[Download](https://github.com/howl-editor/howl/releases/download/0.4.1/howl-0.4.1.tgz)
+
### Howl 0.4, released 2016-05-31
[Download](https://github.com/howl-editor/howl/releases/download/0.4/howl-0.4.tgz)
diff --git a/site/source/images/blog/0-5-released/new-bundles.png b/site/source/images/blog/0-5-released/new-bundles.png
new file mode 100644
index 000000000..11ea86f0d
Binary files /dev/null and b/site/source/images/blog/0-5-released/new-bundles.png differ
diff --git a/site/source/index.haml b/site/source/index.haml
index bc79dd0bd..0e3af8599 100644
--- a/site/source/index.haml
+++ b/site/source/index.haml
@@ -48,12 +48,12 @@
.col-lg-4
%h2 Try it out!
%p
- Howl #{link_to "version 0.4.1", "/getit.html"}
- was released on 2016-10-14. Howl source is available on
+ Howl #{link_to "version 0.5", "/getit.html"}
+ was released on 2016-06-30. Howl source is available on
#{link_to "GitHub", "https://github.com/howl-editor/howl"} and released under
the #{link_to "MIT", "http://opensource.org/licenses/MIT"} license.
- Howl is currently developed on and available for Linux, though porting to other
- operating systems is possible.
+ Howl is developed on Linux and should build cleanly at least on Linux,
+ FreeBSD and OpenBSD. Porting to other operating systems should be possible.
%a.btn.btn-primary(href="getit.html") Download & install »
diff --git a/site/source/layouts/base_layout.haml b/site/source/layouts/base_layout.haml
index 68278cb6a..26aa95f8d 100644
--- a/site/source/layouts/base_layout.haml
+++ b/site/source/layouts/base_layout.haml
@@ -59,7 +59,7 @@
.footer-blurb
%div The Howl editor.
%div
- Copyright 2012-2016
+ Copyright 2012-2017
%a.alert-link(href='https://github.com/howl-editor/howl/contributors')
The Howl Developers.
diff --git a/site/source/versions/0.3/doc/api/application.html b/site/source/versions/0.3/doc/api/application.html
deleted file mode 100644
index 8351c0611..000000000
--- a/site/source/versions/0.3/doc/api/application.html
+++ /dev/null
@@ -1,120 +0,0 @@
-
-
-
The Application object acts as the main hub within the Howl editor. There exists
one and only one instantiated application object per Howl instance, available as
howl.app.
Properties
buffers
A list of currently open Buffer:s. The list is ordered by how recently a
buffer was shown. Thus, a currently showing buffer will come before a buffer
that is not shown, and not showing buffers will be ordered according to the
timestamp they were last shown.
A list of all existing Editor:s. Each editor can be placed in only one window
at a time, but this list holds all editors present for the current Howl instance
- regardless of whether they’re placed in the currently focused window or not.
next_buffer
This is the most recent buffer that is currently not showing in any editor. If
all buffers are currently showing it’s the first buffer in .buffers.
Adds the existing buffer to .buffers. If show is true, shows the buffer in
the currently active editor.
close_buffer (buffer, force = false)
Removes buffer from .buffers. If the buffer is modified, and force is not
true, the user is prompted before closing the buffer.
editor_for_buffer (buffer)
Returns the editor currently showing buffer, or nil if the buffer is not
currently showing in any editor.
new_buffer (buffer_mode = nil)
Creates a new buffer, and adds it to .buffers. buffer_mode can optionally be
specified to assign a specific mode for the new buffer directly. When not
specified, the default mode is used. See mode for more information about
buffer modes.
new_editor (options = {})
Creates a new Editor. Unless options specify otherwise, the newly created
editor is added to the currently focused window, to the right of the currently
focused existing editor. It’s set to show the buffer from the .next_buffer
property. The editor is added to .editors before the return of the method.
options can contain any of the following keys:
buffer: The buffer that should be shown in the editor. Defaults to .next_buffer.
window: The window to add the editor to. Defaults to the currently focused window.
placement: How the new editor should be placed in the target window. See
Window.add_view for more information about possible
placement values.
Example use (Moonscript):
buffer=howl.app\new_buffer!buffer.text='Show this text in the new buffer'howl.app\new_editor:buffer
new_window (properties = {})
Creates a new application Window. properties is table of window properties
to set for the new window, such as title, height and width. The window is added
to .windows before the return of the method. Returns the newly created window.
open_file (file, editor = _G.editor)
Opens the provided file. By default, unless editor specifies a
specific editor to open the file into, the file is opened in the currently
active editor. Emits the file-opened signal if the file was opened
successfully. If the file was successfully opened, returns the Buffer and the
Editor holding the buffer. Otherwise nil is returned.
save_all ()
Saves all modified buffers in one go.
save_session ()
Saves the current editing session to disk. This includes things such as
information about what buffers are open, the current state of the window, etc.
synchronize ()
Synchronizes all open files with their respective files, if any. This will cause
any non-modified buffers to be reloaded from disk, should the file be more
recently modified than the buffer.
quit (force = false)
Requests for Howl to quit. If any open buffers are modified, and force is not
true, the user will be prompted for verification before actually quitting.
Buffers are in-memory containers of text. While they are often associated with a
specific file on disk, this need not be the case. Instead they simply represent
some textual content loaded into memory, available for manipulation within Howl.
Buffer manipulation is typically done in one of two ways; it can be done as a
result of a user interacting with an Editor displaying a particular buffer, or
it can be done programmatically by manipulating the buffer directly.
Buffers can be created directly and used without being associated with a file or
an Editor, or without showing up in the buffer list. But if you want the
buffer to show up in the buffer list you need to either create it through, or
register it with, Application.
Whether the buffer contains any undo information that can be undo via the
undo method. You can assign false to clear any undo information
currently available for a particular buffer.
A configuration object that can be used to access and manipulate config
variables for a certain buffer. This object is automatically chained to the
buffer’s mode’s config property, meaning it will defer to what is set for the
mode (and in extension set globally) should a particular configuration variable
not be set specifically for the buffer.
data
A general-purpose table that can be used for storing arbitrary information about
a particular buffer. Intended as a way for any Howl code to have a place to
assign data with a buffer. Similar to properties but ephemeral,
i.e. any data in this table will be lost upon a restart. As this is shared by
all Howl code, take care to namespace any specific data properly.
eol
The line ending currently in effect for the buffer. One of:
'\n'
'\r\n'
'\r'
file
An optional file associated with the current buffer. Assigning to this causes
the buffer to be associated with assigned file, and loaded with the file’s
contents. If the file does not exist, the buffer’s current contents will be
emptied. The buffer’s title is automatically updated from the file’s
name as part of the assignment.
last_shown
A timestamp value, as obtained from Lua’s os.time, specifying when the buffer
was last showing.
length
The length of the buffer’s text, in code points.
lines
An instance of Lines for the buffer that allows for line based access to the
content.
any previously lexed content is re-lexed using the new mode’s lexer, if any
modified
A boolean indicating whether the buffer is modified or not. You can explicitly
assign to this to force a particular status.
modified_on_disk
For a buffer with an associated file, this is a boolean indicating whether the
file has changed since its contents was loaded into the buffer. Always false for
a buffer without an associated file.
multibyte
A boolean indicating whether the buffer’s text contains multibyte characters.
properties
A general-purpose table that can be used for storing arbitrary information about
a particular buffer. Intended as a way for any Howl code to have a place where
to store persistent information for a buffer. The contents of this is
automatically serialized and restored with the session. As this is shared by all
Howl code, take care to namespace any specific data properly.
read_only
A boolean specifying whether the buffer is read-only or not. A read-only buffer
can not be modified. Assign to this to control the status.
showing
A boolean indicating whether the buffer is currently showing in any editor.
size
The size of the buffer’s text, in bytes.
text
The buffer’s text. Assigning to this causes the entire buffer contents to be
replaced with the assigned text.
title
The buffer’s title. This is automatically set whenever assigning a file
to a buffer, but can be explicitly specified as well. Assigning to this causes
the buffer-title-set signal to be emitted.
Functions
Buffer(mode = {})
Creates a new buffer, optionally specifying its mode.
Methods
append(text)
Appends text to the end of the buffer’s current text.
as_one_undo(f)
Invokes the function f, and collects any modifications performed within f as
one undo group. Calling this, and subsequently calling undo will thus
undo all modifications made within f.
byte_offset(char_offset)
Returns the byte offset corresponding to the passed char_offset. Raises an
error if char_offset is out of bounds.
char_offset(byte_offset)
Returns the character offset corresponding to the passed byte_offset. Raises
an error if byte_offset is out of bounds.
Deletes the text between start_pos and end_pos, which specify an inclusive
range.
find(search, init = 1)
Searches for the text search in the the buffer’s text starting at character
position init. Returns character offsets start_pos, end_pos of the first
match, or nil if no match was found. A negative init specifies an offset
from the end, where -1 means the last character of the buffer.
Inserts text at the position given by pos, and returns the position right
after newly inserted text. examples.
lex(end_pos)
Lexes the buffer content using the modes lexer, if available. The
content is lexed up until end_pos.
redo()
Redo the last, previously undone, buffer modification.
reload (force = false)
Reloads the buffer contents from its associated file. Raises an error
if the buffer does not have any associated file. Emits the buffer-reloaded
signal. Returns true if the buffer was successfully loaded and false
otherwise. A modified buffer will not be reloaded (with false being returned),
unless force is true.
replace(pattern, replacement)
Replaces all occurrences of pattern with replacement, and returns the number
of replacements made. pattern can be either a Lua pattern, or a regular
expression.
rfind(search, init = @length)
Reverse search: searches backwards for the text search in the buffer’s text
starting at the character position init. Returns character offsets
start_pos, end_pos of the first match, or nil if no match was found. A
negative init specifies an offset from the end, where -1 means the last
character of the buffer. The rightmost character of the match found may be at
the init position, however, no part of the match will be to the right of
init.
Saves the buffer’s content to its associated file, if any. Emits the
buffer-saved signal. As part of saving the content, optionally removes any
trailing white-space and ensures that there’s an eol at the end of the file,
according to the strip_trailing_whitespace and ensure_newline_at_eof
configuration variables.
save_as (file)
Associates the buffer with, and saves the buffer’s content to file. The save
is performed using the same semantics as for save().
sub(start_pos, end_pos)
Returns the text from character offset start_pos to end_pos (both
inclusive). Returns an empty string when start_pos is larger than end_pos.
Negative offsets count from end of the buffer.
The clipboard module keeps track of copied text in Howl, and handles
synchronization with the system clipboard. It provides two ways of remembering
clipboard items: As a list of anynomous clips that is automatically updated with
each copy/delete/cut operation, and within named registers.
Clipboard items
A clipboard item is a simple Lua table. The simplest and most common type of
item contains only one field, text, that contains the text of the item. There
is no real restriction on what additional fields can be available for a
clipboard item (the fields can be specified when doing a push), but so
far one specific field is in use; The whole_lines field, when set to true,
indicates that the text should be considered a block of stand-alone lines,
rather than a simple chunk of text.
A table (list) of clipboard items available on the clipboard, with the most
recent item being at index 1 in the table. The maximum number of clipboard items
is controlled by the clipboard_max_items config variable. clips is
automatically updated whenever a new item is push()ed, prepending the
new item and removing older items as necessary.
current
The most recent anynomous clipboard item available on the clipboard.
registers
A table containing named clipboard items. As an example, suppose a clipboard
item containing the text “hello” has been push()ed to the abc
register. In that case the registers table would look like the following:
{abc={text:'hello'}}
Functions
push (item, options = {})
Pushes the specified item to the clipboard. item can either be table
containing a text field, along with optional additional fields, or it can be a
string in which case a clipboard item table is automatically constructed.
The optional options table allows for specifying a named register where to
store the item. The to field specifies the register name to use for storing
the clip in this case.
The pushed item is made available to the system clipboard automatically, except
when pushing to a named register using the to field in options.
Examples:
-- Push some text to the clipboardhowl.clipboard.push('my text')-- Push a clipboard item with additional fieldshowl.clipboard.push({text='my text',whole_lines=true})-- Push some text to the register 'a'howl.clipboard.push('my text',{to='a'})
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. To get an overview
of currently available variables, type set and press space at the readline
to view a list.
Configuration variables can be specified at three different levels in Howl,
in ascending order of priority:
Globally
The value set for the variable is used unless overridden by a mode or buffer
specific setting (the set command always sets variables globally).
Per mode
The value is set for a particular mode (e.g. “Lua” or “Ruby”), and is applied
whenever a buffer with that particular mode is active. The value is used unless
overridden by a buffer specific setting, and overrides any global setting.
Per buffer
The value is set for a particular buffer, and is applied whenever that buffer is
active. The value overrides any mode specific or global setting.
As described above, variables can be set on three different levels. No matter
the on what level they’re set, they’re always set (and accessed) using config
objects. For global accesses, you would use howl.config (this module). For
mode variables you access variables using the config object on a particular mode
instance, and similarly for buffer variables you use the config object for a
particular buffer.
The following code snippet illustrates the idiomatic ways of setting variables
on different levels:
A table of all known variables definitions, keyed by the variable name. For more
information about the structure of the definitions, see define.
Functions
define (options)
Defines a new config variable. Options can contain the following fields:
name: The name of the configuration variable (required)
description: A description of the configuration variable (required)
scope: An optional value specifying the scope of the variable. One of
local and global. Local variables are only allowed to be set for a
Buffer or a mode, whereas a global variable can only be directly on
the global config.
validate: A function that will be used for validating any values set
for this variable. Whenever a value is set for the variable, this function
will be invoked with the new value as sole parameter. The function should
return true if the value is valid, and false otherwise.
convert: A function that will be used for converting a value into a type
suitable for the variable. Whenever a value is set for the variable, this function
will be invoked with the new value as sole parameter, and the return value,
if not nil, will be used as the value. Keep in mind that variables are set not
only via code, but also interactively through commands. In the latter case, values
will invariably be strings.
tostring: A function that will be used for transforming a value into a
string representation suitable for displaying. This would typically be used for
more advanced option types. For symmetry it’s recommended that any convert
function is able to successfully convert the return value of tostring back
into a native representation.
options: A list (table) of valid values for the variable. Any set value will
be validated to be part of this list (after conversion), if set.
type_of: To simplify defining new variables in Howl, there are a set
of predefined types you can use that will handle validation, conversion,
etc. of variable values for you. You use one of these by specifying the
name of the predefined type here (as a string). Currently predefined
types are:
boolean
number
string
string_list
get (name)
Gets the global value of the variable named name. While getting the value of a
variable using get is perfectly fine, note that the idiomatic way of getting
variables values globally is to just to index the config module, like so:
localval=howl.config.my_variable
local_proxy ()
Returns a new configuration proxy object. A proxy object offers access to all
configuration variables defined in Howl, using simple indexing:
Proxy objects offers one additional feature in addition to the above; the
possibility of chaining to a different configuration object other than the
global howl.config module. Using the chain_to method, it’s possible to create
hierarchies of configuration objects (as is done in Howl for modes and buffers):
In the above example, proxy would defer any lookups not set locally to the
global howl.config module, and next_proxy would defer any lookups to proxy.
Proxies work against the global configuration variable definitions, and respects
any validations, conversions, etc., specified.
set (name, value)
Globally sets the value of the configuration variable with name name to be
value. An error is raised for any of the following scenarios:
There exists no known variable with name name
value is not a valid value for the parameter
The parameter was defined with the scope “local”
Upon a successful change, any listeners are notified. To remove any previously
set value, pass nil as value. While setting a variable using set is
perfectly fine, note that the idiomatic way of setting variables globally is to
just assign to the variable name in the config module, like so:
howl.config.my_variable=true
watch (name, callback)
Registers a listener for the variable named name. callback, which must be
callable, will be invoked whenever the specified variable has a new value set.
callback will be invoked with three parameters:
name - The name of the parameter being set
value - The new value of the parameter
is_local - A boolean indicating whether the value was set locally or globally.
The howl.interact module acts as the central registry of interactions in Howl
and lets you register new interactions as well as invoke interactions. An
interaction is a piece of functionality that is invoked as a function call and
it retrieves some information from the user. Interactions use the command line,
and optionally additional widgets, to get information from the user. For
example, consider this call to the read_text interaction:
name=howl.interact.read_textprompt:'Enter your name:'
Here the read_text interaction displays the given prompt in the command line
and lets the user type some text. When the user presses enter, the command
line is closed and the read_text function returns the text entered by user. If
the user presses escape, the function returns nil.
Interactions are commonly used to read user input when implementing interactive
commands. Howl includes a number of built-in interactions, such
as select_file, which lets the user choose a file, and select, which lets
the user choose an item from a list of options - see Built-in
interactions below for details.
An interaction is implemented as simple table that provides the name of the
interaction, a description, and either a handler or a factory field. Simple
interactions that just customize other interactions can be implemented easily
with just a handler function. More complex interactions that need greater
control on the command line behavior are implemented as factory based
interactions. Details for both handler and factory based interactions are in
register below.
Interactions are run by the command line, which maintains a stack of running
interactions. While one or more interactions are running, the command line API
can be used to display prompts in the command line, read and update the command
line text, as well as attach helper widgets above the command line (for example,
a ListWidget may show a completion list).
See also:
The CommandLine module for details about the command
line API
The command module for more information about commands in Howl
Functions
register (def)
Registers a new interaction. Registered interactions are available as fields on
the interact module itself, using the interaction name.
def is a table with the following fields:
name: [required] The name of the interaction.
description: [required] A short description of the interaction.
handler or factory: [required] One of handler or factory must be
specified, but not both.
The handler function implements the interaction and returns the result of the
interaction. Here is an example definition of a handler:
The above handler displays a selection list containing three items and lets the
user select one. Note that it reuses the select interaction. Handler functions
are blocking - i.e. the function does not return until the result of the
interaction is available.
The handler function may accept arguments. Any arguments passed when calling the
interaction are passed through to the handler function.
Interactions can also be implemented as factory based interactions. The
factory field is a function that returns an interaction instance table. This
table describes how various events should be handled and has the following
fields:
run: [required] A function that is called when the interaction is invoked.
This function is called with a finish callback function as the first argument,
followed by all arguments that were passed in the interaction call. The command
line is displayed and holds the cursor while the interaction is active. The
interaction must call finish whenever the result of the interaction is ready
and it must pass the result as the argument to finish. The interaction is
active until finish is called, so it is important to call finish at some
point.
on_update: [optional] A function that is called every time the text in the
command line is updated. The interaction instance table and the new text are
passed as two arguments to the function.
If the command line API is used to update the command line text from within
the run or the on_update function then on_update is not called. However,
if the command line text is updated when the user types some text, or from
within a keymap function, on_update is called.
keymap: [optional] A keymap that is used while the
interaction is active. This table specifies a mapping from keystroke names to
functions. When a key matching the keystroke name is pressed, the function is
invoked and the interaction instance table is passed as the first argument.
Here is an example implementation of an interaction using a factor:
The above example displays ‘Text:’ as the command line prompt and lets the user
enter any text in the command line. Whenever the text is updated by the user,
the interaction shows it in an info message. When the user presses enter, the
interaction finishes, returning the text entered by the user. If the user
presses escape, the interaction finishes, returning nil.
Note the special key called binding_for in the keymap. This demonstrates how a
keystroke can be specified indirectly instead
of by hard-coding. In the above example, the “view-close” key within
“binding-for” refers to the keystroke currently bound to the “view-close”
command. This means if the user presses the keystroke that is bound to the
“view-close” command - which is alt_w by default - the associated function
will be invoked, closing the command line and returning nil. If the user has
changed the key binding for the “view-close” command, that keystroke will be
bound to the function above instead.
unregister (name)
Unregister an interaction with the name name.
Built-in interactions
read_text (opts)
Lets the user enter free form text in the command line. Returns the text entered
by the user when the user presses enter, or nil if the user presses
escape. opts is a table that contains the following fields:
prompt: [optional] The prompt displayed in the command line.
title: [optional] The title displayed in the command line title bar.
Displays a list of options to the user and lets the user select one by using the
up and down arrow keys and pressing enter. Also lets the user narrow down
the options by typing something in the command line - the options list is then
filtered to show only those items that match the entered text.
Allows customization such as multiple columns, column headers, styling, user
provided selection etc. These are described below.
If the user presses enter, returns a table containing two fields - selection
and text, where:
selection is the item selected by the user (or nil if allow_new_value
was specified and the user specified option was selected - see allow_new_value
below).
text is the command line text at the time enter was pressed.
If the user presses escape, nil is returned.
opts is a table that specifies:
items or matcher: [required] One of items or matcher must be
specified, but not both.
items is a table containing a list of items, where each item represents
one select-able option and can be either a string for a single column list, or a
table for a multiple column list. When each item is a table, it contains a list
of strings, one each for each column. Instead of a string, a
StyledText object can be used as well.
matcher is a function that accepts a string and returns a table of items
similar to items. When called with the empty string, matcher should return a
list of all options. As the user types text into the command line, the matcher
function is called repeatedly and passed the typed text - it should return a
filtered list of items matching the given text.
prompt: [optional] The prompt displayed in the command line.
title: [optional] The title displayed in the command line title bar.
columns: [optional] A table containing the header text and style for each
column. Identical to the columns argument in the
StyledText.for_table function.
keymap: [optional] An additional keymap to used for this interaction.
on_selection_change: [optional] A function callback that is called
whenever the user changes the currently selected item (usually by using the
arrow keys). The callback function is called with the three arguments
(selection, text, items), where:
selection is the newly selected item
text is the current text in the command line
items is the current (possibly filtered) list of items
selection: [optional] The item that is initially selected by default. This
must be an item in the items list.
hide_until_tab: [optional, default: false] When set to true, the list of
items is initially hidden and only displayed when the user presses tab.
allow_new_value: [optional, default: false] When set to true, allows the
user to choose an option that is user specified and not available in the list of
available items. The user does this by typing some text that does not exactly
match any available option. This causes an additional option containing the
user’s text to be automatically added to the list of options. The user can then
select this new option (identifiable because it shows ‘New’ next to it) and
press enter.
reverse: [optional, default: false] When set to true, the list is displayed reversed,
i.e. the first item is displayed at the bottom and subsequent items above it.
Examples:
The following example displays a list of three items with a column header. It
also lets the user specify a color that is not in the given list.
color=howl.interact.selectitems:{'red','blue','green'}columns:{{header:'Color'}}allow_new_value:trueifcolorifcolor.selectionlog.info'You selected:'..color.selectionelselog.info'You selected a new color:'..color.text
The following example displays a two column list. It also shows how string
fields can be used in the items table. Unlike numerically indexed fields, string
fields are not displayed, but they can be used to associate additional data with
each item.
action=howl.interact.selectitems:{{'Run','Run this file',cmd:'run'},{'Compile','Compile this file',cmd:'compile'},}ifactionifaction.selection.cmd=='run'log.info'running...'elselog.info'compiling...'
select_buffer (opts)
Lets the user select a buffer from a list of all buffers. opts is a table
containing:
prompt: [optional] The prompt displayed in the command line. Default is no prompt.
title: [optional] The title displayed in the command line title bar. Default is ‘Buffers’.
Returns the Buffer selected by the user, or nil if the user
presses escape.
select_directory (opts)
Lets the user select a directory. Displays sub directories in a completion list
and allows the user to navigate the file system using either the completion list
or typing a path in the command line.
opts is a table containing:
title: [optional] The title displayed in the command line title bar. Default is ‘Directory’.
allow_new: [optional, default: false] When true, allows the user to
choose a nonexistent path by typing it in the command line and pressing enter.
Returns the File selected by the user, or nil if the user presses escape.
Note that if allow_new was specified, the returned file object may refer to a
nonexistent path.
select_file (opts)
Lets the user select a file. Displays files in the completion list and allows
the user to navigate the file system using the completion list or typing a path
in the command line.
opts is a table containing:
title: [optional] The title displayed in the command line title bar.
Default is ‘File’.
allow_new: [optional, default: false] When true, allows the user to
choose a nonexistent path by typing it in the command line and pressing enter.
directory_reader: [optional] A callback function that is used for getting
the list of files in any directory. The function should accept one argument - a
File object for a directory - and should return a list of File objects for
the contents of the given directory.
Returns the File selected by the user, or nil if the user presses escape.
Note that if allow_new was specified, the returned file object may refer to a
nonexistent path.
select_file_in_project (opts)
Lets the user select a file from a completion list containing all files in the
current project. opts is a table containing:
title: [optional] The title displayed in the command line title bar.
Default is the project path.
Returns the File selected by the user, or nil if the user presses escape.
select_line(opts)
Lets the user select a line from a list of source lines. opts is a table
similar to the table accepted by select, with the following
differences:
items, matcher and on_selection_change cannot be specified.
lines must be provided and should be a list of Line objects.
If the user presses enter, returns a table containing:
text: the command line text at the time enter was pressed.
column: the first position within line that matches the user entered text.
If the user presses escape, nil is returned.
select_location(opts)
Very similar to select, lets the user select an item from a list of
options. In addition, it displays a preview of the currently selected option in
the editor. Each item in items (or returned by matcher) must also have the
following fields:
file or buffer: One of file or buffer must be provided. This specifies
which file or buffer is previewed in the editor when this item is selected:
line_nr: The line number in file or buffer that is centered during the
preview.
yes_or_no (opts)
Lets the user select either ‘Yes’ or ‘No’ as an answer to a question. Returns
true if the user selects ‘Yes’, false if the user selects ‘No’ and nil if
the user presses escape. opts is table containing:
prompt: [optional] The prompt displayed in the command line. Default is no prompt.
title: [optional] The title displayed in the command line title bar. Default is no title.
Lua, by itself, does not provide regular expression. Instead it provides its own
more limited form of pattern matching. Regular expressions are instead provided
by the howl.regex module as an extension. To blend in with Lua, the operations
provided by the regex module closely mimics the corresponding operations found
in the Lua string standard library. Support for regular expressions is also
included in Howl’s string extensions, making it easy to use
within your code. Since regular expressions are not native to Lua, there’s no
syntactical sugar available for constructing a regular expression. Instead
regular expression are constructed as ordinary strings. The global function
r provides a constructor function for this. Since this is available in the
global namespace, it’s possible to construct a regular expression anywhere
within Howl just by prefixing a string with r, like so:
my_regex=r'\\d+[lL]'
You can then either use provided methods directly on the regular expression:
r'(r\\w+)\\s+(\\S+)':match('red right hand')-- => "red", "right"
Or use Howl’s string extensions which allows for passing in
regular expressions instead of Lua patterns:
locals='red right hand's:ufind(r'(\\w+)',5)-- => 5, 9, "right"s:umatch(r'(r\\w+)\\s+(\\S+)')-- => "red", "right"
Howl’s regular expressions are implemented as Perl compatible regular
expressions. While it’s an implementation detail, susceptible to change, they
are currently implemented on top of GLibs regular expression support. You can
read more about the full syntax supported by the implementation
here.
Holds the regular expression string used to construct the regular expression.
r('\\d+').pattern-- => '\\d+'
capture_count
Holds the the number of capturing groups in the regular expression:
r('foo(bar)(\\w+)').capture_count-- => 2
Functions
is_instance (v)
Returns true if v is a regular expression instance, and false otherwise.
r (pattern)
Constructs a regular expression from pattern. As was noted in the overview,
this is available globally as simple r. Raises an error if pattern is not a
valid regular expression. This function also accepts regular expressions as
parameters, in which case the passed regular expression is returned as is.
Methods
match (string [, init])
Matches the regular expression against string. If init is specified, starts
matching from that position. Has the same semantics as Lua’s string.match,
with the one significant difference that init as well as any returned
positional captures are treated as character offsets.
Finds the first match of the regular expression in s, optionally starting at
init if specified. Has the same semantics as Lua’s string.find, with the
one significant difference that init as well as any returned indices are
treated as character offsets.
locals='red right hand's:ufind(r'(\\w+)',5)-- => 5, 9, "right"
gmatch (s)
Returns an iterator function, where each consecutive call returns the next match
of the regular expression in s. Has the same semantics as Lua’s
string.gmatch, with the one significant difference that any positional
captures are returned as character offsets.
Signals provide a way of sending and receiving notifications about various
events that happens within Howl. For example, there are signals emitted whenever
text is added or deleted in a buffer, or a key is pressed in Howl, etc. By
“connecting” a handler for signal, you can easily hook into the ordinary workings
to add your own additional functionality. Signals are defined by their name, and
each signal can provide additional information about the event as parameters.
Each signal can have multiple handlers connected at a given time, which will all
be invoked, provided a handler does not explicitly halt the processing (see
emit for more information).
To view the list of currently registered signals within Howl as well as
information about the parameters you can use the describe-signal command.
This is a table of all currently defined signals within Howl, keyed by their
name. The value associated with each key is the signal information as passed to
register.
Functions
connect (name, handler [, index])
Connects handler to the signal specified by name. The optional index
argument specifies where in the handler list the handler should be placed. All
handlers for a specific signal are stored in a list, and the index specifies the
order in which they are invoked whenever a signal is emitted, where the handler
with index 1 is invoked first, followed by the handlers with greater indices.
An error is raised when trying to connect a handler for a signal that has not
been registered.
disconnect (name, handler)
Disconnects handler from the signal specified by name.
emit (name, parameters)
Emits the signal specified by name, along with any optional parameters
contained in parameters. parameters, if specified, should be a table with
keys matching those of the parameters specified for register. An
error is raised when trying to emit a signal that has not been registered.
When a signal is emitted each connected handler is invoked in turn, with
parameters as the sole argument. Should any handler return true, the
processing is halted and emit returns true. Otherwise, false is returned.
Any error triggered in a signal handler is logged, and processing continues.
register (name, options)
Registers the signal specified in name, with the options specified in
options. options can contain the following fields:
description: A textual description of what the signal is for (required)
Example of how to register a signal:
signal.register'mode-registered',description:'Signaled right after a mode was registered',parameters:name:'The name of the mode'
The timer module provides support for “timers”, that is having functions invoked
at a later time. All callbacks are always invoked on the main GUI thread.
Invokes callback as soon as possible, passing along any optional extra
parameters passed to asap. It might be unclear what the value of having a
callback invoked as soon as possible is, compared to just invoking directly. The
rationale for this is that there are cases where you want to schedule
destructive buffer modifications, but are not allowed to do so at the current
point in time (e.g. when in a signal handler for the text-deleted signal).
after (seconds, callback, …)
Invokes callback after approximately seconds seconds, passing along any
optional extra parameters passed to after. seconds can contain fractions,
allowing you schedule callbacks at sub-second rates.
As an example, the below snippet would cause the text “I was invoked with Log
me!” to be logged after approximately 500 milliseconds:
callback=(text)->log.info"I was invoked with #{text}"timer.after0.5,callback,'Log me!'
Instances of CommandLine are used to control the command line widget to obtain
user input while running an interaction. Each Window
instance has an associated .command_line field which
is used to access the command line instance.
Interactions work closely with the command line to obtain user input - the
command line API is used from within a running interaction to update things like
the displayed prompt. When no interaction is running the command line
functionality is not available.
Using the command line API is essential only when implementing new interactions.
Various built-in interactions can be
used to obtain user input and should be preferred where applicable.
The command line maintains a stack of running interactions. Whenever an
interaction is started, the new interaction is pushed onto the stack of
running interactions. When an interaction finishes, it is popped off the stack.
The command line maintains state for each running interaction independently. The
topmost interaction on the stack is called the active interaction.
The command line view contains the following widgets:
Command text entry: This is the primary text input widget that holds the
cursor while the command line is displayed. It shows both the prompt and the
text. The prompt is text set via code that is not user editable and
displayed before the text, which is editable text entered by the user. When
multiple interactions are running, the prompt and text for each is displayed
from left to right, however only the active interaction text (i.e. the rightmost
text) is editable.
Title bar: This contains an optional title for the command line view. See
title.
Notification bar: This displays notification messages. See
notify.
The prompt shown in the command line. This property gets or sets the prompt for
the active interaction. Read/write.
text
The user editable text currently in the command line. This property gets or sets
the text for the active interaction. Read/write.
title
The title of the CommandLine view. This property only gets or sets the title for
the active interaction. Read/write.
Methods
add_widget (name, widget)
Adds a custom widget widget in the command line view. name is the name used
to identify the widget. Widgets added are associated with the active interaction
and when the active interaction finishes, the associated widgets are
automatically removed. Currently two types of widgets are available - widgets
must be an instance of either ListWidget or NotificationWidget. Widgets may
provide their own keymap. The keymap for the active
interaction takes precedence over keymaps for the attached widgets.
clear ()
Clears the text part of the command line. The prompt is left intact.
clear_all ()
Clears the entire command line, including any prompts and texts from other
running interactions. When the active interaction exits, the prompts and texts
from other running interactions are automatically restored.
clear_notification ()
Clears any notification messages displayed, if any, and hides the notification
bar.
notify (text, level=‘info’)
Shows the notification bar containing the text message. The level can be
‘info’, ‘warn’ or ‘error’ and the message is styled accordingly.
pop_spillover ()
Returns and clears any unprocessed spillover text. See
write_spillover for a description of spillover.
remove_widget (name)
Removes the widget identified by name from the command line view.
write (text)
Appends text to the current text in the command line. This affects the text
for the active interaction only.
write_spillover (text)
Saves text as the current spillover. The spillover is the part of the text
that is left unprocessed by the current interaction but may be processed by
another interaction that is invoked. There is only one spillover for the command
line.
For example, if the text ‘open path/to/folder’ is pasted into the command line,
the active interaction may only process ‘open’ and write ‘path/to/folder’ to
spillover before invoking other interactions. An invoked interaction might then
use pop_spillover to retrieve ‘path/to/folder’ and process it.
Editors are the primary way of manipulating Buffers. They’re graphical editing
components which display the contents of a buffer visually and lets the user
manipulate them. An editor always contains a buffer, and is typically always
shown to the user.
Contains a Chunk representing the currently active text block. If no selection
is present, the chunk contains the entire buffer. With a selection present, the
chunk spans the current selection.
active_lines
Contains a list of the currently active lines. If no selection is present, this
will contain one element, the current line. With a selection
present, this holds all Lines included in the current selection.
Assigning another buffer to this property would cause that buffer to be
displayed in the editor, and would cause the before-buffer-switch and
after-buffer-switch signals to be emitted.
cursor
A Cursor instance for the particular editor. Can be used to access and
manipulate the cursor.
cursor_line_highlighted
A boolean controlling whether the line containing the cursor is highlighted.
Note that this is typically controlled via the cursor_line_highlighted
configuration variable instead of being set explicitly for an editor instance.
current_context
Contains the currently active context, i.e. the context for the
current cursor position. Read-only.
current_line
Contains the currently active line, i.e. the line that the cursor is
currently positioned on. Read-only.
horizontal_scrollbar
A boolean controlling whether the editor shows a horizontal scrollbar or not.
Note that this is typically controlled via the horizontal_scrollbar
configuration variable instead of being set explicitly for an editor instance.
indentation_guides
Controls how indentation guides are shown for the particular editor. Valid
values are (strings):
none: No indentation guides are shown
real: Indentation guides are shown inside real indentation white space
on: Indentation guides are shown
Note that this is typically controlled via the indentation_guides
configuration variable instead of being set explicitly for an editor instance.
indicator
A table of “indicators” for the current editor. An error is raised if you try to
access an unknown indicator (see register_indicator for
more information).
Example of modifying an existing indicator from a key handler:
howl.bindings.push{editor:{shift_i:(editor)->editor.indicator.vi.label='My interesting VI info text'}}
line_at_bottom
Holds the line number of the line visible at the bottom of the editor window.
Assigning this scrolls the editor window so the specified line is visible as
close to the bottom as possible.
line_at_center
Holds the line number of the line at the center of the editor window.
Assigning this scrolls the editor window so the specified line is as close
to the center as possible.
line_at_top
Holds the line number of the line visible at the top of the editor window.
Assigning this scrolls the editor window so the specified line is visible as
close to the top as possible.
line_numbers
A boolean controlling whether the editor shows line number to the left of the
text or not.
Note that this is typically controlled via the line_numbers configuration
variable instead of being set explicitly for an editor instance.
line_wrapping
Controls how line wrapping is performed. Valid values are (strings):
none: Lines are not wrapped
word: Lines are wrapped on word boundaries
character: Lines are wrapped on character boundaries
Note that this is typically controlled via the line_wrapping configuration
variable instead of being set explicitly for an editor instance.
lines_on_screen
Holds the number of lines currently visible on the screen. Read-only.
overtype
A boolean indicating whether typing inserts new characters in the .buffer or
overwrites them.
searcher
A Searcher instance for the particular editor. Can be used to initialize and
manipulate searches for the containing editor.
selection
A Selection instance for the particular editor. Can be used to access and
manipulate the selection.
vertical_scrollbar
A boolean controlling whether the editor shows a vertical scrollbar or not.
Note that this is typically controlled via the vertical_scrollbar
configuration variable instead of being set explicitly for an editor instance.
Functions
Editor (buffer)
Constructs a new Editor instance, displaying the specified buffer. You would
typically not use this directly, but instead create a new editor via
Application.new_editor.
Registers an indicator with the specified id. Placement indicates where the
indicator should be place. Possible values (strings) are:
top_left: Adds the the indicator to the top indicator bar, to the left.
top_right: Adds the the indicator to the top indicator bar, to the right.
bottom_left: Adds the the indicator to the bottom indicator bar, to the left.
bottom_right: Adds the the indicator to the bottom indicator bar, to the right.
An indicator is a simple label by default, but it’s possible to add an arbitrary
widget as an indicator via the factory parameter. If specified, factory must
be a callable object that when called returns a Gtk widget.
unregister_indicator (id)
Unregisters the indicator with the specified id.
Methods
backward_to_match (str)
Moves the cursor backwards to the next reverse match of str, within the
current line. Does nothing if str could not be found.
comment ()
Comments the current line or selection, if possible, by forwarding the request
to the current mode.
complete ()
Starts a completion at the current cursor position.
copy_line ()
Copies the current line to the clipboard.
delete_back ()
Deletes the preceeding character, if one is present. With a selection present,
deletes the selection.
delete_forward ()
Deletes the the current character, if one is present. With a selection present,
deletes the selection.
delete_line ()
Deletes the current line.
delete_to_end_of_line ()
Deletes from the current cursor column to the end of the current line.
duplicate_current ()
Duplicates the current line if no selection is present. With a selection
present, duplicates the text included in the selection.
forward_to_match (str)
Moves the cursor forward to the next match of str, within the current line.
Does nothing if str could not be found in the remainder of the line.
grab_focus ()
Grabs focus for the specified editor, i.e. causes the editor to be focused.
indent ()
Indents the current line or selection, if possible, by forwarding the request to
the current
mode.
indent_all ()
Indents all lines in the current buffer if possible, by selecting all lines and
forwarding the request to the current
mode.
insert (text)
Inserts text at the current cursor position.
join_lines ()
Joins the current line with the following line. Any space between the two lines
is collapsed to one space. The cursor is positioned at the end of the current
line, as it was before the join.
new_line ()
Inserts a new line at the current cursor position.
paste (opts = {})
Pastes the current contents of the clipboard, or a specific clipboard item, at
the current cursor position. opts is an optional table of options. It
currently can contain the following options:
where: Specifies where the clip is pasted. By default, the clip is inserted
at the current cursor position, or in the case of a multi-line clipboard item
above the current line. If where is specified as “after”, the behaviour
changes so that the clip is pasted one position to the right of the current
cursor position, or in the case of a multi-line clipboard item below the current
line.
clip: A specific clipboard item to paste.
redo ()
Redo:s the last undone edit operation, if any.
remove_popup ()
Removes any popup currently showing for the editor.
scroll_down ()
Scrolls the editor window down one line, if possible. I.e. causes the line below
the currently last showing line to be visible.
scroll_up ()
Scrolls the editor window up one line, if possible. I.e. causes the line before
the currently first showing line to be visible.
shift_left ()
If a selection is present, shift the entire selection one indent level to the
left. With no selection present, the current line is shifted one indentation
level to the left.
shift_right ()
If a selection is present, shift the entire selection one indent level to the
right. With no selection present, the current line is shifted one indentation
level to the right.
show_popup (popup, options = {})
Display the popup for the specific editor. The popup is displayed at
the current cursor position, unless otherwise specified in options. The can
only be one popup for a given editor at one time, invoking show_popup when an
existing popup is active will cause that popup to close.
options can contain the
following keys:
position: The character position at which to show the popup.
persistent: A boolean indicating whether the popup should remain shown as the user types. The default behaviour is to automatically remove the popup in response to a key press.
smart_tab ()
Inserts a tab if no selection is present, and indents the current selection on
indentation level to the right if a selection is present.
The behaviour in the first case is dependent on several configuration
variables.
Whether an actual tab is inserted or not is dependent on the use_tabs variable.
Invoking smart_tab when in leading white-space causes the current line to be indented if the tab_indents variable is set to true.
smart_back_tab ()
Dedents the current selection on indentation level to the left if a selection is
present.
If a selection is not present, then:
It dedents the current line if the cursor is in leading white-space or at the start of line content.
Moves the cursor one indentation level to the left if the cursor is in the middle of text.
to_gobject ()
Returns the Gtk view for the Editor.
toggle_comment ()
Comments or uncomments the current line or selection, if possible, by forwarding
the request to the current mode.
transform_active_lines (f)
A helper for transforming .active_lines within the scope of
Buffer.as_one_undo for the current buffer. Invokes
f with .active_lines, with any modifications being recorded as one undo
operation.
uncomment ()
Uncomments the current line or selection, if possible, by forwarding the request
to the current
mode.
undo ()
Undo:s the last edit operation, if any.
with_position_restored (f)
Invokes f, and restores the position to the original line and column after f
has returned. Should the indentation level for the current line have changed,
attempts to automatically adjust the column for the new indentation.
Below are the Howl specs in HTML format. While the specs are certainly not
complete, they are provided here in the hope that they may be useful for
better understanding the API, as well as providing some code examples.
Bundle specs are currently not included in the below list.
Howl is strongly in favor of completions, and will offer them whenever and
wherever possible. This section aims to provide an overview of Howl completions
work, and how to use them for best effect. Alternatively, if you consider
auto-completions a nuisance and would like to cut down on them you’ll learn how
to do that here as well.
Using completions
Interacting with completions
There are currently two different places where you’ll encounter completions: In
editors while editing text, and in the command line while entering commands. While
the completions offered differs as one would expect, the way you interact with a
completion list is the same:
You can press enter to accept the completion given. This will cause the
currently selected completion to be inserted at the cursor. The completion will
either be simply inserted at the cursor, or it will optionally replace the
current word. This behaviour is controlled by the hungry_completion
configuration variable.
You can press escape to remove the completion list.
You can continue typing, which will update the available completions. One
reason for this is that you want to narrow down the list of completions
so that the desired completion becomes selected, and choosable by the enter
key. Another is that the desired completion is not currently in the list of
completions. Completions in Howl are not “static”, but are updated each
time you type. So the initial list of alternatives are not necessarily
the only alternatives for completion. We’ll see next how completions are
matched which will give you an idea of how to utilize this for less typing.
You can navigate the current list of completions manually and choose one.
Pressing down or ctrl_n will move down the list, while up and ctrl_p
will move up the list. page_up will move one page up, and page_down will
move one page down.
When completing, Howl will try to match your input string against the available
completions in two ways: Exact matching and boundary matching. An exact
match means that your input string is found as-is in the completion. A boundary
match means that all parts of your input string matches at one or more
boundaries in the completion, typically defined as underscores, slashes, etc.
The below image illustrates the two different types of matches for a completion
list:
In the above example we can see that “aa” matches “attr_accessor” as a boundary
match, while “mraardvark” is an exact match. The order of the completions above
is no coincidence - boundary matches are preferred over exact matches.
Finally, a note about a gotcha:
As long as a completion list is showing, enter will always select the active
completion. This is typically what you want. However, at times you just want add
a new line, or enter the text as written. To avoid selecting the completion,
enter escape to close the completion list first.
Configuring completions
Here are some configuration variables you might want to tweak in order to
control completions:
complete:
Controls the mode of how completions are started. This is of interest
particularly if you want turn off automatically shown completion lists. If you
turn it off, you will have to explicitly request completions using the
editor-complete command for editors (bound to ctrl_space by default) or by
pressing tab in the command line.
completion_max_shown:
Controls the number of completions shown in the completion list.
hungry_completion:
Whether a selected completion will replace the current word or not.
completion_popup_after:
When auto-complete is one, this variable controls after how many characters the
completion list should pop up after.
completion_skip_auto_within:
This variable, unset by default, contains a list of style patterns where the
completion list should not automatically pop up.
inbuffer_completion_max_buffers:
For the in-buffer completer, this controls the number of open buffers that are
consulted for completions.
inbuffer_completion_same_mode_only:
For the in-buffer completer, this controls whether only open buffers with the
same mode as the current one is consulted or not.
Howl looks for a startup file in the Howl user directory: ~/.howl. It
searches for either ~/.howl/init.lua or ~/.howl/init.moon. Which one
to pick depends on your preference with regards to language - init.moon
for Moonscript and init.lua for
Lua. 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. While the startup
file would typically be mostly used for various type of configuration,
there’s no restriction to what you can do in it - you have access to the entire
Howl API.
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 an 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 heremy_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. To get an overview
of currently available variables, type set and press space at the command
line to view a list.
Configuration variables can be specified at three different levels in Howl,
in ascending order of priority:
Globally
The value set for the variable is used unless overridden by a mode or buffer
specific setting (the set command always sets variables globally).
Per mode
The value is set for a particular mode (e.g. “Lua” or “Ruby”), and is applied
whenever a buffer with that particular mode is active. The value is used unless
overridden by a buffer specific setting, and overrides any global setting.
Per buffer
The value is set for a particular buffer, and is applied whenever that buffer
is active. The value overrides any mode specific or global setting.
As an example of how this could be used a real life scenario, consider the
case of indentation: You might generally prefer your source code to be indented
with two spaces. However, some languages might have generally accepted style
guidelines where four spaces is considered the norm. Even so, certain projects
written in such a language might have adopted the inexplicable custom of using
three spaces for indentation.
In such a scenario, you could set the indent variable to 2 globally, override
it with 4 for a given mode, and override with 3 for any buffer with an associated
file in a certain directory.
Programmatic access
As described above, variables can be set on three different levels. No matter
the on what level they’re set, they’re always set (and accessed) using
config objects. For global accesses, you can use the main config object in
the howl namespace. For mode variables 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:
Let’s have a look at configuring the indent variable as discussed in the
overview, using the below example Moonscript init file (init.moon):
importconfig,mode,signalfromhowlimportFilefromhowl.fs-- Set indent globally to two spacesconfig.indent=2-- Use four spaces for C filesmode.configure'c',{indent:4}-- Hook up a signal handler to set it to three for this weird projectthat_project_root=File'/home/nino/code/that_project'signal.connect'file-opened',(args)->ifargs.file\is_belowthat_project_rootargs.buffer.config.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.
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 signal.connect to add a signal handler
for the file-opened signal, and set the indent for a certain buffer with
an associated file under a given directory.
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 bindingseditor={-- bind ctrl_k to a named commandctrl_k='editor-cut-to-end-of-line',-- bind ctrl_shift_x to a closurectrl_shift_x=function(editor)-- replace the active chunk with a reversed bracked enclosed versioneditor.active_chunk.text="<"..editor.active_chunk.text.ureverse..">"end},-- Bind the Emacs find-file binding (C-x C-f) to the open commandctrl_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.command.vi_on!
Consult the documentation for the command module for more
information.
This section attempts to highlight a few things that you might encounter while
editing, or that might simplify your editing experience.
Auto pairs
Auto pairs, where a matching end character is inserted automatically as you type
the starting character, is supported out of the box in Howl. This can save you
some typing as you don’t have to type out the ending character for every
combination of [], {}, etc. If you select some text and type an auto pair
character such as [, auto pairs will enclose the selection in matching start
and end characters. Exactly what pairs are enabled for a buffer is specified
by the buffer’s mode.
In case you find auto pairs annoying, the configuration variable
auto_pair lets you specify whether you want this on or not.
Code blocks
Code blocks are code snippets that are automatically inserted as you type. They
differ from completions in that they are inserted without any prompting, and can
include more text than a single completion would. As an example, if you were to
type the following Lua, and press enter:
functionfoo()-- <- cursor here
Howl would automatically insert the matching end for you, like so:
functionfoo()-- <- cursor hereend
The configuration variable auto_format lets you specify whether you want this on
or not.
Buffer structure
When editing a larger buffer, it can be challenging to quickly jump to a
specific part of it. The buffer-structure command (bound to alt_s by
default) can provide you with an outline for the current buffer:
How well this works is depending on the language mode - should the mode not
provide custom support for this a general, indentation-based, structure is
provided.
Buffer search
The buffer-search-forward and buffer-search-backward commands (bound to
ctrl_f and ctrl_r respectively) provide an easy way to find exact matches
near the cursor. The visible matches are highlighted in real-time, as you type
your search text.
The match closest to the cursor is focused and you can use the up and down
keys to jump between different matches. Hitting enter moves the cursor to the
focused match.
Whole word search
Looking only for whole word matches can be useful when there happen to be many
sub-string matches that you want to ignore. The buffer-search-word-forward and
buffer-search-word-backward commands (bound to ctrl_period and ctrl_comma)
work similar to the buffer search commands above, but they only match whole
words and they also automatically search for the current word at the cursor.
Note that the match within ‘text_len’ is not highlighted in the screenshot
above.
The up and down keys jump between the matches for these commands as well.
Buffer grep
Buffer grep works as an alternative to the regular buffer-search-forward command for
searching for something in the current buffer. It let’s you grep all lines in
the current buffer for a search string and displays all matching lines in
real-time as you type:
This is decidedly less effective than doing a plain search, which can be a
factor for large buffers.
Replacement
The buffer-replace and buffer-replace-regex commands provide a way to
replace multiple matches of some text or a regular expression in the current
buffer.
The simpler buffer-replace command is used for replacing exact matches of some
text. After invoking buffer-replace, you type the text you want to match (also
called the target text), followed by / (the forward slash is the default
separator), followed by the replacement text. As an example, if you want to
replace all instances of ‘showing’ with ‘visible’, you would invoke
buffer-replace and then type ‘showing/visible’.
As you type, the displayed preview buffer is updated to show the effect of your
replacement. You can use the up and down arrow keys to jump between
different matches in the preview buffer. You can press alt_enter to toggle
whether or not the currently focussed match should be replaced with the target -
this lets you selectively preserve some matches from being replaced.
Once you are happy with the replacements as displayed in the preview buffer, you
can press enter to commit the replacements - this updates the original buffer.
If you want to use ‘/’ as part of your target text, you need to use a different
separator. To specify this, type backspace immediately after invoking
buffer-replace - this deletes the automatically inserted leading ‘/’. Now type
a separator of your choice (for example, ‘#’), followed by the target text, the
chosen spearator, and then the replacement text.
The buffer-replace-regex command works similarly to buffer-replace but the
target text is specified as a regular expression and not as an exact match. In
addition, the replacement text can contain back-references to specific parts of
the target. A back-reference is specified as ‘\’ followed by a number. For
example, ‘\1’ refers to the first group in the matched text.
Selecting some text in the editor before invoking a replace command restricts
the replacement to the selected text only.
Comments
The editor-toggle-comment is bound to ctrl_slash by default, and let’s you
quickly comment and uncomment code.
Clipboard history
Howl manages its own clipboard, and lets you paste cut or copied text other than
the latest text in the clipboard. The editor-paste.. command (bound to
ctrl_shift_v by default) opens a list of previous clips and pastes any
available clip that you choose:
Word wrapping
Howl provides optional support for hard wrapping of text paragraphs. The
fill-paragraph command, bound to alt_q by default, will reflow a paragraph
so that each line is at most as long as the configuration variable
hard_wrap_column specifies.
You can also turn on automatic reflowing of paragraphs if you like, by
customizing the auto_reflow_text configuration variable. This reflow the
current paragraph as you type if needed. For example, the author keeps this in
his ~/.howl/init.moon to enable automatic reflowing for markdown documents:
Unlike most other feature, this is not enabled by default, so you have to
explicitly turn it on.
Version control diffs
The version control support in Howl is currently rather spartan, and will be
expanded in future releases. However, if you’re using Git you might find the
vc-diff and vc-diff-file commands useful. The former displays a complete
diff for your entire repository, while the latter displays a diff for the
current file.
Documentation popup
Support for this is dependent on the language mode, and is currently only
available for Lua and Moonscript.
The show-doc-at-cursor command, bound to ctrl_q by default, pops up
documentation for the symbol at the cursor if available:
Howl provides a text-oriented interface, and so you want see any traditional
graphical open file dialogs. Instead you’ll open files from the command line,
using commands. First off, the open command lets you navigate the file system
and select a file to open. It’s bound to ctrl_o in the default keymap, and is
also aliased as e for those more comfortable with VI. Triggering that command
opens up the command line prompt and displays the contents of the current
directory, as determined by the current buffer:
Once you’re in the prompt, you can then select the file of your choice. You can
choose the file from the list by manually navigating using the arrow keys,
ctrl_p, ctrl_n, etc., if you want. However, it’s usually much faster to
narrow down the list by typing something that matches the file you want. Just as
with completions (as described in the previous section),
your input string will be matched against the available files using boundary
matching or exact matching. Once the selected file ends up at top, simply press
enter to open it.
If the file you selected is a directory, the list and prompt will update itself
for the selected directory, letting you pick a file there. On the other hand, if
you want to go up a directory level, press backspace. For convenience, if you
type ~/ or / at the start of a prompt, you will be directly transferred to
your home directory and the root directory respectively.
Opening a file within a project
Navigating the file system and selecting a file for opening is all fine and good
for the odd file you want to open. Most of the time however, you’re likely
working within the context of a project of some sort. In that case it can
quickly get tedious to navigate directories up and down, and especially for
larger projects, since you might not even be entirely sure where a desired file
is placed. Fortunately, Howl offers the project-open command to help with
this.
Howl provides simple and light-weight support for projects. In Howl, a project
is currently defined as root directory containing the project files below, with
an optional version control system attached to it. The project-open command
(bound to ctrl_p by default) provides a way of selecting a file to open from
all the files contained in your project. Thanks to the matching capabilities,
this often provides a much faster way of opening files than navigating the
project directory structure do. Below you’ll see an example for the Howl project
itself:
Saving buffers
Invoke the save command to save the current buffer to a file. If the buffer
has an associated file, it will get saved to that file, and otherwise you’ll be
prompted for the file name to save the buffer to. The save command is bound to
ctrl_s in the default keymap, and is also aliased as w.
To save a buffer with an associated file to another file, invoke the save-as
command (bound to ctrl_shift_s in the default keymap). There’s also a related
command, save-and-quit, that allows you to save any modified buffers and exit
Howl in one go.
Switching between open buffers
While Howl provides the ability to view more than one buffer at a time by
supporting multiple open views, you’ll likely have more buffers open than you
can fit on your screen. In order to switch to another buffer, you can use the
switch-buffer command (bound to ctrl_b by default):
This let’s you select an open buffer to display in the current view. The list as
presented is ordered by access time, thus you’ll see your most recent buffers at
the top with less recently used buffers below. As always, you can type to narrow
down the list.
Another command that might prove useful to you is
switch-to-last-hidden-buffer. This will switch to the most recently accessed
buffer that is not currently showing in any view, and is thus useful for quickly
switching between to related files in the same view.
Creating new buffers / files
So what do you do if you just want to create a new buffer, that will eventually
get saved to a new file? Well, there is a new-buffer command available for
this, which will create a new buffer without an associated file, that you can
later save to a named file. This is not bound to any key by default however, and
the reason for that is that it’s not considered that useful. Most of the time
when you want to create a new file, you already know what the file should be
named. And as is the case with some other editors, such as Emacs or Vim, it is
not a requirement for a file to actually exists in order to successfully open
it. Thus, if you want to create a new file whose name you already know, just
open the file using the open command and enter the new name of the file.
If this sounds strange to you, consider that a buffer and a file are two
different entities, and that a buffer only has an association with a file. So
when you open a non-existing file, you create a new buffer with an association
to the specified file, which does not have to exist. As you save the buffer, the
file will be created as necessary.
So you’ve installed Howl, but how do you actually use it? (if you haven’t
installed it yet, see the instructions here). As you might have
read earlier, Howl is rather minimalistic when it comes to the user interface,
and it prefers text-based interfaces over the traditional graphical ones. As
such, you will not find the typical menu or toolbar that might otherwise help
you get started with other applications. In this section we’ll look at the basic
concepts of Howl, which will hopefully help you get a better understanding of
what Howl is and how you can use it.
The visual components
To begin with, let’s examine the basic visual components that you see when you
use Howl. Using one of the screen shots as an example:
As per the above image, the three basic visual components are windows, views and
the command line.
Windows
When you start up Howl you’ll see one window, containing everything else. You
could potentially have multiple windows open for the same Howl instance, even
though this is not well-tested at the current time.
Views (Editors)
A window can contain an arbitrary number of views, which are any type of
graphical component. Currently there are only type of view available, called an
“editor”. Editors are the source editing components you’ll work with most of the
time. Editors themselves contain other visual components, such as header and
footer components with “indicators” used for displaying for example the current
position in the file. An editor always displays exactly one buffer.
As can be seen in one of the screen
shots it’s possible to have multiple
views/editors along each other in the same window.
Command line
The command line component is where you enter your commands. As we will see,
commands are the primary way of interacting with Howl, used for mostly anything
within Howl. The command line allows you to input these commands, and provides
completions as necessary.
Other basic concepts
Buffers
Buffers are what you work with when you edit. Buffers are typically associated
with a file, used for storing the buffer contents on disk. This is not
necessarily the case however, as buffers can just as well exist without any
association to a given file (consider for instance the “Untitled” buffer you see
when you first open Howl without passing any arguments). You can have as many
buffers open as you want, only limited by the amount of available memory. You
can choose to display a given buffer in an existing editor by switching buffers
(via the switch-buffer command).
Modes
All buffers have a mode associated with them. Modes handles everything
language/format specific for a certain buffer, such as indentation support,
syntax highlighting, etc. Modes are typically assigned to a buffer
automatically, e.g. when a file is opened a mode is automatically selected based
on the file’s extension, etc.
Key bindings
Key bindings are used for triggering certain actions whenever a certain key
combination is entered. Actions are typically commands, but can also be custom
functions.
Signals
Signals are fired as a result of different actions within Howl, and provides a
generic way of receiving notification. You could for instance register to be
notified whenever a buffer was saved.
Entering commands
Manual entry
As said previously, most interactions with Howl will typically be the result of
a command. So let’s gets started with manually entering some basic commands. To
enter you first command, you need to open the command line. In the default keymap,
this is “bound” (mapped) to the alt+x key combination, so enter that to open
the command line. You should now see the command line being opened, awaiting your
command. If you want to, press tab to bring up a completion list of available
commands.
As an example, let’s open a file for editing. Enter open and press space to
open a file. You will automatically be presented with completions. Navigate up
and down the directory tree as needed, using backspace and enter, and press
enter once you’ve found the file you wanted.
Using completions
Completions are available within the command line, using the tab key. Completions
are enabled by default for most commands as you will see, but they are not
automatically shown when entering commands. To explicitly request completions of
the available commands, press tab. To cancel completions, press escape. For
commands that want some kind of hierarchal input, such as file commands,
pressing backspace when at the beginning of a prompt allows you to move up in
the hierarchy.
The completion list will automatically filter itself to match whatever you type
in the command line.
Using keyboard shortcuts
Manually entering commands is typically not something you want to do for
commands that you invoke often. Unsurprisingly, any command can be bound to a
key combination as well. Howl comes with a default keymap for the most basic
bindings (not complete by any measure, so please suggest missing additions). So
in the previous example, you could have more quickly opened a file using the
ctrl+o key binding. Assigning your own combinations is easy, and will be
discussed later on in the manual. Note: If you bring up the completion list at
the command prompt, you’ll see that it includes the key bindings for the listed
commands when available.
VI users:
Howl ships with a basic VI bundle, which you can activate with the vi-on
command. It’s rather incomplete at this point and will be improved, but contains
at least some of the basic editing functionality.
As noted at the top of the documentation index, the documentation is not
complete. This means that there’s a lot more interesting stuff about Howl that
has yet to documented, both for the API documentation and the manual. This
includes things such as Howl’s bundle system and how you can write your own
bundles, how to add support for a new language, how to create a new theme, etc.
Unfortunately there are only so many hours in a day.
Meanwhile, if this looks interesting to you, then dive in! Don’t be afraid of
browsing through the source to see what’s there. If you’re wondering about how
something works, have a look to see if there’s any spec that
covers it. And you can always get in contact.
While most of the time spent developing is likely to be editing, there’s often a
need for running external commands, such as compilers, test, etc., as part of
the work flow. Howl provides two different commands for this purpose, exec and
project-exec, bound to ctrl_shift_r and ctrl_alt_r respectively. They both
work the same way, allowing you execute a command of your choice from within a
directory, displaying any output in a buffer. The difference is that
project-exec starts out from from the root of your current project directory,
while exec starts out in the directory associated with the current buffer.
Interacting with the prompt
Upon executing one of the above commands, you’ll end up in the prompt. The
prompt offers specific completions and ways of making it easier to input your
command. Just as with the ordinary prompt for opening a file, you can enter
backspace to move up one directory level. Entering ~ and / allows you to
quickly run a command from your home directory, or the root directory,
respectively. Completions are available both for commands themselves as well as
arguments, and support completion of arguments spanning multiple directory
levels (e.g. ./my-dir/sub-dir/foo).
As a final convenience, the prompt supports an internal cd command, allowing
you to move to a different directory within the prompt.
Running commands
Once you have typed your command, you can run it by pressing enter. Both the
exec and project-exec commands will launch the specified command in the
directory displayed in the prompt, using your shell. The fact that your shell is
used for this allows for the use of any ordinary shell aliases you normally use
(provided that they are available for non-login shells), as well as shell
constructs such as for loops, etc.
The command thus launched will be associated with a new buffer, in which any
output from the command will be displayed. Commands will not block the editor
while running, so you’re free to resume your other tasks while the the command
runs. There is also no limitation on the number of concurrently executing
commands you might have - they will all be associated with their own buffers
that you can switch between as you please, as illustrated by the below image.
Also illustrated by the above image is the fact that Howl adds some extra
support for displaying a command’s output, with the example in question showing
off Howl’s support for ANSI color escape codes. For less fanciful commands Howl
will display any standard output plainly, while error output will be shown in a
different style to allow you to quickly differentiate between the two.
project-build
Howl features another execution command, project-build, bound to ctrl_shift_b. This is the same as
project-exec, but it executes the command defined in config.project_build_command.
Dealing with rogue commands
While a well behaved command will exit on its own, occasionally there are those
that need an helping hand. Pressing Ctrl + c when in a process buffer will
send the SIGINT signal to the currently running process, hopefully hastening
its way towards a graceful exit (Ctrl + c while a selection is active will
still only copy the selection). For the obstinate cases, Ctrl + backslash can
be used to send the SIGKILL signal.
When you start Howl, you’ll be presented with one window, containing one editor
view. Assuming there is sufficient screen estate to spare, it’s often desirable
to have multiple views open in the same window, which let’s you view one or more
buffers simultaneously. This is supported in Howl, where windows can contain an
arbitrary number of views, arranged in a grid pattern.
In the above picture you have two editors in the first row, each occupying one
column each. In the bottom row you see one editor view occupying two columns.
While the most you’ll likely ever want is around two or three separate view, you
can divide windows up in unreasonable ways should you so desire:
There is currently no way to manually resize views; views are reflowed to fill
the entire window, and will occupy the maximum amount of space available to
them.
View commands
Below is a list of some useful commands that work with views:
Creating views
view-new-right-of: Creates a new view, right of the current one.
view-new-left-of: Creates a new view, left of the current one.
view-new-above: Creates a new view, above the current one.
view-new-below: Creates a new view, below the current one.
Navigating views
view-left: Moves focus to the view left of the current one.
view-right: Moves focus to the view right of the current one.
view-up: Moves focus to the view above the current one.
view-down: Moves focus to the view below the current one.
view-next: Moves focus to the next view in the grid. Bound to ctrl_tab
in the default keymap.
Each of the four directional commands above (view-left, view-right, view-up and
view-down) have two additional companion commands:
view-<direction>-wraparound
These commands will wrap around the grid if no view could be found in the
specified direction. The view-right-wraparound command for instance would go
to the view to the right, should it exist. If not, it would go to first view in
the next row should that exist, and to the first view of the first row if not.
view-<direction>-or-create
These will automatically create a new view in the specified direction, if
necessary. For instance, the view-right-or-create command would go to the view
to the right if there was a view to the right. Should no such view exist
however, it would be created first. The last set of commands are bound to
shift_alt_left + <arrow key> in the default keymap.
Manipulating views
view-close: Closes/removes the current view. Bound to ctrl_w in the
default keymap.
assert.is_not_nilgrammar\match'one'assert.is_not_nilgrammar\match'so one match'assert.is_not_nilgrammar\match'!one'assert.is_not_nilgrammar\match'one()'assert.is_not_nilgrammar\match'then two2,'assert.is_nilgrammar\match'three'
only matches standalone words, not substring occurences
adds special case translations for certain common keys
for_keynames={kp_up:'up'kp_down:'down'kp_left:'left'kp_right:'right'kp_page_up:'page_up'kp_page_down:'page_down'iso_left_tab:'tab'-- shifts are automatically prependedreturn:'enter'altL:'alt'altR:'alt'shiftL:'shift'shiftR:'shift'ctrlL:'ctrl'ctrlR:'ctrl'}forname,alternativeinpairsfor_keynamestranslations=bindings.translate_keykey_code:123,key_name:nameassert.includestranslations,alternative
substitutes certain key names to prevent ambiguity
keymap={k:->error'a to the k log'}bindings.process{character:'k',key_code:65},'mybad',{keymap}assert.is_not.equal#log.entries,0assert.equallog.entries[#log.entries].message,'a to the k log'
(.. when the handler is a string)
runs the command with command.run() and returns true
the word boundaries are determined using the variable word_pattern
b.config.word_pattern='[Əl]+'assert.equal'Əll',context_at(3).word.textb.config.word_pattern='["Ə%w]+'assert.equal'"HƏllo"',context_at(3).word.textassert.equal'"HƏllo"',context_at(8).word.text-- after "assert.equal'',context_at(9).word.text-- after ','
.modified indicates and allows setting the modified status
b=Buffer{}assert.is_falseb.modifiedb.text='hello'assert.is_trueb.modifiedb.modified=falseassert.is_falseb.modifiedb.modified=trueassert.is_trueb.modifiedassert.equalb.text,'hello'-- toggling should not have changed text
.read_only can be set to mark the buffer as read-only
with_tmpfile(file)->config.ensure_newline_at_eof=trueb=buffer''b.file=fileb.text='look mah no newline!'b\save!assert.equal'look mah no newline!\n',b.textassert.equalfile.contents,b.text
(.. when config.ensure_newline_at_eof is false)
does not appends a newline
with_tmpfile(file)->config.ensure_newline_at_eof=falseb=buffer''b.file=fileb.text='look mah no newline!'b\save!assert.equal'look mah no newline!',b.textassert.equalfile.contents,b.text
returns completions for local matches in the buffer
buffer.text=[[
Hello there
some symbol (foo) {
if yike {
say_it = 'blarg'
s
}
}
other sion (arg) {
saphire = 'that too'
}
]]comps=complete_atbuffer.lines[5].end_postable.sortcompsassert.same{'saphire','say_it','sion','some','symbol'},comps
does not include the token being completed itself
buffer.text=[[
text
te
noice
test
]]assert.same{'text','test'},complete_atlines[2].end_pos-1assert.same{'test'},complete_at3
favours matches close to the current position
buffer.text=[[
two
twitter
tw
other
and other
twice
twitter
]]assert.same{'twitter','two','twice'},complete_atlines[3].end_pos
offers "smart" completions after the local ones
buffer.text=[[
two
twitter
_fatwa
tw
the_water
]]assert.same{'twitter','two','the_water','_fatwa'},complete_atlines[4].end_pos
works with unicode
buffer.text=[[
hellö
häst
h
]]assert.same{'häst','hellö'},complete_atlines[3].end_pos
detects existing words using the word_pattern variable
options can be a table of tables containg values and descriptions
options={{'one','description for one'}{'two','description for two'}}config.definename:'with_options_desc',description:'test',:optionsassert.raises'option',->config.set'with_options_desc','three'config.set'with_options_desc','one'
define(..) invokes watchers with <name>, <default-value> and false
callback=spy.new->config.watch'undefined',callbackconfig.definename:'undefined',description:'springs into life',default:123assert.spy(callback).was_called_with'undefined',123,false
returns true if the line can be combined with the following one
buffer.text='itty\nbitty'assert.is_truetext.can_reflowlines[1],10buffer.text='itty bitty\nshort\nlong by itself'assert.is_truetext.can_reflowlines[2],10
returns false if the line can not be combined with the previous one
before_each->interact.registername:'interaction_call'description:'calls passed in function'handler:(f)->f!interaction_instance=run:(@finish,f)=>f(finish)interact.registername:'interaction_with_factory',description:'calls passed in function f(finish)'factory:->moon.copyinteraction_instanceafter_each->interact.unregister'interaction_call'interact.unregister'interaction_with_factory'
(.. for a spec with .handler)
locali1_specbefore_each->i1_spec=name:'interaction1'description:'interaction with handler'handler:spy.new->return'r1','r2'interact.registeri1_specafter_each->interact.unregisteri1_spec.name
calls the interaction handler(...), returns result
locali2_spec,i2_interactorbefore_each->i2_interactor=run:spy.new(@finish,...)=>returni2_spec=name:'interaction2'description:'interaction with factory'factory:->i2_interactorinteract.registeri2_specafter_each->interact.unregisteri2_spec.name
.<name>(...) invokes the interaction method run(finish, ...)
it 'reads all the streams content in one go', (done) ->
content=string.rep'This is my line of text. Rinse, wash and repeat',500,'\n'with_stream_forcontent,(stream)->read=stream\read_all!assert.equal#content,#readassert.equalcontent,readassert.is_nilstream\read10done!
uses the same indent as for the previous line if it is a comment
indentation.more_after={'{'}mode.comment_syntax='#'buffer.text=" # I'm commenting thank you very much {\n# and still are\n"indent!assert.equals2,lines[2].indentation
adjust any illegal indentation (not divisable by indent)
build={}line='äåöLinƏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣbutnowforsomesingleΤΥΦΧĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏ'fori=1,3000build[#build+1]=lines=table.concatbuild,'\n'sci\insert_text0,sfori=1,3000*line.ulen,3007assert.equals\byte_offset(i),sci\byte_offset(i-1)+1fori=1,3000*#line,3007assert.equals\char_offset(i),sci\char_offset(i-1)+1fori=2000*#line,100,-2003sci\delete_rangei,20sci\insert_texti,'ordinary ascii text here's=sci\get_text!c_offset=sci\char_offset(i+100-1)+1assert.equals\char_offset(i+100),c_offsetassert.equals\byte_offset(c_offset),sci\byte_offset(c_offset-1)+1
color handling
automatically converts between color values and strings
buffer.text='hƏllo\n world!'cursor.pos=8buffer2=Buffer{}buffer2.text='a whole different whale'editor.buffer=buffer2cursor.pos=15editor.buffer=bufferassert.equal8,cursor.poseditor.buffer=buffer2assert.equal15,cursor.pos
list.matcher=->{'one','two','three'}list.columns={{header:'Takes up one line'}}list.max_height=3*get_row_height(list)list\update!assert.matchbuf.text,'one'assert.is_not.matchbuf.text,'two'
displays info about the currently shown items
list.matcher=->{'one','two','three'}list.max_height=2*get_row_height(list)list\update!assert.matchbuf.text,'showing 1 to 1 out of 3'
buffer.text='no means no'cursor.pos=1searcher\forward_to'no'assert.equal1,cursor.pos
handles growing match from empty
buffer.text='no means no'cursor.pos=1searcher\forward_to''assert.equal1,cursor.possearcher\forward_to'n'assert.equal1,cursor.possearcher\forward_to'no'assert.equal1,cursor.pos
assert.equal'äöx',s\usub3-- j defaults to -1assert.equal'öx',s\usub-2-- i counts from backassert.equal'aåäöx',s\usub-7-- is corrected to 1assert.equal'aåäöx',s\usub1,123-- j is corrected to last characterassert.equal'',s\usub3,2-- empty string when i < j
character access using indexing notation
single character strings can be accessed using indexing notation
s='aåäöx'assert.equal'a',s[1]assert.equal'ä',s[3]
accesses using invalid indexes returns an empty string
s='abc'assert.equal'',s[0]assert.equal'',s[4]
the index can be negative similarily to sub()
s='aåäöx'assert.equal'ä',s[-3]
umatch(pattern [, init])
init specifies a character offset
assert.same{'ö',4},{'äåö'\umatch'(%S+)()',3}
if init is greater than the length nil is returned
The Application object acts as the main hub within the Howl editor. There exists
one and only one instantiated application object per Howl instance, available as
howl.app.
Properties
buffers
A list of currently open Buffer:s. The list is ordered by how recently a
buffer was shown. Thus, a currently showing buffer will come before a buffer
that is not shown, and not showing buffers will be ordered according to the
timestamp they were last shown.
A list of all existing Editor:s. Each editor can be placed in only one window
at a time, but this list holds all editors present for the current Howl instance
- regardless of whether they’re placed in the currently focused window or not.
idle
A number providing information on how long the application has been idle, in
seconds (with fractions). As the idle is reset upon activity this is useful
primarily in timers and idle callbacks.
next_buffer
This is the most recent buffer that is currently not showing in any editor. If
all buffers are currently showing it’s the first buffer in .buffers.
Adds the existing buffer to .buffers. If show is true, shows the buffer in
the currently active editor.
close_buffer (buffer, force = false)
Removes buffer from .buffers. If the buffer is modified, and force is not
true, the user is prompted before closing the buffer.
editor_for_buffer (buffer)
Returns the editor currently showing buffer, or nil if the buffer is not
currently showing in any editor.
new_buffer (buffer_mode = nil)
Creates a new buffer, and adds it to .buffers. buffer_mode can optionally be
specified to assign a specific mode for the new buffer directly. When not
specified, the default mode is used. See mode for more information about
buffer modes.
new_editor (options = {})
Creates a new Editor. Unless options specify otherwise, the newly created
editor is added to the currently focused window, to the right of the currently
focused existing editor. It’s set to show the buffer from the .next_buffer
property. The editor is added to .editors before the return of the method.
options can contain any of the following keys:
buffer: The buffer that should be shown in the editor. Defaults to .next_buffer.
window: The window to add the editor to. Defaults to the currently focused window.
placement: How the new editor should be placed in the target window. See
Window.add_view for more information about possible
placement values.
Example use (Moonscript):
buffer=howl.app\new_buffer!buffer.text='Show this text in the new buffer'howl.app\new_editor:buffer
new_window (properties = {})
Creates a new application Window. properties is table of window properties
to set for the new window, such as title, height and width. The window is added
to .windows before the return of the method. Returns the newly created window.
open_file (file, editor = _G.editor)
Opens the provided file. By default, unless editor specifies a
specific editor to open the file into, the file is opened in the currently
active editor. Emits the file-opened signal if the file was opened
successfully. If the file was successfully opened, returns the Buffer and the
Editor holding the buffer. Otherwise nil is returned.
save_all ()
Saves all modified buffers in one go.
save_session ()
Saves the current editing session to disk. This includes things such as
information about what buffers are open, the current state of the window, etc.
synchronize ()
Synchronizes all open files with their respective files, if any. This will cause
any non-modified buffers to be reloaded from disk, should the file be more
recently modified than the buffer.
quit (force = false)
Requests for Howl to quit. If any open buffers are modified, and force is not
true, the user will be prompted for verification before actually quitting.
+
+
+
+
+
+
diff --git a/site/source/versions/0.3/doc/api/bindings.html b/site/source/versions/0.5/doc/api/bindings.html
similarity index 88%
rename from site/source/versions/0.3/doc/api/bindings.html
rename to site/source/versions/0.5/doc/api/bindings.html
index d395813a2..d42804c43 100644
--- a/site/source/versions/0.3/doc/api/bindings.html
+++ b/site/source/versions/0.5/doc/api/bindings.html
@@ -10,56 +10,54 @@
+
+
+
-
howl.bindings handles the set of active key bindings within Howl. “Bindings” in
this context refers to the various actions that will be executed as the result of
a key press, and we say that a key is bound to a certain action whenever that action
will trigger as a result of the key being pressed.
The way this works in Howl is that bindings keeps track of an arbitrary number
of “keymaps” that are searched whenever a key is pressed. A keymap is simple a
Lua table with keys matching key translations. The keymaps are stacked, and they
will all be searched for a matching action whenever a key is pressed. Typically
processing stops whenever the first action has been triggered, but it’s possible
for a handler to allow a key press to propagate further down the stack if it so
chooses.
Keymaps are as said simple Lua tables, that maps “key translations” to actions.
Each key press is represented as a “key event”, which is also a simple Lua table.
Below you can see an example of a key event resulting from pressing
Control + Shift + a:
-- Key event{character="A",-- the character corresponding to the key press, if anykey_code=65,-- the code of the key pressedkey_name="a",-- a symbolic name for the key pressed, if anyalt=false,-- true if the alt key was held down during the key presscontrol=true,-- true if the control key was held down during the key pressmeta=false,-- true if the meta key was held down during the key pressshift=true,-- true if the shift key was held down during the key presssuper=false-- true if the super key was held down during the key press}
As part of processing the key event is translated to a list of
possible string representations using translate_key, which
for the above example would result in the following list of translations:
{"ctrl_A","ctrl_shift_a","ctrl_shift_65"}
All keymaps are then searched in order for keys matching any of the translations.
If you read the documentation for process you’ll see that all key
events are processed for a particular originating source. In the typical case
this will be “editor”, indicating the key press originated from an
editor. When searching keymaps, any keymap is first inspected
to see if it has a source specific keymap table, in which case this is searched
first before any top-level bindings. Consider the following keymap:
{ctrl_b=function()print("A general binding")end,ctrl_c='my_general_command',editor={ctrl_shift_a=function(editor)print("An editor binding")end}}
Should the key event example above be dispatched against this keymap with the
source being “editor”, it would trigger the “ctrl_shift_a” binding. The top-level
bindings (e.g. “ctrl_b”) would trigger regardless of source. Also note that
the editor specific binding can make use of a source specific extra argument,
an editor instance in this case.
Any matching value found in a keymap is considered an action. Should a keymap not have any
matching keys but have a callable field named on_unhandled, that is
invoked with the key event, event source, key translations and any extra parameters
passed to dispatch, and any truthy result is used as the action.
See the documentation for dispatch for further information about these parameters.
Actions can be one of three different things:
It can be a string, in which case it’s considered a command and will be dispatched
using command.run.
It can be a callable object (a function or table providing a meta-table __call), in
which case it’s invoked with any extra parameters passed to dispatch
(the typical case being the editor instance for which the key press originated).
The key event will be considered handled unless the handler returns false.
It can be an ordinary, non-callable, table. This table is interpreted as an additional
keymap, which will be pushed using the pop option.
Indirect bindings
When writing keymaps for non-editor sources, a special key called binding_for
can be used in the keymap to bind an action to a key press indirectly by using a
command name as the key. For example, if you wanted to support pasting in your
readline input, instead of binding the action directly to the ctrl_v key
press, you might want to bind whichever key is bound to the editor-paste
command. This can be specified by the following keymap:
{binding_for={['editor-paste']:function()...end}}
This ensures that if the user binds a new key press to the editor-paste
command, that new key press will now trigger the bound action above, providing a
better experience for the user.
Protip:
You can use the describe-key command to interactively view information for any
particular key press, i.e. the key event and translations.
True if there’s currently a capture handler installed, and false otherwise.
.keymaps
This is a list of the currently active keymaps. This is a stack, with latter keymaps taking precedence over earlier ones.
Functions
action_for (translation)
Searches the stack of kemaps for the given key translation and returns the first
bound action found. An action may be a string (i.e. a command name) or a
function object. If no binding can be found for the translation, nil is
returned.
cancel_capture ()
Removes any installed capture handler.
capture (handler)
Installs a capture handler. The handler, which should be callable, will
intercept any key events being sent to process for processing. It
will be invoked with the key event, source, key translations and any extra
parameters passed to process. Unless the handler returns false, it will
automatically be removed after the invocation. There can be only one capture
handler installed at any given time. Installing a capture handler when an
existing one is already set will simply override the previous one.
dispatch (key_event, source, keymaps, …)
Explicitly dispatches the key event against the specified list of keymaps.
source is the source of the key press, e.g. “editor”. keymaps is the
list of keymaps that will be searched. Any additional arguments are passed
as is to any callable actions.
Note:
Unlike process, dispatch will not automatically include any of the
keymaps in the binding stack, it will only search keymaps.
keystrokes_for (action, source)
Finds all keystrokes (i.e. translations) that are bound to the specified
action. source, if given, specifies the source specific keymaps to search as
well. Returns a table containing all keystrokes found, or an empty table if no
binding was found.
For example:
-- look up the binding for the `project-open` command:howl.bindings.keystrokes_for('project-open')-- => { 'ctrl_p' }-- look up the binding for the `buffer-search-forward` command:howl.bindings.keystrokes_for('buffer-search-forward','editor')-- => { 'ctrl_f' }-- but since that's a command only bound for editor sources,-- it's not bound globallyhowl.bindings.keystrokes_for('buffer-search-forward')-- => {}
pop ()
Pops the top-most keymap of the stack. Raises an error if the stack is empty.
process (key_event, source, extra_keymaps = {}, …)
Processes the key_event by dispatching it against the list of keymaps present
in the bindings stack. source is the source of the key press, e.g. “editor”.
extra_keymaps is an optional list of additional keymaps that will be searched;
if specified these will be searched in order before any of the keymaps in the
stack. Any additional arguments are passed as is to any callable
actions.
Should any capture handler be installed via capture, this will be
invoked first and further processing will be skipped.
The key-press signal is emitted before dispatching, and further processing
will be skipped if this is handled.
push (keymap, options = {})
Pushes keymap onto the bindings stack. options can contain any of the following keys:
block: When set to true, this prevents any keymaps lower in the stack to be searched for
matching actions, effectively making this the only keymap available.
pop: When set to true, this causes the keymap to be popped from the stack automatically
after the next key dispatch. If pop is set, the map is implicitly blocking as
well.
remove (keymap)
Removes the specified keymap from the stack. Returns true if the keymap was removed successfully and false if it was not found.
translate_key (event)
Returns a list of translations for the passed in key event.
Example (Lua):
-- Given the following key eventlocalkey_event={alt=false,character="A",control=true,key_code=65,key_name="a",meta=false,shift=true,super=false}bindings.translate_key(key_event)-- returns{"ctrl_A","ctrl_shift_a","ctrl_shift_65"}