pax_global_header00006660000000000000000000000064144415325730014522gustar00rootroot0000000000000052 comment=d87154ec7014063e6c7e0dfe16c2a7be93471114 lang-python-6.1.3/000077500000000000000000000000001444153257300137715ustar00rootroot00000000000000lang-python-6.1.3/.github/000077500000000000000000000000001444153257300153315ustar00rootroot00000000000000lang-python-6.1.3/.github/workflows/000077500000000000000000000000001444153257300173665ustar00rootroot00000000000000lang-python-6.1.3/.github/workflows/dispatch.yml000066400000000000000000000006371444153257300217160ustar00rootroot00000000000000name: Trigger CI on: push jobs: build: name: Dispatch to main repo runs-on: ubuntu-latest steps: - name: Emit repository_dispatch uses: mvasigh/dispatch-action@main with: # You should create a personal access token and store it in your repository token: ${{ secrets.DISPATCH_AUTH }} repo: dev owner: codemirror event_type: push lang-python-6.1.3/.gitignore000066400000000000000000000001271444153257300157610ustar00rootroot00000000000000/node_modules package-lock.json /dist /test/*.js /test/*.d.ts /test/*.d.ts.map .tern-* lang-python-6.1.3/.npmignore000066400000000000000000000001001444153257300157570ustar00rootroot00000000000000/src /test /node_modules .tern-* rollup.config.js tsconfig.json lang-python-6.1.3/CHANGELOG.md000066400000000000000000000047661444153257300156170ustar00rootroot00000000000000## 6.1.3 (2023-06-12) ### Bug fixes Fix a bug where blocks started after a wrapped argument list or similar construct were indented too far. ## 6.1.2 (2023-03-01) ### Bug fixes Don't indent lines after a dedented comment line. ## 6.1.1 (2022-12-24) ### Bug fixes Remove leftover log statements. ## 6.1.0 (2022-11-18) ### New features The `globalCompletion` completion source (included in the language support returned from `python()`) completes standard Python globals and keywords. Export a `localCompletionSource` function that completes locally defined variables. Included in the support extensions returned from `python()`. ## 6.0.4 (2022-10-24) ### Bug fixes Make sure the language object has a name. ## 6.0.3 (2022-10-19) ### Bug fixes Add proper indentation handling of `else` clauses in `try` statements. ## 6.0.2 (2022-09-22) ### Bug fixes Allow prefixed strings to be closed by `closeBrackets`. ## 6.0.1 (2022-07-21) ### Bug fixes Fix (non-)auto indentation in template strings and comments. ## 6.0.0 (2022-06-08) ### Breaking changes Update dependencies to 6.0.0 ## 0.20.0 (2022-04-20) ### Bug fixes Add folding information for set and tuple expressions. ## 0.19.5 (2022-04-06) ### Bug fixes Make sure * and ** modifiers are highlighted as such, add modifier tag for FormatSpec nodes. ## 0.19.4 (2022-01-26) ### Bug fixes Fix issue where folding body nodes folded away the newline after the body. ## 0.19.3 (2022-01-20) ### Bug fixes Fix the way block bodies are folded. ## 0.19.2 (2021-08-11) ### Bug fixes Make sure that indenting an else/elif/except/finally that's indented too deep moves it back up. ## 0.19.1 (2021-08-11) ### Bug fixes Fix incorrect versions for @lezer dependencies. ## 0.19.0 (2021-08-11) ### Bug fixes Improve indentation for dictionaries, arrays, and tuples. Fix delimitedIndent calls Indentation on deindented blank lines after a block will no longer return to the block's indentation level. ## 0.18.1 (2021-07-20) ### Bug fixes Fix highlighting of property names. Improve indentation support Don't deindent when pressing enter at the end of the document. Properly indent else/elif/except syntax. ## 0.18.0 (2021-03-03) ### Breaking changes Update dependencies to 0.18. ## 0.17.2 (2021-01-12) ### Bug fixes Improves the highlighting specificity for names of function and class definitions. ## 0.17.1 (2021-01-06) ### New features The package now also exports a CommonJS module. ## 0.17.0 (2020-12-29) ### Breaking changes First numbered release. lang-python-6.1.3/LICENSE000066400000000000000000000021361444153257300150000ustar00rootroot00000000000000MIT License Copyright (C) 2018-2021 by Marijn Haverbeke and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. lang-python-6.1.3/README.md000066400000000000000000000051671444153257300152610ustar00rootroot00000000000000 # @codemirror/lang-python [![NPM version](https://img.shields.io/npm/v/@codemirror/lang-python.svg)](https://www.npmjs.org/package/@codemirror/lang-python) [ [**WEBSITE**](https://codemirror.net/) | [**ISSUES**](https://github.com/codemirror/dev/issues) | [**FORUM**](https://discuss.codemirror.net/c/next/) | [**CHANGELOG**](https://github.com/codemirror/lang-python/blob/main/CHANGELOG.md) ] This package implements Python language support for the [CodeMirror](https://codemirror.net/) code editor. The [project page](https://codemirror.net/) has more information, a number of [examples](https://codemirror.net/examples/) and the [documentation](https://codemirror.net/docs/). This code is released under an [MIT license](https://github.com/codemirror/lang-python/tree/main/LICENSE). We aim to be an inclusive, welcoming community. To make that explicit, we have a [code of conduct](http://contributor-covenant.org/version/1/1/0/) that applies to communication around the project. # API Reference
globalCompletion: CompletionSource

