diff --git a/README.md b/README.md
index 03ab5dd..a49be3f 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ Dylan.
## Current Status
-As of 2022-11-07, the server implements
+As of 2024-04-19, the server implements
* Jump to declaration
* Jump to definition
@@ -19,104 +19,4 @@ definition" will show a list containing the generic function and its specific
methods, whereas "jump to declaration" will jump straight to the generic
function.
-We are currently using version [3.15 of the LSP
-protocol](https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/).
-
-
-## Opening Projects
-
-The LSP server needs to be able to open a project (that is, a Dylan library)
-associated with the file you're editing when you turn on LSP in your editor. It
-assumes you are using a [dylan-tool](https://github.com/dylan-lang/dylan-tool)
-workspace and searches for a project to open as follows:
-
-1. If there is a `workspace.json` file and that file has a `"default-library"`
- property, the specified library is opened.
-
-2. It uses `dylan-tool` to choose a library defined in the workspace. This is
- [generally](https://github.com/dylan-lang/dylan-tool/blob/292b7bf761745c9fa810511c9888f802dd787011/sources/workspaces/workspaces.dylan#L151)
- the test suite library, if one exists.
-
-Normally you shouldn't need to set any environment variables; everything is
-derived from the full pathname to the `dylan-compiler` executable, which must
-be on your `PATH`.
-
-## Emacs Usage
-
-1. Make sure the `dylan-lsp-server` executable is on your `PATH`, or customize
- the `lsp-dylan-exe-pathname` elisp variable. See below for more on
- customization.
-
-1. Install [lsp-mode](https://github.com/emacs-lsp/lsp-mode) and Dylan mode.
- Both of these are available from MELPA.
-
-2. When you jump to another `.dylan` file, that file does not automatically
- have LSP enabled so you must use `M-x lsp` again. To make this automatic,
- add this to your emacs init file:
-
- `(add-hook 'dylan-mode-hook 'lsp)`
-
-3. Start emacs and make sure that `lsp-dylan.el` is loaded. For example:
-
- `emacs --load=/path/to/lsp-dylan/lsp-dylan.el`
-
- You will probably want to modify your Emacs init file to load the file.
-
-4. Open a Dylan source file and type `M-x lsp` to start the client (unless you
- added the hook above, in which case it started automatically).
-
-The client starts the LSP server (the `dylan-lsp-server` executable) and
-connects to it.
-
-The emacs client has a customization group "lsp-dylan" which is a member of the
-"Language Server (lsp-mode)" group, and has the following variables:
-
-* `lsp-dylan-exe-pathname`
-* `lsp-dylan-extra-command-line-options`
-* `lsp-dylan-log-pathname`
-* `lsp-dylan-open-dylan-release`
-
-These are documented in the customization interface within emacs. Use `M-x
-customize-group` `lsp-dylan` to customize these variables.
-
-## Visual Studio Code Usage
-
-These instructions were tested on Linux and macOS.
-
-1. Install Visual Studio Code and `npm`.
-2. The VS Code extension is in the folder `vscode-dylan`. It is necessary to
- run `npm install` in this folder before starting the extension for the
- first time, and any time a git pull updates the dependencies.
-3. Open the `vscode-dylan` folder in VS Code.
-4. In the debug viewlet, click the green play arrow (Launch Extension) or
- press `F5`.
-5. A build process will begin in 'watch mode'; whenever the source is changed,
- the extension will be rebuilt. It is possible to debug the VS Code
- extension in this window, set breakpoints, watch variables and so on.
-6. A new VS Code window will open with the extension running.
-7. Open a folder with a Dylan project in it.
-8. If `dylan-lsp-server` is on the system path, it will be found. Otherwise,
- open the Settings *in the new extension window*, find the Dylan section
- under Extensions, and edit the path to the LSP server. The full, absolute
- pathname to the executable needs to be specified. It is usually better to
- set this in the 'User' scope, otherwise it will only apply to that
- particular project.
-9. It should now be possible to use the extension window to edit Dylan code
- using LSP.
-10. If the VS Code extension is changed, it is necessary to restart the
- extension host, or just close and re-open the extension window.
-
-
-## References
-
-* [Intro to LSP from
- Microsoft](https://docs.microsoft.com/en-us/visualstudio/extensibility/language-server-protocol)
- Besides being a quick introduction, this has links to some other tools that
- would help in developing VS Code integration for Dylan.
-
-* [LSP v3.15
- Specification](https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/)
- This is the version we are currently coding to.
-
-* [langserver.org](https://langserver.org/) lists LSP implementations that
- support at least one of the six major LSP features.
+See documentation/source/index.rst for full documentation.
diff --git a/documentation/Makefile b/documentation/Makefile
new file mode 100644
index 0000000..be50b8a
--- /dev/null
+++ b/documentation/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?= -v
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = source
+BUILDDIR = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/documentation/make.bat b/documentation/make.bat
new file mode 100644
index 0000000..6247f7e
--- /dev/null
+++ b/documentation/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=source
+set BUILDDIR=build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/documentation/source/conf.py b/documentation/source/conf.py
new file mode 100644
index 0000000..80d8ba3
--- /dev/null
+++ b/documentation/source/conf.py
@@ -0,0 +1,58 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+import os
+import sys
+sys.path.insert(0, os.path.abspath('../../_packages/sphinx-extensions/current/src/sphinxcontrib'))
+sys.path.insert(0, os.path.abspath('../../../_packages/sphinx-extensions/current/src/sphinxcontrib'))
+import dylan.themes as dylan_themes
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'lsp-dylan'
+copyright = '2019, Peter Hull'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'dylan.domain'
+]
+
+# Necessary to make things like '.. current-module:: foo' work.
+primary_domain = 'dylan'
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = []
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'furo'
+# html_theme = dylan_themes.get_html_theme_default()
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
diff --git a/documentation/source/index.rst b/documentation/source/index.rst
new file mode 100644
index 0000000..b53d324
--- /dev/null
+++ b/documentation/source/index.rst
@@ -0,0 +1,241 @@
+.. highlight:: shell
+
+*********************
+Dylan Language Server
+*********************
+
+This is an implementation of the `Language Server Protocol
+`_ for Dylan.
+
+.. toctree::
+ :hidden:
+
+Current Status
+==============
+
+As of 2024-04-19, the server implements
+
+* Jump to declaration
+* Jump to definition
+* Diagnostics (i.e., compiler warnings)
+* Hover (i.e., argument lists)
+
+When applied to a symbol which is bound to a generic function, "jump to
+definition" will show a list containing the generic function and its specific
+methods, whereas "jump to declaration" will jump straight to the generic
+function.
+
+Installation
+============
+
+1. First install `Open Dylan `_ 2023.1 or newer.
+
+2. Clone the `lsp-dylan repository `_::
+
+ $ git clone --recursive https://github.com/dylan-lang/lsp-dylan
+
+3. Update the workspace so that dependencies are installed and the registry is
+ created::
+
+ $ cd lsp-dylan
+ $ dylan update
+
+4. Build the ``dylan-lsp-server`` binary. This will install the binary in
+ ``${DYLAN}/bin``. If :envvar:`DYLAN` is not defined it defaults to
+ ``${HOME}/dylan``.
+ ::
+
+ $ make install
+
+ or just run these commands::
+
+ $ dylan build --unify dylan-lsp-server
+ $ cp _build/sbin/dylan-lsp-server /usr/local/bin/
+
+5. Make sure ``dylan-lsp-server`` is on your :envvar:`PATH`.
+
+
+Usage
+=====
+
+The LSP server needs to be able to open a project (that is, a Dylan library)
+associated with the file you're editing when you turn on LSP in your editor. It
+assumes you are using a `dylan-tool
+`_ workspace and searches for a
+project to open as follows:
+
+1. If there is a :file:`workspace.json` file and that file has a
+ `"default-library"` property, the specified library is opened.
+
+2. It uses the :program:`dylan` tool to choose a library defined in the
+ workspace. This is `generally
+ `_
+ the test suite library, if one exists; otherwise it chooses a project
+ arbitrarily.
+
+Normally you shouldn't need to set any environment variables; everything is
+derived from the full pathname to the :program:`dylan-compiler` executable,
+which must be on your :envvar:`PATH`.
+
+When you open each new file in your editor the LSP client may try to start a
+new project if the file isn't part of the same :program:`dylan` workspace
+directory. If you want the client to use just one project, use a `multi-package
+workspace `_.
+
+.. note:: Always run ``dylan update`` and ``dylan build -a`` in your workspace
+ **before** starting the LSP server, or :program:`dylan-lsp-server`
+ may not be able to open your project. (This requirement will be
+ removed in a future release.)
+
+
+Emacs Usage
+-----------
+
+1. Make sure the :program:`dylan-lsp-server` executable is on your
+ :envvar:`PATH`, or customize the ``lsp-dylan-exe-pathname`` elisp variable. See
+ below for more on customization.
+
+2. Install `lsp-mode `_ and `dylan-mode
+ `_. Both of these are
+ available from MELPA.
+
+3. When you jump to another :file:`.dylan` file, that file does not
+ automatically have LSP enabled so you must use ``M-x lsp`` again. To make
+ this automatic, add this to your emacs init file:
+
+ .. code-block:: elisp
+
+ (add-hook 'dylan-mode-hook 'lsp)
+
+4. Start emacs and make sure that :file:`lsp-dylan.el` is loaded. For example::
+
+ emacs --load=/path/to/lsp-dylan/lsp-dylan.el
+
+ You will probably want to modify your Emacs init file to load the file with
+
+ .. code-block:: elisp
+
+ (load "/path/to/lsp-dylan/lsp-dylan.el")
+
+5. Open a Dylan source file and type ``M-x lsp`` to start the client (unless
+ you added the hook above, in which case it started automatically).
+
+The client starts the LSP server (the `dylan-lsp-server` executable) and
+connects to it. You should see a message telling you what Dylan project was
+opened.
+
+The emacs client has a customization group "lsp-dylan" which is a member of the
+"Language Server (lsp-mode)" group, and has the following variables:
+
+* ``lsp-dylan-exe-pathname``
+* ``lsp-dylan-extra-command-line-options``
+* ``lsp-dylan-log-pathname``
+* ``lsp-dylan-open-dylan-release``
+
+These are documented in the customization interface within emacs. Use ``M-x
+customize-group`` ``lsp-dylan`` to customize these variables.
+
+.. note:: Emacs lsp-mode saves state in :file:`~/.emacs.d/.lsp-session-v1`. If
+ you have a problem with Dylan's LSP support it's a good idea to
+ delete this file and try again.
+
+
+Visual Studio Code Usage
+------------------------
+
+These instructions were tested on Linux and macOS.
+
+1. Install Visual Studio Code and ``npm``.
+
+2. The VS Code extension is in the folder ``vscode-dylan``. It is necessary to
+ run ``npm install`` in this folder before starting the extension for the
+ first time, and any time a ``git pull`` updates the dependencies.
+
+3. Open the ``vscode-dylan`` folder in VS Code.
+
+4. In the debug viewlet, click the green play arrow (Launch Extension) or
+ press ``F5``.
+
+5. A build process will begin in 'watch mode'; whenever the source is changed,
+ the extension will be rebuilt. It is possible to debug the VS Code
+ extension in this window, set breakpoints, watch variables and so on.
+
+6. A new VS Code window will open with the extension running.
+
+7. Open a folder with a Dylan project in it.
+
+8. If :program:`dylan-lsp-server` is on the system path, it will be
+ found. Otherwise, open the Settings *in the new extension window*, find the
+ Dylan section under Extensions, and edit the path to the LSP server. The
+ full, absolute pathname to the executable needs to be specified. It is
+ usually better to set this in the 'User' scope, otherwise it will only
+ apply to that particular project.
+
+9. It should now be possible to use the extension window to edit Dylan code
+ using LSP.
+
+10. If the VS Code extension is changed, it is necessary to restart the
+ extension host, or just close and re-open the extension window.
+
+
+LSP Server Development
+======================
+
+This section contains notes for people interested in helping to improve LSP
+support for Dylan.
+
+Open Dylan
+----------
+
+Unless you're an Open Dylan expert already, you'll probably find that you want
+to add debug statements in the Open Dylan IDE code to figure out what's going
+on....
+
+1. Turn on the ``--debug-opendylan`` by customizing
+ ``lsp-dylan-extra-command-line-options``. This causes extra in the
+ ``*lsp-dylan::stderr*`` buffer from calls to the ``debug-out`` macro.
+
+2. Create a multi-package workspace with both the ``lsp-dylan`` repo and the
+ ``opendylan`` repo::
+
+ $ mkdir lsp; cd lsp
+ $ git clone --recursive https://github.com/dylan-lang/lsp-dylan
+ $ git clone --recursive https://github.com/dylan-lang/opendylan
+ $ echo '{ "default-library": "dylan-lsp-server" }' > workspace.json
+
+3. Sprinkle calls like ``debug-out(#"lsp", "your message here", ...)`` around
+ in the Open Dylan code as needed.
+
+4. Remember to delete :file:`~/.emacs.d/.lsp-session-v1`` as needed. I (cgay)
+ usually start a new emacs after rebuilding :program:``dylan-lsp-server``,
+ like this::
+
+ $ rm -f ~/.emacs.d/.lsp-session-v1; emacs &
+
+ If you don't start a new emacs, you probably want to at least kill the old
+ :program:`dylan-lsp-server` process. I (cgay) usually rebuild like this::
+
+ $ pkill -f bin/dylan-lsp-server; make install
+
+
+References
+==========
+
+* `Intro to LSP from Microsoft
+ `_ -
+ Besides being a quick introduction, this has links to some other tools that
+ would help in developing VS Code integration for Dylan.
+
+* `LSP v3.15 Specification
+ `_ -
+ This is the version we are currently coding to.
+
+* `langserver.org `_ lists LSP implementations that
+ support at least one of the six major LSP features.
+
+
+Index and Search
+================
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/dylan-package.json b/dylan-package.json
index 45027a6..094fa34 100644
--- a/dylan-package.json
+++ b/dylan-package.json
@@ -10,6 +10,7 @@
"uncommon-dylan@0.2",
],
"dev-dependencies": [
+ "sphinx-extensions",
"testworks",
"vscode-dylan"
],