dixi
dixi copied to clipboard
A wiki based on firm theoretical foundations
[[https://travis-ci.org/liamoc/dixi][file:https://travis-ci.org/liamoc/dixi.svg]] [[http://hackage.haskell.org/package/dixi][file:https://img.shields.io/hackage/v/dixi.svg]] [[http://haskell.org][file:https://img.shields.io/badge/language-Haskell-blue.svg]] [[https://github.com/liamoc/dixi/blob/master/LICENSE][file:http://img.shields.io/badge/license-BSD3-brightgreen.svg]]
#+ATTR_HTML: alt="Dixi" [[file: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.
#+BEGIN_SRC sh cabal update cabal install dixi #+END_SRC
You can also build it from source, using the usual ~cabal~ ceremony.
#+BEGIN_SRC sh cabal sandbox init cabal install --only-dependencies # be warned, this will take some time cabal configure cabal build ./dist/build/dixi/dixi #+END_SRC
If you prefer, you can also use ~stack~ rather than ~cabal~.
#+BEGIN_SRC sh stack build stack exec dixi #+END_SRC
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:
#+BEGIN_SRC yaml 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. #+END_SRC
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:
#+BEGIN_SRC sh dixi my/other/config.yaml #+END_SRC sh
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' [[http://orgmode.org][Org Mode]], as read by [[http://pandoc.org][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
#+BEGIN_EXAMPLE [[][a wikilink]] (for org mode) a wikilink (for markdown) [[a wikilink]] (for mediawiki) [[a wikilink|Custom title]] (for mediawiki) #+END_EXAMPLE
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~.
#+BEGIN_SRC sh 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. #+END_SRC
** 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 [[http://home.solcon.nl/mklooster/darcs/patch-calculus.html][the theory of patches]] (really, just the [[https://en.wikipedia.org/wiki/Groupoid][groupoid structure]] of patches) to allow us to easily compose and revert patches. This is embodied in my [[https://github.com/liamoc/patches-vector][patches-vector]] library.
- The use of [[https://en.wikipedia.org/wiki/Operational_transformation][operational transformation]] to move patches relative to other patches, and handle merging, which is also in my [[https://github.com/liamoc/patches-vector][patches-vector]] library.
- The use of efficient [[https://github.com/liamoc/composition-tree][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 [[https://en.wikipedia.org/wiki/Refinement_(computing)][data refinement]] of a list.
- The use of the [[http://acid-state.seize.it/][acid-state]] library to store these composition trees, which provides proper [[https://en.wikipedia.org/wiki/ACID][ACID]] guarantees for immutable Haskell data structures.
- The use of the [[http://haskell-servant.github.io/][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 [[http://pandoc.org][pandoc]] is used, which makes the wiki rather full featured without me having to do very much in the area of document formatting.