Autocompletion for built-in Python globals and keywords.

localCompletionSource(contextCompletionContext) → CompletionResult | null

Completion source that looks up locally defined names in Python code.

pythonLanguage: LRLanguage

A language provider based on the Lezer Python parser, extended with highlighting and indentation information.

python() → LanguageSupport

Python language support.

lang-python-6.1.3/package.json000066400000000000000000000016641444153257300162660ustar00rootroot00000000000000{ "name": "@codemirror/lang-python", "version": "6.1.3", "description": "Python language support for the CodeMirror code editor", "scripts": { "test": "cm-runtests", "prepare": "cm-buildhelper src/python.ts" }, "keywords": [ "editor", "code" ], "author": { "name": "Marijn Haverbeke", "email": "marijn@haverbeke.berlin", "url": "http://marijnhaverbeke.nl" }, "type": "module", "main": "dist/index.cjs", "exports": { "import": "./dist/index.js", "require": "./dist/index.cjs" }, "types": "dist/index.d.ts", "module": "dist/index.js", "sideEffects": false, "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.3.2", "@codemirror/language": "^6.8.0", "@lezer/python": "^1.1.4" }, "devDependencies": { "@codemirror/buildhelper": "^1.0.0" }, "repository": { "type": "git", "url": "https://github.com/codemirror/lang-python.git" } } lang-python-6.1.3/src/000077500000000000000000000000001444153257300145605ustar00rootroot00000000000000lang-python-6.1.3/src/README.md000066400000000000000000000021001444153257300160300ustar00rootroot00000000000000 # @codemirror/lang-python [![NPM version](https://img.shields.io/npm/v/@codemirror/lang-python.svg)](https://www.npmjs.org/package/@codemirror/lang-python) [ [**WEBSITE**](https://codemirror.net/) | [**ISSUES**](https://github.com/codemirror/dev/issues) | [**FORUM**](https://discuss.codemirror.net/c/next/) | [**CHANGELOG**](https://github.com/codemirror/lang-python/blob/main/CHANGELOG.md) ] This package implements Python language support for the [CodeMirror](https://codemirror.net/) code editor. The [project page](https://codemirror.net/) has more information, a number of [examples](https://codemirror.net/examples/) and the [documentation](https://codemirror.net/docs/). This code is released under an [MIT license](https://github.com/codemirror/lang-python/tree/main/LICENSE). We aim to be an inclusive, welcoming community. To make that explicit, we have a [code of conduct](http://contributor-covenant.org/version/1/1/0/) that applies to communication around the project. # API Reference @python @pythonLanguagelang-python-6.1.3/src/complete.ts000066400000000000000000000164311444153257300167450ustar00rootroot00000000000000import {NodeWeakMap, SyntaxNodeRef, SyntaxNode, IterMode} from "@lezer/common" import {Completion, CompletionContext, CompletionResult, completeFromList, ifNotIn, snippetCompletion as snip} from "@codemirror/autocomplete" import {syntaxTree} from "@codemirror/language" import {Text} from "@codemirror/state" const cache = new NodeWeakMap() const ScopeNodes = new Set([ "Script", "Body", "FunctionDefinition", "ClassDefinition", "LambdaExpression", "ForStatement", "MatchClause" ]) function defID(type: string) { return (node: SyntaxNodeRef, def: (node: SyntaxNodeRef, type: string) => void, outer: boolean) => { if (outer) return false let id = node.node.getChild("VariableName") if (id) def(id, type) return true } } const gatherCompletions: { [node: string]: (node: SyntaxNodeRef, def: (node: SyntaxNodeRef, type: string) => void, outer: boolean) => void | boolean } = { FunctionDefinition: defID("function"), ClassDefinition: defID("class"), ForStatement(node, def, outer) { if (outer) for (let child = node.node.firstChild; child; child = child.nextSibling) { if (child.name == "VariableName") def(child, "variable") else if (child.name == "in") break } }, ImportStatement(_node, def) { let {node} = _node let isFrom = node.firstChild?.name == "from" for (let ch = node.getChild("import"); ch; ch = ch.nextSibling) { if (ch.name == "VariableName" && ch.nextSibling?.name != "as") def(ch, isFrom ? "variable" : "namespace") } }, AssignStatement(node, def) { for (let child = node.node.firstChild; child; child = child.nextSibling) { if (child.name == "VariableName") def(child, "variable") else if (child.name == ":" || child.name == "AssignOp") break } }, ParamList(node, def) { for (let prev = null, child = node.node.firstChild; child; child = child.nextSibling) { if (child.name == "VariableName" && (!prev || !/\*|AssignOp/.test(prev.name))) def(child, "variable") prev = child } }, CapturePattern: defID("variable"), AsPattern: defID("variable"), __proto__: null as any } function getScope(doc: Text, node: SyntaxNode) { let cached = cache.get(node) if (cached) return cached let completions: Completion[] = [], top = true function def(node: SyntaxNodeRef, type: string) { let name = doc.sliceString(node.from, node.to) completions.push({label: name, type}) } node.cursor(IterMode.IncludeAnonymous).iterate(node => { if (node.name) { let gather = gatherCompletions[node.name] if (gather && gather(node, def, top) || !top && ScopeNodes.has(node.name)) return false top = false } else if (node.to - node.from > 8192) { // Allow caching for bigger internal nodes for (let c of getScope(doc, node.node)) completions.push(c) return false } }) cache.set(node, completions) return completions } const Identifier = /^[\w\xa1-\uffff][\w\d\xa1-\uffff]*$/ const dontComplete = ["String", "FormatString", "Comment", "PropertyName"] /// Completion source that looks up locally defined names in /// Python code. export function localCompletionSource(context: CompletionContext): CompletionResult | null { let inner = syntaxTree(context.state).resolveInner(context.pos, -1) if (dontComplete.indexOf(inner.name) > -1) return null let isWord = inner.name == "VariableName" || inner.to - inner.from < 20 && Identifier.test(context.state.sliceDoc(inner.from, inner.to)) if (!isWord && !context.explicit) return null let options: Completion[] = [] for (let pos: SyntaxNode | null = inner; pos; pos = pos.parent) { if (ScopeNodes.has(pos.name)) options = options.concat(getScope(context.state.doc, pos)) } return { options, from: isWord ? inner.from : context.pos, validFor: Identifier } } const globals: readonly Completion[] = [ "__annotations__", "__builtins__", "__debug__", "__doc__", "__import__", "__name__", "__loader__", "__package__", "__spec__", "False", "None", "True" ].map(n => ({label: n, type: "constant"})).concat([ "ArithmeticError", "AssertionError", "AttributeError", "BaseException", "BlockingIOError", "BrokenPipeError", "BufferError", "BytesWarning", "ChildProcessError", "ConnectionAbortedError", "ConnectionError", "ConnectionRefusedError", "ConnectionResetError", "DeprecationWarning", "EOFError", "Ellipsis", "EncodingWarning", "EnvironmentError", "Exception", "FileExistsError", "FileNotFoundError", "FloatingPointError", "FutureWarning", "GeneratorExit", "IOError", "ImportError", "ImportWarning", "IndentationError", "IndexError", "InterruptedError", "IsADirectoryError", "KeyError", "KeyboardInterrupt", "LookupError", "MemoryError", "ModuleNotFoundError", "NameError", "NotADirectoryError", "NotImplemented", "NotImplementedError", "OSError", "OverflowError", "PendingDeprecationWarning", "PermissionError", "ProcessLookupError", "RecursionError", "ReferenceError", "ResourceWarning", "RuntimeError", "RuntimeWarning", "StopAsyncIteration", "StopIteration", "SyntaxError", "SyntaxWarning", "SystemError", "SystemExit", "TabError", "TimeoutError", "TypeError", "UnboundLocalError", "UnicodeDecodeError", "UnicodeEncodeError", "UnicodeError", "UnicodeTranslateError", "UnicodeWarning", "UserWarning", "ValueError", "Warning", "ZeroDivisionError" ].map(n => ({label: n, type: "type"}))).concat([ "bool", "bytearray", "bytes", "classmethod", "complex", "float", "frozenset", "int", "list", "map", "memoryview", "object", "range", "set", "staticmethod", "str", "super", "tuple", "type" ].map(n => ({label: n, type: "class"}))).concat([ "abs", "aiter", "all", "anext", "any", "ascii", "bin", "breakpoint", "callable", "chr", "compile", "delattr", "dict", "dir", "divmod", "enumerate", "eval", "exec", "exit", "filter", "format", "getattr", "globals", "hasattr", "hash", "help", "hex", "id", "input", "isinstance", "issubclass", "iter", "len", "license", "locals", "max", "min", "next", "oct", "open", "ord", "pow", "print", "property", "quit", "repr", "reversed", "round", "setattr", "slice", "sorted", "sum", "vars", "zip" ].map(n => ({label: n, type: "function"}))) export const snippets: readonly Completion[] = [ snip("def ${name}(${params}):\n\t${}", { label: "def", detail: "function", type: "keyword" }), snip("for ${name} in ${collection}:\n\t${}", { label: "for", detail: "loop", type: "keyword" }), snip("while ${}:\n\t${}", { label: "while", detail: "loop", type: "keyword" }), snip("try:\n\t${}\nexcept ${error}:\n\t${}", { label: "try", detail: "/ except block", type: "keyword" }), snip("if ${}:\n\t\n", { label: "if", detail: "block", type: "keyword" }), snip("if ${}:\n\t${}\nelse:\n\t${}", { label: "if", detail: "/ else block", type: "keyword" }), snip("class ${name}:\n\tdef __init__(self, ${params}):\n\t\t\t${}", { label: "class", detail: "definition", type: "keyword" }), snip("import ${module}", { label: "import", detail: "statement", type: "keyword" }), snip("from ${module} import ${names}", { label: "from", detail: "import", type: "keyword" }) ] /// Autocompletion for built-in Python globals and keywords. export const globalCompletion = ifNotIn(dontComplete, completeFromList(globals.concat(snippets))) lang-python-6.1.3/src/python.ts000066400000000000000000000067471444153257300164670ustar00rootroot00000000000000import {parser} from "@lezer/python" import {SyntaxNode} from "@lezer/common" import {delimitedIndent, indentNodeProp, TreeIndentContext, foldNodeProp, foldInside, LRLanguage, LanguageSupport} from "@codemirror/language" import {globalCompletion, localCompletionSource} from "./complete" export {globalCompletion, localCompletionSource} function indentBody(context: TreeIndentContext, node: SyntaxNode) { let base = context.baseIndentFor(node) let line = context.lineAt(context.pos, -1), to = line.from + line.text.length // Don't consider blank, deindented lines at the end of the // block part of the block if (/^\s*($|#)/.test(line.text) && context.node.to < to + 100 && !/\S/.test(context.state.sliceDoc(to, context.node.to)) && context.lineIndent(context.pos, -1) <= base) return null // A normally deindenting keyword that appears at a higher // indentation than the block should probably be handled by the next // level if (/^\s*(else:|elif |except |finally:)/.test(context.textAfter) && context.lineIndent(context.pos, -1) > base) return null return base + context.unit } /// A language provider based on the [Lezer Python /// parser](https://github.com/lezer-parser/python), extended with /// highlighting and indentation information. export const pythonLanguage = LRLanguage.define({ name: "python", parser: parser.configure({ props: [ indentNodeProp.add({ Body: context => indentBody(context, context.node) ?? context.continue(), IfStatement: cx => /^\s*(else:|elif )/.test(cx.textAfter) ? cx.baseIndent : cx.continue(), TryStatement: cx => /^\s*(except |finally:|else:)/.test(cx.textAfter) ? cx.baseIndent : cx.continue(), "TupleExpression ComprehensionExpression ParamList ArgList ParenthesizedExpression": delimitedIndent({closing: ")"}), "DictionaryExpression DictionaryComprehensionExpression SetExpression SetComprehensionExpression": delimitedIndent({closing: "}"}), "ArrayExpression ArrayComprehensionExpression": delimitedIndent({closing: "]"}), "String FormatString": () => null, Script: context => { if (context.pos + /\s*/.exec(context.textAfter)![0].length >= context.node.to) { let endBody = null for (let cur: SyntaxNode | null = context.node, to = cur.to;;) { cur = cur.lastChild if (!cur || cur.to != to) break if (cur.type.name == "Body") endBody = cur } if (endBody) { let bodyIndent = indentBody(context, endBody) if (bodyIndent != null) return bodyIndent } } return context.continue() } }), foldNodeProp.add({ "ArrayExpression DictionaryExpression SetExpression TupleExpression": foldInside, Body: (node, state) => ({from: node.from + 1, to: node.to - (node.to == state.doc.length ? 0 : 1)}) }) ], }), languageData: { closeBrackets: { brackets: ["(", "[", "{", "'", '"', "'''", '"""'], stringPrefixes: ["f", "fr", "rf", "r", "u", "b", "br", "rb", "F", "FR", "RF", "R", "U", "B", "BR", "RB"] }, commentTokens: {line: "#"}, indentOnInput: /^\s*([\}\]\)]|else:|elif |except |finally:)$/ } }) /// Python language support. export function python() { return new LanguageSupport(pythonLanguage, [ pythonLanguage.data.of({autocomplete: localCompletionSource}), pythonLanguage.data.of({autocomplete: globalCompletion}), ]) } lang-python-6.1.3/test/000077500000000000000000000000001444153257300147505ustar00rootroot00000000000000lang-python-6.1.3/test/test-indent.ts000066400000000000000000000016551444153257300175650ustar00rootroot00000000000000import ist from "ist" import {EditorState} from "@codemirror/state" import {getIndentation} from "@codemirror/language" import {python} from "@codemirror/lang-python" function check(code: string) { return () => { code = /^\n*([^]*)/.exec(code)![1] let state = EditorState.create({doc: code, extensions: [python().language]}) for (let pos = 0, lines = code.split("\n"), i = 0; i < lines.length; i++) { let line = lines[i], indent = /^\s*/.exec(line)![0].length ist(`${getIndentation(state, pos)} (${i + 1})`, `${indent} (${i + 1})`) pos += line.length + 1 } } } describe("python indentation", () => { it("indents bodies", check(` def foo(): bar baz `)) it("indents function arg lists", check(` foo( bar, baz )`)) it("indents nested bodies", check(` def foo(): if True: a elif False: b else: c `)) it("dedents except", check(` try: foo() except e: bar() `)) })