@hydranium/core 1.0.0-next.22 → 1.0.0-next.220
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.
- package/README.md +14 -8
- package/lib/documents/ast-document-manager.d.ts +219 -122
- package/lib/documents/ast-document-manager.d.ts.map +1 -1
- package/lib/documents/ast-document-manager.js +241 -130
- package/lib/documents/ast-document-manager.js.map +1 -1
- package/lib/documents/client-ids.d.ts +5 -19
- package/lib/documents/client-ids.d.ts.map +1 -1
- package/lib/documents/client-ids.js +5 -19
- package/lib/documents/client-ids.js.map +1 -1
- package/lib/documents/client-session-errors.d.ts +15 -0
- package/lib/documents/client-session-errors.d.ts.map +1 -0
- package/lib/documents/client-session-errors.js +15 -0
- package/lib/documents/client-session-errors.js.map +1 -0
- package/lib/documents/client-session-registry.d.ts +146 -0
- package/lib/documents/client-session-registry.d.ts.map +1 -0
- package/lib/documents/client-session-registry.js +207 -0
- package/lib/documents/client-session-registry.js.map +1 -0
- package/lib/documents/dirty-state-tracker.d.ts +79 -0
- package/lib/documents/dirty-state-tracker.d.ts.map +1 -0
- package/lib/documents/dirty-state-tracker.js +69 -0
- package/lib/documents/dirty-state-tracker.js.map +1 -0
- package/lib/documents/document-release-handler.d.ts +179 -0
- package/lib/documents/document-release-handler.d.ts.map +1 -0
- package/lib/documents/document-release-handler.js +283 -0
- package/lib/documents/document-release-handler.js.map +1 -0
- package/lib/documents/document-release-scheduler.d.ts +67 -0
- package/lib/documents/document-release-scheduler.d.ts.map +1 -0
- package/lib/documents/document-release-scheduler.js +80 -0
- package/lib/documents/document-release-scheduler.js.map +1 -0
- package/lib/documents/file-system-task-queue.d.ts +49 -0
- package/lib/documents/file-system-task-queue.d.ts.map +1 -0
- package/lib/documents/file-system-task-queue.js +34 -0
- package/lib/documents/file-system-task-queue.js.map +1 -0
- package/lib/documents/hydranium-text-documents.d.ts +399 -282
- package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
- package/lib/documents/hydranium-text-documents.js +816 -483
- package/lib/documents/hydranium-text-documents.js.map +1 -1
- package/lib/documents/index.d.ts +10 -2
- package/lib/documents/index.d.ts.map +1 -1
- package/lib/documents/index.js +10 -2
- package/lib/documents/index.js.map +1 -1
- package/lib/documents/language-client-shadow.d.ts +218 -0
- package/lib/documents/language-client-shadow.d.ts.map +1 -0
- package/lib/documents/language-client-shadow.js +283 -0
- package/lib/documents/language-client-shadow.js.map +1 -0
- package/lib/documents/model-ledger.d.ts +47 -0
- package/lib/documents/model-ledger.d.ts.map +1 -0
- package/lib/documents/model-ledger.js +30 -0
- package/lib/documents/model-ledger.js.map +1 -0
- package/lib/documents/text-ledger.d.ts +64 -0
- package/lib/documents/text-ledger.d.ts.map +1 -0
- package/lib/documents/text-ledger.js +63 -0
- package/lib/documents/text-ledger.js.map +1 -0
- package/lib/documents/version-sync-service.d.ts +134 -0
- package/lib/documents/version-sync-service.d.ts.map +1 -0
- package/lib/documents/version-sync-service.js +171 -0
- package/lib/documents/version-sync-service.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -1
- package/lib/langium/ast-extension/ast-extension-service.d.ts.map +1 -1
- package/lib/langium/ast-extension/ast-extension-service.js.map +1 -1
- package/lib/langium/ast-extension/ast-node-builder.d.ts +32 -9
- package/lib/langium/ast-extension/ast-node-builder.d.ts.map +1 -1
- package/lib/langium/ast-extension/ast-node-builder.js +60 -22
- package/lib/langium/ast-extension/ast-node-builder.js.map +1 -1
- package/lib/langium/bootstrap.d.ts +5 -5
- package/lib/langium/bootstrap.d.ts.map +1 -1
- package/lib/langium/bootstrap.js +42 -17
- package/lib/langium/bootstrap.js.map +1 -1
- package/lib/langium/build-phase-pass/build-phase-pass-service.d.ts.map +1 -1
- package/lib/langium/build-phase-pass/build-phase-pass-service.js.map +1 -1
- package/lib/langium/composite-ast-reflection.d.ts +43 -0
- package/lib/langium/composite-ast-reflection.d.ts.map +1 -0
- package/lib/langium/composite-ast-reflection.js +92 -0
- package/lib/langium/composite-ast-reflection.js.map +1 -0
- package/lib/langium/config/configuration-provider.d.ts +81 -0
- package/lib/langium/config/configuration-provider.d.ts.map +1 -0
- package/lib/langium/config/configuration-provider.js +112 -0
- package/lib/langium/config/configuration-provider.js.map +1 -0
- package/lib/langium/config/index.d.ts +1 -0
- package/lib/langium/config/index.d.ts.map +1 -1
- package/lib/langium/config/index.js +1 -0
- package/lib/langium/config/index.js.map +1 -1
- package/lib/langium/config/settings.js.map +1 -1
- package/lib/langium/diagnostics/hydranium-langium-profiler.d.ts.map +1 -1
- package/lib/langium/diagnostics/hydranium-langium-profiler.js.map +1 -1
- package/lib/langium/diagnostics/logger.d.ts +10 -3
- package/lib/langium/diagnostics/logger.d.ts.map +1 -1
- package/lib/langium/diagnostics/logger.js +12 -5
- package/lib/langium/diagnostics/logger.js.map +1 -1
- package/lib/langium/diagnostics/lsp-logger.d.ts +17 -0
- package/lib/langium/diagnostics/lsp-logger.d.ts.map +1 -1
- package/lib/langium/diagnostics/lsp-logger.js +57 -16
- package/lib/langium/diagnostics/lsp-logger.js.map +1 -1
- package/lib/langium/diagnostics/server-tracer.d.ts.map +1 -1
- package/lib/langium/diagnostics/server-tracer.js.map +1 -1
- package/lib/langium/document-builder/build-pipeline-integration.d.ts +21 -1
- package/lib/langium/document-builder/build-pipeline-integration.d.ts.map +1 -1
- package/lib/langium/document-builder/build-pipeline-integration.js +32 -5
- package/lib/langium/document-builder/build-pipeline-integration.js.map +1 -1
- package/lib/langium/document-builder/build-session.d.ts +93 -0
- package/lib/langium/document-builder/build-session.d.ts.map +1 -0
- package/lib/langium/document-builder/build-session.js +72 -0
- package/lib/langium/document-builder/build-session.js.map +1 -0
- package/lib/langium/document-builder/document-builder.d.ts +401 -29
- package/lib/langium/document-builder/document-builder.d.ts.map +1 -1
- package/lib/langium/document-builder/document-builder.js +698 -61
- package/lib/langium/document-builder/document-builder.js.map +1 -1
- package/lib/langium/document-builder/index.d.ts +1 -0
- package/lib/langium/document-builder/index.d.ts.map +1 -1
- package/lib/langium/document-builder/index.js +1 -0
- package/lib/langium/document-builder/index.js.map +1 -1
- package/lib/langium/documentation/comment-provider.d.ts.map +1 -1
- package/lib/langium/documentation/comment-provider.js.map +1 -1
- package/lib/langium/integration-services.d.ts +61 -19
- package/lib/langium/integration-services.d.ts.map +1 -1
- package/lib/langium/integration-services.js +10 -5
- package/lib/langium/integration-services.js.map +1 -1
- package/lib/langium/integrity/integrity-rule.d.ts +16 -8
- package/lib/langium/integrity/integrity-rule.d.ts.map +1 -1
- package/lib/langium/integrity/integrity-rule.js.map +1 -1
- package/lib/langium/integrity/integrity-service.d.ts +81 -24
- package/lib/langium/integrity/integrity-service.d.ts.map +1 -1
- package/lib/langium/integrity/integrity-service.js +264 -57
- package/lib/langium/integrity/integrity-service.js.map +1 -1
- package/lib/langium/keys/containment.d.ts +64 -0
- package/lib/langium/keys/containment.d.ts.map +1 -0
- package/lib/langium/keys/containment.js +53 -0
- package/lib/langium/keys/containment.js.map +1 -0
- package/lib/langium/keys/index.d.ts +1 -0
- package/lib/langium/keys/index.d.ts.map +1 -1
- package/lib/langium/keys/index.js +1 -0
- package/lib/langium/keys/index.js.map +1 -1
- package/lib/langium/keys/name-based-key-provider.d.ts +4 -0
- package/lib/langium/keys/name-based-key-provider.d.ts.map +1 -1
- package/lib/langium/keys/name-based-key-provider.js +4 -0
- package/lib/langium/keys/name-based-key-provider.js.map +1 -1
- package/lib/langium/keys/positional-key-provider.d.ts.map +1 -1
- package/lib/langium/keys/positional-key-provider.js.map +1 -1
- package/lib/langium/labeling/label-provider.d.ts.map +1 -1
- package/lib/langium/labeling/label-provider.js.map +1 -1
- package/lib/langium/language-module.d.ts +29 -4
- package/lib/langium/language-module.d.ts.map +1 -1
- package/lib/langium/language-module.js +18 -4
- package/lib/langium/language-module.js.map +1 -1
- package/lib/langium/model-service/client-session.d.ts +343 -0
- package/lib/langium/model-service/client-session.d.ts.map +1 -0
- package/lib/langium/model-service/client-session.js +411 -0
- package/lib/langium/model-service/client-session.js.map +1 -0
- package/lib/langium/model-service/index.d.ts +2 -0
- package/lib/langium/model-service/index.d.ts.map +1 -1
- package/lib/langium/model-service/index.js +2 -0
- package/lib/langium/model-service/index.js.map +1 -1
- package/lib/langium/model-service/model-events.d.ts +61 -0
- package/lib/langium/model-service/model-events.d.ts.map +1 -0
- package/lib/langium/model-service/model-events.js +10 -0
- package/lib/langium/model-service/model-events.js.map +1 -0
- package/lib/langium/model-service/model-service.d.ts +432 -282
- package/lib/langium/model-service/model-service.d.ts.map +1 -1
- package/lib/langium/model-service/model-service.js +504 -438
- package/lib/langium/model-service/model-service.js.map +1 -1
- package/lib/langium/module.d.ts +157 -35
- package/lib/langium/module.d.ts.map +1 -1
- package/lib/langium/module.js +52 -35
- package/lib/langium/module.js.map +1 -1
- package/lib/langium/naming/name-provider.d.ts +25 -4
- package/lib/langium/naming/name-provider.d.ts.map +1 -1
- package/lib/langium/naming/name-provider.js +2 -1
- package/lib/langium/naming/name-provider.js.map +1 -1
- package/lib/langium/naming/name-separator-validation.d.ts +23 -0
- package/lib/langium/naming/name-separator-validation.d.ts.map +1 -1
- package/lib/langium/naming/name-separator-validation.js +30 -1
- package/lib/langium/naming/name-separator-validation.js.map +1 -1
- package/lib/langium/project/abstract-project-manager.d.ts.map +1 -1
- package/lib/langium/project/abstract-project-manager.js +9 -2
- package/lib/langium/project/abstract-project-manager.js.map +1 -1
- package/lib/langium/project/project-change-event.d.ts +2 -2
- package/lib/langium/project/single-project-manager.d.ts.map +1 -1
- package/lib/langium/project/single-project-manager.js.map +1 -1
- package/lib/langium/residency/cst-residency-service.d.ts +31 -11
- package/lib/langium/residency/cst-residency-service.d.ts.map +1 -1
- package/lib/langium/residency/cst-residency-service.js +23 -57
- package/lib/langium/residency/cst-residency-service.js.map +1 -1
- package/lib/langium/scope/ast-node-description-provider.d.ts.map +1 -1
- package/lib/langium/scope/ast-node-description-provider.js.map +1 -1
- package/lib/langium/scope/hydranium-scope-computation.d.ts.map +1 -1
- package/lib/langium/scope/hydranium-scope-computation.js.map +1 -1
- package/lib/langium/scope/hydranium-scope-provider.d.ts +48 -13
- package/lib/langium/scope/hydranium-scope-provider.d.ts.map +1 -1
- package/lib/langium/scope/hydranium-scope-provider.js +56 -20
- package/lib/langium/scope/hydranium-scope-provider.js.map +1 -1
- package/lib/langium/scope/reference-builder.d.ts.map +1 -1
- package/lib/langium/scope/reference-builder.js.map +1 -1
- package/lib/langium/scope/reference-candidate-provider.d.ts.map +1 -1
- package/lib/langium/scope/reference-candidate-provider.js.map +1 -1
- package/lib/langium/scope/scope-extension-service.d.ts.map +1 -1
- package/lib/langium/scope/scope-extension-service.js.map +1 -1
- package/lib/langium/serialization/abstract-serializer.d.ts +11 -20
- package/lib/langium/serialization/abstract-serializer.d.ts.map +1 -1
- package/lib/langium/serialization/abstract-serializer.js +12 -21
- package/lib/langium/serialization/abstract-serializer.js.map +1 -1
- package/lib/langium/serialization/json-serializer.d.ts +1 -1
- package/lib/langium/serialization/json-serializer.d.ts.map +1 -1
- package/lib/langium/serialization/json-serializer.js.map +1 -1
- package/lib/langium/serialization/yaml-serializer.d.ts.map +1 -1
- package/lib/langium/serialization/yaml-serializer.js.map +1 -1
- package/lib/langium/service-registry.d.ts +29 -1
- package/lib/langium/service-registry.d.ts.map +1 -1
- package/lib/langium/service-registry.js +37 -0
- package/lib/langium/service-registry.js.map +1 -1
- package/lib/langium/shared-services.d.ts +23 -6
- package/lib/langium/shared-services.d.ts.map +1 -1
- package/lib/langium/shared-services.js.map +1 -1
- package/lib/langium/transfer/transfer-encoder.d.ts +77 -26
- package/lib/langium/transfer/transfer-encoder.d.ts.map +1 -1
- package/lib/langium/transfer/transfer-encoder.js +46 -24
- package/lib/langium/transfer/transfer-encoder.js.map +1 -1
- package/lib/langium/trivia/comment-preserver.d.ts +423 -0
- package/lib/langium/trivia/comment-preserver.d.ts.map +1 -0
- package/lib/langium/trivia/comment-preserver.js +906 -0
- package/lib/langium/trivia/comment-preserver.js.map +1 -0
- package/lib/langium/trivia/document-ending-preserver.d.ts +43 -0
- package/lib/langium/trivia/document-ending-preserver.d.ts.map +1 -0
- package/lib/langium/trivia/document-ending-preserver.js +48 -0
- package/lib/langium/trivia/document-ending-preserver.js.map +1 -0
- package/lib/langium/trivia/index.d.ts +14 -0
- package/lib/langium/trivia/index.d.ts.map +1 -0
- package/lib/langium/trivia/index.js +14 -0
- package/lib/langium/trivia/index.js.map +1 -0
- package/lib/langium/trivia/trivia-contribution.d.ts +37 -0
- package/lib/langium/trivia/trivia-contribution.d.ts.map +1 -0
- package/lib/langium/trivia/trivia-contribution.js +10 -0
- package/lib/langium/trivia/trivia-contribution.js.map +1 -0
- package/lib/langium/trivia/trivia-preserver.d.ts +50 -0
- package/lib/langium/trivia/trivia-preserver.d.ts.map +1 -0
- package/lib/langium/trivia/trivia-preserver.js +10 -0
- package/lib/langium/trivia/trivia-preserver.js.map +1 -0
- package/lib/langium/trivia/trivia-service.d.ts +70 -0
- package/lib/langium/trivia/trivia-service.d.ts.map +1 -0
- package/lib/langium/trivia/trivia-service.js +56 -0
- package/lib/langium/trivia/trivia-service.js.map +1 -0
- package/lib/langium/update-rewrite/normalize-empty-strings.d.ts.map +1 -1
- package/lib/langium/update-rewrite/update-rewrite-service.d.ts.map +1 -1
- package/lib/langium/update-rewrite/update-rewrite-service.js.map +1 -1
- package/lib/langium/update-rewrite/update-rewrite.d.ts +1 -1
- package/lib/langium/validation/document-validator.d.ts +294 -10
- package/lib/langium/validation/document-validator.d.ts.map +1 -1
- package/lib/langium/validation/document-validator.js +448 -5
- package/lib/langium/validation/document-validator.js.map +1 -1
- package/lib/langium/validation/validation-contribution-collector.d.ts +9 -1
- package/lib/langium/validation/validation-contribution-collector.d.ts.map +1 -1
- package/lib/langium/validation/validation-contribution-collector.js +1 -1
- package/lib/langium/validation/validation-contribution-collector.js.map +1 -1
- package/lib/langium/workspace/document-uri-policy.d.ts +18 -14
- package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
- package/lib/langium/workspace/document-uri-policy.js +10 -9
- package/lib/langium/workspace/document-uri-policy.js.map +1 -1
- package/lib/langium/workspace/file-not-found.d.ts +23 -0
- package/lib/langium/workspace/file-not-found.d.ts.map +1 -0
- package/lib/langium/workspace/file-not-found.js +31 -0
- package/lib/langium/workspace/file-not-found.js.map +1 -0
- package/lib/langium/workspace/file-system-provider.d.ts +135 -9
- package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/file-system-provider.js +93 -14
- package/lib/langium/workspace/file-system-provider.js.map +1 -1
- package/lib/langium/workspace/hydranium-langium-document-factory.d.ts +56 -1
- package/lib/langium/workspace/hydranium-langium-document-factory.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-langium-document-factory.js +79 -0
- package/lib/langium/workspace/hydranium-langium-document-factory.js.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-lock.d.ts +43 -1
- package/lib/langium/workspace/hydranium-workspace-lock.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-lock.js +58 -1
- package/lib/langium/workspace/hydranium-workspace-lock.js.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-manager.d.ts +82 -9
- package/lib/langium/workspace/hydranium-workspace-manager.d.ts.map +1 -1
- package/lib/langium/workspace/hydranium-workspace-manager.js +128 -10
- package/lib/langium/workspace/hydranium-workspace-manager.js.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts +26 -3
- package/lib/langium/workspace/in-memory-file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/in-memory-file-system-provider.js +41 -15
- package/lib/langium/workspace/in-memory-file-system-provider.js.map +1 -1
- package/lib/langium/workspace/index-manager.d.ts.map +1 -1
- package/lib/langium/workspace/index-manager.js.map +1 -1
- package/lib/langium/workspace/index.d.ts +1 -0
- package/lib/langium/workspace/index.d.ts.map +1 -1
- package/lib/langium/workspace/index.js +1 -0
- package/lib/langium/workspace/index.js.map +1 -1
- package/lib/langium/workspace/initialize-workspace.d.ts +31 -2
- package/lib/langium/workspace/initialize-workspace.d.ts.map +1 -1
- package/lib/langium/workspace/initialize-workspace.js +13 -5
- package/lib/langium/workspace/initialize-workspace.js.map +1 -1
- package/lib/langium/workspace/langium-documents.d.ts +86 -17
- package/lib/langium/workspace/langium-documents.d.ts.map +1 -1
- package/lib/langium/workspace/langium-documents.js +101 -29
- package/lib/langium/workspace/langium-documents.js.map +1 -1
- package/lib/langium/workspace/persistent-file-system-provider.d.ts +1 -8
- package/lib/langium/workspace/persistent-file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/persistent-file-system-provider.js +0 -7
- package/lib/langium/workspace/persistent-file-system-provider.js.map +1 -1
- package/lib/{documents → langium/workspace}/self-save-registry.d.ts +38 -7
- package/lib/langium/workspace/self-save-registry.d.ts.map +1 -0
- package/lib/{documents → langium/workspace}/self-save-registry.js +29 -16
- package/lib/langium/workspace/self-save-registry.js.map +1 -0
- package/lib/langium/workspace/virtual-document.d.ts +48 -15
- package/lib/langium/workspace/virtual-document.d.ts.map +1 -1
- package/lib/langium/workspace/virtual-document.js +78 -18
- package/lib/langium/workspace/virtual-document.js.map +1 -1
- package/lib/langium/workspace/write-lock-scope.d.ts +20 -10
- package/lib/langium/workspace/write-lock-scope.d.ts.map +1 -1
- package/lib/langium/workspace/write-lock-scope.js +12 -4
- package/lib/langium/workspace/write-lock-scope.js.map +1 -1
- package/lib/locale/index.d.ts +10 -0
- package/lib/locale/index.d.ts.map +1 -0
- package/lib/locale/index.js +10 -0
- package/lib/locale/index.js.map +1 -0
- package/lib/locale/server-locale.d.ts +73 -0
- package/lib/locale/server-locale.d.ts.map +1 -0
- package/lib/locale/server-locale.js +61 -0
- package/lib/locale/server-locale.js.map +1 -0
- package/lib/lsp/completion/hydranium-completion-provider.d.ts +44 -2
- package/lib/lsp/completion/hydranium-completion-provider.d.ts.map +1 -1
- package/lib/lsp/completion/hydranium-completion-provider.js +68 -0
- package/lib/lsp/completion/hydranium-completion-provider.js.map +1 -1
- package/lib/lsp/connection-features.d.ts +23 -0
- package/lib/lsp/connection-features.d.ts.map +1 -0
- package/lib/lsp/connection-features.js +60 -0
- package/lib/lsp/connection-features.js.map +1 -0
- package/lib/lsp/diagnostics-connection.d.ts +27 -0
- package/lib/lsp/diagnostics-connection.d.ts.map +1 -0
- package/lib/lsp/diagnostics-connection.js +53 -0
- package/lib/lsp/diagnostics-connection.js.map +1 -0
- package/lib/lsp/hydranium-document-update-handler.d.ts +92 -81
- package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
- package/lib/lsp/hydranium-document-update-handler.js +153 -99
- package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
- package/lib/lsp/index.d.ts +3 -1
- package/lib/lsp/index.d.ts.map +1 -1
- package/lib/lsp/index.js +3 -1
- package/lib/lsp/index.js.map +1 -1
- package/lib/lsp/lsp-latency.d.ts +39 -0
- package/lib/lsp/lsp-latency.d.ts.map +1 -0
- package/lib/lsp/lsp-latency.js +58 -0
- package/lib/lsp/lsp-latency.js.map +1 -0
- package/lib/lsp/semantic-token-provider.d.ts +34 -1
- package/lib/lsp/semantic-token-provider.d.ts.map +1 -1
- package/lib/lsp/semantic-token-provider.js +55 -8
- package/lib/lsp/semantic-token-provider.js.map +1 -1
- package/lib/lsp/shared-module.d.ts +4 -8
- package/lib/lsp/shared-module.d.ts.map +1 -1
- package/lib/lsp/shared-module.js.map +1 -1
- package/lib/lsp/start-language-server.d.ts +8 -7
- package/lib/lsp/start-language-server.d.ts.map +1 -1
- package/lib/lsp/start-language-server.js +13 -7
- package/lib/lsp/start-language-server.js.map +1 -1
- package/lib/messages/carriers.d.ts +54 -0
- package/lib/messages/carriers.d.ts.map +1 -0
- package/lib/messages/carriers.js +62 -0
- package/lib/messages/carriers.js.map +1 -0
- package/lib/messages/index.d.ts +25 -0
- package/lib/messages/index.d.ts.map +1 -0
- package/lib/messages/index.js +25 -0
- package/lib/messages/index.js.map +1 -0
- package/lib/messages/renderer.d.ts +142 -0
- package/lib/messages/renderer.d.ts.map +1 -0
- package/lib/messages/renderer.js +165 -0
- package/lib/messages/renderer.js.map +1 -0
- package/lib/node/event-loop-monitor.js.map +1 -1
- package/lib/node/heap-ceiling.d.ts +61 -0
- package/lib/node/heap-ceiling.d.ts.map +1 -0
- package/lib/node/heap-ceiling.js +72 -0
- package/lib/node/heap-ceiling.js.map +1 -0
- package/lib/node/index.d.ts +1 -1
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +1 -1
- package/lib/node/index.js.map +1 -1
- package/lib/node/latency-from-env.d.ts +1 -1
- package/lib/node/latency-from-env.js +1 -1
- package/lib/node/lint-grammar.js.map +1 -1
- package/lib/node/measure-memory.d.ts.map +1 -1
- package/lib/node/measure-memory.js +1 -0
- package/lib/node/measure-memory.js.map +1 -1
- package/lib/node/memory-monitor.js.map +1 -1
- package/lib/node/node-file-system-provider.d.ts +41 -6
- package/lib/node/node-file-system-provider.d.ts.map +1 -1
- package/lib/node/node-file-system-provider.js +109 -49
- package/lib/node/node-file-system-provider.js.map +1 -1
- package/lib/node/profile-capture.d.ts +8 -2
- package/lib/node/profile-capture.d.ts.map +1 -1
- package/lib/node/profile-capture.js +1 -1
- package/lib/node/profile-capture.js.map +1 -1
- package/lib/node/profile-digest.js.map +1 -1
- package/lib/node/profiling-run.d.ts +13 -3
- package/lib/node/profiling-run.d.ts.map +1 -1
- package/lib/node/profiling-run.js +17 -8
- package/lib/node/profiling-run.js.map +1 -1
- package/lib/node/rename-over-open-readers.d.ts +52 -0
- package/lib/node/rename-over-open-readers.d.ts.map +1 -0
- package/lib/node/rename-over-open-readers.js +66 -0
- package/lib/node/rename-over-open-readers.js.map +1 -0
- package/lib/node/socket-launcher.d.ts +20 -4
- package/lib/node/socket-launcher.d.ts.map +1 -1
- package/lib/node/socket-launcher.js +5 -4
- package/lib/node/socket-launcher.js.map +1 -1
- package/lib/node/stdio-launcher.d.ts +6 -5
- package/lib/node/stdio-launcher.d.ts.map +1 -1
- package/lib/node/stdio-launcher.js +2 -2
- package/lib/node/stdio-launcher.js.map +1 -1
- package/lib/testing/document-uri-policy-conformance.js.map +1 -1
- package/lib/testing/fake-description.js.map +1 -1
- package/lib/testing/fake-document.d.ts +16 -4
- package/lib/testing/fake-document.d.ts.map +1 -1
- package/lib/testing/fake-document.js +18 -3
- package/lib/testing/fake-document.js.map +1 -1
- package/lib/testing/index.d.ts +1 -1
- package/lib/testing/index.d.ts.map +1 -1
- package/lib/testing/index.js +2 -1
- package/lib/testing/index.js.map +1 -1
- package/lib/testing/langium-test-helpers.d.ts.map +1 -1
- package/lib/testing/langium-test-helpers.js +1 -0
- package/lib/testing/langium-test-helpers.js.map +1 -1
- package/lib/testing/make-noop-language-services.js.map +1 -1
- package/lib/testing/make-noop-shared-services.d.ts +14 -0
- package/lib/testing/make-noop-shared-services.d.ts.map +1 -1
- package/lib/testing/make-noop-shared-services.js +28 -2
- package/lib/testing/make-noop-shared-services.js.map +1 -1
- package/lib/testing/make-test-services.d.ts +72 -14
- package/lib/testing/make-test-services.d.ts.map +1 -1
- package/lib/testing/make-test-services.js +42 -10
- package/lib/testing/make-test-services.js.map +1 -1
- package/lib/testing/make-test-tracer.d.ts +12 -0
- package/lib/testing/make-test-tracer.d.ts.map +1 -1
- package/lib/testing/make-test-tracer.js +13 -0
- package/lib/testing/make-test-tracer.js.map +1 -1
- package/lib/testing/node/golden-corpus.js.map +1 -1
- package/lib/testing/node/index.d.ts +1 -0
- package/lib/testing/node/index.d.ts.map +1 -1
- package/lib/testing/node/index.js +1 -0
- package/lib/testing/node/index.js.map +1 -1
- package/lib/testing/node/lsp-harness.d.ts.map +1 -1
- package/lib/testing/node/lsp-harness.js +2 -0
- package/lib/testing/node/lsp-harness.js.map +1 -1
- package/lib/testing/node/lsp-server-connection.d.ts +11 -3
- package/lib/testing/node/lsp-server-connection.d.ts.map +1 -1
- package/lib/testing/node/lsp-server-connection.js +43 -10
- package/lib/testing/node/lsp-server-connection.js.map +1 -1
- package/lib/testing/node/scratch-workspace.d.ts.map +1 -1
- package/lib/testing/node/scratch-workspace.js +10 -5
- package/lib/testing/node/scratch-workspace.js.map +1 -1
- package/lib/testing/node/spawned-server.d.ts +14 -0
- package/lib/testing/node/spawned-server.d.ts.map +1 -1
- package/lib/testing/node/spawned-server.js +34 -2
- package/lib/testing/node/spawned-server.js.map +1 -1
- package/lib/testing/node/unhandled-rejections.d.ts +20 -0
- package/lib/testing/node/unhandled-rejections.d.ts.map +1 -0
- package/lib/testing/node/unhandled-rejections.js +32 -0
- package/lib/testing/node/unhandled-rejections.js.map +1 -0
- package/lib/testing/playwright/browser-capture-bridge.js.map +1 -1
- package/lib/testing/playwright/e2e-profiling.js.map +1 -1
- package/lib/testing/playwright/flaky-network-proxy.d.ts +76 -0
- package/lib/testing/playwright/flaky-network-proxy.d.ts.map +1 -0
- package/lib/testing/playwright/flaky-network-proxy.js +164 -0
- package/lib/testing/playwright/flaky-network-proxy.js.map +1 -0
- package/lib/testing/playwright/index.d.ts +1 -0
- package/lib/testing/playwright/index.d.ts.map +1 -1
- package/lib/testing/playwright/index.js +1 -0
- package/lib/testing/playwright/index.js.map +1 -1
- package/lib/testing/playwright/server-log-capture.d.ts +24 -8
- package/lib/testing/playwright/server-log-capture.d.ts.map +1 -1
- package/lib/testing/playwright/server-log-capture.js +27 -6
- package/lib/testing/playwright/server-log-capture.js.map +1 -1
- package/lib/testing/playwright/server-log-rename-reporter.d.ts.map +1 -1
- package/lib/testing/playwright/server-log-rename-reporter.js +10 -1
- package/lib/testing/playwright/server-log-rename-reporter.js.map +1 -1
- package/lib/testing/run-update-pipeline.d.ts +4 -4
- package/lib/testing/run-update-pipeline.d.ts.map +1 -1
- package/lib/testing/stub-ast-document-manager.d.ts +11 -52
- package/lib/testing/stub-ast-document-manager.d.ts.map +1 -1
- package/lib/testing/stub-ast-document-manager.js +24 -65
- package/lib/testing/stub-ast-document-manager.js.map +1 -1
- package/lib/testing/stub-document-builder.d.ts +26 -11
- package/lib/testing/stub-document-builder.d.ts.map +1 -1
- package/lib/testing/stub-document-builder.js +78 -5
- package/lib/testing/stub-document-builder.js.map +1 -1
- package/lib/testing/stub-hydranium-text-documents.d.ts +33 -10
- package/lib/testing/stub-hydranium-text-documents.d.ts.map +1 -1
- package/lib/testing/stub-hydranium-text-documents.js +115 -16
- package/lib/testing/stub-hydranium-text-documents.js.map +1 -1
- package/lib/testing/stub-index-manager.js.map +1 -1
- package/lib/testing/stub-langium-documents.d.ts +3 -2
- package/lib/testing/stub-langium-documents.d.ts.map +1 -1
- package/lib/testing/stub-langium-documents.js.map +1 -1
- package/lib/testing/stub-model-service.d.ts +7 -6
- package/lib/testing/stub-model-service.d.ts.map +1 -1
- package/lib/testing/stub-model-service.js +4 -4
- package/lib/testing/stub-model-service.js.map +1 -1
- package/lib/testing/stub-project-manager.js.map +1 -1
- package/lib/testing/stub-self-save-registry.d.ts +1 -1
- package/lib/testing/stub-self-save-registry.d.ts.map +1 -1
- package/lib/testing/stub-service-registry.d.ts +1 -1
- package/lib/testing/stub-service-registry.js.map +1 -1
- package/lib/testing/stub-writable-file-system.d.ts +1 -1
- package/lib/testing/stub-writable-file-system.d.ts.map +1 -1
- package/lib/util/connection-liveness.d.ts +7 -6
- package/lib/util/connection-liveness.d.ts.map +1 -1
- package/lib/util/connection-liveness.js +35 -14
- package/lib/util/connection-liveness.js.map +1 -1
- package/lib/util/environment.d.ts.map +1 -1
- package/lib/util/environment.js.map +1 -1
- package/lib/util/registry.d.ts.map +1 -1
- package/package.json +32 -48
- package/src/documents/ast-document-manager.ts +379 -231
- package/src/documents/client-ids.ts +5 -22
- package/src/documents/client-session-errors.ts +24 -0
- package/src/documents/client-session-registry.ts +262 -0
- package/src/documents/dirty-state-tracker.ts +130 -0
- package/src/documents/document-release-handler.ts +365 -0
- package/src/documents/document-release-scheduler.ts +121 -0
- package/src/documents/file-system-task-queue.ts +68 -0
- package/src/documents/hydranium-text-documents.ts +931 -595
- package/src/documents/index.ts +10 -2
- package/src/documents/language-client-shadow.ts +451 -0
- package/src/documents/model-ledger.ts +66 -0
- package/src/documents/text-ledger.ts +112 -0
- package/src/documents/version-sync-service.ts +267 -0
- package/src/index.ts +7 -0
- package/src/langium/ast-extension/ast-node-builder.ts +66 -22
- package/src/langium/bootstrap.ts +42 -17
- package/src/langium/composite-ast-reflection.ts +107 -0
- package/src/langium/config/configuration-provider.ts +119 -0
- package/src/langium/config/index.ts +1 -0
- package/src/langium/diagnostics/logger.ts +12 -5
- package/src/langium/diagnostics/lsp-logger.ts +59 -15
- package/src/langium/document-builder/build-pipeline-integration.ts +50 -5
- package/src/langium/document-builder/build-session.ts +87 -0
- package/src/langium/document-builder/document-builder.ts +825 -59
- package/src/langium/document-builder/index.ts +1 -0
- package/src/langium/integration-services.ts +83 -24
- package/src/langium/integrity/integrity-rule.ts +16 -8
- package/src/langium/integrity/integrity-service.ts +287 -62
- package/src/langium/keys/containment.ts +87 -0
- package/src/langium/keys/index.ts +1 -0
- package/src/langium/keys/name-based-key-provider.ts +4 -0
- package/src/langium/language-module.ts +48 -7
- package/src/langium/model-service/client-session.ts +644 -0
- package/src/langium/model-service/index.ts +2 -0
- package/src/langium/model-service/model-events.ts +75 -0
- package/src/langium/model-service/model-service.ts +790 -468
- package/src/langium/module.ts +210 -64
- package/src/langium/naming/name-provider.ts +27 -5
- package/src/langium/naming/name-separator-validation.ts +34 -5
- package/src/langium/project/abstract-project-manager.ts +9 -1
- package/src/langium/project/project-change-event.ts +2 -2
- package/src/langium/residency/cst-residency-service.ts +46 -15
- package/src/langium/scope/hydranium-scope-provider.ts +60 -22
- package/src/langium/serialization/abstract-serializer.ts +13 -32
- package/src/langium/service-registry.ts +41 -2
- package/src/langium/shared-services.ts +27 -6
- package/src/langium/transfer/transfer-encoder.ts +104 -37
- package/src/langium/trivia/comment-preserver.ts +1100 -0
- package/src/langium/trivia/document-ending-preserver.ts +55 -0
- package/src/langium/trivia/index.ts +14 -0
- package/src/langium/trivia/trivia-contribution.ts +39 -0
- package/src/langium/trivia/trivia-preserver.ts +54 -0
- package/src/langium/trivia/trivia-service.ts +99 -0
- package/src/langium/update-rewrite/update-rewrite.ts +1 -1
- package/src/langium/validation/document-validator.ts +537 -11
- package/src/langium/validation/validation-contribution-collector.ts +10 -1
- package/src/langium/workspace/document-uri-policy.ts +18 -14
- package/src/langium/workspace/file-not-found.ts +35 -0
- package/src/langium/workspace/file-system-provider.ts +205 -17
- package/src/langium/workspace/hydranium-langium-document-factory.ts +117 -0
- package/src/langium/workspace/hydranium-workspace-lock.ts +86 -2
- package/src/langium/workspace/hydranium-workspace-manager.ts +154 -14
- package/src/langium/workspace/in-memory-file-system-provider.ts +48 -17
- package/src/langium/workspace/index.ts +1 -0
- package/src/langium/workspace/initialize-workspace.ts +43 -5
- package/src/langium/workspace/langium-documents.ts +124 -33
- package/src/langium/workspace/persistent-file-system-provider.ts +1 -8
- package/src/{documents → langium/workspace}/self-save-registry.ts +54 -15
- package/src/langium/workspace/virtual-document.ts +96 -19
- package/src/langium/workspace/write-lock-scope.ts +24 -11
- package/src/locale/index.ts +10 -0
- package/src/locale/server-locale.ts +86 -0
- package/src/lsp/completion/hydranium-completion-provider.ts +82 -2
- package/src/lsp/connection-features.ts +67 -0
- package/src/lsp/diagnostics-connection.ts +56 -0
- package/src/lsp/hydranium-document-update-handler.ts +187 -108
- package/src/lsp/index.ts +3 -1
- package/src/lsp/lsp-latency.ts +62 -0
- package/src/lsp/semantic-token-provider.ts +74 -7
- package/src/lsp/shared-module.ts +4 -8
- package/src/lsp/start-language-server.ts +13 -7
- package/src/messages/carriers.ts +78 -0
- package/src/messages/index.ts +36 -0
- package/src/messages/renderer.ts +212 -0
- package/src/node/heap-ceiling.ts +108 -0
- package/src/node/index.ts +1 -1
- package/src/node/latency-from-env.ts +1 -1
- package/src/node/measure-memory.ts +1 -0
- package/src/node/node-file-system-provider.ts +124 -53
- package/src/node/profile-capture.ts +9 -3
- package/src/node/profiling-run.ts +30 -8
- package/src/node/rename-over-open-readers.ts +78 -0
- package/src/node/socket-launcher.ts +24 -8
- package/src/node/stdio-launcher.ts +8 -7
- package/src/testing/fake-document.ts +24 -5
- package/src/testing/index.ts +2 -1
- package/src/testing/langium-test-helpers.ts +1 -0
- package/src/testing/make-noop-shared-services.ts +50 -2
- package/src/testing/make-test-services.ts +125 -31
- package/src/testing/make-test-tracer.ts +26 -0
- package/src/testing/node/index.ts +1 -0
- package/src/testing/node/lsp-harness.ts +2 -0
- package/src/testing/node/lsp-server-connection.ts +66 -12
- package/src/testing/node/scratch-workspace.ts +10 -5
- package/src/testing/node/spawned-server.ts +36 -2
- package/src/testing/node/unhandled-rejections.ts +31 -0
- package/src/testing/parse-semantic-root.ts +1 -1
- package/src/testing/playwright/flaky-network-proxy.ts +240 -0
- package/src/testing/playwright/index.ts +1 -0
- package/src/testing/playwright/server-log-capture.ts +45 -11
- package/src/testing/playwright/server-log-rename-reporter.ts +12 -1
- package/src/testing/run-update-pipeline.ts +4 -4
- package/src/testing/stub-ast-document-manager.ts +36 -138
- package/src/testing/stub-document-builder.ts +102 -18
- package/src/testing/stub-hydranium-text-documents.ts +165 -27
- package/src/testing/stub-langium-documents.ts +3 -2
- package/src/testing/stub-model-service.ts +9 -8
- package/src/testing/stub-self-save-registry.ts +1 -1
- package/src/testing/stub-service-registry.ts +1 -1
- package/src/testing/stub-writable-file-system.ts +1 -1
- package/src/util/connection-liveness.ts +37 -14
- package/src/util/environment.ts +9 -1
- package/lib/documents/language-client-text-shadow.d.ts +0 -101
- package/lib/documents/language-client-text-shadow.d.ts.map +0 -1
- package/lib/documents/language-client-text-shadow.js +0 -156
- package/lib/documents/language-client-text-shadow.js.map +0 -1
- package/lib/documents/self-save-registry.d.ts.map +0 -1
- package/lib/documents/self-save-registry.js.map +0 -1
- package/lib/lsp/instrument-connection.d.ts +0 -36
- package/lib/lsp/instrument-connection.d.ts.map +0 -1
- package/lib/lsp/instrument-connection.js +0 -62
- package/lib/lsp/instrument-connection.js.map +0 -1
- package/lib/node/process-memory.d.ts +0 -66
- package/lib/node/process-memory.d.ts.map +0 -1
- package/lib/node/process-memory.js +0 -252
- package/lib/node/process-memory.js.map +0 -1
- package/src/documents/language-client-text-shadow.ts +0 -175
- package/src/lsp/instrument-connection.ts +0 -66
- package/src/node/process-memory.ts +0 -299
package/src/documents/index.ts
CHANGED
|
@@ -8,7 +8,15 @@
|
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
|
|
10
10
|
export * from './client-ids.js';
|
|
11
|
-
export * from './
|
|
11
|
+
export * from './client-session-errors.js';
|
|
12
|
+
export * from './client-session-registry.js';
|
|
13
|
+
export * from './language-client-shadow.js';
|
|
12
14
|
export * from './hydranium-text-documents.js';
|
|
15
|
+
export * from './model-ledger.js';
|
|
16
|
+
export * from './text-ledger.js';
|
|
17
|
+
export * from './dirty-state-tracker.js';
|
|
18
|
+
export * from './document-release-handler.js';
|
|
19
|
+
export * from './document-release-scheduler.js';
|
|
20
|
+
export * from './version-sync-service.js';
|
|
13
21
|
export * from './ast-document-manager.js';
|
|
14
|
-
export * from './
|
|
22
|
+
export * from './file-system-task-queue.js';
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import { type CanonicalUri, type LanguageClientUri, textHash, type Tracer } from '@hydranium/protocol';
|
|
11
|
+
import { diffLines } from 'diff';
|
|
12
|
+
import { Range, type TextDocumentsConfiguration, type TextEdit, uinteger } from 'vscode-languageserver';
|
|
13
|
+
import { TextDocument, type TextDocumentContentChangeEvent } from 'vscode-languageserver-textdocument';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The language client's open of a document under one URI, from its didOpen to
|
|
17
|
+
* its didClose. Each URI is its own editor buffer with its own version counter,
|
|
18
|
+
* so a file reached through a symlink and its real path has one of these each.
|
|
19
|
+
*/
|
|
20
|
+
export interface LanguageClientDocumentState {
|
|
21
|
+
/** The version the client last declared for this URI. */
|
|
22
|
+
declaredVersion: number;
|
|
23
|
+
/**
|
|
24
|
+
* The version an applied versioned push moved this URI to, ahead of its
|
|
25
|
+
* echo. Apart from `declaredVersion`, whose staleness guard would drop that
|
|
26
|
+
* echo and strand its pending push.
|
|
27
|
+
*/
|
|
28
|
+
pushedVersion?: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* One text pushed to the language client whose echo has not come back yet.
|
|
33
|
+
* Outbound pushes and inbound echoes are uncorrelated on the wire; a FIFO of
|
|
34
|
+
* these per URI is the explicit correlation.
|
|
35
|
+
*/
|
|
36
|
+
export interface PendingLanguageClientPush {
|
|
37
|
+
/** {@link textHash} of the text this push moves the client to. */
|
|
38
|
+
readonly afterHash: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** A push {@link LanguageClientShadow.preparePush} has queued, for the store to send and settle. */
|
|
42
|
+
export interface PreparedLanguageClientPush {
|
|
43
|
+
readonly clientUri: LanguageClientUri;
|
|
44
|
+
readonly edits: TextEdit[];
|
|
45
|
+
/**
|
|
46
|
+
* The client version the edits are addressed at, so the client refuses a
|
|
47
|
+
* push its buffer has outrun; `null` for a full replace, which lands on any
|
|
48
|
+
* buffer and is the caller's retry after a refusal.
|
|
49
|
+
*/
|
|
50
|
+
readonly version: number | null;
|
|
51
|
+
/**
|
|
52
|
+
* Record what the client answered. Only the first call counts; a refusal of
|
|
53
|
+
* an addressed push is logged; an answer that arrives after the client
|
|
54
|
+
* reopened the URI changes nothing.
|
|
55
|
+
*/
|
|
56
|
+
notifyOutcome(outcome: LanguageClientPushOutcome): void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** What the client answered a {@link PreparedLanguageClientPush}. */
|
|
60
|
+
export type LanguageClientPushOutcome = 'applied' | 'refused' | 'failed';
|
|
61
|
+
|
|
62
|
+
/** What an incoming language-client change is, as {@link LanguageClientShadow.acceptChange} finds it. */
|
|
63
|
+
export type LanguageClientChangeVerdict =
|
|
64
|
+
/** The client is reporting a text we pushed it. The synced document is already there. */
|
|
65
|
+
| { readonly kind: 'echo' }
|
|
66
|
+
/**
|
|
67
|
+
* The client's buffer holds a text we did not push it — a keystroke that
|
|
68
|
+
* raced a push, or an edit to a buffer the store has already been written
|
|
69
|
+
* past. Its ranges address that buffer, so applied to the synced text they
|
|
70
|
+
* splice the wrong lines; `text` is what it now holds, and is authoritative.
|
|
71
|
+
*/
|
|
72
|
+
| { readonly kind: 'divergent'; readonly text: string }
|
|
73
|
+
/** The client's buffer is the synced text, so its ranges apply as sent. */
|
|
74
|
+
| { readonly kind: 'direct' };
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The store's model of what the LSP language client holds for each URI it
|
|
78
|
+
* opened: the text, the version it declared and the version a push moved it
|
|
79
|
+
* to, and the pushes it has not echoed yet. The store speaks the protocol;
|
|
80
|
+
* this answers what an incoming change is and what an outgoing push sends.
|
|
81
|
+
*
|
|
82
|
+
* Keyed by the URI the client opened under, which differs from the store's
|
|
83
|
+
* canonical key when the path does not match its real path, so one document
|
|
84
|
+
* can have several.
|
|
85
|
+
*
|
|
86
|
+
* A push is a diff against the text the client holds rather than a full
|
|
87
|
+
* replace: a full-range replace on a large source makes Monaco re-tokenise the
|
|
88
|
+
* whole document, observed as multi-second hangs.
|
|
89
|
+
*/
|
|
90
|
+
export interface LanguageClientShadow {
|
|
91
|
+
/**
|
|
92
|
+
* The client opened `key` under `clientUri` holding `text`. `firstOpen`,
|
|
93
|
+
* the store's first open of `key`: that text becomes the diff baseline;
|
|
94
|
+
* otherwise there is none, since a buffer opened from disk can lag the
|
|
95
|
+
* synced text, and a push of other text is a full replace. Either replaces
|
|
96
|
+
* what was tracked for `clientUri` before the open. A no-op when this URI
|
|
97
|
+
* is already open.
|
|
98
|
+
*/
|
|
99
|
+
addOpen(key: CanonicalUri, clientUri: LanguageClientUri, version: number, text: string, firstOpen: boolean): void;
|
|
100
|
+
/** The version the client last declared for `key` under `clientUri`; `undefined` when it never opened it there. */
|
|
101
|
+
declaredVersion(key: CanonicalUri, clientUri: LanguageClientUri): number | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* Take `version` as the client's newest for `clientUri`, and classify its
|
|
104
|
+
* change against `document`, the synced document. The caller has already
|
|
105
|
+
* dropped a stale change. After a `direct` or `divergent` verdict the caller
|
|
106
|
+
* commits the change and reports the synced text through
|
|
107
|
+
* {@link LanguageClientShadow.setClientText}: a `direct` change advances what
|
|
108
|
+
* the client was last heard to hold only through that call, and without it
|
|
109
|
+
* the next change is rebuilt against a stale text.
|
|
110
|
+
*/
|
|
111
|
+
acceptChange(
|
|
112
|
+
key: CanonicalUri,
|
|
113
|
+
clientUri: LanguageClientUri,
|
|
114
|
+
version: number,
|
|
115
|
+
document: TextDocument,
|
|
116
|
+
changes: TextDocumentContentChangeEvent[]
|
|
117
|
+
): LanguageClientChangeVerdict;
|
|
118
|
+
/** The client holds `text` with nothing in flight. */
|
|
119
|
+
setClientText(clientUri: LanguageClientUri, text: string): void;
|
|
120
|
+
/** The client closed `clientUri`; what it held there is forgotten. */
|
|
121
|
+
removeOpen(key: CanonicalUri, clientUri: LanguageClientUri): void;
|
|
122
|
+
/** Whether the client has `key` open: under `clientUri` when given, else under any URI. */
|
|
123
|
+
isOpen(key: CanonicalUri, clientUri?: LanguageClientUri): boolean;
|
|
124
|
+
/** Forget every URI the client holds `key` under. */
|
|
125
|
+
removeAllOpens(key: CanonicalUri): void;
|
|
126
|
+
/**
|
|
127
|
+
* The URIs a push of `key` goes to: each open of it, none when the client
|
|
128
|
+
* has not opened it. A client applies a push to a closed file by opening
|
|
129
|
+
* it, and an open racing its own push leaves no text to diff against.
|
|
130
|
+
*/
|
|
131
|
+
pushTargets(key: CanonicalUri): LanguageClientUri[];
|
|
132
|
+
/**
|
|
133
|
+
* Diff `text` against what the client holds under `clientUri` and queue the
|
|
134
|
+
* push for echo correlation, which has to precede the RPC because an echo
|
|
135
|
+
* can arrive before its response. `undefined` when there is nothing to send,
|
|
136
|
+
* which includes a `clientUri` the client no longer has open: a close can
|
|
137
|
+
* land while the push to another of its URIs is in flight.
|
|
138
|
+
*/
|
|
139
|
+
preparePush(key: CanonicalUri, clientUri: LanguageClientUri, text: string): PreparedLanguageClientPush | undefined;
|
|
140
|
+
/**
|
|
141
|
+
* Drop the diff baseline and the pushes in flight under `clientUri`; its
|
|
142
|
+
* next push is a full replace, or nothing when the client was last heard to
|
|
143
|
+
* hold that text. What the client was last heard to hold stays, and its
|
|
144
|
+
* changes are still rebuilt against it.
|
|
145
|
+
*/
|
|
146
|
+
invalidateClientText(clientUri: LanguageClientUri): void;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Upper bound on the pending pushes per URI. Echoes normally return within
|
|
151
|
+
* milliseconds; a queue this deep means the client stopped echoing.
|
|
152
|
+
*/
|
|
153
|
+
const PENDING_ECHO_CAP = 32;
|
|
154
|
+
|
|
155
|
+
/** The range every full-document replace emitted here carries. */
|
|
156
|
+
const FULL_RANGE = Range.create(0, 0, uinteger.MAX_VALUE, uinteger.MAX_VALUE);
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Whether `edits` is the single full-document replace a push emits when it has
|
|
160
|
+
* no usable baseline. A full replace is position-independent and lands on any
|
|
161
|
+
* client buffer; a line-keyed diff lands only on the text it was diffed
|
|
162
|
+
* against, so only the latter needs a client-version gate.
|
|
163
|
+
*/
|
|
164
|
+
export function isFullReplace(edits: readonly TextEdit[]): boolean {
|
|
165
|
+
if (edits.length !== 1) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
const { start, end } = edits[0].range;
|
|
169
|
+
return start.line === FULL_RANGE.start.line && start.character === FULL_RANGE.start.character && end.line === FULL_RANGE.end.line;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export class DefaultLanguageClientShadow<T extends TextDocument = TextDocument> implements LanguageClientShadow {
|
|
173
|
+
protected readonly opens = new Map<CanonicalUri, Map<LanguageClientUri, LanguageClientDocumentState>>();
|
|
174
|
+
/** The diff baseline: the text the client holds once every push in flight has landed. */
|
|
175
|
+
protected readonly baselines = new Map<LanguageClientUri, string>();
|
|
176
|
+
/**
|
|
177
|
+
* What the client was last heard to hold: the text of its open, advanced
|
|
178
|
+
* through every change since. Each change's ranges address the text the
|
|
179
|
+
* previous one left, so changes are rebuilt against this; the diff baseline
|
|
180
|
+
* moves ahead at a push and does not hold it. A push compares against it
|
|
181
|
+
* for equality only: a line-keyed diff keyed to it splices a buffer the
|
|
182
|
+
* client may have moved past.
|
|
183
|
+
*/
|
|
184
|
+
protected readonly heardTexts = new Map<LanguageClientUri, string>();
|
|
185
|
+
protected readonly pending = new Map<LanguageClientUri, PendingLanguageClientPush[]>();
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @param configuration the store's text-document factories, the store's own
|
|
189
|
+
* `create` and `update`. Probes go through them rather than `TextDocument`
|
|
190
|
+
* directly, so an adopter's custom text-document type applies ranges here
|
|
191
|
+
* as it does on the synced document; the bare `TextDocument.update` also
|
|
192
|
+
* refuses a document it did not create.
|
|
193
|
+
*/
|
|
194
|
+
constructor(
|
|
195
|
+
protected readonly configuration: TextDocumentsConfiguration<T>,
|
|
196
|
+
protected readonly tracer: Tracer
|
|
197
|
+
) {}
|
|
198
|
+
|
|
199
|
+
addOpen(key: CanonicalUri, clientUri: LanguageClientUri, version: number, text: string, firstOpen: boolean): void {
|
|
200
|
+
let uris = this.opens.get(key);
|
|
201
|
+
if (uris?.has(clientUri)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (!uris) {
|
|
205
|
+
uris = new Map();
|
|
206
|
+
this.opens.set(key, uris);
|
|
207
|
+
}
|
|
208
|
+
uris.set(clientUri, { declaredVersion: version });
|
|
209
|
+
// Dropped: a seed set before the open names no buffer, and a line diff
|
|
210
|
+
// against it splices text the client does not hold.
|
|
211
|
+
this.invalidateClientText(clientUri);
|
|
212
|
+
this.heardTexts.set(clientUri, text);
|
|
213
|
+
if (firstOpen) {
|
|
214
|
+
this.baselines.set(clientUri, text);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
declaredVersion(key: CanonicalUri, clientUri: LanguageClientUri): number | undefined {
|
|
219
|
+
return this.opens.get(key)?.get(clientUri)?.declaredVersion;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
acceptChange(
|
|
223
|
+
key: CanonicalUri,
|
|
224
|
+
clientUri: LanguageClientUri,
|
|
225
|
+
version: number,
|
|
226
|
+
document: TextDocument,
|
|
227
|
+
changes: TextDocumentContentChangeEvent[]
|
|
228
|
+
): LanguageClientChangeVerdict {
|
|
229
|
+
const state = this.opens.get(key)?.get(clientUri);
|
|
230
|
+
if (state) {
|
|
231
|
+
state.declaredVersion = version;
|
|
232
|
+
}
|
|
233
|
+
return this.classify(clientUri, document, changes);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Reconstruct the client's resulting buffer against what it was last heard
|
|
238
|
+
* to hold, which its ranges address whatever was pushed meanwhile.
|
|
239
|
+
*
|
|
240
|
+
* The client applies pushes in order, so the first echo belongs to the
|
|
241
|
+
* oldest entry. Matching against every pending hash, not only the oldest,
|
|
242
|
+
* recognises an echo a newer push already superseded, and consumes
|
|
243
|
+
* everything older too. A reconstruction matching none means the client's
|
|
244
|
+
* buffer went somewhere we did not send it, and the queue drops.
|
|
245
|
+
*
|
|
246
|
+
* Content equality is a sound echo proof because entries live only between
|
|
247
|
+
* a push and its echo, and `didChange` arrives in mutation order: an undo
|
|
248
|
+
* back to a previously pushed text revisits a past state, while the queue
|
|
249
|
+
* holds only in-flight ones.
|
|
250
|
+
*/
|
|
251
|
+
protected classify(
|
|
252
|
+
clientUri: LanguageClientUri,
|
|
253
|
+
document: TextDocument,
|
|
254
|
+
changes: TextDocumentContentChangeEvent[]
|
|
255
|
+
): LanguageClientChangeVerdict {
|
|
256
|
+
// The synced text stands in only for a URI with nothing recorded, which
|
|
257
|
+
// has nothing in flight either.
|
|
258
|
+
const heard = this.heardTexts.get(clientUri) ?? document.getText();
|
|
259
|
+
const pending = this.pending.get(clientUri);
|
|
260
|
+
if (!pending?.length && heard === document.getText()) {
|
|
261
|
+
// The ranges apply to the synced text as sent, and the caller's
|
|
262
|
+
// setClientText records the result. Were it rebuilt here too, every
|
|
263
|
+
// keystroke would copy the whole text a second time and rescan its lines.
|
|
264
|
+
return { kind: 'direct' };
|
|
265
|
+
}
|
|
266
|
+
const probe = this.configuration.create(clientUri, document.languageId, 0, heard);
|
|
267
|
+
const reconstructed = this.configuration.update(probe, changes, 0).getText();
|
|
268
|
+
this.heardTexts.set(clientUri, reconstructed);
|
|
269
|
+
if (pending?.length) {
|
|
270
|
+
const matchIndex = pending.findIndex(push => push.afterHash === textHash(reconstructed));
|
|
271
|
+
if (matchIndex >= 0) {
|
|
272
|
+
pending.splice(0, matchIndex + 1);
|
|
273
|
+
return { kind: 'echo' };
|
|
274
|
+
}
|
|
275
|
+
this.pending.delete(clientUri);
|
|
276
|
+
}
|
|
277
|
+
return heard === document.getText() ? { kind: 'direct' } : { kind: 'divergent', text: reconstructed };
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
setClientText(clientUri: LanguageClientUri, text: string): void {
|
|
281
|
+
this.baselines.set(clientUri, text);
|
|
282
|
+
this.heardTexts.set(clientUri, text);
|
|
283
|
+
this.pending.delete(clientUri);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
removeOpen(key: CanonicalUri, clientUri: LanguageClientUri): void {
|
|
287
|
+
const uris = this.opens.get(key);
|
|
288
|
+
if (uris?.delete(clientUri)) {
|
|
289
|
+
this.invalidateClientText(clientUri);
|
|
290
|
+
this.heardTexts.delete(clientUri);
|
|
291
|
+
if (uris.size === 0) {
|
|
292
|
+
this.opens.delete(key);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
isOpen(key: CanonicalUri, clientUri?: LanguageClientUri): boolean {
|
|
298
|
+
const uris = this.opens.get(key);
|
|
299
|
+
return clientUri === undefined ? uris !== undefined : (uris?.has(clientUri) ?? false);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
removeAllOpens(key: CanonicalUri): void {
|
|
303
|
+
for (const clientUri of this.opens.get(key)?.keys() ?? []) {
|
|
304
|
+
this.invalidateClientText(clientUri);
|
|
305
|
+
this.heardTexts.delete(clientUri);
|
|
306
|
+
}
|
|
307
|
+
this.opens.delete(key);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
pushTargets(key: CanonicalUri): LanguageClientUri[] {
|
|
311
|
+
return [...(this.opens.get(key)?.keys() ?? [])];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
preparePush(key: CanonicalUri, clientUri: LanguageClientUri, text: string): PreparedLanguageClientPush | undefined {
|
|
315
|
+
// Captured now: a reopen while the push is in flight replaces the state.
|
|
316
|
+
const state = this.opens.get(key)?.get(clientUri);
|
|
317
|
+
if (state === undefined) {
|
|
318
|
+
return undefined;
|
|
319
|
+
}
|
|
320
|
+
const edits = this.computeEdits(clientUri, text);
|
|
321
|
+
if (edits.length === 0) {
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
|
324
|
+
this.recordPendingPush(clientUri, text);
|
|
325
|
+
// Gating a full replace turns a stale-by-one version into a refused
|
|
326
|
+
// update for no safety gain, and refuses the retry after a rejection.
|
|
327
|
+
const version = isFullReplace(edits) ? null : Math.max(state.declaredVersion, state.pushedVersion ?? state.declaredVersion);
|
|
328
|
+
let settled = false;
|
|
329
|
+
return {
|
|
330
|
+
clientUri,
|
|
331
|
+
edits,
|
|
332
|
+
version,
|
|
333
|
+
notifyOutcome: outcome => {
|
|
334
|
+
if (!settled) {
|
|
335
|
+
settled = true;
|
|
336
|
+
if (outcome === 'refused' && version !== null) {
|
|
337
|
+
this.tracer
|
|
338
|
+
.with(key)
|
|
339
|
+
.warn(
|
|
340
|
+
`Language client refused applyEdit addressed at version ${version} (it last declared version ${state.declaredVersion})`
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
// A reopen while the push was in flight reset what is tracked for the new buffer.
|
|
344
|
+
if (this.opens.get(key)?.get(clientUri) === state) {
|
|
345
|
+
this.settle(clientUri, version, state, outcome);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** What a prepared push's {@link PreparedLanguageClientPush.notifyOutcome} does. */
|
|
353
|
+
protected settle(
|
|
354
|
+
clientUri: LanguageClientUri,
|
|
355
|
+
version: number | null,
|
|
356
|
+
state: LanguageClientDocumentState | undefined,
|
|
357
|
+
outcome: LanguageClientPushOutcome
|
|
358
|
+
): void {
|
|
359
|
+
if (outcome !== 'applied') {
|
|
360
|
+
this.invalidateClientText(clientUri);
|
|
361
|
+
} else if (version !== null && state) {
|
|
362
|
+
// A client steps once per applied edit that changes its buffer. Left
|
|
363
|
+
// to the echo, a push sent next is refused at the old version.
|
|
364
|
+
state.pushedVersion = version + 1;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
invalidateClientText(clientUri: LanguageClientUri): void {
|
|
369
|
+
this.baselines.delete(clientUri);
|
|
370
|
+
this.pending.delete(clientUri);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* The edits that bring the client from its baseline to `text`, moving the
|
|
375
|
+
* baseline to `text`. A full replace without a baseline, none when the
|
|
376
|
+
* client was last heard to hold exactly `text` (pushing it anyway dirties
|
|
377
|
+
* the buffer and adds an undo step), and otherwise a line diff, verified by
|
|
378
|
+
* applying it: a diff that does not reproduce `text` falls back to a full
|
|
379
|
+
* replace rather than corrupting the client.
|
|
380
|
+
*/
|
|
381
|
+
protected computeEdits(clientUri: LanguageClientUri, text: string): TextEdit[] {
|
|
382
|
+
const old = this.baselines.get(clientUri);
|
|
383
|
+
if (old === text) {
|
|
384
|
+
return [];
|
|
385
|
+
}
|
|
386
|
+
this.baselines.set(clientUri, text);
|
|
387
|
+
const fullReplace: TextEdit = { range: FULL_RANGE, newText: text };
|
|
388
|
+
if (old === undefined) {
|
|
389
|
+
return this.heardTexts.get(clientUri) === text ? [] : [fullReplace];
|
|
390
|
+
}
|
|
391
|
+
const edits = diffToEdits(old, text);
|
|
392
|
+
const probe = this.configuration.create(clientUri, 'plaintext', 0, old);
|
|
393
|
+
if (TextDocument.applyEdits(probe, edits) !== text) {
|
|
394
|
+
this.tracer.with(clientUri).warn('Diff apply-verify fallback (apply-verify-mismatch) — using full-document replace');
|
|
395
|
+
return [fullReplace];
|
|
396
|
+
}
|
|
397
|
+
return edits;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** Bounded, so an echo that never arrives cannot grow the queue without limit. */
|
|
401
|
+
protected recordPendingPush(clientUri: LanguageClientUri, text: string): void {
|
|
402
|
+
let queue = this.pending.get(clientUri);
|
|
403
|
+
if (!queue) {
|
|
404
|
+
queue = [];
|
|
405
|
+
this.pending.set(clientUri, queue);
|
|
406
|
+
}
|
|
407
|
+
queue.push({ afterHash: textHash(text) });
|
|
408
|
+
if (queue.length > PENDING_ECHO_CAP) {
|
|
409
|
+
queue.shift();
|
|
410
|
+
this.tracer.with(clientUri).debug(`Pending-echo queue exceeded ${PENDING_ECHO_CAP} entries; dropped the oldest`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Convert a {@link diffLines} result to a list of LSP {@link TextEdit}s keyed on line positions
|
|
417
|
+
* in the *old* text. Contiguous added/removed hunks are coalesced into a single replace so the
|
|
418
|
+
* client sees one edit per changed region.
|
|
419
|
+
*/
|
|
420
|
+
export function diffToEdits(oldText: string, newText: string): TextEdit[] {
|
|
421
|
+
const hunks = diffLines(oldText, newText);
|
|
422
|
+
const edits: TextEdit[] = [];
|
|
423
|
+
let oldLine = 0;
|
|
424
|
+
let i = 0;
|
|
425
|
+
while (i < hunks.length) {
|
|
426
|
+
const hunk = hunks[i];
|
|
427
|
+
if (!hunk.added && !hunk.removed) {
|
|
428
|
+
oldLine += hunk.count ?? 0;
|
|
429
|
+
i++;
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
// Coalesce a run of add/remove hunks into a single replace for this region.
|
|
433
|
+
let removedLines = 0;
|
|
434
|
+
let addedText = '';
|
|
435
|
+
while (i < hunks.length && (hunks[i].added || hunks[i].removed)) {
|
|
436
|
+
if (hunks[i].removed) {
|
|
437
|
+
removedLines += hunks[i].count ?? 0;
|
|
438
|
+
}
|
|
439
|
+
if (hunks[i].added) {
|
|
440
|
+
addedText += hunks[i].value;
|
|
441
|
+
}
|
|
442
|
+
i++;
|
|
443
|
+
}
|
|
444
|
+
edits.push({
|
|
445
|
+
range: Range.create(oldLine, 0, oldLine + removedLines, 0),
|
|
446
|
+
newText: addedText
|
|
447
|
+
});
|
|
448
|
+
oldLine += removedLines;
|
|
449
|
+
}
|
|
450
|
+
return edits;
|
|
451
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import { type AstNode } from '@hydranium/langium';
|
|
11
|
+
import { asModelVersion, type ModelVersion, UNRECORDED_VERSION } from '@hydranium/protocol';
|
|
12
|
+
|
|
13
|
+
/** What {@link ModelLedger} holds for one root. */
|
|
14
|
+
export interface ModelRecord {
|
|
15
|
+
readonly version: ModelVersion;
|
|
16
|
+
/** For a root whose CST no longer is the text it describes: changed in place, or shed. */
|
|
17
|
+
readonly text?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The version of the text each root was parsed from, and that text where the
|
|
22
|
+
* root's CST does not hold it. Stores what it is told; the rest of the
|
|
23
|
+
* framework relies on these:
|
|
24
|
+
*
|
|
25
|
+
* - every workspace root is recorded through `VersionSyncService.modelProduced` when produced;
|
|
26
|
+
* - a version is recorded only for text the store held at that version, else `STALE_VERSION`;
|
|
27
|
+
* - the builder's placeholder for a file it has not parsed carries no version;
|
|
28
|
+
* - re-recording a root without text keeps the text recorded before.
|
|
29
|
+
*/
|
|
30
|
+
export interface ModelLedger {
|
|
31
|
+
record(root: AstNode, version: number, text?: string): void;
|
|
32
|
+
/** `UNRECORDED_VERSION`, which every write conflicts with, for a root nothing recorded. */
|
|
33
|
+
versionOf(root: AstNode): ModelVersion;
|
|
34
|
+
/** The recorded text, else the root's CST text; `undefined` for a root with neither. */
|
|
35
|
+
textOf(root: AstNode): string | undefined;
|
|
36
|
+
/** Mark `root`, registered before any parse, as no parse of any text, dropping its record. */
|
|
37
|
+
markPlaceholder(root: AstNode): void;
|
|
38
|
+
/** Keyed on the root, not its state: a rebuilt document is reset below `Parsed` but keeps its root. */
|
|
39
|
+
isPlaceholder(root: AstNode): boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class DefaultModelLedger implements ModelLedger {
|
|
43
|
+
protected readonly records = new WeakMap<AstNode, ModelRecord>();
|
|
44
|
+
protected readonly placeholders = new WeakSet<AstNode>();
|
|
45
|
+
|
|
46
|
+
record(root: AstNode, version: number, text?: string): void {
|
|
47
|
+
this.records.set(root, { version: asModelVersion(version), text: text ?? this.records.get(root)?.text });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
versionOf(root: AstNode): ModelVersion {
|
|
51
|
+
return this.records.get(root)?.version ?? UNRECORDED_VERSION;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
textOf(root: AstNode): string | undefined {
|
|
55
|
+
return this.records.get(root)?.text ?? root.$cstNode?.root.fullText;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
markPlaceholder(root: AstNode): void {
|
|
59
|
+
this.placeholders.add(root);
|
|
60
|
+
this.records.delete(root);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
isPlaceholder(root: AstNode): boolean {
|
|
64
|
+
return this.placeholders.has(root);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
|
|
10
|
+
import { type CanonicalUri, type TextVersion, textHash } from '@hydranium/protocol';
|
|
11
|
+
import { type TextDocument } from 'vscode-languageserver-textdocument';
|
|
12
|
+
|
|
13
|
+
/** What {@link TextLedger} holds for a document: where its version sequence stands, kept across closes and reopens. */
|
|
14
|
+
export interface TextRecord {
|
|
15
|
+
readonly version: TextVersion;
|
|
16
|
+
/** {@link textHash} of the text at that version. */
|
|
17
|
+
readonly hash: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Where each document's {@link TextVersion} sequence stands, and who authored
|
|
22
|
+
* each version; the text-side counterpart of `ModelLedger`.
|
|
23
|
+
*
|
|
24
|
+
* A record survives the document's release and is never pruned, not even when
|
|
25
|
+
* the file is deleted: a sequence that restarts lets a write based on the old
|
|
26
|
+
* text pass the base-version gate. Authors last only until the release.
|
|
27
|
+
*/
|
|
28
|
+
export interface TextLedger {
|
|
29
|
+
/**
|
|
30
|
+
* The version a first open of `key` with `text` starts at: the record's
|
|
31
|
+
* version when the text is unchanged, one step on when it changed;
|
|
32
|
+
* `undefined` without a record.
|
|
33
|
+
*/
|
|
34
|
+
openingVersion(key: CanonicalUri, text: string): TextVersion | undefined;
|
|
35
|
+
/** Keep where the sequence of the released `document` stands. */
|
|
36
|
+
record(key: CanonicalUri, document: TextDocument): void;
|
|
37
|
+
recordOf(key: CanonicalUri): TextRecord | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Text reached the closed document `key` outside the store's write paths.
|
|
40
|
+
* Steps the record iff `text` differs from it, and starts one at `0` when
|
|
41
|
+
* there is none.
|
|
42
|
+
*/
|
|
43
|
+
reconcile(key: CanonicalUri, text: string): TextVersion;
|
|
44
|
+
/** {@link textHash} of `document`'s text, taken once per version. */
|
|
45
|
+
hashOf(document: TextDocument): string;
|
|
46
|
+
setAuthor(key: CanonicalUri, version: TextVersion, author: string): void;
|
|
47
|
+
/** The author of `version`, or of the latest version when `version` is omitted. */
|
|
48
|
+
authorOf(key: CanonicalUri, version?: TextVersion): string | undefined;
|
|
49
|
+
clearAuthors(key: CanonicalUri): void;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class DefaultTextLedger implements TextLedger {
|
|
53
|
+
protected readonly records = new Map<CanonicalUri, TextRecord>();
|
|
54
|
+
protected readonly authors = new Map<CanonicalUri, string[]>();
|
|
55
|
+
protected readonly hashes = new WeakMap<TextDocument, { readonly version: number; readonly hash: string }>();
|
|
56
|
+
|
|
57
|
+
openingVersion(key: CanonicalUri, text: string): TextVersion | undefined {
|
|
58
|
+
const recorded = this.records.get(key);
|
|
59
|
+
if (recorded === undefined) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
return recorded.hash === textHash(text) ? recorded.version : recorded.version + 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
record(key: CanonicalUri, document: TextDocument): void {
|
|
66
|
+
this.records.set(key, { version: document.version, hash: this.hashOf(document) });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
recordOf(key: CanonicalUri): TextRecord | undefined {
|
|
70
|
+
return this.records.get(key);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
reconcile(key: CanonicalUri, text: string): TextVersion {
|
|
74
|
+
const hash = textHash(text);
|
|
75
|
+
const recorded = this.records.get(key);
|
|
76
|
+
if (recorded?.hash === hash) {
|
|
77
|
+
return recorded.version;
|
|
78
|
+
}
|
|
79
|
+
const version = recorded === undefined ? 0 : recorded.version + 1;
|
|
80
|
+
this.records.set(key, { version, hash });
|
|
81
|
+
return version;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
hashOf(document: TextDocument): string {
|
|
85
|
+
const taken = this.hashes.get(document);
|
|
86
|
+
if (taken?.version === document.version) {
|
|
87
|
+
return taken.hash;
|
|
88
|
+
}
|
|
89
|
+
const hash = textHash(document.getText());
|
|
90
|
+
this.hashes.set(document, { version: document.version, hash });
|
|
91
|
+
return hash;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
setAuthor(key: CanonicalUri, version: TextVersion, author: string): void {
|
|
95
|
+
let history = this.authors.get(key);
|
|
96
|
+
if (!history) {
|
|
97
|
+
history = [];
|
|
98
|
+
this.authors.set(key, history);
|
|
99
|
+
}
|
|
100
|
+
history[version] = author;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
authorOf(key: CanonicalUri, version?: TextVersion): string | undefined {
|
|
104
|
+
const history = this.authors.get(key);
|
|
105
|
+
// `!== undefined` so version 0 is not read as "latest".
|
|
106
|
+
return version !== undefined ? history?.[version] : history?.at(-1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
clearAuthors(key: CanonicalUri): void {
|
|
110
|
+
this.authors.delete(key);
|
|
111
|
+
}
|
|
112
|
+
}
|