summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--docs/Makefile19
-rw-r--r--docs/assets/hello-world-completion.pngbin0 -> 3076 bytes
-rw-r--r--docs/make.bat35
-rw-r--r--docs/requirements.txt220
-rw-r--r--docs/source/conf.py288
-rw-r--r--docs/source/index.rst51
-rw-r--r--docs/source/pages/getting_started.rst94
-rw-r--r--docs/source/pages/migrating-to-v1.rst241
-rw-r--r--docs/source/pages/reference.rst8
-rw-r--r--docs/source/pages/reference/clients.rst8
-rw-r--r--docs/source/pages/reference/protocol.rst11
-rw-r--r--docs/source/pages/reference/servers.rst11
-rw-r--r--docs/source/pages/reference/types.rst10
-rw-r--r--docs/source/pages/reference/workspace.rst9
-rw-r--r--docs/source/pages/testing.rst24
-rw-r--r--docs/source/pages/tutorial.rst207
-rw-r--r--docs/source/pages/user-guide.rst536
17 files changed, 1772 insertions, 0 deletions
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..69fe55e
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,19 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+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) \ No newline at end of file
diff --git a/docs/assets/hello-world-completion.png b/docs/assets/hello-world-completion.png
new file mode 100644
index 0000000..669b263
--- /dev/null
+++ b/docs/assets/hello-world-completion.png
Binary files differ
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 0000000..4d9eb83
--- /dev/null
+++ b/docs/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%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
+
+:end
+popd
diff --git a/docs/requirements.txt b/docs/requirements.txt
new file mode 100644
index 0000000..2cc6cd4
--- /dev/null
+++ b/docs/requirements.txt
@@ -0,0 +1,220 @@
+alabaster==0.7.13 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
+ --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+attrs==23.1.0 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04 \
+ --hash=sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015
+babel==2.12.1 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610 \
+ --hash=sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455
+cattrs==23.1.2 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:b2bb14311ac17bed0d58785e5a60f022e5431aca3932e3fc5cc8ed8639de50a4 \
+ --hash=sha256:db1c821b8c537382b2c7c66678c3790091ca0275ac486c76f3c8f3920e83c657
+certifi==2023.7.22 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
+ --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
+charset-normalizer==3.2.0 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96 \
+ --hash=sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c \
+ --hash=sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710 \
+ --hash=sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706 \
+ --hash=sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020 \
+ --hash=sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252 \
+ --hash=sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad \
+ --hash=sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329 \
+ --hash=sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a \
+ --hash=sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f \
+ --hash=sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6 \
+ --hash=sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4 \
+ --hash=sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a \
+ --hash=sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46 \
+ --hash=sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2 \
+ --hash=sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23 \
+ --hash=sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace \
+ --hash=sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd \
+ --hash=sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982 \
+ --hash=sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10 \
+ --hash=sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2 \
+ --hash=sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea \
+ --hash=sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09 \
+ --hash=sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5 \
+ --hash=sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149 \
+ --hash=sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489 \
+ --hash=sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9 \
+ --hash=sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80 \
+ --hash=sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592 \
+ --hash=sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3 \
+ --hash=sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6 \
+ --hash=sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed \
+ --hash=sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c \
+ --hash=sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200 \
+ --hash=sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a \
+ --hash=sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e \
+ --hash=sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d \
+ --hash=sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6 \
+ --hash=sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623 \
+ --hash=sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669 \
+ --hash=sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3 \
+ --hash=sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa \
+ --hash=sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9 \
+ --hash=sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2 \
+ --hash=sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f \
+ --hash=sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1 \
+ --hash=sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4 \
+ --hash=sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a \
+ --hash=sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8 \
+ --hash=sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3 \
+ --hash=sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029 \
+ --hash=sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f \
+ --hash=sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959 \
+ --hash=sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22 \
+ --hash=sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7 \
+ --hash=sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952 \
+ --hash=sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346 \
+ --hash=sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e \
+ --hash=sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d \
+ --hash=sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299 \
+ --hash=sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd \
+ --hash=sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a \
+ --hash=sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3 \
+ --hash=sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037 \
+ --hash=sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94 \
+ --hash=sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c \
+ --hash=sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858 \
+ --hash=sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a \
+ --hash=sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449 \
+ --hash=sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c \
+ --hash=sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918 \
+ --hash=sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1 \
+ --hash=sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c \
+ --hash=sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac \
+ --hash=sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa
+colorama==0.4.6 ; python_full_version >= "3.7.9" and python_version < "4" and sys_platform == "win32" \
+ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+docutils==0.18.1 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c \
+ --hash=sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06
+exceptiongroup==1.1.3 ; python_full_version >= "3.7.9" and python_version < "3.11" \
+ --hash=sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9 \
+ --hash=sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3
+idna==3.4 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
+ --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
+imagesize==1.4.1 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
+ --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
+importlib-metadata==6.7.0 ; python_full_version >= "3.7.9" and python_version < "3.10" \
+ --hash=sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4 \
+ --hash=sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5
+jinja2==3.1.2 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+lsprotocol==2023.0.0a3 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:2896c5a30c34846e3d5687e35715961f49bf7b92a36e4fb2b707ff65f19087f7 \
+ --hash=sha256:d704e4e00419f74bece9795de4b34d02aa555fc0131fec49f59ac9eb46816e51
+markupsafe==2.1.3 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
+ --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
+ --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
+ --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
+ --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
+ --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
+ --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
+ --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
+ --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
+ --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
+ --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
+ --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
+ --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
+ --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
+ --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
+ --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
+ --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
+ --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
+ --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
+ --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
+ --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
+ --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
+ --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
+ --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
+ --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
+ --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
+ --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
+ --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
+ --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
+ --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
+ --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
+ --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
+ --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
+ --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
+ --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
+ --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
+ --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
+ --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
+ --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
+ --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
+ --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
+ --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
+ --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
+ --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
+ --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
+ --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
+ --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
+ --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
+ --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
+ --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2
+packaging==23.1 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
+ --hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
+pygments==2.16.1 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
+ --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
+pytz==2023.3 ; python_full_version >= "3.7.9" and python_version < "3.9" \
+ --hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \
+ --hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb
+requests==2.31.0 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
+ --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
+snowballstemmer==2.2.0 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
+ --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
+sphinx-rtd-theme==1.3.0 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:46ddef89cc2416a81ecfbeaceab1881948c014b1b6e4450b815311a89fb977b0 \
+ --hash=sha256:590b030c7abb9cf038ec053b95e5380b5c70d61591eb0b552063fbe7c41f0931
+sphinx==5.3.0 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d \
+ --hash=sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5
+sphinxcontrib-applehelp==1.0.2 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a \
+ --hash=sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58
+sphinxcontrib-devhelp==1.0.2 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e \
+ --hash=sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4
+sphinxcontrib-htmlhelp==2.0.0 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07 \
+ --hash=sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2
+sphinxcontrib-jquery==4.1 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a \
+ --hash=sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae
+sphinxcontrib-jsmath==1.0.1 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
+ --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
+sphinxcontrib-qthelp==1.0.3 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72 \
+ --hash=sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6
+sphinxcontrib-serializinghtml==1.1.5 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd \
+ --hash=sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952
+typeguard==3.0.2 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:bbe993854385284ab42fd5bd3bee6f6556577ce8b50696d6cb956d704f286c8e \
+ --hash=sha256:fee5297fdb28f8e9efcb8142b5ee219e02375509cd77ea9d270b5af826358d5a
+typing-extensions==4.7.1 ; python_full_version >= "3.7.9" and python_version < "3.11" \
+ --hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \
+ --hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2
+urllib3==2.0.4 ; python_full_version >= "3.7.9" and python_version < "4" \
+ --hash=sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11 \
+ --hash=sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4
+zipp==3.15.0 ; python_full_version >= "3.7.9" and python_version < "3.10" \
+ --hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \
+ --hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556
diff --git a/docs/source/conf.py b/docs/source/conf.py
new file mode 100644
index 0000000..b3b3bfc
--- /dev/null
+++ b/docs/source/conf.py
@@ -0,0 +1,288 @@
+# -*- coding: utf-8 -*-
+#
+# Configuration file for the Sphinx documentation builder.
+#
+# This file does only contain a selection of the most common options. For a
+# full list see the documentation:
+# http://www.sphinx-doc.org/en/master/config
+
+# -- 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('.'))
+import importlib.metadata
+import re
+from docutils import nodes
+
+
+# -- Project information -----------------------------------------------------
+
+project = "pygls"
+copyright = "Open Law Library"
+author = "Open Law Library"
+
+# The short X.Y version
+version = importlib.metadata.version("pygls")
+# The full version, including alpha/beta/rc tags
+release = version
+
+title = "pygls Documentation"
+description = "a pythonic generic language server"
+
+
+# -- General configuration ---------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ "sphinx.ext.autodoc",
+ "sphinx.ext.intersphinx",
+ "sphinx.ext.napoleon",
+]
+
+autodoc_member_order = "groupwise"
+autodoc_typehints = "description"
+autodoc_typehints_description_target = "all"
+
+intersphinx_mapping = {
+ "python": ("https://docs.python.org/3/", None),
+}
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ["_templates"]
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = ".rst"
+
+# The master toctree document.
+master_doc = "index"
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = "en"
+
+# 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 = []
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = None
+
+
+# -- 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 = "sphinx_rtd_theme"
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# 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']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# The default sidebars (for documents that don't match any pattern) are
+# defined by theme itself. Builtin themes are using these templates by
+# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
+# 'searchbox.html']``.
+#
+# html_sidebars = {}
+
+
+# -- Options for HTMLHelp output ---------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = "pyglsdoc"
+
+
+# -- Options for LaTeX output ------------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, "pygls.tex", title, author, "manual"),
+]
+
+
+# -- Options for manual page output ------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [(master_doc, "pygls", description, [author], 1)]
+
+
+# -- Options for Texinfo output ----------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, "pygls", title, author, "pygls", description, "Miscellaneous"),
+]
+
+
+# -- Options for Epub output -------------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = project
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+#
+# epub_identifier = ''
+
+# A unique identification for the text.
+#
+# epub_uid = ''
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ["search.html"]
+
+
+def lsp_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
+ """Link to sections within the lsp specification."""
+
+ anchor = text.replace("$/", "").replace("/", "_")
+ ref = f"https://microsoft.github.io/language-server-protocol/specification.html#{anchor}"
+
+ node = nodes.reference(rawtext, text, refuri=ref, **options)
+ return [node], []
+
+
+CODE_FENCE_PATTERN = re.compile(r"```(\w+)?")
+LINK_PATTERN = re.compile(r"\{@link ([^}]+)\}")
+LITERAL_PATTERN = re.compile(r"(?<![`:])`([^`]+)`(?!_)")
+MD_LINK_PATTERN = re.compile(r"\[`?([^\]]+?)`?\]\(([^)]+)\)")
+SINCE_PATTERN = re.compile(r"@since ([\d\.]+)")
+
+
+def process_docstring(app, what, name, obj, options, lines):
+ """Fixup LSP docstrings so that they work with reStructuredText syntax
+
+ - Replaces ``@since <version>`` with ``**LSP v<version>**``
+
+ - Replaces ``{@link <item>}`` with ``:class:`~lsprotocol.types.<item>` ``
+
+ - Replaces markdown hyperlink with reStructuredText equivalent
+
+ - Replaces inline markdown code (single "`") with reStructuredText inline code
+ (double "`")
+
+ - Inserts the required newline before a bulleted list
+
+ - Replaces code fences with code blocks
+
+ - Fixes indentation
+ """
+
+ line_breaks = []
+ code_fences = []
+
+ for i, line in enumerate(lines):
+ if line.startswith("- "):
+ line_breaks.append(i)
+
+ # Does the line need dedenting?
+ if line.startswith(" " * 4) and not lines[i - 1].startswith(" "):
+ # Be sure to modify the original list *and* the line the rest of the
+ # loop will use.
+ line = lines[i][4:]
+ lines[i] = line
+
+ if (match := SINCE_PATTERN.search(line)) is not None:
+ start, end = match.span()
+ lines[i] = "".join([line[:start], f"**LSP v{match.group(1)}**", line[end:]])
+
+ if (match := LINK_PATTERN.search(line)) is not None:
+ start, end = match.span()
+ item = match.group(1)
+
+ lines[i] = "".join(
+ [line[:start], f":class:`~lsprotocol.types.{item}`", line[end:]]
+ )
+
+ if (match := MD_LINK_PATTERN.search(line)) is not None:
+ start, end = match.span()
+ text = match.group(1)
+ target = match.group(2)
+
+ line = "".join([line[:start], f"`{text} <{target}>`__", line[end:]])
+ lines[i] = line
+
+ if (match := LITERAL_PATTERN.search(line)) is not None:
+ start, end = match.span()
+ lines[i] = "".join([line[:start], f"`{match.group(0)}` ", line[end:]])
+
+ if (match := CODE_FENCE_PATTERN.match(line)) is not None:
+ open_ = len(code_fences) % 2 == 0
+ lang = match.group(1) or ""
+
+ if open_:
+ code_fences.append((i, lang))
+ line_breaks.extend([i, i + 1])
+ else:
+ code_fences.append(i)
+
+ # Rewrite fenced code blocks
+ open_ = -1
+ for fence in code_fences:
+ if isinstance(fence, tuple):
+ open_ = fence[0] + 1
+ lines[fence[0]] = f".. code-block:: {fence[1]}"
+ else:
+ # Indent content
+ for j in range(open_, fence):
+ lines[j] = f" {lines[j]}"
+
+ lines[fence] = ""
+
+ # Insert extra line breaks
+ for offset, line in enumerate(line_breaks):
+ lines.insert(line + offset, "")
+
+
+def setup(app):
+ app.add_role("lsp", lsp_role)
+ app.connect("autodoc-process-docstring", process_docstring)
diff --git a/docs/source/index.rst b/docs/source/index.rst
new file mode 100644
index 0000000..3fc264c
--- /dev/null
+++ b/docs/source/index.rst
@@ -0,0 +1,51 @@
+.. pygls documentation master file, created by
+ sphinx-quickstart on Sun Nov 25 16:16:27 2018.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+*pygls*
+=======
+
+`pygls`_ (pronounced like “pie glass”) is a generic implementation of
+the `Language Server Protocol`_ written in the Python programming language. It
+allows you to write your own `language server`_ in just a few lines of code.
+
+Features
+--------
+
+- cross-platform support
+- TCP/IP and STDIO communication
+- runs in asyncio event loop
+- register LSP features and custom commands as:
+
+ - asynchronous functions (coroutines)
+ - synchronous functions
+ - functions that will be executed in separate thread
+
+- thread management
+- in-memory workspace with *full* and *incremental* document updates
+- type-checking
+- good test coverage
+
+Python Versions
+---------------
+
+*pygls* works with Python 3.8+.
+
+User Guide
+----------
+
+.. toctree::
+ :maxdepth: 2
+
+ pages/getting_started
+ pages/tutorial
+ pages/user-guide
+ pages/testing
+ pages/migrating-to-v1
+ pages/reference
+
+
+.. _Language Server Protocol: https://microsoft.github.io/language-server-protocol/specification
+.. _Language server: https://langserver.org/
+.. _pygls: https://github.com/openlawlibrary/pygls
diff --git a/docs/source/pages/getting_started.rst b/docs/source/pages/getting_started.rst
new file mode 100644
index 0000000..e73d20f
--- /dev/null
+++ b/docs/source/pages/getting_started.rst
@@ -0,0 +1,94 @@
+Getting Started
+===============
+
+This document explains how to install *pygls* and get started writing language
+servers that are based on it.
+
+.. note::
+
+ Before going any further, if you are not familiar with *language servers*
+ and *Language Server Protocol*, we recommend reading following articles:
+
+ - `Language Server Protocol Overview <https://microsoft.github.io/language-server-protocol/overview>`_
+ - `Language Server Protocol Specification <https://microsoft.github.io/language-server-protocol/specification>`_
+ - `Language Server Protocol SDKs <https://microsoft.github.io/language-server-protocol/implementors/sdks/>`_
+
+
+Installation
+------------
+
+To get the latest release from *PyPI*, simply run:
+
+.. code:: console
+
+ pip install pygls
+
+Alternatively, *pygls* source code can be downloaded from our `GitHub`_ page and installed with following command:
+
+.. code:: console
+
+ pip install git+https://github.com/openlawlibrary/pygls
+
+Quick Start
+-----------
+
+Spin the Server Up
+~~~~~~~~~~~~~~~~~~
+
+*pygls* is a language server that can be started without writing any additional
+code:
+
+.. code:: python
+
+ from pygls.server import LanguageServer
+
+ server = LanguageServer('example-server', 'v0.1')
+
+ server.start_tcp('127.0.0.1', 8080)
+
+After running the code above, server will start listening for incoming
+``Json RPC`` requests on ``http://127.0.0.1:8080``.
+
+Register Features and Commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+*pygls* comes with an API for registering additional features like
+``code completion``, ``find all references``, ``go to definition``, etc.
+
+.. code:: python
+
+ @server.feature(TEXT_DOCUMENT_COMPLETION, CompletionOptions(trigger_characters=[',']))
+ def completions(params: CompletionParams):
+ """Returns completion items."""
+ return CompletionList(
+ is_incomplete=False,
+ items=[
+ CompletionItem(label='Item1'),
+ CompletionItem(label='Item2'),
+ CompletionItem(label='Item3'),
+ ]
+ )
+
+… as well as custom commands:
+
+.. code:: python
+
+ @server.command('myVerySpecialCommandName')
+ def cmd_return_hello_world(ls, *args):
+ return 'Hello World!'
+
+See the :mod:`lsprotocol.types` module for the complete and canonical list of available features.
+
+Tutorial
+--------
+
+We recommend completing the :ref:`tutorial <tutorial>`, especially if you
+haven't worked with language servers before.
+
+User Guide
+----------
+
+To reveal the full potential of *pygls* (``thread management``, ``coroutines``,
+``multi-root workspace``, ``TCP/STDIO communication``, etc.) keep reading.
+
+.. _GitHub: https://github.com/openlawlibrary/pygls
diff --git a/docs/source/pages/migrating-to-v1.rst b/docs/source/pages/migrating-to-v1.rst
new file mode 100644
index 0000000..527a810
--- /dev/null
+++ b/docs/source/pages/migrating-to-v1.rst
@@ -0,0 +1,241 @@
+Migrating to v1.0
+=================
+
+The most notable change of the ``v1.0`` release of ``pygls`` is the removal of its hand written LSP type and method definitions in favour of relying on the types provided by the `lsprotocol`_ library which are automatically generated from the LSP specification.
+As as side effect this has also meant the removal of `pydantic`_ as a dependency, since ``lsprotocol`` uses `attrs`_ and `cattrs`_ for serialisation and validation.
+
+This guide outlines how to adapt an existing server to the breaking changes introduced in this release.
+
+Known Migrations
+----------------
+You may find insight and inspiration from these projects that have already successfully migrated to v1:
+
+* `jedi-language-server`_
+* `vscode-ruff`_
+* `esbonio`_
+* `yara-language-server`_
+
+Updating Imports
+----------------
+
+The ``pygls.lsp.methods`` and ``pygls.lsp.types`` modules no longer exist.
+Instead, all types and method names should now be imported from the ``lsprotocol.types`` module.
+
+Additionally, the following types and constants have been renamed.
+
+================================================================== ==============
+pygls lsprotocol
+================================================================== ==============
+``CODE_ACTION`` ``TEXT_DOCUMENT_CODE_ACTION``
+``CODE_LENS`` ``TEXT_DOCUMENT_CODE_LENS``
+``COLOR_PRESENTATION`` ``TEXT_DOCUMENT_COLOR_PRESENTATION``
+``COMPLETION`` ``TEXT_DOCUMENT_COMPLETION``
+``DECLARATION`` ``TEXT_DOCUMENT_DECLARATION``
+``DEFINITION`` ``TEXT_DOCUMENT_DEFINITION``
+``DOCUMENT_COLOR`` ``TEXT_DOCUMENT_DOCUMENT_COLOR``
+``DOCUMENT_HIGHLIGHT`` ``TEXT_DOCUMENT_DOCUMENT_HIGHLIGHT``
+``DOCUMENT_LINK`` ``TEXT_DOCUMENT_DOCUMENT_LINK``
+``DOCUMENT_SYMBOL`` ``TEXT_DOCUMENT_DOCUMENT_SYMBOL``
+``FOLDING_RANGE`` ``TEXT_DOCUMENT_FOLDING_RANGE``
+``FORMATTING`` ``TEXT_DOCUMENT_FORMATTING``
+``HOVER`` ``TEXT_DOCUMENT_HOVER``
+``IMPLEMENTATION`` ``TEXT_DOCUMENT_IMPLEMENTATION``
+``LOG_TRACE_NOTIFICATION`` ``LOG_TRACE``
+``ON_TYPE_FORMATTING`` ``TEXT_DOCUMENT_ON_TYPE_FORMATTING``
+``PREPARE_RENAME`` ``TEXT_DOCUMENT_PREPARE_RENAME``
+``PROGRESS_NOTIFICATION`` ``PROGRESS``
+``RANGE_FORMATTING`` ``TEXT_DOCUMENT_RANGE_FORMATTING``
+``REFERENCES`` ``TEXT_DOCUMENT_REFERENCES``
+``RENAME`` ``TEXT_DOCUMENT_RENAME``
+``SELECTION_RANGE`` ``TEXT_DOCUMENT_SELECTION_RANGE``
+``SET_TRACE_NOTIFICATION`` ``SET_TRACE``
+``SIGNATURE_HELP`` ``TEXT_DOCUMENT_SIGNATURE_HELP``
+``TEXT_DOCUMENT_CALL_HIERARCHY_INCOMING_CALLS`` ``CALL_HIERARCHY_INCOMING_CALLS``
+``TEXT_DOCUMENT_CALL_HIERARCHY_OUTGOING_CALLS`` ``CALL_HIERARCHY_OUTGOING_CALLS``
+``TEXT_DOCUMENT_CALL_HIERARCHY_PREPARE`` ``TEXT_DOCUMENT_PREPARE_CALL_HIERARCHY``
+``TYPE_DEFINITION`` ``TEXT_DOCUMENT_TYPE_DEFINITION``
+``WORKSPACE_FOLDERS`` ``WORKSPACE_WORKSPACE_FOLDERS``
+``ApplyWorkspaceEditResponse`` ``ApplyWorkspaceEditResult``
+``ClientInfo`` ``InitializeParamsClientInfoType``
+``CodeActionDisabled`` ``CodeActionDisabledType``
+``CodeActionLiteralSupportActionKindClientCapabilities`` ``CodeActionClientCapabilitiesCodeActionLiteralSupportTypeCodeActionKindType``
+``CodeActionLiteralSupportClientCapabilities`` ``CodeActionClientCapabilitiesCodeActionLiteralSupportType``
+``CompletionItemClientCapabilities`` ``CompletionClientCapabilitiesCompletionItemType``
+``CompletionItemKindClientCapabilities`` ``CompletionClientCapabilitiesCompletionItemKindType``
+``CompletionTagSupportClientCapabilities`` ``CompletionClientCapabilitiesCompletionItemTypeTagSupportType``
+``DocumentSymbolCapabilitiesTagSupport`` ``DocumentSymbolClientCapabilitiesTagSupportType``
+``InsertTextModeSupportClientCapabilities`` ``CompletionClientCapabilitiesCompletionItemTypeInsertTextModeSupportType``
+``MarkedStringType`` ``MarkedString``
+``MarkedString`` ``MarkedString_Type1``
+``PrepareRename`` ``PrepareRenameResult_Type1``
+``PublishDiagnosticsTagSupportClientCapabilities`` ``PublishDiagnosticsClientCapabilitiesTagSupportType``
+``ResolveSupportClientCapabilities`` ``CodeActionClientCapabilitiesResolveSupportType``
+``SemanticTokensRequestsFull`` ``SemanticTokensRegistrationOptionsFullType1``
+``SemanticTokensRequests`` ``SemanticTokensClientCapabilitiesRequestsType``
+``ServerInfo`` ``InitializeResultServerInfoType``
+``ShowMessageRequestActionItem`` ``ShowMessageRequestClientCapabilitiesMessageActionItemType``
+``SignatureHelpInformationClientCapabilities`` ``SignatureHelpClientCapabilitiesSignatureInformationType``
+``SignatureHelpInformationParameterInformationClientCapabilities`` ``SignatureHelpClientCapabilitiesSignatureInformationTypeParameterInformationType``
+``TextDocumentContentChangeEvent`` ``TextDocumentContentChangeEvent_Type1``
+``TextDocumentContentChangeTextEvent`` ``TextDocumentContentChangeEvent_Type2``
+``TextDocumentSyncOptionsServerCapabilities`` ``TextDocumentSyncOptions``
+``Trace`` ``TraceValues``
+``URI`` ``str``
+``WorkspaceCapabilitiesSymbolKind`` ``WorkspaceSymbolClientCapabilitiesSymbolKindType``
+``WorkspaceCapabilitiesTagSupport`` ``WorkspaceSymbolClientCapabilitiesTagSupportType``
+``WorkspaceFileOperationsServerCapabilities`` ``FileOperationOptions``
+``WorkspaceServerCapabilities`` ``ServerCapabilitiesWorkspaceType``
+================================================================== ==============
+
+Custom Models
+-------------
+
+One of the most obvious changes is the switch to `attrs`_ and `cattrs`_ for serialization and deserialisation.
+This means that any custom models used by your language server will need to be converted to an ``attrs`` style class.
+
+.. code-block:: python
+
+ # Before
+ from pydantic import BaseModel, Field
+
+ class ExampleConfig(BaseModel):
+ build_dir: Optional[str] = Field(None, alias="buildDir")
+
+ builder_name: str = Field("html", alias="builderName")
+
+ conf_dir: Optional[str] = Field(None, alias="confDir")
+
+.. code-block:: python
+
+ # After
+ import attrs
+
+ @attrs.define
+ class ExampleConfig:
+ build_dir: Optional[str] = attrs.field(default=None)
+
+ builder_name: str = attrs.field(default="html")
+
+ conf_dir: Optional[str] = attrs.field(default=None)
+
+
+Pygls provides a default `converter`_ that it will use when converting your models to/from JSON, which should be sufficient for most scenarios.
+
+.. code-block:: pycon
+
+ >>> from pygls.protocol import default_converter
+ >>> converter = default_converter()
+
+ >>> config = ExampleConfig(builder_name='epub', conf_dir='/path/to/conf')
+ >>> converter.unstructure(config)
+ {'builderName': 'epub', 'confDir': '/path/to/conf'} # Note how snake_case is converted to camelCase
+
+ >>> converter.structure({'builderName': 'epub', 'confDir': '/path/to/conf'}, ExampleConfig)
+ ExampleConfig(build_dir=None, builder_name='epub', conf_dir='/path/to/conf')
+
+However, depending on the complexity of your type definitions you may find the default converter fail to parse some of your types.
+
+.. code-block:: pycon
+
+ >>> from typing import Literal, Union
+
+ >>> @attrs.define
+ ... class ExampleConfig:
+ ... num_jobs: Union[Literal["auto"], int] = attrs.field(default='auto')
+ ...
+
+ >>> converter.structure({'numJobs': 'auto'}, ExampleConfig)
+ + Exception Group Traceback (most recent call last):
+ | File "<stdin>", line 1, in <module>
+ | File "/.../python3.10/site-packages/cattrs/converters.py", li
+ ne 309, in structure
+ | return self._structure_func.dispatch(cl)(obj, cl)
+ | File "<cattrs generated structure __main__.ExampleConfig-2>", line 10, in structure_ExampleConfig
+ | if errors: raise __c_cve('While structuring ' + 'ExampleConfig', errors, __cl)
+ | cattrs.errors.ClassValidationError: While structuring ExampleConfig (1 sub-exception)
+ +-+---------------- 1 ----------------
+ | Traceback (most recent call last):
+ | File "<cattrs generated structure __main__.ExampleConfig-2>", line 6, in structure_ExampleConfig
+ | res['num_jobs'] = __c_structure_num_jobs(o['numJobs'], __c_type_num_jobs)
+ | File "/.../python3.10/site-packages/cattrs/converters.py",
+ line 377, in _structure_error
+ | raise StructureHandlerNotFoundError(msg, type_=cl)
+ | cattrs.errors.StructureHandlerNotFoundError: Unsupported type: typing.Union[typing.Literal['auto'], int].
+ Register a structure hook for it.
+ | Structuring class ExampleConfig @ attribute num_jobs
+ +------------------------------------
+
+In which case you can extend the converter provided by ``pygls`` with your own `structure hooks`_
+
+.. code-block:: python
+
+ from pygls.protocol import default_converter
+
+ def custom_converter():
+ converter = default_converter()
+ converter.register_structure_hook(Union[Literal['auto', int], lambda obj, _: obj)
+
+ return converter
+
+You can then override the default converter used by ``pygls`` when constructing your language server instance
+
+.. code-block:: python
+
+ server = LanguageServer(
+ name="my-language-server", version="v1.0", converter_factory=custom_converter
+ )
+
+See the `hooks.py`_ module in ``lsprotocol`` for some example structure hooks
+
+Miscellaneous
+-------------
+
+Mandatory ``name`` and ``version``
+""""""""""""""""""""""""""""""""""
+
+It is now necessary to provide a name and version when constructing an instance of the ``LanguageServer`` class
+
+.. code-block:: python
+
+ from pygls.server import LanguageServer
+
+ server = LanguageServer(name="my-language-server", version="v1.0")
+
+
+``ClientCapabilities.get_capability`` is now ``get_capability``
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+.. code-block:: python
+
+ # Before
+ from pygls.lsp.types import ClientCapabilities
+
+ client_capabilities = ClientCapabilities()
+ commit_character_support = client_capabilities.get_capability(
+ "text_document.completion.completion_item.commit_characters_support", False
+ )
+
+.. code-block:: python
+
+ # After
+ from lsprotocol.types import ClientCapabilities
+ from pygls.capabilities import get_capability
+
+ client_capabilities = ClientCapabilities()
+ commit_character_support = get_capability(
+ client_capabilities,
+ "text_document.completion.completion_item.commit_characters_support",
+ False
+ )
+
+.. _attrs: https://www.attrs.org/en/stable/index.html
+.. _cattrs: https://cattrs.readthedocs.io/en/stable/
+.. _converter: https://cattrs.readthedocs.io/en/stable/converters.html
+.. _hooks.py: https://github.com/microsoft/lsprotocol/blob/main/lsprotocol/_hooks.py
+.. _lsprotocol: https://github.com/microsoft/lsprotocol
+.. _pydantic: https://pydantic-docs.helpmanual.io/
+.. _structure hooks: https://cattrs.readthedocs.io/en/stable/structuring.html#registering-custom-structuring-hooks
+.. _jedi-language-server: https://github.com/pappasam/jedi-language-server/pull/230
+.. _yara-language-server: https://github.com/avast/yls/pull/34
+.. _vscode-ruff: https://github.com/charliermarsh/vscode-ruff/pull/37
+.. _esbonio: https://github.com/swyddfa/esbonio/pull/484
diff --git a/docs/source/pages/reference.rst b/docs/source/pages/reference.rst
new file mode 100644
index 0000000..2b0aa56
--- /dev/null
+++ b/docs/source/pages/reference.rst
@@ -0,0 +1,8 @@
+API Reference
+=============
+
+.. toctree::
+ :glob:
+ :maxdepth: 2
+
+ reference/*
diff --git a/docs/source/pages/reference/clients.rst b/docs/source/pages/reference/clients.rst
new file mode 100644
index 0000000..b4c37ed
--- /dev/null
+++ b/docs/source/pages/reference/clients.rst
@@ -0,0 +1,8 @@
+Clients
+=======
+
+.. autoclass:: pygls.lsp.client.BaseLanguageClient
+ :members:
+
+.. autoclass:: pygls.client.JsonRPCClient
+ :members:
diff --git a/docs/source/pages/reference/protocol.rst b/docs/source/pages/reference/protocol.rst
new file mode 100644
index 0000000..e9bd2f7
--- /dev/null
+++ b/docs/source/pages/reference/protocol.rst
@@ -0,0 +1,11 @@
+Protocol
+========
+
+
+.. autoclass:: pygls.protocol.LanguageServerProtocol
+ :members:
+
+.. autoclass:: pygls.protocol.JsonRPCProtocol
+ :members:
+
+.. autofunction:: pygls.protocol.default_converter
diff --git a/docs/source/pages/reference/servers.rst b/docs/source/pages/reference/servers.rst
new file mode 100644
index 0000000..2a664ed
--- /dev/null
+++ b/docs/source/pages/reference/servers.rst
@@ -0,0 +1,11 @@
+Servers
+=======
+
+.. autoclass:: pygls.server.LanguageServer
+ :members:
+
+.. autoclass:: pygls.server.Server
+ :members:
+
+
+
diff --git a/docs/source/pages/reference/types.rst b/docs/source/pages/reference/types.rst
new file mode 100644
index 0000000..1cbcb1f
--- /dev/null
+++ b/docs/source/pages/reference/types.rst
@@ -0,0 +1,10 @@
+Types
+=====
+
+LSP type definitions in ``pygls`` are provided by the `lsprotocol <https://github.com/microsoft/lsprotocol>`__ library
+
+.. automodule:: lsprotocol.types
+ :members:
+ :undoc-members:
+
+
diff --git a/docs/source/pages/reference/workspace.rst b/docs/source/pages/reference/workspace.rst
new file mode 100644
index 0000000..1e392dc
--- /dev/null
+++ b/docs/source/pages/reference/workspace.rst
@@ -0,0 +1,9 @@
+Workspace
+=========
+
+.. autoclass:: pygls.workspace.TextDocument
+ :members:
+
+.. autoclass:: pygls.workspace.Workspace
+ :members:
+
diff --git a/docs/source/pages/testing.rst b/docs/source/pages/testing.rst
new file mode 100644
index 0000000..9910835
--- /dev/null
+++ b/docs/source/pages/testing.rst
@@ -0,0 +1,24 @@
+.. _testing:
+
+Testing
+=======
+
+Unit Tests
+----------
+
+Writing unit tests for registered features and commands are easy and you don't
+have to mock the whole language server. If you skipped the advanced usage page,
+take a look at :ref:`passing language server instance <passing-instance>`
+section for more details.
+
+Integration Tests
+-----------------
+
+Integration tests coverage includes the whole workflow, from sending the client
+request, to getting the result from the server. Since the *Language Server
+Protocol* defines bidirectional communication between the client and the
+server, we used *pygls* to simulate the client and send desired requests to the
+server. To get a better understanding of how to set it up, take a look at our test
+`fixtures`_.
+
+.. _fixtures: https://github.com/openlawlibrary/pygls/blob/main/tests/conftest.py
diff --git a/docs/source/pages/tutorial.rst b/docs/source/pages/tutorial.rst
new file mode 100644
index 0000000..6db7f6c
--- /dev/null
+++ b/docs/source/pages/tutorial.rst
@@ -0,0 +1,207 @@
+.. _tutorial:
+
+Tutorial
+========
+
+In order to help you with using *pygls* in VSCode, we have created the `vscode-playground`_ extension.
+
+.. note::
+
+ This extension is meant to provide an environment in which you can easily experiment with a *pygls* powered language server.
+ It is not necessary in order to use *pygls* with other text editors.
+
+ If you decide you want to publish your language server on the VSCode marketplace this
+ `template extension <https://github.com/microsoft/vscode-python-tools-extension-template>`__
+ from Microsoft a useful starting point.
+
+Prerequisites
+-------------
+
+In order to setup and run the example VSCode extension, you need following software
+installed:
+
+* `Visual Studio Code <https://code.visualstudio.com/>`_ editor
+* `Python 3.8+ <https://www.python.org/downloads/>`_
+* `vscode-python <https://marketplace.visualstudio.com/items?itemName=ms-python.python>`_ extension
+* A clone of the `pygls <https://github.com/openlawlibrary/pygls>`_ repository
+
+.. note::
+ If you have created virtual environment, make sure that you have *pygls* installed
+ and `selected appropriate python interpreter <https://code.visualstudio.com/docs/python/environments>`_
+ for the *pygls* project.
+
+
+Running the Example
+-------------------
+
+For a step-by-step guide on how to setup and run the example follow `README`_.
+
+Hacking the Extension
+---------------------
+
+When you have successfully setup and run the extension, open `server.py`_ and
+go through the code.
+
+We have implemented following capabilities:
+
+- ``textDocument/completion`` feature
+- ``countDownBlocking`` command
+- ``countDownNonBlocking`` command
+- ``textDocument/didChange`` feature
+- ``textDocument/didClose`` feature
+- ``textDocument/didOpen`` feature
+- ``showConfigurationAsync`` command
+- ``showConfigurationCallback`` command
+- ``showConfigurationThread`` command
+
+When running the extension in *debug* mode, you can set breakpoints to see
+when each of above mentioned actions gets triggered.
+
+Visual Studio Code supports *Language Server Protocol*, which means, that every
+action on the client-side, will result in sending request or notification to
+the server via JSON RPC.
+
+Debug Code Completions
+~~~~~~~~~~~~~~~~~~~~~~
+
+Set a breakpoint inside ``completion`` function and go back to opened *json*
+file in your editor. Now press ``ctrl + space`` (``control + space`` on mac) to
+show completion list and you will hit the breakpoint. When you continue
+debugging, the completion list pop-up won't show up because it was closing when
+the editor lost focus.
+
+Similarly, you can debug any feature or command.
+
+Keep the breakpoint and continue to the next section.
+
+Blocking Command Test
+~~~~~~~~~~~~~~~~~~~~~
+
+In order to demonstrate you that blocking the language server will reject other
+requests, we have registered a custom command which counts down 10 seconds and
+sends notification messages to the client.
+
+1. Press **F1**, find and run ``Count down 10 seconds [Blocking]`` command.
+2. Try to show *code completions* while counter is still ticking.
+
+Language server is **blocked**, because ``time.sleep`` is a
+**blocking** operation. This is why you didn't hit the breakpoint this time.
+
+.. hint::
+
+ To make this command **non blocking**, add ``@json_server.thread()``
+ decorator, like in code below:
+
+ .. code-block:: python
+
+ @json_server.thread()
+ @json_server.command(JsonLanguageServer.CMD_COUNT_DOWN_BLOCKING)
+ def count_down_10_seconds_blocking(ls, *args):
+ # Omitted
+
+ *pygls* uses a **thread pool** to execute functions that are marked with
+ a ``thread`` decorator.
+
+
+Non-Blocking Command Test
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Python 3.4 introduced *asyncio* module which allows us to use asynchronous
+functions (aka *coroutines*) and do `cooperative multitasking`_. Using the
+`await` keyword inside your coroutine will give back control to the
+scheduler and won't block the main thread.
+
+1. Press **F1** and run the ``Count down 10 seconds [Non Blocking]`` command.
+2. Try to show *code completions* while counter is still ticking.
+
+Bingo! We hit the breakpoint! What just happened?
+
+The language server was **not blocked** because we used ``asyncio.sleep`` this
+time. The language server was executing *just* in the *main* thread.
+
+
+Text Document Operations
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Opening and closing a JSON file will display appropriate notification message
+in the bottom right corner of the window and the file content will be
+validated. Validation will be performed on content changes, as well.
+
+Show Configuration Data
+~~~~~~~~~~~~~~~~~~~~~~~
+
+There are *three* ways for getting configuration section from the client
+settings.
+
+.. note::
+
+ *pygls*' built-in coroutines are suffixed with *async* word, which means that
+ you have to use the *await* keyword in order to get the result (instead of
+ *asyncio.Future* object).
+
+- **Get the configuration inside a coroutine**
+
+.. code-block:: python
+
+ config = await ls.get_configuration_async(ConfigurationParams([
+ ConfigurationItem('', JsonLanguageServer.CONFIGURATION_SECTION)
+ ]))
+
+- **Get the configuration inside a normal function**
+
+We already saw that we *don't* want to block the main thread. Sending the
+configuration request to the client will result with the response from it, but
+we don't know when. You have to pass *callback* function which will be
+triggered once response from the client is received.
+
+.. code-block:: python
+
+ def _config_callback(config):
+ try:
+ example_config = config[0].exampleConfiguration
+
+ ls.show_message(
+ f'jsonServer.exampleConfiguration value: {example_config}'
+ )
+
+ except Exception as e:
+ ls.show_message_log(f'Error ocurred: {e}')
+
+ ls.get_configuration(ConfigurationParams([
+ ConfigurationItem('', JsonLanguageServer.CONFIGURATION_SECTION)
+ ]), _config_callback)
+
+As you can see, the above code is hard to read.
+
+- **Get the configuration inside a threaded function**
+
+Blocking operations such as ``future.result(1)`` should not be used inside
+normal functions, but to increase the code readability, you can add the
+*thread* decorator to your function to use *pygls*' *thread pool*.
+
+.. code-block:: python
+
+ @json_server.thread()
+ @json_server.command(JsonLanguageServer.CMD_SHOW_CONFIGURATION_THREAD)
+ def show_configuration_thread(ls: JsonLanguageServer, *args):
+ """Gets exampleConfiguration from the client settings using a thread pool."""
+ try:
+ config = ls.get_configuration(ConfigurationParams([
+ ConfigurationItem('', JsonLanguageServer.CONFIGURATION_SECTION)
+ ])).result(2)
+
+ # ...
+
+This way you won't block the main thread. *pygls* will start a new thread when
+executing the function.
+
+Modify the Example
+~~~~~~~~~~~~~~~~~~
+
+We encourage you to continue to :ref:`user guide <user-guide>` and
+modify this example.
+
+.. _vscode-playground: https://github.com/openlawlibrary/pygls/blob/main/examples/vscode-playground
+.. _README: https://github.com/openlawlibrary/pygls/blob/main/examples/vscode-playground/README.md
+.. _server.py: https://github.com/openlawlibrary/pygls/blob/main/examples/servers/json_server.py
+.. _cooperative multitasking: https://en.wikipedia.org/wiki/Cooperative_multitasking
diff --git a/docs/source/pages/user-guide.rst b/docs/source/pages/user-guide.rst
new file mode 100644
index 0000000..c0ce43e
--- /dev/null
+++ b/docs/source/pages/user-guide.rst
@@ -0,0 +1,536 @@
+.. _user-guide:
+
+User Guide
+==========
+
+Language Server
+---------------
+
+The language server is responsible for managing the connection with the client as well as sending and receiving messages over
+the `Language Server Protocol <https://microsoft.github.io/language-server-protocol/>`__
+which is based on the `Json RPC protocol <https://www.jsonrpc.org/specification>`__.
+
+Connections
+~~~~~~~~~~~
+
+*pygls* supports :ref:`ls-tcp`, :ref:`ls-stdio` and :ref:`ls-websocket` connections.
+
+.. _ls-tcp:
+
+TCP
+^^^
+
+TCP connections are usually used while developing the language server.
+This way the server can be started in *debug* mode separately and wait
+for the client connection.
+
+.. note:: Server should be started **before** the client.
+
+The code snippet below shows how to start the server in *TCP* mode.
+
+.. code:: python
+
+ from pygls.server import LanguageServer
+
+ server = LanguageServer('example-server', 'v0.1')
+
+ server.start_tcp('127.0.0.1', 8080)
+
+.. _ls-stdio:
+
+STDIO
+^^^^^
+
+STDIO connections are useful when client is starting the server as a child
+process. This is the way to go in production.
+
+The code snippet below shows how to start the server in *STDIO* mode.
+
+.. code:: python
+
+ from pygls.server import LanguageServer
+
+ server = LanguageServer('example-server', 'v0.1')
+
+ server.start_io()
+
+.. _ls-websocket:
+
+WEBSOCKET
+^^^^^^^^^
+
+WEBSOCKET connections are used when you want to expose language server to
+browser based editors.
+
+The code snippet below shows how to start the server in *WEBSOCKET* mode.
+
+.. code:: python
+
+ from pygls.server import LanguageServer
+
+ server = LanguageServer('example-server', 'v0.1')
+
+ server.start_ws('0.0.0.0', 1234)
+
+Logging
+~~~~~~~
+
+Logs are useful for tracing client requests, finding out errors and
+measuring time needed to return results to the client.
+
+*pygls* uses built-in python *logging* module which has to be configured
+before server is started.
+
+Official documentation about logging in python can be found
+`here <https://docs.python.org/3/howto/logging-cookbook.html>`__. Below
+is the minimal setup to setup logging in *pygls*:
+
+.. code:: python
+
+ import logging
+
+ from pygls.server import LanguageServer
+
+ logging.basicConfig(filename='pygls.log', filemode='w', level=logging.DEBUG)
+
+ server = LanguageServer('example-server', 'v0.1')
+
+ server.start_io()
+
+Overriding ``LanguageServerProtocol``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you have a reason to override the existing ``LanguageServerProtocol`` class,
+you can do that by inheriting the class and passing it to the ``LanguageServer``
+constructor.
+
+Custom Error Reporting
+~~~~~~~~~~~~~~~~~~~~~~
+
+The default :class:`~pygls.server.LanguageServer` will send a :lsp:`window/showMessage` notification to the client to display any uncaught exceptions in the server.
+To override this behaviour define your own :meth:`~pygls.server.LanguageServer.report_server_error` method like so:
+
+.. code:: python
+
+ class CustomLanguageServer(LanguageServer):
+ def report_server_error(self, error: Exception, source: Union[PyglsError, JsonRpcException]):
+ pass
+
+Handling Client Messages
+------------------------
+
+.. admonition:: Requests vs Notifications
+
+ Unlike a *request*, a *notification* message has no ``id`` field and the server *must not* reply to it.
+ This means that, even if you return a result inside a handler function for a notification, the result won't be passed to the client.
+
+ The ``Language Server Protocol``, unlike ``Json RPC``, allows bidirectional communication between the server and the client.
+
+For the majority of the time, a language server will be responding to requests and notifications sent from the client.
+*pygls* refers to the handlers for all of these messages as *features* with one exception.
+
+The Language Server protocol allows a server to define named methods that a client can invoke by sending a :lsp:`workspace/executeCommand` request.
+Unsurprisingly, *pygls* refers to these named methods a *commands*.
+
+*Built-In* Features
+~~~~~~~~~~~~~~~~~~~
+
+*pygls* comes with following predefined set of handlers for the following
+`Language Server Protocol <https://microsoft.github.io/language-server-protocol/>`__
+(LSP) features:
+
+.. note::
+
+ *Built-in* features in most cases should *not* be overridden.
+
+ If you need to do some additional processing of one of the messages listed below, register a feature with the same name and your handler will be called immediately after the corresponding built-in feature.
+
+**Lifecycle Messages**
+
+- The :lsp:`initialize` request is sent as a first request from client to the server to setup their communication.
+ *pygls* automatically computes registered LSP capabilities and sends them as part of the :class:`~lsprotocol.types.InitializeResult` response.
+
+- The :lsp:`shutdown` request is sent from the client to the server to ask the server to shutdown.
+
+- The :lsp:`exit` notification is sent from client to the server to ask the server to exit the process.
+ *pygls* automatically releases all resources and stops the process.
+
+**Text Document Synchronization**
+
+- The :lsp:`textDocument/didOpen` notification will tell *pygls* to create a document in the in-memory workspace which will exist as long as the document is opened in editor.
+
+- The :lsp:`textDocument/didChange` notification will tell *pygls* to update the document text.
+ *pygls* supports *full* and *incremental* document changes.
+
+- The :lsp:`textDocument/didClose` notification will tell *pygls* to remove a document from the in-memory workspace.
+
+**Notebook Document Synchronization**
+
+- The :lsp:`notebookDocument/didOpen` notification will tell *pygls* to create a notebook document in the in-memory workspace which will exist as long as the document is opened in editor.
+
+- The :lsp:`notebookDocument/didChange` notification will tell *pygls* to update the notebook document include its content, metadata, execution results and cell structure.
+
+- The :lsp:`notebookDocument/didClose` notification will tell *pygls* to remove the notebook from the in-memory workspace.
+
+**Miscellanous**
+
+- The :lsp:`workspace/didChangeWorkspaceFolders` notification will tell *pygls* to update in-memory workspace folders.
+
+- The :lsp:`workspace/executeCommand` request will tell *pygls* to execute a custom command.
+
+- The :lsp:`$/setTrace` notification tells *pygls* to update the server's :class:`TraceValue <lsprotocol.types.TraceValues>`.
+
+.. _ls-handlers:
+
+Registering Handlers
+~~~~~~~~~~~~~~~~~~~~
+
+.. seealso::
+
+ It's recommeded that you follow the :ref:`tutorial <tutorial>` before reading this section.
+
+- The :func:`~pygls.server.LanguageServer.feature` decorator is used to register a handler for a given LSP message.
+- The :func:`~pygls.server.LanguageServer.command` decorator is used to register a named command.
+
+The following applies to both feature and command handlers.
+
+Language servers using *pygls* run in an *asyncio event loop*.
+They *asynchronously* listen for incoming messages and, depending on the way handler is registered, apply different execution strategies to process the message.
+
+Depending on the use case, handlers can be registered in three different ways:
+
+- as an :ref:`async <ls-handler-async>` function
+- as a :ref:`synchronous <ls-handler-sync>` function
+- as a :ref:`threaded <ls-handler-thread>` function
+
+.. _ls-handler-async:
+
+*Asynchronous* Functions (*Coroutines*)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*pygls* supports ``python 3.8+`` which has a keyword ``async`` to
+specify coroutines.
+
+The code snippet below shows how to register a command as a coroutine:
+
+.. code:: python
+
+ @json_server.command(JsonLanguageServer.CMD_COUNT_DOWN_NON_BLOCKING)
+ async def count_down_10_seconds_non_blocking(ls, *args):
+ # Omitted
+
+Registering a *feature* as a coroutine is exactly the same.
+
+Coroutines are functions that are executed as tasks in *pygls*'s *event
+loop*. They should contain at least one *await* expression (see
+`awaitables <https://docs.python.org/3.5/glossary.html#term-awaitable>`__
+for details) which tells event loop to switch to another task while
+waiting. This allows *pygls* to listen for client requests in a
+*non blocking* way, while still only running in the *main* thread.
+
+Tasks can be canceled by the client if they didn't start executing (see
+`Cancellation
+Support <https://microsoft.github.io/language-server-protocol/specification#cancelRequest>`__).
+
+.. warning::
+
+ Using computation intensive operations will *block* the main thread and
+ should be *avoided* inside coroutines. Take a look at
+ `threaded functions <#threaded-functions>`__ for more details.
+
+.. _ls-handler-sync:
+
+*Synchronous* Functions
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Synchronous functions are regular functions which *blocks* the *main*
+thread until they are executed.
+
+`Built-in features <#built-in-features>`__ are registered as regular
+functions to ensure correct state of language server initialization and
+workspace.
+
+The code snippet below shows how to register a command as a regular
+function:
+
+.. code:: python
+
+ @json_server.command(JsonLanguageServer.CMD_COUNT_DOWN_BLOCKING)
+ def count_down_10_seconds_blocking(ls, *args):
+ # Omitted
+
+Registering *feature* as a regular function is exactly the same.
+
+.. warning::
+
+ Using computation intensive operations will *block* the main thread and
+ should be *avoided* inside regular functions. Take a look at
+ `threaded functions <#threaded-functions>`__ for more details.
+
+.. _ls-handler-thread:
+
+*Threaded* Functions
+^^^^^^^^^^^^^^^^^^^^
+
+*Threaded* functions are just regular functions, but marked with
+*pygls*'s ``thread`` decorator:
+
+.. code:: python
+
+ # Decorator order is not important in this case
+ @json_server.thread()
+ @json_server.command(JsonLanguageServer.CMD_COUNT_DOWN_BLOCKING)
+ def count_down_10_seconds_blocking(ls, *args):
+ # Omitted
+
+*pygls* uses its own *thread pool* to execute above function in *daemon*
+thread and it is *lazy* initialized first time when function marked with
+``thread`` decorator is fired.
+
+*Threaded* functions can be used to run blocking operations. If it has been a
+while or you are new to threading in Python, check out Python's
+``multithreading`` and `GIL <https://en.wikipedia.org/wiki/Global_interpreter_lock>`__
+before messing with threads.
+
+.. _passing-instance:
+
+Passing Language Server Instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Using language server methods inside registered features and commands are quite
+common. We recommend adding language server as a **first parameter** of a
+registered function.
+
+There are two ways of doing this:
+
+- **ls** (**l**\anguage **s**\erver) naming convention
+
+Add **ls** as first parameter of a function and *pygls* will automatically pass
+the language server instance.
+
+.. code-block:: python
+
+ @json_server.command(JsonLanguageServer.CMD_COUNT_DOWN_BLOCKING)
+ def count_down_10_seconds_blocking(ls, *args):
+ # Omitted
+
+
+- add **type** to first parameter
+
+Add the **LanguageServer** class or any class derived from it as a type to
+first parameter of a function
+
+.. code-block:: python
+
+ @json_server.command(JsonLanguageServer.CMD_COUNT_DOWN_BLOCKING)
+ def count_down_10_seconds_blocking(ser: JsonLanguageServer, *args):
+ # Omitted
+
+
+Using outer ``json_server`` instance inside registered function will make
+writing unit :ref:`tests <testing>` more difficult.
+
+Communicating with the Client
+-----------------------------
+
+.. important::
+
+ Most of the messages listed here cannot be sent until the LSP session has been initialized.
+ See the section on the :lsp:`initiaiize` request in the specification for more details.
+
+In addition to responding to requests, there are a number of additional messages a server can send to the client.
+
+Configuration
+~~~~~~~~~~~~~
+
+The :lsp:`workspace/configuration` request is sent from the server to the client in order to fetch configuration settings from the client.
+Depending on how the handler is registered (see :ref:`here <ls-handlers>`) you can use the :meth:`~pygls.server.LanguageServer.get_configuration` or :meth:`~pygls.server.LanguageServer.get_configuration_async` methods to request configuration from the client:
+
+- *asynchronous* functions (*coroutines*)
+
+ .. code:: python
+
+ # await keyword tells event loop to switch to another task until notification is received
+ config = await ls.get_configuration(
+ WorkspaceConfigurationParams(
+ items=[
+ ConfigurationItem(scope_uri='doc_uri_here', section='section')
+ ]
+ )
+ )
+
+- *synchronous* functions
+
+ .. code:: python
+
+ # callback is called when notification is received
+ def callback(config):
+ # Omitted
+
+ params = WorkspaceConfigurationParams(
+ items=[
+ ConfigurationItem(scope_uri='doc_uri_here', section='section')
+ ]
+ )
+ config = ls.get_configuration(params, callback)
+
+- *threaded* functions
+
+ .. code:: python
+
+ # .result() will block the thread
+ config = ls.get_configuration(
+ WorkspaceConfigurationParams(
+ items=[
+ ConfigurationItem(scope_uri='doc_uri_here', section='section')
+ ]
+ )
+ ).result()
+
+Publish Diagnostics
+~~~~~~~~~~~~~~~~~~~
+
+:lsp:`textDocument/publishDiagnostics` notifications are sent from the server to the client to highlight errors or potential issues. e.g. syntax errors or unused variables.
+
+Usually this notification is sent after document is opened, or on document content change:
+
+.. code:: python
+
+ @json_server.feature(TEXT_DOCUMENT_DID_OPEN)
+ async def did_open(ls, params: DidOpenTextDocumentParams):
+ """Text document did open notification."""
+ ls.show_message("Text Document Did Open")
+ ls.show_message_log("Validating json...")
+
+ # Get document from workspace
+ text_doc = ls.workspace.get_text_document(params.text_document.uri)
+
+ diagnostic = Diagnostic(
+ range=Range(
+ start=Position(line-1, col-1),
+ end=Position(line-1, col)
+ ),
+ message="Custom validation message",
+ source="Json Server"
+ )
+
+ # Send diagnostics
+ ls.publish_diagnostics(text_doc.uri, [diagnostic])
+
+Show Message
+~~~~~~~~~~~~
+
+:lsp:`window/showMessage` is a notification that is sent from the server to the client to display a prominant text message. e.g. VSCode will render this as a notification popup
+
+.. code:: python
+
+ @json_server.command(JsonLanguageServer.CMD_COUNT_DOWN_NON_BLOCKING)
+ async def count_down_10_seconds_non_blocking(ls, *args):
+ for i in range(10):
+ # Sends message notification to the client
+ ls.show_message(f"Counting down... {10 - i}")
+ await asyncio.sleep(1)
+
+Show Message Log
+~~~~~~~~~~~~~~~~
+
+:lsp:`window/logMessage` is a notification that is sent from the server to the client to display a discrete text message. e.g. VSCode will display the message in an :guilabel:`Output` channel.
+
+.. code:: python
+
+ @json_server.command(JsonLanguageServer.CMD_COUNT_DOWN_NON_BLOCKING)
+ async def count_down_10_seconds_non_blocking(ls, *args):
+ for i in range(10):
+ # Sends message log notification to the client
+ ls.show_message_log(f"Counting down... {10 - i}")
+ await asyncio.sleep(1)
+
+Workspace Edits
+~~~~~~~~~~~~~~~
+
+The :lsp:`workspace/applyEdit` request allows your language server to ask the client to modify particular documents in the client's workspace.
+
+.. code:: python
+
+ def apply_edit(self, edit: WorkspaceEdit, label: str = None) -> ApplyWorkspaceEditResponse:
+ # Omitted
+
+ def apply_edit_async(self, edit: WorkspaceEdit, label: str = None) -> ApplyWorkspaceEditResponse:
+ # Omitted
+
+Custom Notifications
+~~~~~~~~~~~~~~~~~~~~
+
+.. warning::
+
+ Custom notifications are not part of the LSP specification and dedicated support for your custom notification(s) will have to be added to each language client you intend to support.
+
+A custom notification can be sent to the client using the :meth:`~pygls.server.LanguageServer.send_notification` method
+
+.. code:: python
+
+ server.send_notification('myCustomNotification', 'test data')
+
+
+The Workspace
+-------------
+
+The :class:`~pygls.workspace.Workspace` is a python object that holds information about workspace folders, opened documents and is responsible for synchronising server side document state with that of the client.
+
+**Text Documents**
+
+The :class:`~pygls.workspace.TextDocument` class is how *pygls* represents a text document.
+Given a text document's uri the :meth:`~pygls.workspace.Workspace.get_text_document` method can be used to access the document itself:
+
+.. code:: python
+
+ @json_server.feature(TEXT_DOCUMENT_DID_OPEN)
+ async def did_open(ls, params: DidOpenTextDocumentParams):
+
+ # Get document from workspace
+ text_doc = ls.workspace.get_text_document(params.text_document.uri)
+
+**Notebook Documents**
+
+.. seealso::
+
+ See the section on :lsp:`notebookDocument/synchronization` in the specification for full details on how notebook documents are handled
+
+- A notebook's structure, metadata etc. is represented using the :class:`~lsprotocol.types.NotebookDocument` class from ``lsprotocol``.
+- The contents of a single notebook cell is represented using a standard :class:`~pygls.workspace.TextDocument`
+
+In order to receive notebook documents from the client, your language server must provide an instance of :class:`~lsprotocol.types.NotebookDocumentSyncOptions` which declares the kind of notebooks it is interested in
+
+.. code-block:: python
+
+ server = LanguageServer(
+ name="example-server",
+ version="v0.1",
+ notebook_document_sync=types.NotebookDocumentSyncOptions(
+ notebook_selector=[
+ types.NotebookDocumentSyncOptionsNotebookSelectorType2(
+ cells=[
+ types.NotebookDocumentSyncOptionsNotebookSelectorType2CellsType(
+ language="python"
+ )
+ ]
+ )
+ ]
+ ),
+ )
+
+To access the contents of a notebook cell you would call the workspace's :meth:`~pygls.workspace.Workspace.get_text_document` method as normal.
+
+.. code-block:: python
+
+ cell_doc = ls.workspace.get_text_document(cell_uri)
+
+To access the notebook itself call the workspace's :meth:`~pygls.workspace.Workspace.get_notebook_document` method with either the uri of the notebook *or* the uri of any of its cells.
+
+.. code-block:: python
+
+ notebook_doc = ls.workspace.get_notebook_document(notebook_uri=notebook_uri)
+
+ # -- OR --
+
+ notebook_doc = ls.workspace.get_notebook_document(cell_uri=cell_uri)