summaryrefslogtreecommitdiffstats
path: root/docs/source/pages/tutorial.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/source/pages/tutorial.rst')
-rw-r--r--docs/source/pages/tutorial.rst207
1 files changed, 207 insertions, 0 deletions
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