Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save bollwyvl/836bb8775f351b579b7204eccc15971f to your computer and use it in GitHub Desktop.
Save bollwyvl/836bb8775f351b579b7204eccc15971f to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h1 style=\"font-size: 72px; font-family: 'Lakki Reddy', cursive; color: orange;\">Bringing the Language Server Protocol to Jupyter(Lab)</h1>\n",
"\n",
"> ## ⸻ @krassowski, @bollwyvl"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# **What is the Language Server Protocol?**\n",
"\n",
"> _A Language Server is meant to provide the language-specific smarts and communicate with **development tools** over a protocol that enables inter-process communication._\n",
">\n",
"> _The idea behind the Language Server Protocol (LSP) is to standardize the protocol for how such **servers** and **development tools** communicate. This way, a single **Language Server** can be **re-used** in multiple development tools, which in turn can support **multiple languages** with minimal effort._\n",
">\n",
"> ## ⸻ [microsoft.github.io/language-server-protocol](https://microsoft.github.io/language-server-protocol)\n",
"> _**emphasis** ours_"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **But Practically...**\n",
"- ### **markdown** specification (on the above site)\n",
"- ### reference **server**, `vscode-language-server-node`\n",
"- ### reference **client**, `vscode`\n",
"- ### number of **other clients**\n",
"- ### a lot of language **servers**\n",
"\n",
"> _For more excruciating detail, see this [gist](https://gist.github.com/bollwyvl/7a128978b8ae89ab02bbd5b84d07a4b7)_"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# **What is a Language Server?**\n",
"- ## a process that speaks JSON-RPC 2.0 over `stdin`/`stdout` (or sometimes TCP)\n",
"- ## the messages are things like\n",
" - ### 🙋 I opened a file!\n",
" - ### 🤖 YOUR FILE HAS TRAILING WHITESPACE\n",
" - ### 🙋 I fixed some whitespace\n",
" - ### 🤖 THERE IS NOTHING WRONG NOW\n",
" - ### 🙋 I hovered over a symbol!\n",
" - ### 🤖 IT'S A FUNCTION\n",
" - ### 🙋 Where did it come from?\n",
" - ### 🤖 THIS OTHER FILE OVER HERE"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# **Sounds a lot like the Jupyter Message Spec**\n",
"- ## Yep\n",
"- ## But it's good to have both\n",
" - ### **Kernel** (usually) does **dynamic analysis**, so can do More Things \n",
" - ### **Language Server** (usually) does **static analysis**, so (usually) faster\n",
" - ### Also, it doesn't make sense to have Kernels for some things \n",
"- ## **Future** kernels could contribute their own LSP messages"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h1 style=\"font-family: 'Lakki Reddy', cursive; font-size: 128px; color: orange;\">SPOOKY DEMO</h1>"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'🎃🎃🎃🎃🎃🎃🎃🎃🎃🎃more pumpkins'"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"pumpkins = \"🎃\" * 10\n",
"pumpkins + \"more pumpkins\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pumpkins + 2"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"Chicken = 0\n",
"chicken = {\n",
" chicken for chicken in range(10)\n",
" if chicken in [Chicken] \n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# this_variable_is_not_used - 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# **What have we done on [@krassowski/jupyterlab-lsp](https://github.com/krassowski/jupyterlab-lsp)**\n",
"- ## Reuse existing LSP <-> CodeMirror bridge\n",
"- ## Implement `Jump to Definition`\n",
"- ## TypeScript Unit tests on Travis CI\n",
"- ## Traitnado-based LSP WebSocket proxy\n",
"- ## Python Unit tests and Browser tests on Azure Pipelines\n",
"- ## Upstream PRs\n",
" - ### `yaml-language-server`\n",
" - ### conda-forge (for `r-languageserver`)\n",
" - ### `void` on"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# **Next Steps**\n",
"- ## Keep putting out releases people can try out\n",
"- ## Keep heading towards proposal to JupyterLab core\n",
"- ## Encourage some contributors\n",
"- ## Add/Test more Language Servers (and Features)\n",
"- ## Warm up the [JEP PR #26](https://github.com/jupyter/enhancement-proposals/pull/26)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%file spooky.csscss\n",
"@import url('https://fonts.googleapis.com/css?family=Lakki+Reddy&display=swap');\n",
"#main {\n",
" --jp-border-width: 0.01px;\n",
" --pumpkin: rgba(245, 124, 0, 0.75);\n",
" --ghost: rgba(255, 255, 255, 0.5);\n",
"}\n",
"#main .cm-lsp-highlight:not(:empty) {\n",
" background-color: var(--pumpkin);\n",
" border-radius: 5px;\n",
" color: yellow !important;\n",
" text-shadow: 0 0 5px yellow;\n",
" padding: 0.25em 0;\n",
" font-weight: bold;\n",
" position: relative;\n",
" border-left: none;\n",
" border-right: none;\n",
" transition: all 1s;\n",
"}\n",
".cm-lsp-highlight:not(:empty)::before {\n",
" content: '🍃';\n",
" font-size: 0.9em;\n",
" top: -0.9em;\n",
" left: 50%;\n",
" color: green;\n",
" position: absolute;\n",
" text-shadow: none;\n",
" transition: all 1s;\n",
"}\n",
"#main\n",
" .cm-lsp-diagnostic-Error:not(.cm-lsp-highlight):not(.cm-lsp-highlight-Write) {\n",
" color: black !important;\n",
" background-color: var(--ghost);\n",
" border-radius: 1em 1em 0 0;\n",
" font-weight: bold;\n",
" padding: 0.25em 0.25em 0.1em 0.25em;\n",
" position: relative;\n",
" text-decoration-color: transparent;\n",
" margin: 0 0.2em;\n",
" transition: all 1s;\n",
"}\n",
".cm-lsp-diagnostic-Error:not(.cm-lsp-highlight):not(.cm-lsp-highlight-Write):before {\n",
" position: absolute;\n",
" left: 0;\n",
" right: 0;\n",
" top: -10%;\n",
" height: 110%;\n",
" border-bottom: dotted 2px var(--ghost) !important;\n",
" content: '';\n",
" transition: all 1s;\n",
"}\n",
"#main\n",
" .cm-lsp-diagnostic-Warning:not(.cm-lsp-highlight-Write):not(.cm-lsp-diagnostic-Error) {\n",
" position: relative;\n",
" color: green;\n",
" font-weight: bold;\n",
" text-shadow: 0 0 10px green;\n",
" text-decoration: none;\n",
" font-size: 2em;\n",
" -webkit-text-stroke: 1px rgba(0, 50, 0, 0.5);\n",
" font-family: 'Lakki Reddy', cursive;\n",
" transition: all 1s;\n",
"}\n",
"body .jp-HoverBox {\n",
" min-width: 300px;\n",
" overflow-y: auto;\n",
"}\n",
"body .jp-HoverBox,\n",
"body .jp-HoverBox * {\n",
" background-color: black !important;\n",
" color: red !important;\n",
" font-family: 'Lakki Reddy', cursive;\n",
" font-size: 16px !important;\n",
" text-align: center;\n",
" font-weight: bold;\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>@import url('https://fonts.googleapis.com/css?family=Lakki+Reddy&display=swap');\n",
"#main {\n",
" --jp-border-width: 0.01px;\n",
" --pumpkin: rgba(245, 124, 0, 0.75);\n",
" --ghost: rgba(255, 255, 255, 0.5);\n",
"}\n",
"#main .cm-lsp-highlight:not(:empty) {\n",
" background-color: var(--pumpkin);\n",
" border-radius: 5px;\n",
" color: yellow !important;\n",
" text-shadow: 0 0 5px yellow;\n",
" padding: 0.25em 0;\n",
" font-weight: bold;\n",
" position: relative;\n",
" border-left: none;\n",
" border-right: none;\n",
" transition: all 1s;\n",
"}\n",
".cm-lsp-highlight:not(:empty)::before {\n",
" content: '🍃';\n",
" font-size: 0.9em;\n",
" top: -0.9em;\n",
" left: 50%;\n",
" color: green;\n",
" position: absolute;\n",
" text-shadow: none;\n",
" transition: all 1s;\n",
"}\n",
"#main\n",
" .cm-lsp-diagnostic-Error:not(.cm-lsp-highlight):not(.cm-lsp-highlight-Write) {\n",
" color: black !important;\n",
" background-color: var(--ghost);\n",
" border-radius: 1em 1em 0 0;\n",
" font-weight: bold;\n",
" padding: 0.25em 0.25em 0.1em 0.25em;\n",
" position: relative;\n",
" text-decoration-color: transparent;\n",
" margin: 0 0.2em;\n",
" transition: all 1s;\n",
"}\n",
".cm-lsp-diagnostic-Error:not(.cm-lsp-highlight):not(.cm-lsp-highlight-Write):before {\n",
" position: absolute;\n",
" left: 0;\n",
" right: 0;\n",
" top: -10%;\n",
" height: 110%;\n",
" border-bottom: dotted 2px var(--ghost) !important;\n",
" content: '';\n",
" transition: all 1s;\n",
"}\n",
"#main\n",
" .cm-lsp-diagnostic-Warning:not(.cm-lsp-highlight-Write):not(.cm-lsp-diagnostic-Error) {\n",
" position: relative;\n",
" color: green;\n",
" font-weight: bold;\n",
" text-shadow: 0 0 10px green;\n",
" text-decoration: none;\n",
" font-size: 2em;\n",
" -webkit-text-stroke: 1px rgba(0, 50, 0, 0.5);\n",
" font-family: 'Lakki Reddy', cursive;\n",
" transition: all 1s;\n",
"}\n",
"body .jp-HoverBox {\n",
" min-width: 300px;\n",
" overflow-y: auto;\n",
"}\n",
"body .jp-HoverBox,\n",
"body .jp-HoverBox * {\n",
" background-color: black !important;\n",
" color: red !important;\n",
" font-family: 'Lakki Reddy', cursive;\n",
" font-size: 16px !important;\n",
" text-align: center;\n",
" font-weight: bold;\n",
"}\n",
"</style>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pathlib\n",
"import IPython \n",
"css = pathlib.Path(\"spooky.css\").read_text()\n",
"IPython.display.HTML(f\"<style>{css}</style>\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment