# Dunlin - a extensible Fennel-based web browser

<img src="dunlin.png" data-align="right" style="width: 33%" />

> The dunlin (Calidris alpina) is a small wader. It is a circumpolar
> breeder in Arctic or subarctic regions. Birds that breed in northern
> Europe and Asia are long-distance migrants, wintering south to Africa,
> southeast Asia and the Middle East. Birds that breed in Alaska and the
> Canadian Arctic migrate short distances to the Pacific and Atlantic
> coasts of North America, although those nesting in northern Alaska
> overwinter in Asia.

Dunlin is a GTK-based Webkit browser which can be extended in (indeed,
is mostly written in) [Fennel](https://www.fennel-lang.org).

## Why does the world need another half-assed Webkit browser?

It doesn't, really. But me, personally, I think I do. I want
a browser that lets me easily customize it to do things
like:

* watch a local html file and reload when it changes
* find the open tab for my home Fediverse instance (or open one if
  needed) and post a message/share a link to what I'm looking at
* search the {Lua reference, Ruby docs, GTK docs} for a given term
  instead of wading through the SEO cesspool that is the internet in
  2022
* search in previously "liked" pages for the thing I found three weeks
  ago, instead of ... ditto
* find the tab that's playing music and pause the player (instead of
  muting it)
* more stuff I haven't thought of

Full disclosure: Dunlin today can do none of these things - or much of
anything else either, right now - but if I borrow enough design
decisions from Emacs, I hope some day it will.

## Installation and getting started

If you're using Nix, you can run `nix-shell` to pull all the
dependencies. Otherwise ... apt-get and Luarocks? Refer to
`default.nix` and `shell.nix`, and obtain:

* All Lua packages listed in any `lua5_3.withPackages` stanza
* All system packages listed in any `buildInputs` or `nativeBuildInputs`
 stanzas.

To run the browser,

```sh
$ fennel dunlin.fnl
```

Dunlin will open a socket in `$XDG_RUNTIME_DIR` to allow communication
with a Fennel REPL. You can run the `repl.sh` script to connect to it
with [socat](http://www.dest-unreach.org/socat/).

### Running tests

Tests are in `test/*.fnl`. The test coverage is not 100% nor will it
ever be, probably: tests exist only for the bits that were hard to
write (algorithmically complex) and easy to test (not full of UI).

`make watch` will watch the filesystem in this directory and run the
tests whenever something changes.

### Running everything

There's a `Procfile` that starts the test runner and a Fennel repl and
probably in time some other useful things. I use it with [Overmind](https://github.com/DarthSim/overmind#readme) - `overmind start -D;  overmind connect`
to create a tmux session.

## Customizing

_This is all quite fluid right now and I reserve the right to change
things_. In particular, I anticipate the need to bind to non-key events
(mouse events, on-screen buttons, touch gestures)

(Among) the concepts you need to know here are "commands" and "bindings".

* A "command" is a chunk of code that may be invoked interactively,
plus a descrition of the parameters it needs and their default values.
For example, `visit-location` needs a `url` parameter for the location
and a `buffer` parameter that says which tab should visit it.

* A "binding" is a sequence of keystrokes which map to a command: it
may supply zero or more parameter values to the command. For example,
(as of git commit cde0b8cd56d; YMMV if you're reading this significantly
before or after 2022-12-23) the `g` binding invokes `visit-location`
with the `buffer` parameter set to `main`, and the `url` parameter
unset.

When a command is invoked without all parameter values, Dunlin will
prompt for each missing parameter in the "commander" text entry widget.
A command with no binding may be invoked by pressing `M-x` (hold down
the "meta" or "alt" key and press `x`) and then typing the command name.

To see how commands are implemented, read the code in `command.fnl`.
There is a simple keymap in `dunlin.fnl`, and you can see the details
of how keymaps work in `keymap.fnl`

When writing key bindings or printing errors, Dunlin assumes that the
key producing "Mod 1" (often labelled Alt) is the Meta key, and the
key producing "Mod 4" (on a PC, typically the key with the Windows logo)
is the Super key. For me this matches how Emacs does it, but I would
welcome reports of machines/setups that don't act ths way


## Contributing

If you like (or see the potential in) Dunlin enough to want to
contribute to it, that is awesome and you have just made my day!

However, I need to point out that it's under active development:
my vision for how it'll end up is indefinite in some places and
poorly articulated in others. So, please, don't send me code
that you're personally invested in and would be disappointed if
I reject/ignore it because it doesn't fit some plan that you
didn't know about when you wrote it.

You can checkout Dunlin from https://gti.telent.net/dan/dunlin. I
haven't put it on Github because I have uneasy feelings about the
ongoing centralisation of Open Source, but certainly don't let that
stop you. You can [email me your change](mailto:dan@telent.net) as a
patch, or you can point me at code on your preferred source code
hosting service - whatever works for you. I reserve the right to be
less flexible in future if I start drowning in changes.
