dunlin/doc/index.md

5.8 KiB

Dunlin - a extensible Fennel-based web browser

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.

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,

$ 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.

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

Fennel style

https://fennel-lang.org/style is my style bible, although there are places I have departed from it. In particular, I have used CamelCase to name several modules which act as classes, so that I can distinguish buffer (an object which represents a buffer, and understands messages like visit or name or location) from Buffer (the factory which instantiates buffer objects). There is probably a nicer way to do this, but I haven't found it yet.

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 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.