From e97deffb700551911e94f065a329d9b9a2a8bbf0 Mon Sep 17 00:00:00 2001 From: kazk Date: Fri, 16 Sep 2022 15:18:26 -0700 Subject: [PATCH] Add Python example with pyright --- examples/pyright/.gitignore | 26 ++++ examples/pyright/README.md | 20 +++ examples/pyright/favicon.svg | 15 +++ examples/pyright/index.html | 18 +++ examples/pyright/package.json | 24 ++++ examples/pyright/src/main.ts | 122 ++++++++++++++++++ examples/pyright/src/style.css | 21 +++ examples/pyright/src/vite-env.d.ts | 1 + examples/pyright/tsconfig.json | 20 +++ examples/pyright/workspace/preloaded.py | 4 + examples/pyright/workspace/pyrightconfig.json | 8 ++ examples/pyright/workspace/solution.py | 7 + .../pyright/workspace/tests/test_solution.py | 10 ++ pnpm-lock.yaml | 29 +++++ 14 files changed, 325 insertions(+) create mode 100644 examples/pyright/.gitignore create mode 100644 examples/pyright/README.md create mode 100644 examples/pyright/favicon.svg create mode 100644 examples/pyright/index.html create mode 100644 examples/pyright/package.json create mode 100644 examples/pyright/src/main.ts create mode 100644 examples/pyright/src/style.css create mode 100644 examples/pyright/src/vite-env.d.ts create mode 100644 examples/pyright/tsconfig.json create mode 100644 examples/pyright/workspace/preloaded.py create mode 100644 examples/pyright/workspace/pyrightconfig.json create mode 100644 examples/pyright/workspace/solution.py create mode 100644 examples/pyright/workspace/tests/test_solution.py diff --git a/examples/pyright/.gitignore b/examples/pyright/.gitignore new file mode 100644 index 0000000..f694356 --- /dev/null +++ b/examples/pyright/.gitignore @@ -0,0 +1,26 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +bin/ diff --git a/examples/pyright/README.md b/examples/pyright/README.md new file mode 100644 index 0000000..2bc22b9 --- /dev/null +++ b/examples/pyright/README.md @@ -0,0 +1,20 @@ +# @qualified/codemirror-workspace Python demo + +--- + +Install [`pnpm`] if you don't have it installed: + +``` +npm i -g pnpm@6 +``` + +Install [`lsp-ws-proxy`](https://github.com/qualified/lsp-ws-proxy) (v0.8.0+ is required) by downloading a binary from [releases](https://github.com/qualified/lsp-ws-proxy/releases) and moving it in `PATH` or `./bin`. + +Run the following to start a dev server: + +```bash +pnpm install +pnpm dev +``` + +[`pnpm`]: https://pnpm.js.org/ diff --git a/examples/pyright/favicon.svg b/examples/pyright/favicon.svg new file mode 100644 index 0000000..de4aedd --- /dev/null +++ b/examples/pyright/favicon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/examples/pyright/index.html b/examples/pyright/index.html new file mode 100644 index 0000000..da31f23 --- /dev/null +++ b/examples/pyright/index.html @@ -0,0 +1,18 @@ + + + + + + + CodeMirror Workspace Python Demo + + +
+
+
+
+
+ + + + diff --git a/examples/pyright/package.json b/examples/pyright/package.json new file mode 100644 index 0000000..e0f1300 --- /dev/null +++ b/examples/pyright/package.json @@ -0,0 +1,24 @@ +{ + "name": "@qualified/codemirror-workspace-demo-python", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "concurrently 'vite' 'pnpm start-proxy'", + "build": "tsc && vite build", + "preview": "concurrently 'vite preview' 'pnpm start-proxy'", + "start-proxy": "cd workspace && PATH=$(pwd)/../bin:$PATH RUST_LOG=info,lsp_ws_proxy=debug lsp-ws-proxy --remap -l 9990 -- pyright-langserver --stdio" + }, + "dependencies": { + "@qualified/codemirror-workspace": "workspace:0.5.0", + "codemirror": "^5.59.2", + "marked": "^4.0.17" + }, + "devDependencies": { + "@types/codemirror": "^5.0.0", + "@types/marked": "^4.0.3", + "concurrently": "^7.2.2", + "pyright": "^1.1.271", + "typescript": "^4.7.4", + "vite": "^2.9.9" + } +} diff --git a/examples/pyright/src/main.ts b/examples/pyright/src/main.ts new file mode 100644 index 0000000..039b3fd --- /dev/null +++ b/examples/pyright/src/main.ts @@ -0,0 +1,122 @@ +import "./style.css"; + +import CodeMirror from "codemirror"; +import "codemirror/mode/python/python"; +import "codemirror/lib/codemirror.css"; +import "codemirror/theme/idea.css"; +// ShowHint addon is required for completion capability. +import "codemirror/addon/hint/show-hint.css"; +import "codemirror/addon/hint/show-hint"; +import "codemirror/addon/edit/matchbrackets"; +import "codemirror/addon/edit/closebrackets"; +import "codemirror/addon/runmode/runmode"; +// import "codemirror/keymap/vim"; + +import { marked } from "marked"; + +import { Workspace } from "@qualified/codemirror-workspace"; +import "@qualified/codemirror-workspace/css/default.css"; + +import preloadedPy from "../workspace/preloaded.py?raw"; +import solutionPy from "../workspace/solution.py?raw"; +import solutionTestPy from "../workspace/tests/test_solution.py?raw"; + +const modeMap: { [k: string]: string } = { + python: "python", +}; + +const highlight = (code: string, language: string) => { + const mode = modeMap[language] || "text/plain"; + const tmp = document.createElement("div"); + CodeMirror.runMode(code, mode, tmp, { tabSize: 4 }); + return tmp.innerHTML; +}; + +marked.use({ + // @ts-ignore renderer can be object literal + renderer: { + code(code: string, language: string | undefined) { + if (!language) language = "text"; + code = highlight(code, language); + // We need to add a class for the theme (e.g., `cm-s-idea`) on the wrapper. + // If we're using a custom theme, it can apply its styles to `code[class^="language-"]` + // and use Marked's default `code` with `highlight` option. + return `
${code}
`; + }, + }, +}); + +const $ = (sel: string) => { + const el = document.querySelector(sel); + if (!el) throw new Error(`No element matching ${sel}`); + return el as HTMLElement; +}; + +const config: CodeMirror.EditorConfiguration = { + theme: "idea", + // keyMap: "vim", + gutters: ["cmw-gutter"], + lineNumbers: true, + matchBrackets: true, + autoCloseBrackets: true, + indentUnit: 4, +}; + +const workspace = new Workspace({ + rootUri: "source://", + getLanguageAssociation: (uri: string) => { + if (uri.endsWith(".py")) { + return { + languageId: "python", + languageServerIds: ["pyright-langserver"], + }; + } + // Workspace will ignore the file if null is returned. + return null; + }, + getConnectionString: async (id: string) => { + return id ? `ws://localhost:9990?name=${id}` : ""; + }, + // Support Markdown documentation + renderMarkdown: (markdown) => marked(markdown), + configs: { + "pyright-langserver": { + settings: { + python: { + analysis: { + autoSearchPaths: true, + useLibraryCodeForTypes: true, + diagnosticMode: "openFiles", + }, + }, + }, + }, + }, +}); + +workspace.openTextDocument( + "preloaded.py", + CodeMirror($("#preloaded-editor"), { + ...config, + mode: "python", + value: preloadedPy, + }) +); + +workspace.openTextDocument( + "solution.py", + CodeMirror($("#solution-editor"), { + ...config, + mode: "python", + value: solutionPy, + }) +); + +workspace.openTextDocument( + "tests/solution_test.py", + CodeMirror($("#test-editor"), { + ...config, + mode: "python", + value: solutionTestPy, + }) +); diff --git a/examples/pyright/src/style.css b/examples/pyright/src/style.css new file mode 100644 index 0000000..d14f887 --- /dev/null +++ b/examples/pyright/src/style.css @@ -0,0 +1,21 @@ +.CodeMirror { + height: 100% !important; +} + +.editor { + width: 100%; + height: 220px; + overflow: auto; + border-bottom: 1px solid #ccc; +} + +.editors { + padding: 2rem; + margin: 0 auto; + max-width: 80ch; +} + +.buttons { + margin: 0 auto; + text-align: center; +} diff --git a/examples/pyright/src/vite-env.d.ts b/examples/pyright/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/examples/pyright/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/pyright/tsconfig.json b/examples/pyright/tsconfig.json new file mode 100644 index 0000000..fbd0225 --- /dev/null +++ b/examples/pyright/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "strict": true, + "sourceMap": true, + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "skipLibCheck": true + }, + "include": ["src"] +} diff --git a/examples/pyright/workspace/preloaded.py b/examples/pyright/workspace/preloaded.py new file mode 100644 index 0000000..b134e54 --- /dev/null +++ b/examples/pyright/workspace/preloaded.py @@ -0,0 +1,4 @@ +# preloaded.py +def helper(a, b): + """ A helper doc. """ + return a * b diff --git a/examples/pyright/workspace/pyrightconfig.json b/examples/pyright/workspace/pyrightconfig.json new file mode 100644 index 0000000..69deaf0 --- /dev/null +++ b/examples/pyright/workspace/pyrightconfig.json @@ -0,0 +1,8 @@ +{ + "include": ["./"], + "executionEnvironments": [ + { + "root": "./" + } + ] +} diff --git a/examples/pyright/workspace/solution.py b/examples/pyright/workspace/solution.py new file mode 100644 index 0000000..03bf3f8 --- /dev/null +++ b/examples/pyright/workspace/solution.py @@ -0,0 +1,7 @@ +# solution.py +from preloaded import helper + + +def add(a, b): + print(helper(a, b)) + return a + b diff --git a/examples/pyright/workspace/tests/test_solution.py b/examples/pyright/workspace/tests/test_solution.py new file mode 100644 index 0000000..57ed4ab --- /dev/null +++ b/examples/pyright/workspace/tests/test_solution.py @@ -0,0 +1,10 @@ +# tests/test_solution.py +import unittest + +# TODO Fix `solution` not resolved +from solution import add + + +class TestAddition(unittest.TestCase): + def test_add(self): + self.assertEqual(add(1, 1), 2) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0f68fed..4db882b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,6 +43,29 @@ importers: vscode-css-languageserver-bin: 1.4.0 vscode-html-languageserver-bin: 1.4.0 + examples/pyright: + specifiers: + '@qualified/codemirror-workspace': workspace:0.5.0 + '@types/codemirror': ^5.0.0 + '@types/marked': ^4.0.3 + codemirror: ^5.59.2 + concurrently: ^7.2.2 + marked: ^4.0.17 + pyright: ^1.1.271 + typescript: ^4.7.4 + vite: ^2.9.9 + dependencies: + '@qualified/codemirror-workspace': link:../../packages/codemirror-workspace + codemirror: 5.63.3 + marked: 4.0.17 + devDependencies: + '@types/codemirror': 5.60.0 + '@types/marked': 4.0.3 + concurrently: 7.2.2 + pyright: 1.1.271 + typescript: 4.7.4 + vite: 2.9.12 + examples/rust-analyzer: specifiers: '@qualified/codemirror-workspace': workspace:0.5.0 @@ -4549,6 +4572,12 @@ packages: resolution: {integrity: sha512-ksWccjmXOHU2gJBnH0cK1lSYdvSZ0zLoCMSz/nTGh6hDvCSgcRxDyIcOBD6KNxFz3xhMPm/T267Tbe2JRymKEQ==} dev: true + /pyright/1.1.271: + resolution: {integrity: sha512-46QQLQLT5U+wmKqG9R193loBASqqcIZYwWrwTCWNTHIRYTxEbaHwGWDlmX19R3lmlIBDu9I9m5MyPmYs/2v5dg==} + engines: {node: '>=12.0.0'} + hasBin: true + dev: true + /queue-microtask/1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true