Skip to content

liamoc/dixi

Repository files navigation

https://travis-ci.org/liamoc/dixi.svg https://img.shields.io/hackage/v/dixi.svg https://img.shields.io/badge/language-Haskell-blue.svg http://img.shields.io/badge/license-BSD3-brightgreen.svg

https://raw.githubusercontent.com/liamoc/dixi/master/logo.png

dīxī (v. fp. s. perf. act. ind.) to speak, to declare.

This project is a simple wiki developed based on a firm theoretical foundation. The details are explained in the section “What makes this special?” below.

Notably, dixi supports editing of any version of a page, and the changes will be propagated through to the latest version in a way that makes sense.

It is also able to revert changes (or the composition of several changes) from deep in a document’s history and preserve every other change.

Right now the wiki doesn’t support many bells and whistles, such as administrator control or user accounts, but they’re coming.

Using

You can get dixi from Hackage, by using cabal or stack to install it.

cabal update
cabal install dixi

You can also build it from source, using the usual cabal ceremony.

cabal sandbox init
cabal install --only-dependencies  # be warned, this will take some time
cabal configure
cabal build
./dist/build/dixi/dixi

If you prefer, you can also use stack rather than cabal.

stack build
stack exec dixi

Different stack-*.yaml files are available in the repository for various snapshots. By default, we support two recent LTS Haskell versions as well as a recent nightly stackage.

The configuration file is in YAML format, and by default should exist under config.yaml in the current directory. Happily, dixi will prompt you to create a file with the default configuration if it can’t find the file.

The default configuration is simply:

time:
  format: '%T, %F'          # C style format string for displaying times
  timezone: Etc/UTC         # Time zone as found in tzdata
port: 8000                  # TCP port to run on
storage: state              # Directory to store data, must be writable.
readerFormat: org           # Pandoc format to use. Can be any of:
                            #   commonmark, rst, markdown, mediawiki,
                            #   docbook, opml, org, textile, html,
                            #   latex, haddock, twiki, t2t
url: http://localhost:8000  # base url of your application, for links
processors:                 # a list of pandoc document processors to use
- wikilinks                 # right now, we only have the wikilinks processor
static: static              # Directory to store static files like stylesheets, 
                            # served under the /static/ url.
                            # This option can be omitted and static files will
                            # not be served by dixi, if you'd rather nginx
                            # or apache do it for you.
stylesheet: style.css       # Name of the stylesheet file to use.
                            # If dixi is serving static files, you will
                            # be prompted to create a default stylesheet 
                            # in the static directory if one doesn't exist.
math: katex                 # How to handle LaTeX math, can be one of:
                            #   plain, mathml, latexmathml, mathjax, katex
                            # CDN scripts are loaded when any of the last three
                            # methods are chosen.

You can also tell dixi to look elsewhere for a config.yaml by providing the file’s path as a command-line argument, e.g:

dixi my/other/config.yaml

Once dixi is running, just navigate to localhost:8000 (or whatever port dixi is configured to run on) and you will be shown the (presumably blank) Main Page. The toolbar at the top provides most useful tools. Other pages are located at /Page_Title. Underscores are displayed as spaces in the output, and spaces in the URL are converted to underscores.

The page text itself defaults to the format of Emacs’ Org Mode, as read by pandoc, however this can be customised.

Internal wikilinks can be made by making a link that goes nowhere, or by using built-in wiki syntax if your input format supports it

[[][a wikilink]]              (for org mode)
[a wikilink]()                (for markdown)
[[a wikilink]]                (for mediawiki)
[[a wikilink|Custom title]]   (for mediawiki)

This processing can be disabled by removing the wikilinks processor in the list in the configuration file.

JSON API

The entire wiki can also be accessed and modified by a JSON API. Basic API documentation can be generated by running the “test suite” provided in the cabal file, which will in fact generate a markdown file named docs.md, or otherwise whatever name is provided as the first command line argument. If you’re using stack, simply run stack test and view the results.

HTML documentation can then be generated via pandoc or other tools, using the buttondown style provided, courtesy of ryangray.

stack test && stack exec pandoc -- docs.md -s -c buttondown.css -o docs.html

# or in cabal...

cabal test
pandoc docs.md -s -c buttondown.css -o docs.html # Assuming pandoc is in your path.

Future Work

Tons! I’ll use GitHub issues to keep track of features I’d like to add, so look over there.

What makes this special?

Most wikis do not take much care in their implementations. They’re buggy, monstrious pieces of software that violate basic principles of software engineering as well as exhibiting complete disregard for computer science.

It turns out, computer scientists and software engineers have long sinced developed tools, both in theory and practice, that allow us to implement wikis a lot better than has been done previously.

  • The use of the theory of patches (really, just the groupoid structure of patches) to allow us to easily compose and revert patches. This is embodied in my patches-vector library.
  • The use of operational transformation to move patches relative to other patches, and handle merging, which is also in my patches-vector library.
  • The use of efficient composition trees to allow us to efficiently compute the composition of several changes, and also to eliminate the need to store each version of the document independently.
  • The use of property-based testing to formally specify all of the above and test each implementation against its specification, which is rigorous and thorough. For patches-vector, the groupoid laws and several transformation properties are checked. For composition-tree, several properties are derived from the fact that a composition tree is a data refinement of a list.
  • The use of the acid-state library to store these composition trees, which provides proper ACID guarantees for immutable Haskell data structures.
  • The use of the servant library to specify the API and web server for the wiki in a concise, and type-safe way, minimising errors in the CRUD logic, and preventing broken links statically.
  • The use of the Haskell programming language, which provides the type- and eco-systems necessary to make this kind of rigorous software engineering possible.

The other noteworthy thing is that the excellent library pandoc is used, which makes the wiki rather full featured without me having to do very much in the area of document formatting.