python-delphi-lsp 2.0.2__tar.gz → 2.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_delphi_lsp-2.0.4/.github/workflows/ci.yml +42 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/MANIFEST.in +6 -0
- {python_delphi_lsp-2.0.2/python_delphi_lsp.egg-info → python_delphi_lsp-2.0.4}/PKG-INFO +33 -4
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/README.md +32 -3
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/__init__.py +3 -0
- python_delphi_lsp-2.0.4/delphi_lsp/_version.py +1 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/agent_context.py +171 -63
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/agent_layers.py +115 -6
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/agent_templates.py +18 -15
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/agent_workspace.py +7 -2
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/lsp_server.py +195 -33
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/preprocessor.py +32 -10
- python_delphi_lsp-2.0.4/delphi_lsp/progress.py +26 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/project_discovery.py +125 -16
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/project_indexer.py +43 -1
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/pyproject.toml +1 -1
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4/python_delphi_lsp.egg-info}/PKG-INFO +33 -4
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/python_delphi_lsp.egg-info/SOURCES.txt +10 -0
- python_delphi_lsp-2.0.4/scripts/benchmark_github_corpus.py +256 -0
- python_delphi_lsp-2.0.4/scripts/build_github_performance_corpus.py +521 -0
- python_delphi_lsp-2.0.4/scripts/generate_progress_pdf.py +518 -0
- python_delphi_lsp-2.0.4/scripts/run_opencode_lsp_probe.py +816 -0
- python_delphi_lsp-2.0.4/scripts/run_openrouter_github_e2e.py +1393 -0
- python_delphi_lsp-2.0.4/tests/corpora.performance.lock.json +66 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_agent_codebase.py +113 -1
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_agent_context.py +176 -0
- python_delphi_lsp-2.0.4/tests/test_github_performance_corpus.py +240 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_lsp_support.py +243 -18
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_opencode_probe.py +475 -25
- python_delphi_lsp-2.0.4/tests/test_openrouter_github_e2e.py +1817 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_package_metadata.py +8 -2
- python_delphi_lsp-2.0.4/tests/test_progress.py +58 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_project_discovery.py +77 -5
- python_delphi_lsp-2.0.2/delphi_lsp/_version.py +0 -1
- python_delphi_lsp-2.0.2/scripts/run_opencode_lsp_probe.py +0 -389
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/LICENSE +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/agent_cli.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/agent_metrics.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/agent_protocol.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/agent_relations.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/binary.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/comment_builder.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/consts.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/grammar.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/lark_builder.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/lark_tokens.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/metrics.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/nodes.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/parser.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/semantic.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/semantic_builder.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/source_reader.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/workspace.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/delphi_lsp/writer.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/opencode.json +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/python_delphi_lsp.egg-info/dependency_links.txt +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/python_delphi_lsp.egg-info/entry_points.txt +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/python_delphi_lsp.egg-info/requires.txt +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/python_delphi_lsp.egg-info/top_level.txt +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/audit_delphi_language_features.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/bootstrap_vllm_codebase_skill_test.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/bootstrap_vllm_opencode_test.ps1 +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/bootstrap_vllm_opencode_test.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/bootstrap_vllm_opencode_test.sh +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/check_ornith_cache.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/generate_release_evidence.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/ollama/ornith-lspctx.Modelfile +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/prepare_ornith_cache.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/start_ornith_vllm.sh +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/scripts/summarize_opencode_request_payloads.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/setup.cfg +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/DeprecatedOnConst.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/VariantRecordFieldAttributes.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/alignedrecords.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/constset.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/deprecatedtype.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/dottedtypes.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/endtoken.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/experimentals.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/externalfunction.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/finalizationinitializationexports.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/forwardoverloaded.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/forwardwithoutsemicolon.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/genericconstraints.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/genericinterfacemethoddelegation.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/implementsgenerictype.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/include file2.inc +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/includefile.inc +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/includefile.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/managedrecords.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/messagemethod.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/multiline.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/nonalignedrecords.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/numbers.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/pointerchars.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/properties.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/strictvisibility.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/tryexcept.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/umlauts.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/legacy_snippets/whitespacearoundifdefcondition.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/library_demo.dpr +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/package_demo.dpk +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/program_demo.dpr +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_advanced.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_attributes.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_basic.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_consumer.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_generics.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_inheritance.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_math.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_properties.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_sections.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_statements.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_types.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_unresolved.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/fixtures/unit_with.pas +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_agent_metrics.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_agent_protocol.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_agent_relations.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_agent_worker.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_agent_workspace.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_bootstrap_vllm_codebase_skill.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_bootstrap_vllm_opencode.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_diagnostics.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_language_feature_matrix.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_legacy_snippets.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_lsp_features.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_metrics.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_opencode_config.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_opencode_request_payloads.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_ornith_cache_prepare.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_parser.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_preprocessor.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_project_indexer.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_release_evidence.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_semantic.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_vllm_start_script.py +0 -0
- {python_delphi_lsp-2.0.2 → python_delphi_lsp-2.0.4}/tests/test_workspace.py +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
name: ${{ matrix.os }} / Python ${{ matrix.python }}
|
|
10
|
+
runs-on: ${{ matrix.os }}
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
15
|
+
python: ["3.10", "3.14"]
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: ${{ matrix.python }}
|
|
21
|
+
cache: pip
|
|
22
|
+
cache-dependency-path: pyproject.toml
|
|
23
|
+
- run: python -m pip install --upgrade pip
|
|
24
|
+
- run: pip install .[test]
|
|
25
|
+
- run: pytest
|
|
26
|
+
|
|
27
|
+
package:
|
|
28
|
+
name: Build and validate distributions
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v4
|
|
32
|
+
- uses: actions/setup-python@v5
|
|
33
|
+
with:
|
|
34
|
+
python-version: "3.14"
|
|
35
|
+
cache: pip
|
|
36
|
+
cache-dependency-path: pyproject.toml
|
|
37
|
+
- run: python -m pip install --upgrade pip build twine
|
|
38
|
+
- run: python -m build
|
|
39
|
+
- run: python -m twine check dist/*
|
|
40
|
+
- run: python -m venv smoke-venv
|
|
41
|
+
- run: smoke-venv/bin/python -m pip install dist/*.whl
|
|
42
|
+
- run: smoke-venv/bin/python -c "import delphi_lsp; print(delphi_lsp.__name__)"
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
include LICENSE
|
|
2
2
|
include README.md
|
|
3
3
|
include opencode.json
|
|
4
|
+
include .github/workflows/ci.yml
|
|
4
5
|
include scripts/check_ornith_cache.py
|
|
5
6
|
include scripts/audit_delphi_language_features.py
|
|
7
|
+
include scripts/build_github_performance_corpus.py
|
|
8
|
+
include scripts/benchmark_github_corpus.py
|
|
6
9
|
include scripts/bootstrap_vllm_opencode_test.py
|
|
7
10
|
include scripts/bootstrap_vllm_codebase_skill_test.py
|
|
8
11
|
include scripts/bootstrap_vllm_opencode_test.ps1
|
|
9
12
|
include scripts/bootstrap_vllm_opencode_test.sh
|
|
10
13
|
include scripts/generate_release_evidence.py
|
|
14
|
+
include scripts/generate_progress_pdf.py
|
|
11
15
|
include scripts/prepare_ornith_cache.py
|
|
12
16
|
include scripts/run_opencode_lsp_probe.py
|
|
17
|
+
include scripts/run_openrouter_github_e2e.py
|
|
13
18
|
include scripts/start_ornith_vllm.sh
|
|
14
19
|
include scripts/summarize_opencode_request_payloads.py
|
|
15
20
|
include scripts/ollama/ornith-lspctx.Modelfile
|
|
21
|
+
include tests/corpora.performance.lock.json
|
|
16
22
|
recursive-include tests *.py *.pas *.inc *.dpr *.dpk
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-delphi-lsp
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
4
4
|
Summary: Python Delphi/Object Pascal parser, semantic indexer, and language server.
|
|
5
5
|
Author: Dark Light
|
|
6
6
|
License-Expression: MPL-2.0
|
|
@@ -41,7 +41,7 @@ Dynamic: license-file
|
|
|
41
41
|
|
|
42
42
|
`python-delphi-lsp` parses Delphi/Object Pascal, builds semantic and project
|
|
43
43
|
indexes, serves LSP, and provides bounded codebase navigation for agents.
|
|
44
|
-
Version 2.0.
|
|
44
|
+
Version 2.0.4 is authored by Dark Light and supports Windows, macOS, and Linux.
|
|
45
45
|
|
|
46
46
|
## Install and quick start
|
|
47
47
|
|
|
@@ -82,6 +82,19 @@ project = ProjectIndexer(
|
|
|
82
82
|
print(project.parsed_units)
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
Long-running discovery and indexing accept a keyword-only `on_progress`
|
|
86
|
+
callback. It receives an immutable `ProgressEvent` with package-controlled
|
|
87
|
+
phase, path, and monotonic counters; callback exceptions are not suppressed.
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from delphi_lsp import ProjectIndexer, ProgressEvent
|
|
91
|
+
|
|
92
|
+
def report(event: ProgressEvent) -> None:
|
|
93
|
+
print(event.phase, event.files_completed, event.path)
|
|
94
|
+
|
|
95
|
+
ProjectIndexer(on_progress=report).index("Main.dpr")
|
|
96
|
+
```
|
|
97
|
+
|
|
85
98
|
## Architecture metrics
|
|
86
99
|
|
|
87
100
|
The public metrics API analyzes a single unit or aggregates a complete project:
|
|
@@ -254,14 +267,30 @@ A generated OpenCode agent starts with this Markdown frontmatter:
|
|
|
254
267
|
```markdown
|
|
255
268
|
---
|
|
256
269
|
description: Inspect Delphi and Object Pascal codebases through python-delphi-lsp.
|
|
257
|
-
mode:
|
|
270
|
+
mode: all
|
|
258
271
|
temperature: 0
|
|
259
272
|
permission:
|
|
260
|
-
"*": deny
|
|
261
273
|
delphi_codebase: allow
|
|
262
274
|
skill:
|
|
263
275
|
"*": deny
|
|
264
276
|
python-delphi-lsp: allow
|
|
277
|
+
lsp: deny
|
|
278
|
+
bash: deny
|
|
279
|
+
read: deny
|
|
280
|
+
glob: deny
|
|
281
|
+
grep: deny
|
|
282
|
+
list: deny
|
|
283
|
+
edit: deny
|
|
284
|
+
write: deny
|
|
285
|
+
patch: deny
|
|
286
|
+
task: deny
|
|
287
|
+
webfetch: deny
|
|
288
|
+
websearch: deny
|
|
289
|
+
question: deny
|
|
290
|
+
todowrite: deny
|
|
291
|
+
todoread: deny
|
|
292
|
+
codebase_map: deny
|
|
293
|
+
code_guidelines: deny
|
|
265
294
|
---
|
|
266
295
|
```
|
|
267
296
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`python-delphi-lsp` parses Delphi/Object Pascal, builds semantic and project
|
|
4
4
|
indexes, serves LSP, and provides bounded codebase navigation for agents.
|
|
5
|
-
Version 2.0.
|
|
5
|
+
Version 2.0.4 is authored by Dark Light and supports Windows, macOS, and Linux.
|
|
6
6
|
|
|
7
7
|
## Install and quick start
|
|
8
8
|
|
|
@@ -43,6 +43,19 @@ project = ProjectIndexer(
|
|
|
43
43
|
print(project.parsed_units)
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
Long-running discovery and indexing accept a keyword-only `on_progress`
|
|
47
|
+
callback. It receives an immutable `ProgressEvent` with package-controlled
|
|
48
|
+
phase, path, and monotonic counters; callback exceptions are not suppressed.
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from delphi_lsp import ProjectIndexer, ProgressEvent
|
|
52
|
+
|
|
53
|
+
def report(event: ProgressEvent) -> None:
|
|
54
|
+
print(event.phase, event.files_completed, event.path)
|
|
55
|
+
|
|
56
|
+
ProjectIndexer(on_progress=report).index("Main.dpr")
|
|
57
|
+
```
|
|
58
|
+
|
|
46
59
|
## Architecture metrics
|
|
47
60
|
|
|
48
61
|
The public metrics API analyzes a single unit or aggregates a complete project:
|
|
@@ -215,14 +228,30 @@ A generated OpenCode agent starts with this Markdown frontmatter:
|
|
|
215
228
|
```markdown
|
|
216
229
|
---
|
|
217
230
|
description: Inspect Delphi and Object Pascal codebases through python-delphi-lsp.
|
|
218
|
-
mode:
|
|
231
|
+
mode: all
|
|
219
232
|
temperature: 0
|
|
220
233
|
permission:
|
|
221
|
-
"*": deny
|
|
222
234
|
delphi_codebase: allow
|
|
223
235
|
skill:
|
|
224
236
|
"*": deny
|
|
225
237
|
python-delphi-lsp: allow
|
|
238
|
+
lsp: deny
|
|
239
|
+
bash: deny
|
|
240
|
+
read: deny
|
|
241
|
+
glob: deny
|
|
242
|
+
grep: deny
|
|
243
|
+
list: deny
|
|
244
|
+
edit: deny
|
|
245
|
+
write: deny
|
|
246
|
+
patch: deny
|
|
247
|
+
task: deny
|
|
248
|
+
webfetch: deny
|
|
249
|
+
websearch: deny
|
|
250
|
+
question: deny
|
|
251
|
+
todowrite: deny
|
|
252
|
+
todoread: deny
|
|
253
|
+
codebase_map: deny
|
|
254
|
+
code_guidelines: deny
|
|
226
255
|
---
|
|
227
256
|
```
|
|
228
257
|
|
|
@@ -48,6 +48,7 @@ from .semantic_builder import SemanticBuilder, SemanticModel, SemanticProblem
|
|
|
48
48
|
from .workspace import WorkspaceSemanticResult, build_workspace_semantics
|
|
49
49
|
from .lsp_server import LspWorkspaceState, create_server
|
|
50
50
|
from .project_discovery import DelphiProjectDiscovery, DiscoveryProblem, discover_delphi_project
|
|
51
|
+
from .progress import ProgressCallback, ProgressEvent
|
|
51
52
|
from .project_indexer import (
|
|
52
53
|
GetUnitSyntaxHook,
|
|
53
54
|
IncludeFileInfo,
|
|
@@ -136,6 +137,8 @@ __all__ = [
|
|
|
136
137
|
'DelphiProjectDiscovery',
|
|
137
138
|
'DiscoveryProblem',
|
|
138
139
|
'discover_delphi_project',
|
|
140
|
+
'ProgressCallback',
|
|
141
|
+
'ProgressEvent',
|
|
139
142
|
'ProjectIndexer',
|
|
140
143
|
'ProjectIndexResult',
|
|
141
144
|
'ProjectProblemType',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.0.4"
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from bisect import bisect_left, bisect_right
|
|
4
4
|
from collections.abc import Mapping
|
|
5
5
|
from dataclasses import dataclass
|
|
6
|
+
from heapq import heappop, heappush
|
|
6
7
|
import hashlib
|
|
7
8
|
import json
|
|
8
9
|
from pathlib import Path, PureWindowsPath
|
|
@@ -14,13 +15,12 @@ from .agent_protocol import (
|
|
|
14
15
|
AgentResponse,
|
|
15
16
|
ContextBudget,
|
|
16
17
|
Focus,
|
|
17
|
-
Page,
|
|
18
18
|
make_target_id,
|
|
19
19
|
paginate_items,
|
|
20
20
|
)
|
|
21
21
|
from .agent_metrics import build_workspace_metrics, project_metric_item, unit_metric_item
|
|
22
22
|
from .agent_relations import ProjectRelationIndex, RelationTarget
|
|
23
|
-
from .agent_workspace import AgentWorkspace, unit_display_path, unit_source_path, unit_target_id
|
|
23
|
+
from .agent_workspace import AgentUnit, AgentWorkspace, unit_display_path, unit_source_path, unit_target_id
|
|
24
24
|
from .consts import AttributeName, SyntaxNodeType
|
|
25
25
|
from .lsp_server import build_outline_semantic_model, multiline_string_block_end
|
|
26
26
|
from .nodes import CompoundSyntaxNode, SyntaxNode
|
|
@@ -121,6 +121,10 @@ class _SourceDocument:
|
|
|
121
121
|
self.tokens = tuple(_lex_delphi(text))
|
|
122
122
|
self.token_starts = tuple(token.start for token in self.tokens)
|
|
123
123
|
self.directive_starts = tuple(token.start for token in self.tokens if token.directive)
|
|
124
|
+
self.declaration_section_indexes = [0]
|
|
125
|
+
self.declaration_section_checkpoints: dict[int, tuple[str, int, int, int]] = {
|
|
126
|
+
0: ("", 0, 0, 0)
|
|
127
|
+
}
|
|
124
128
|
words = [token for token in self.tokens if token.word and not token.escaped]
|
|
125
129
|
self.unit_kind = next(
|
|
126
130
|
(token.value for token in words if token.value in {"unit", "program", "library", "package"}),
|
|
@@ -129,6 +133,7 @@ class _SourceDocument:
|
|
|
129
133
|
implementation = next((token for token in words if token.value == "implementation"), None)
|
|
130
134
|
self.implementation_line = self.line_col(implementation.start)[0] if implementation else 0
|
|
131
135
|
self.routine_spans: dict[int, tuple[int, int] | None] = {}
|
|
136
|
+
self.routine_token_spans: dict[int, tuple[int, int, int] | None] = {}
|
|
132
137
|
self.parser_spans: dict[str, tuple[int, int] | None] = {}
|
|
133
138
|
self._full_parse_attempted = False
|
|
134
139
|
self._full_parse_result: object | None = None
|
|
@@ -230,6 +235,7 @@ class _Registry:
|
|
|
230
235
|
entries: tuple[_SymbolEntry, ...]
|
|
231
236
|
by_target: dict[str, _SymbolEntry]
|
|
232
237
|
sources: dict[Path, _SourceDocument]
|
|
238
|
+
ranked_queries: dict[str, tuple[_SymbolEntry, ...]]
|
|
233
239
|
|
|
234
240
|
|
|
235
241
|
class AgentContext:
|
|
@@ -280,7 +286,12 @@ class AgentContext:
|
|
|
280
286
|
return self._handle_focus(parsed, revision)
|
|
281
287
|
if parsed.action == "find":
|
|
282
288
|
registry = self._require_registry(revision)
|
|
283
|
-
|
|
289
|
+
ranked = registry.ranked_queries.get(parsed.query)
|
|
290
|
+
if ranked is None:
|
|
291
|
+
ranked = tuple(_ranked_entries(registry.entries, parsed.query))
|
|
292
|
+
registry.ranked_queries.clear()
|
|
293
|
+
registry.ranked_queries[parsed.query] = ranked
|
|
294
|
+
items = [entry.card() for entry in ranked]
|
|
284
295
|
return self._response(parsed, revision, items)
|
|
285
296
|
if parsed.action == "inspect":
|
|
286
297
|
registry = self._require_registry(revision)
|
|
@@ -293,9 +304,10 @@ class AgentContext:
|
|
|
293
304
|
previous_project_id = self._workspace.active_project_id
|
|
294
305
|
selected_project_id = requested_project_id or previous_project_id
|
|
295
306
|
if selected_project_id:
|
|
296
|
-
self._workspace.
|
|
307
|
+
revision = self._workspace._select_project_with_revision(selected_project_id)
|
|
308
|
+
else:
|
|
309
|
+
revision = self._workspace.workspace_revision
|
|
297
310
|
current_project_id = self._workspace.active_project_id
|
|
298
|
-
revision = self._workspace.workspace_revision
|
|
299
311
|
|
|
300
312
|
if current_project_id != previous_project_id:
|
|
301
313
|
self._registry = None
|
|
@@ -683,7 +695,14 @@ def _build_registry(workspace: AgentWorkspace, project_id: str, revision: str) -
|
|
|
683
695
|
include_paths=workspace.include_paths,
|
|
684
696
|
)
|
|
685
697
|
sources[source_path] = document
|
|
686
|
-
|
|
698
|
+
if workspace.defines:
|
|
699
|
+
model = build_outline_semantic_model(
|
|
700
|
+
text,
|
|
701
|
+
str(source_path),
|
|
702
|
+
defines=workspace.defines,
|
|
703
|
+
)
|
|
704
|
+
else:
|
|
705
|
+
model = build_outline_semantic_model(text, str(source_path))
|
|
687
706
|
unit_symbols = _collect_raw_symbols(model.unit_scope, unit, source_path, document)
|
|
688
707
|
raw_symbols.extend(_exclude_routine_locals(unit_symbols, document))
|
|
689
708
|
|
|
@@ -782,6 +801,7 @@ def _build_registry(workspace: AgentWorkspace, project_id: str, revision: str) -
|
|
|
782
801
|
entries=entries_tuple,
|
|
783
802
|
by_target={entry.target_id: entry for entry in entries_tuple},
|
|
784
803
|
sources=sources,
|
|
804
|
+
ranked_queries={},
|
|
785
805
|
)
|
|
786
806
|
|
|
787
807
|
|
|
@@ -925,32 +945,47 @@ def _correct_outline_symbol_kind(document: _SourceDocument, symbol: Symbol) -> N
|
|
|
925
945
|
symbol.kind = SymbolKind.TYPE
|
|
926
946
|
|
|
927
947
|
|
|
948
|
+
def _advance_declaration_section(
|
|
949
|
+
state: tuple[str, int, int, int],
|
|
950
|
+
token: _Token,
|
|
951
|
+
) -> tuple[str, int, int, int]:
|
|
952
|
+
section, parentheses, brackets, angles = state
|
|
953
|
+
if token.directive:
|
|
954
|
+
return state
|
|
955
|
+
if token.value == "(":
|
|
956
|
+
parentheses += 1
|
|
957
|
+
elif token.value == ")":
|
|
958
|
+
parentheses = max(0, parentheses - 1)
|
|
959
|
+
elif token.value == "[":
|
|
960
|
+
brackets += 1
|
|
961
|
+
elif token.value == "]":
|
|
962
|
+
brackets = max(0, brackets - 1)
|
|
963
|
+
elif token.value == "<":
|
|
964
|
+
angles += 1
|
|
965
|
+
elif token.value == ">":
|
|
966
|
+
angles = max(0, angles - 1)
|
|
967
|
+
elif not parentheses and not brackets and not angles and token.word:
|
|
968
|
+
if token.value in {"const", "resourcestring", "threadvar", "type", "var"}:
|
|
969
|
+
section = token.value
|
|
970
|
+
elif token.value in {"implementation", "initialization", "finalization"}:
|
|
971
|
+
section = ""
|
|
972
|
+
return section, parentheses, brackets, angles
|
|
973
|
+
|
|
974
|
+
|
|
928
975
|
def _declaration_section(document: _SourceDocument, offset: int) -> str:
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
elif token.value == "]":
|
|
943
|
-
brackets = max(0, brackets - 1)
|
|
944
|
-
elif token.value == "<":
|
|
945
|
-
angles += 1
|
|
946
|
-
elif token.value == ">":
|
|
947
|
-
angles = max(0, angles - 1)
|
|
948
|
-
elif not any((parentheses, brackets, angles)) and token.word:
|
|
949
|
-
if token.value in {"const", "resourcestring", "threadvar", "type", "var"}:
|
|
950
|
-
section = token.value
|
|
951
|
-
elif token.value in {"implementation", "initialization", "finalization"}:
|
|
952
|
-
section = ""
|
|
953
|
-
return section
|
|
976
|
+
target_index = document.first_token_index(offset)
|
|
977
|
+
cached = document.declaration_section_checkpoints.get(target_index)
|
|
978
|
+
if cached is not None:
|
|
979
|
+
return cached[0]
|
|
980
|
+
checkpoint_position = bisect_right(document.declaration_section_indexes, target_index) - 1
|
|
981
|
+
checkpoint_index = document.declaration_section_indexes[checkpoint_position]
|
|
982
|
+
state = document.declaration_section_checkpoints[checkpoint_index]
|
|
983
|
+
for token in document.tokens[checkpoint_index:target_index]:
|
|
984
|
+
state = _advance_declaration_section(state, token)
|
|
985
|
+
insert_at = bisect_left(document.declaration_section_indexes, target_index)
|
|
986
|
+
document.declaration_section_indexes.insert(insert_at, target_index)
|
|
987
|
+
document.declaration_section_checkpoints[target_index] = state
|
|
988
|
+
return state[0]
|
|
954
989
|
|
|
955
990
|
|
|
956
991
|
def _declared_symbol_name(document: _SourceDocument, symbol: Symbol) -> str:
|
|
@@ -1208,20 +1243,47 @@ def _exclude_routine_locals(
|
|
|
1208
1243
|
span = _raw_routine_span(raw, document)
|
|
1209
1244
|
if span is not None:
|
|
1210
1245
|
containers.append((span[0], span[1], raw))
|
|
1246
|
+
if not containers:
|
|
1247
|
+
return symbols
|
|
1211
1248
|
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1249
|
+
containers.sort(key=lambda item: (item[0], item[1]))
|
|
1250
|
+
positioned = sorted(
|
|
1251
|
+
(
|
|
1252
|
+
document.offset(
|
|
1253
|
+
raw.symbol.decl_range.start_line,
|
|
1254
|
+
raw.symbol.decl_range.start_col,
|
|
1255
|
+
),
|
|
1256
|
+
order,
|
|
1257
|
+
raw,
|
|
1217
1258
|
)
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1259
|
+
for order, raw in enumerate(symbols)
|
|
1260
|
+
)
|
|
1261
|
+
active_ends: list[tuple[int, int, int]] = []
|
|
1262
|
+
active_ids: set[int] = set()
|
|
1263
|
+
excluded_orders: set[int] = set()
|
|
1264
|
+
container_index = 0
|
|
1265
|
+
for offset, order, raw in positioned:
|
|
1266
|
+
while (
|
|
1267
|
+
container_index < len(containers)
|
|
1268
|
+
and containers[container_index][0] < offset
|
|
1221
1269
|
):
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1270
|
+
_, end, container = containers[container_index]
|
|
1271
|
+
container_id = id(container)
|
|
1272
|
+
heappush(active_ends, (end, container_index, container_id))
|
|
1273
|
+
active_ids.add(container_id)
|
|
1274
|
+
container_index += 1
|
|
1275
|
+
while active_ends and active_ends[0][0] <= offset:
|
|
1276
|
+
_, _, container_id = heappop(active_ends)
|
|
1277
|
+
active_ids.discard(container_id)
|
|
1278
|
+
raw_id = id(raw)
|
|
1279
|
+
if active_ids and (raw_id not in active_ids or len(active_ids) > 1):
|
|
1280
|
+
excluded_orders.add(order)
|
|
1281
|
+
|
|
1282
|
+
return [
|
|
1283
|
+
raw
|
|
1284
|
+
for order, raw in enumerate(symbols)
|
|
1285
|
+
if order not in excluded_orders
|
|
1286
|
+
]
|
|
1225
1287
|
|
|
1226
1288
|
|
|
1227
1289
|
def _raw_routine_span(
|
|
@@ -1523,6 +1585,7 @@ def _routine_span(
|
|
|
1523
1585
|
document.tokens,
|
|
1524
1586
|
document.token_starts,
|
|
1525
1587
|
token_index,
|
|
1588
|
+
cache=document.routine_token_spans,
|
|
1526
1589
|
)
|
|
1527
1590
|
span = (start, found[1]) if found is not None else None
|
|
1528
1591
|
document.routine_spans[start] = span
|
|
@@ -1534,6 +1597,7 @@ def _find_routine_token_span(
|
|
|
1534
1597
|
token_starts: tuple[int, ...],
|
|
1535
1598
|
start_index: int,
|
|
1536
1599
|
*,
|
|
1600
|
+
cache: dict[int, tuple[int, int, int] | None] | None = None,
|
|
1537
1601
|
depth: int = 0,
|
|
1538
1602
|
) -> tuple[int, int, int] | None:
|
|
1539
1603
|
if depth > 64:
|
|
@@ -1541,56 +1605,100 @@ def _find_routine_token_span(
|
|
|
1541
1605
|
routine_index = _routine_keyword_index(tokens, start_index)
|
|
1542
1606
|
if routine_index is None:
|
|
1543
1607
|
return None
|
|
1608
|
+
spans = cache if cache is not None else {}
|
|
1609
|
+
missing = object()
|
|
1610
|
+
cached = spans.get(routine_index, missing)
|
|
1611
|
+
if cached is not missing:
|
|
1612
|
+
if cached is None:
|
|
1613
|
+
return None
|
|
1614
|
+
return tokens[start_index].start, cached[1], cached[2]
|
|
1615
|
+
|
|
1544
1616
|
heading_end = _heading_semicolon_index(tokens, routine_index)
|
|
1545
1617
|
if heading_end is None:
|
|
1618
|
+
spans[routine_index] = None
|
|
1546
1619
|
return None
|
|
1547
1620
|
|
|
1548
|
-
|
|
1549
|
-
|
|
1621
|
+
frames: list[list[int]] = [[routine_index, heading_end + 1]]
|
|
1622
|
+
|
|
1623
|
+
def reject_active_frames() -> None:
|
|
1624
|
+
for active_routine_index, _ in frames:
|
|
1625
|
+
spans[active_routine_index] = None
|
|
1626
|
+
frames.clear()
|
|
1627
|
+
|
|
1628
|
+
while frames:
|
|
1629
|
+
frame = frames[-1]
|
|
1630
|
+
frame_routine_index, index = frame
|
|
1631
|
+
if index >= len(tokens):
|
|
1632
|
+
reject_active_frames()
|
|
1633
|
+
continue
|
|
1634
|
+
|
|
1550
1635
|
token = tokens[index]
|
|
1551
1636
|
if token.directive:
|
|
1552
|
-
|
|
1637
|
+
reject_active_frames()
|
|
1638
|
+
continue
|
|
1553
1639
|
if token.word and not token.escaped:
|
|
1554
1640
|
if token.value in _NO_BODY_DIRECTIVES:
|
|
1555
|
-
|
|
1641
|
+
spans[frame_routine_index] = None
|
|
1642
|
+
frames.pop()
|
|
1643
|
+
continue
|
|
1556
1644
|
if token.value in {"implementation", "initialization", "finalization"}:
|
|
1557
|
-
|
|
1645
|
+
reject_active_frames()
|
|
1646
|
+
continue
|
|
1558
1647
|
if (
|
|
1559
1648
|
token.value in _STRUCTURED_TYPE_WORDS
|
|
1560
1649
|
and _is_structured_type_opener(tokens, index)
|
|
1561
1650
|
):
|
|
1562
1651
|
if index + 1 < len(tokens) and tokens[index + 1].value == ";":
|
|
1563
|
-
index
|
|
1652
|
+
frame[1] = index + 2
|
|
1564
1653
|
continue
|
|
1565
1654
|
structured_end = _match_end_terminated_block(tokens, index)
|
|
1566
1655
|
if structured_end is None:
|
|
1567
|
-
|
|
1568
|
-
|
|
1656
|
+
reject_active_frames()
|
|
1657
|
+
continue
|
|
1658
|
+
frame[1] = bisect_left(token_starts, structured_end)
|
|
1569
1659
|
continue
|
|
1570
1660
|
if token.value == "end":
|
|
1571
|
-
|
|
1661
|
+
reject_active_frames()
|
|
1662
|
+
continue
|
|
1572
1663
|
if token.value in {"begin", "asm"}:
|
|
1573
1664
|
end = _match_end_terminated_block(tokens, index)
|
|
1574
1665
|
if end is None:
|
|
1575
|
-
|
|
1666
|
+
reject_active_frames()
|
|
1667
|
+
continue
|
|
1576
1668
|
end_index = bisect_left(token_starts, end)
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
token_starts,
|
|
1582
|
-
index,
|
|
1583
|
-
depth=depth + 1,
|
|
1669
|
+
spans[frame_routine_index] = (
|
|
1670
|
+
tokens[frame_routine_index].start,
|
|
1671
|
+
end,
|
|
1672
|
+
end_index,
|
|
1584
1673
|
)
|
|
1674
|
+
frames.pop()
|
|
1675
|
+
continue
|
|
1676
|
+
if token.value in _ROUTINE_WORDS and _is_nested_routine_declaration(tokens, index):
|
|
1677
|
+
nested_routine_index = _routine_keyword_index(tokens, index)
|
|
1678
|
+
if nested_routine_index is None:
|
|
1679
|
+
frame[1] = index + 1
|
|
1680
|
+
continue
|
|
1681
|
+
nested = spans.get(nested_routine_index, missing)
|
|
1682
|
+
if nested is missing:
|
|
1683
|
+
nested_heading_end = _heading_semicolon_index(tokens, nested_routine_index)
|
|
1684
|
+
if nested_heading_end is None:
|
|
1685
|
+
spans[nested_routine_index] = None
|
|
1686
|
+
continue
|
|
1687
|
+
frames.append([nested_routine_index, nested_heading_end + 1])
|
|
1688
|
+
continue
|
|
1585
1689
|
if nested is not None:
|
|
1586
|
-
|
|
1690
|
+
frame[1] = max(index + 1, nested[2])
|
|
1587
1691
|
continue
|
|
1588
1692
|
skipped = _routine_declaration_end_index(tokens, index)
|
|
1589
1693
|
if skipped is not None:
|
|
1590
|
-
|
|
1694
|
+
frame[1] = skipped + 1
|
|
1591
1695
|
continue
|
|
1592
|
-
index
|
|
1593
|
-
|
|
1696
|
+
frame[1] = index + 1
|
|
1697
|
+
|
|
1698
|
+
result = spans.get(routine_index)
|
|
1699
|
+
if result is None:
|
|
1700
|
+
return None
|
|
1701
|
+
return tokens[start_index].start, result[1], result[2]
|
|
1594
1702
|
|
|
1595
1703
|
|
|
1596
1704
|
def _routine_keyword_index(
|