@reqlan/language 1.4.0
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 +24 -0
- package/out/file-path-rewrite.d.ts +25 -0
- package/out/file-path-rewrite.js +56 -0
- package/out/file-path-rewrite.js.map +1 -0
- package/out/generated/ast.d.ts +1157 -0
- package/out/generated/ast.js +980 -0
- package/out/generated/ast.js.map +1 -0
- package/out/generated/grammar.d.ts +7 -0
- package/out/generated/grammar.js +3071 -0
- package/out/generated/grammar.js.map +1 -0
- package/out/generated/module.d.ts +20 -0
- package/out/generated/module.js +32 -0
- package/out/generated/module.js.map +1 -0
- package/out/index.d.ts +34 -0
- package/out/index.js +35 -0
- package/out/index.js.map +1 -0
- package/out/reqlan-attribute-catalog.d.ts +19 -0
- package/out/reqlan-attribute-catalog.js +87 -0
- package/out/reqlan-attribute-catalog.js.map +1 -0
- package/out/reqlan-code-action-provider.d.ts +55 -0
- package/out/reqlan-code-action-provider.js +269 -0
- package/out/reqlan-code-action-provider.js.map +1 -0
- package/out/reqlan-code-lens-provider.d.ts +13 -0
- package/out/reqlan-code-lens-provider.js +27 -0
- package/out/reqlan-code-lens-provider.js.map +1 -0
- package/out/reqlan-code-lens-settings.d.ts +34 -0
- package/out/reqlan-code-lens-settings.js +12 -0
- package/out/reqlan-code-lens-settings.js.map +1 -0
- package/out/reqlan-comment-resolver.d.ts +35 -0
- package/out/reqlan-comment-resolver.js +308 -0
- package/out/reqlan-comment-resolver.js.map +1 -0
- package/out/reqlan-completion-context.d.ts +46 -0
- package/out/reqlan-completion-context.js +244 -0
- package/out/reqlan-completion-context.js.map +1 -0
- package/out/reqlan-completion-provider.d.ts +41 -0
- package/out/reqlan-completion-provider.js +317 -0
- package/out/reqlan-completion-provider.js.map +1 -0
- package/out/reqlan-definition-provider.d.ts +31 -0
- package/out/reqlan-definition-provider.js +240 -0
- package/out/reqlan-definition-provider.js.map +1 -0
- package/out/reqlan-document-highlight-provider.d.ts +10 -0
- package/out/reqlan-document-highlight-provider.js +11 -0
- package/out/reqlan-document-highlight-provider.js.map +1 -0
- package/out/reqlan-document-link-provider.d.ts +14 -0
- package/out/reqlan-document-link-provider.js +24 -0
- package/out/reqlan-document-link-provider.js.map +1 -0
- package/out/reqlan-embedded-file-references.d.ts +11 -0
- package/out/reqlan-embedded-file-references.js +50 -0
- package/out/reqlan-embedded-file-references.js.map +1 -0
- package/out/reqlan-file-link-resolver.d.ts +44 -0
- package/out/reqlan-file-link-resolver.js +347 -0
- package/out/reqlan-file-link-resolver.js.map +1 -0
- package/out/reqlan-file-references.d.ts +15 -0
- package/out/reqlan-file-references.js +72 -0
- package/out/reqlan-file-references.js.map +1 -0
- package/out/reqlan-grammar-config.d.ts +5 -0
- package/out/reqlan-grammar-config.js +9 -0
- package/out/reqlan-grammar-config.js.map +1 -0
- package/out/reqlan-idea-reference-site.d.ts +14 -0
- package/out/reqlan-idea-reference-site.js +47 -0
- package/out/reqlan-idea-reference-site.js.map +1 -0
- package/out/reqlan-idea-summary.d.ts +6 -0
- package/out/reqlan-idea-summary.js +134 -0
- package/out/reqlan-idea-summary.js.map +1 -0
- package/out/reqlan-ignore-error.d.ts +10 -0
- package/out/reqlan-ignore-error.js +42 -0
- package/out/reqlan-ignore-error.js.map +1 -0
- package/out/reqlan-import-bindings.d.ts +12 -0
- package/out/reqlan-import-bindings.js +65 -0
- package/out/reqlan-import-bindings.js.map +1 -0
- package/out/reqlan-import-edits.d.ts +17 -0
- package/out/reqlan-import-edits.js +96 -0
- package/out/reqlan-import-edits.js.map +1 -0
- package/out/reqlan-imports.d.ts +22 -0
- package/out/reqlan-imports.js +61 -0
- package/out/reqlan-imports.js.map +1 -0
- package/out/reqlan-inbound-reference-inlay-label.d.ts +27 -0
- package/out/reqlan-inbound-reference-inlay-label.js +142 -0
- package/out/reqlan-inbound-reference-inlay-label.js.map +1 -0
- package/out/reqlan-inlay-hint-provider.d.ts +15 -0
- package/out/reqlan-inlay-hint-provider.js +54 -0
- package/out/reqlan-inlay-hint-provider.js.map +1 -0
- package/out/reqlan-inlay-hint-settings.d.ts +10 -0
- package/out/reqlan-inlay-hint-settings.js +10 -0
- package/out/reqlan-inlay-hint-settings.js.map +1 -0
- package/out/reqlan-linker.d.ts +26 -0
- package/out/reqlan-linker.js +83 -0
- package/out/reqlan-linker.js.map +1 -0
- package/out/reqlan-markdown-links.d.ts +28 -0
- package/out/reqlan-markdown-links.js +113 -0
- package/out/reqlan-markdown-links.js.map +1 -0
- package/out/reqlan-module.d.ts +41 -0
- package/out/reqlan-module.js +78 -0
- package/out/reqlan-module.js.map +1 -0
- package/out/reqlan-name-catalog.d.ts +23 -0
- package/out/reqlan-name-catalog.js +63 -0
- package/out/reqlan-name-catalog.js.map +1 -0
- package/out/reqlan-name-provider.d.ts +10 -0
- package/out/reqlan-name-provider.js +38 -0
- package/out/reqlan-name-provider.js.map +1 -0
- package/out/reqlan-namespace-import-links.d.ts +10 -0
- package/out/reqlan-namespace-import-links.js +69 -0
- package/out/reqlan-namespace-import-links.js.map +1 -0
- package/out/reqlan-path-completion.d.ts +50 -0
- package/out/reqlan-path-completion.js +304 -0
- package/out/reqlan-path-completion.js.map +1 -0
- package/out/reqlan-path-references.d.ts +5 -0
- package/out/reqlan-path-references.js +124 -0
- package/out/reqlan-path-references.js.map +1 -0
- package/out/reqlan-path-resolve.d.ts +81 -0
- package/out/reqlan-path-resolve.js +245 -0
- package/out/reqlan-path-resolve.js.map +1 -0
- package/out/reqlan-quoted-strings.d.ts +9 -0
- package/out/reqlan-quoted-strings.js +26 -0
- package/out/reqlan-quoted-strings.js.map +1 -0
- package/out/reqlan-reference-at-position.d.ts +20 -0
- package/out/reqlan-reference-at-position.js +89 -0
- package/out/reqlan-reference-at-position.js.map +1 -0
- package/out/reqlan-reference-code-lens.d.ts +32 -0
- package/out/reqlan-reference-code-lens.js +240 -0
- package/out/reqlan-reference-code-lens.js.map +1 -0
- package/out/reqlan-reference-search-site.d.ts +34 -0
- package/out/reqlan-reference-search-site.js +136 -0
- package/out/reqlan-reference-search-site.js.map +1 -0
- package/out/reqlan-references.d.ts +16 -0
- package/out/reqlan-references.js +51 -0
- package/out/reqlan-references.js.map +1 -0
- package/out/reqlan-scope.d.ts +25 -0
- package/out/reqlan-scope.js +259 -0
- package/out/reqlan-scope.js.map +1 -0
- package/out/reqlan-semantic-token-provider.d.ts +8 -0
- package/out/reqlan-semantic-token-provider.js +91 -0
- package/out/reqlan-semantic-token-provider.js.map +1 -0
- package/out/reqlan-token-builder.d.ts +12 -0
- package/out/reqlan-token-builder.js +459 -0
- package/out/reqlan-token-builder.js.map +1 -0
- package/out/reqlan-validator.d.ts +25 -0
- package/out/reqlan-validator.js +119 -0
- package/out/reqlan-validator.js.map +1 -0
- package/out/reqlan-workspace-attribute-catalog.d.ts +6 -0
- package/out/reqlan-workspace-attribute-catalog.js +54 -0
- package/out/reqlan-workspace-attribute-catalog.js.map +1 -0
- package/out/src/file-path-rewrite.d.ts +25 -0
- package/out/src/file-path-rewrite.js +56 -0
- package/out/src/file-path-rewrite.js.map +1 -0
- package/out/src/generated/ast.d.ts +1173 -0
- package/out/src/generated/ast.js +994 -0
- package/out/src/generated/ast.js.map +1 -0
- package/out/src/generated/grammar.d.ts +7 -0
- package/out/src/generated/grammar.js +3045 -0
- package/out/src/generated/grammar.js.map +1 -0
- package/out/src/generated/module.d.ts +20 -0
- package/out/src/generated/module.js +32 -0
- package/out/src/generated/module.js.map +1 -0
- package/out/src/index.d.ts +29 -0
- package/out/src/index.js +30 -0
- package/out/src/index.js.map +1 -0
- package/out/src/reqlan-attribute-catalog.d.ts +19 -0
- package/out/src/reqlan-attribute-catalog.js +87 -0
- package/out/src/reqlan-attribute-catalog.js.map +1 -0
- package/out/src/reqlan-code-action-provider.d.ts +34 -0
- package/out/src/reqlan-code-action-provider.js +206 -0
- package/out/src/reqlan-code-action-provider.js.map +1 -0
- package/out/src/reqlan-comment-resolver.d.ts +35 -0
- package/out/src/reqlan-comment-resolver.js +308 -0
- package/out/src/reqlan-comment-resolver.js.map +1 -0
- package/out/src/reqlan-completion-context.d.ts +46 -0
- package/out/src/reqlan-completion-context.js +244 -0
- package/out/src/reqlan-completion-context.js.map +1 -0
- package/out/src/reqlan-completion-provider.d.ts +41 -0
- package/out/src/reqlan-completion-provider.js +320 -0
- package/out/src/reqlan-completion-provider.js.map +1 -0
- package/out/src/reqlan-definition-provider.d.ts +31 -0
- package/out/src/reqlan-definition-provider.js +240 -0
- package/out/src/reqlan-definition-provider.js.map +1 -0
- package/out/src/reqlan-document-highlight-provider.d.ts +10 -0
- package/out/src/reqlan-document-highlight-provider.js +11 -0
- package/out/src/reqlan-document-highlight-provider.js.map +1 -0
- package/out/src/reqlan-document-link-provider.d.ts +14 -0
- package/out/src/reqlan-document-link-provider.js +24 -0
- package/out/src/reqlan-document-link-provider.js.map +1 -0
- package/out/src/reqlan-embedded-file-references.d.ts +11 -0
- package/out/src/reqlan-embedded-file-references.js +50 -0
- package/out/src/reqlan-embedded-file-references.js.map +1 -0
- package/out/src/reqlan-file-link-resolver.d.ts +44 -0
- package/out/src/reqlan-file-link-resolver.js +347 -0
- package/out/src/reqlan-file-link-resolver.js.map +1 -0
- package/out/src/reqlan-file-references.d.ts +15 -0
- package/out/src/reqlan-file-references.js +72 -0
- package/out/src/reqlan-file-references.js.map +1 -0
- package/out/src/reqlan-grammar-config.d.ts +5 -0
- package/out/src/reqlan-grammar-config.js +9 -0
- package/out/src/reqlan-grammar-config.js.map +1 -0
- package/out/src/reqlan-idea-summary.d.ts +6 -0
- package/out/src/reqlan-idea-summary.js +78 -0
- package/out/src/reqlan-idea-summary.js.map +1 -0
- package/out/src/reqlan-ignore-error.d.ts +10 -0
- package/out/src/reqlan-ignore-error.js +42 -0
- package/out/src/reqlan-ignore-error.js.map +1 -0
- package/out/src/reqlan-import-bindings.d.ts +12 -0
- package/out/src/reqlan-import-bindings.js +65 -0
- package/out/src/reqlan-import-bindings.js.map +1 -0
- package/out/src/reqlan-import-edits.d.ts +17 -0
- package/out/src/reqlan-import-edits.js +96 -0
- package/out/src/reqlan-import-edits.js.map +1 -0
- package/out/src/reqlan-imports.d.ts +22 -0
- package/out/src/reqlan-imports.js +61 -0
- package/out/src/reqlan-imports.js.map +1 -0
- package/out/src/reqlan-inbound-reference-inlay-label.d.ts +23 -0
- package/out/src/reqlan-inbound-reference-inlay-label.js +128 -0
- package/out/src/reqlan-inbound-reference-inlay-label.js.map +1 -0
- package/out/src/reqlan-inlay-hint-provider.d.ts +15 -0
- package/out/src/reqlan-inlay-hint-provider.js +54 -0
- package/out/src/reqlan-inlay-hint-provider.js.map +1 -0
- package/out/src/reqlan-inlay-hint-settings.d.ts +10 -0
- package/out/src/reqlan-inlay-hint-settings.js +10 -0
- package/out/src/reqlan-inlay-hint-settings.js.map +1 -0
- package/out/src/reqlan-linker.d.ts +26 -0
- package/out/src/reqlan-linker.js +86 -0
- package/out/src/reqlan-linker.js.map +1 -0
- package/out/src/reqlan-markdown-links.d.ts +28 -0
- package/out/src/reqlan-markdown-links.js +113 -0
- package/out/src/reqlan-markdown-links.js.map +1 -0
- package/out/src/reqlan-module.d.ts +41 -0
- package/out/src/reqlan-module.js +76 -0
- package/out/src/reqlan-module.js.map +1 -0
- package/out/src/reqlan-name-catalog.d.ts +23 -0
- package/out/src/reqlan-name-catalog.js +63 -0
- package/out/src/reqlan-name-catalog.js.map +1 -0
- package/out/src/reqlan-name-provider.d.ts +10 -0
- package/out/src/reqlan-name-provider.js +38 -0
- package/out/src/reqlan-name-provider.js.map +1 -0
- package/out/src/reqlan-namespace-import-links.d.ts +10 -0
- package/out/src/reqlan-namespace-import-links.js +81 -0
- package/out/src/reqlan-namespace-import-links.js.map +1 -0
- package/out/src/reqlan-path-completion.d.ts +50 -0
- package/out/src/reqlan-path-completion.js +304 -0
- package/out/src/reqlan-path-completion.js.map +1 -0
- package/out/src/reqlan-path-references.d.ts +5 -0
- package/out/src/reqlan-path-references.js +124 -0
- package/out/src/reqlan-path-references.js.map +1 -0
- package/out/src/reqlan-path-resolve.d.ts +59 -0
- package/out/src/reqlan-path-resolve.js +173 -0
- package/out/src/reqlan-path-resolve.js.map +1 -0
- package/out/src/reqlan-quoted-strings.d.ts +9 -0
- package/out/src/reqlan-quoted-strings.js +26 -0
- package/out/src/reqlan-quoted-strings.js.map +1 -0
- package/out/src/reqlan-reference-at-position.d.ts +20 -0
- package/out/src/reqlan-reference-at-position.js +89 -0
- package/out/src/reqlan-reference-at-position.js.map +1 -0
- package/out/src/reqlan-references.d.ts +16 -0
- package/out/src/reqlan-references.js +51 -0
- package/out/src/reqlan-references.js.map +1 -0
- package/out/src/reqlan-scope.d.ts +25 -0
- package/out/src/reqlan-scope.js +266 -0
- package/out/src/reqlan-scope.js.map +1 -0
- package/out/src/reqlan-semantic-token-provider.d.ts +8 -0
- package/out/src/reqlan-semantic-token-provider.js +97 -0
- package/out/src/reqlan-semantic-token-provider.js.map +1 -0
- package/out/src/reqlan-token-builder.d.ts +12 -0
- package/out/src/reqlan-token-builder.js +459 -0
- package/out/src/reqlan-token-builder.js.map +1 -0
- package/out/src/reqlan-validator.d.ts +25 -0
- package/out/src/reqlan-validator.js +119 -0
- package/out/src/reqlan-validator.js.map +1 -0
- package/out/src/reqlan-workspace-attribute-catalog.d.ts +6 -0
- package/out/src/reqlan-workspace-attribute-catalog.js +54 -0
- package/out/src/reqlan-workspace-attribute-catalog.js.map +1 -0
- package/out/test/code-actions.test.d.ts +1 -0
- package/out/test/code-actions.test.js +126 -0
- package/out/test/code-actions.test.js.map +1 -0
- package/out/test/comment-in-string.test.d.ts +1 -0
- package/out/test/comment-in-string.test.js +100 -0
- package/out/test/comment-in-string.test.js.map +1 -0
- package/out/test/completion.test.d.ts +1 -0
- package/out/test/completion.test.js +467 -0
- package/out/test/completion.test.js.map +1 -0
- package/out/test/file-path-rewrite.test.d.ts +1 -0
- package/out/test/file-path-rewrite.test.js +64 -0
- package/out/test/file-path-rewrite.test.js.map +1 -0
- package/out/test/ignore-error.test.d.ts +1 -0
- package/out/test/ignore-error.test.js +87 -0
- package/out/test/ignore-error.test.js.map +1 -0
- package/out/test/implicit-import-extension.test.d.ts +1 -0
- package/out/test/implicit-import-extension.test.js +203 -0
- package/out/test/implicit-import-extension.test.js.map +1 -0
- package/out/test/import-edits.test.d.ts +1 -0
- package/out/test/import-edits.test.js +20 -0
- package/out/test/import-edits.test.js.map +1 -0
- package/out/test/inlay-hints.test.d.ts +1 -0
- package/out/test/inlay-hints.test.js +238 -0
- package/out/test/inlay-hints.test.js.map +1 -0
- package/out/test/linking.test.d.ts +1 -0
- package/out/test/linking.test.js +754 -0
- package/out/test/linking.test.js.map +1 -0
- package/out/test/naked-strings.test.d.ts +1 -0
- package/out/test/naked-strings.test.js +50 -0
- package/out/test/naked-strings.test.js.map +1 -0
- package/out/test/parsing.test.d.ts +1 -0
- package/out/test/parsing.test.js +773 -0
- package/out/test/parsing.test.js.map +1 -0
- package/out/test/path-resolve.test.d.ts +1 -0
- package/out/test/path-resolve.test.js +88 -0
- package/out/test/path-resolve.test.js.map +1 -0
- package/out/test/references.test.d.ts +1 -0
- package/out/test/references.test.js +168 -0
- package/out/test/references.test.js.map +1 -0
- package/out/test/rqconfig.test.d.ts +1 -0
- package/out/test/rqconfig.test.js +275 -0
- package/out/test/rqconfig.test.js.map +1 -0
- package/out/test/test-requirement-refs.d.ts +8 -0
- package/out/test/test-requirement-refs.js +35 -0
- package/out/test/test-requirement-refs.js.map +1 -0
- package/out/test/testing.test.d.ts +1 -0
- package/out/test/testing.test.js +23 -0
- package/out/test/testing.test.js.map +1 -0
- package/out/test/validating.test.d.ts +1 -0
- package/out/test/validating.test.js +117 -0
- package/out/test/validating.test.js.map +1 -0
- package/out/tsconfig.tsbuildinfo +1 -0
- package/package.json +54 -0
- package/src/chevrotain.d.ts +8 -0
- package/src/file-path-rewrite.ts +96 -0
- package/src/generated/ast.ts +1481 -0
- package/src/generated/grammar.ts +3074 -0
- package/src/generated/module.ts +38 -0
- package/src/index.ts +34 -0
- package/src/reqlan-attribute-catalog.ts +100 -0
- package/src/reqlan-code-action-provider.ts +385 -0
- package/src/reqlan-code-lens-provider.ts +54 -0
- package/src/reqlan-code-lens-settings.ts +42 -0
- package/src/reqlan-comment-resolver.ts +372 -0
- package/src/reqlan-comment.langium +23 -0
- package/src/reqlan-completion-context.ts +330 -0
- package/src/reqlan-completion-provider.ts +400 -0
- package/src/reqlan-definition-provider.ts +319 -0
- package/src/reqlan-document-highlight-provider.ts +21 -0
- package/src/reqlan-document-link-provider.ts +45 -0
- package/src/reqlan-embedded-file-references.ts +72 -0
- package/src/reqlan-file-link-resolver.ts +485 -0
- package/src/reqlan-file-references.ts +84 -0
- package/src/reqlan-grammar-config.ts +14 -0
- package/src/reqlan-idea-reference-site.ts +74 -0
- package/src/reqlan-idea-summary.ts +162 -0
- package/src/reqlan-ignore-error.ts +50 -0
- package/src/reqlan-import-bindings.ts +87 -0
- package/src/reqlan-import-edits.ts +124 -0
- package/src/reqlan-imports.ts +115 -0
- package/src/reqlan-inbound-reference-inlay-label.ts +194 -0
- package/src/reqlan-inlay-hint-provider.ts +88 -0
- package/src/reqlan-inlay-hint-settings.ts +15 -0
- package/src/reqlan-linker.ts +108 -0
- package/src/reqlan-markdown-links.ts +136 -0
- package/src/reqlan-module.ts +104 -0
- package/src/reqlan-name-catalog.ts +81 -0
- package/src/reqlan-name-provider.ts +56 -0
- package/src/reqlan-namespace-import-links.ts +92 -0
- package/src/reqlan-path-completion.ts +420 -0
- package/src/reqlan-path-references.ts +140 -0
- package/src/reqlan-path-resolve.ts +346 -0
- package/src/reqlan-quoted-strings.ts +30 -0
- package/src/reqlan-reference-at-position.ts +154 -0
- package/src/reqlan-reference-code-lens.ts +323 -0
- package/src/reqlan-reference-search-site.ts +202 -0
- package/src/reqlan-references.ts +76 -0
- package/src/reqlan-scope.ts +312 -0
- package/src/reqlan-semantic-token-provider.ts +113 -0
- package/src/reqlan-token-builder.ts +492 -0
- package/src/reqlan-validator.ts +149 -0
- package/src/reqlan-workspace-attribute-catalog.ts +62 -0
- package/src/reqlan.langium +236 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classification labels and summary stats for reference CodeLens buttons.
|
|
3
|
+
* Click opens a reference card; navigation stays on document links / go-to-definition.
|
|
4
|
+
*/
|
|
5
|
+
import { AstUtils, GrammarUtils, URI, type AstNode } from 'langium';
|
|
6
|
+
import { Command, type CodeLens, type Range } from 'vscode-languageserver';
|
|
7
|
+
import { statSync } from 'node:fs';
|
|
8
|
+
import {
|
|
9
|
+
isBracketReference,
|
|
10
|
+
isFileReference,
|
|
11
|
+
isFileSymbolReference,
|
|
12
|
+
isIdea,
|
|
13
|
+
isIdeaSet,
|
|
14
|
+
isLocalReference,
|
|
15
|
+
isOneLinerIdea,
|
|
16
|
+
isQualifiedReference,
|
|
17
|
+
isWikiLink,
|
|
18
|
+
type IdeaDeclaration,
|
|
19
|
+
type IdeaSet
|
|
20
|
+
} from './generated/ast.js';
|
|
21
|
+
import {
|
|
22
|
+
collectInboundReferencers,
|
|
23
|
+
type ReferencedDeclaration
|
|
24
|
+
} from './reqlan-inbound-reference-inlay-label.js';
|
|
25
|
+
import {
|
|
26
|
+
listFolderFileNames,
|
|
27
|
+
resolveFileReferenceLink,
|
|
28
|
+
type ResolvedFileLink
|
|
29
|
+
} from './reqlan-file-link-resolver.js';
|
|
30
|
+
import {
|
|
31
|
+
isNamespaceImportOnlyReference,
|
|
32
|
+
resolveNamespaceImportReferenceLink
|
|
33
|
+
} from './reqlan-namespace-import-links.js';
|
|
34
|
+
import { pathResolveContextFromServices } from './reqlan-path-resolve.js';
|
|
35
|
+
import { referenceIdea } from './reqlan-references.js';
|
|
36
|
+
import { summarizeIdeaDeclaration, truncateSummary } from './reqlan-idea-summary.js';
|
|
37
|
+
import {
|
|
38
|
+
REQLAN_OPEN_REFERENCE_CODE_LENS_COMMAND,
|
|
39
|
+
type ReferenceCodeLensPayload
|
|
40
|
+
} from './reqlan-code-lens-settings.js';
|
|
41
|
+
import type { ReqlanServices } from './reqlan-module.js';
|
|
42
|
+
|
|
43
|
+
export type ReferenceCodeLensClassification =
|
|
44
|
+
| { kind: 'idea'; declaration: ReferencedDeclaration }
|
|
45
|
+
| { kind: 'reqlan-file'; link: ResolvedFileLink }
|
|
46
|
+
| { kind: 'file'; link: ResolvedFileLink; extension: string }
|
|
47
|
+
| { kind: 'folder'; link: ResolvedFileLink };
|
|
48
|
+
|
|
49
|
+
export function classifyReferenceForCodeLens(
|
|
50
|
+
services: ReqlanServices,
|
|
51
|
+
node: AstNode
|
|
52
|
+
): ReferenceCodeLensClassification | undefined {
|
|
53
|
+
if (!isBracketReference(node) && !isWikiLink(node)) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
const target = node.target;
|
|
57
|
+
if (isLocalReference(target) || isQualifiedReference(target)) {
|
|
58
|
+
if (isNamespaceImportOnlyReference(target)) {
|
|
59
|
+
const link = resolveNamespaceImportReferenceLink(
|
|
60
|
+
target,
|
|
61
|
+
services.shared.workspace.LangiumDocuments,
|
|
62
|
+
services.shared.workspace.FileSystemProvider,
|
|
63
|
+
pathResolveContextFromServices(services)
|
|
64
|
+
);
|
|
65
|
+
return classifyResolvedFileLink(link);
|
|
66
|
+
}
|
|
67
|
+
const ideaRef = referenceIdea(target);
|
|
68
|
+
if (ideaRef?.ref) {
|
|
69
|
+
return { kind: 'idea', declaration: ideaRef.ref };
|
|
70
|
+
}
|
|
71
|
+
if (isQualifiedReference(target) && target.ideaset?.ref) {
|
|
72
|
+
return { kind: 'idea', declaration: target.ideaset.ref };
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
if (isFileReference(target) || isFileSymbolReference(target)) {
|
|
77
|
+
const link = resolveFileReferenceLink(
|
|
78
|
+
target,
|
|
79
|
+
services.shared.workspace.LangiumDocuments,
|
|
80
|
+
services.shared.workspace.FileSystemProvider,
|
|
81
|
+
pathResolveContextFromServices(services)
|
|
82
|
+
);
|
|
83
|
+
if (isFileSymbolReference(target) && target.symbols.length > 0) {
|
|
84
|
+
const idea = resolveFileSymbolIdea(services, link, target.symbols[0]!);
|
|
85
|
+
if (idea) {
|
|
86
|
+
return { kind: 'idea', declaration: idea };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return classifyResolvedFileLink(link);
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function classifyResolvedFileLink(link: ResolvedFileLink | undefined): ReferenceCodeLensClassification | undefined {
|
|
95
|
+
if (!link || link.resolution === 'missing') {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
if (link.resolution === 'folder') {
|
|
99
|
+
return { kind: 'folder', link };
|
|
100
|
+
}
|
|
101
|
+
const extension = fileExtension(link.targetUri);
|
|
102
|
+
if (!extension || extension === 'rq') {
|
|
103
|
+
return { kind: 'reqlan-file', link };
|
|
104
|
+
}
|
|
105
|
+
return { kind: 'file', link, extension };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function resolveFileSymbolIdea(
|
|
109
|
+
services: ReqlanServices,
|
|
110
|
+
link: ResolvedFileLink | undefined,
|
|
111
|
+
symbolName: string
|
|
112
|
+
): IdeaDeclaration | IdeaSet | undefined {
|
|
113
|
+
if (!link || link.resolution !== 'file') {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const targetDocument = services.shared.workspace.LangiumDocuments.getDocument(URI.parse(link.targetUri));
|
|
117
|
+
if (!targetDocument) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
for (const candidate of AstUtils.streamAst(targetDocument.parseResult.value)) {
|
|
121
|
+
if ((isIdea(candidate) || isOneLinerIdea(candidate) || isIdeaSet(candidate)) && candidate.name === symbolName) {
|
|
122
|
+
return candidate;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function referenceCodeLensTitle(classification: ReferenceCodeLensClassification): string {
|
|
129
|
+
switch (classification.kind) {
|
|
130
|
+
case 'idea':
|
|
131
|
+
return 'open idea';
|
|
132
|
+
case 'reqlan-file':
|
|
133
|
+
return 'open reqlan file';
|
|
134
|
+
case 'file':
|
|
135
|
+
return `open ${classification.extension} file`;
|
|
136
|
+
case 'folder':
|
|
137
|
+
return 'open folder';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function buildReferenceCodeLens(
|
|
142
|
+
services: ReqlanServices,
|
|
143
|
+
node: AstNode,
|
|
144
|
+
classification: ReferenceCodeLensClassification
|
|
145
|
+
): CodeLens | undefined {
|
|
146
|
+
const range = codeLensRange(node);
|
|
147
|
+
if (!range) {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
const payload = payloadForClassification(services, classification);
|
|
151
|
+
if (!payload) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
const title = payload.classification;
|
|
155
|
+
const tooltip = payload.stats.length > 0
|
|
156
|
+
? `${payload.displayName} · ${payload.stats.join(' · ')}`
|
|
157
|
+
: payload.displayName;
|
|
158
|
+
const command = Command.create(title, REQLAN_OPEN_REFERENCE_CODE_LENS_COMMAND, payload);
|
|
159
|
+
command.tooltip = tooltip;
|
|
160
|
+
return { range, command };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function buildReferenceCodeLensStats(
|
|
164
|
+
services: ReqlanServices,
|
|
165
|
+
classification: ReferenceCodeLensClassification
|
|
166
|
+
): string[] {
|
|
167
|
+
const parts: string[] = [];
|
|
168
|
+
if (classification.kind === 'idea') {
|
|
169
|
+
const referencers = collectInboundReferencers(services, classification.declaration).length;
|
|
170
|
+
const references = countOutboundReferences(classification.declaration);
|
|
171
|
+
parts.push(`${referencers} referencer${referencers === 1 ? '' : 's'}`);
|
|
172
|
+
parts.push(`${references} reference${references === 1 ? '' : 's'}`);
|
|
173
|
+
const edited = fileLastEditedLabel(AstUtils.getDocument(classification.declaration).uri.toString());
|
|
174
|
+
if (edited) {
|
|
175
|
+
parts.push(`last edited ${edited}`);
|
|
176
|
+
}
|
|
177
|
+
return parts;
|
|
178
|
+
}
|
|
179
|
+
if (classification.kind === 'folder') {
|
|
180
|
+
const files = classification.link.folderFiles
|
|
181
|
+
?? listFolderFileNames(
|
|
182
|
+
services.shared.workspace.FileSystemProvider,
|
|
183
|
+
URI.parse(classification.link.targetUri)
|
|
184
|
+
);
|
|
185
|
+
parts.push(`${files.length} file${files.length === 1 ? '' : 's'}`);
|
|
186
|
+
return parts;
|
|
187
|
+
}
|
|
188
|
+
const edited = fileLastEditedLabel(classification.link.targetUri);
|
|
189
|
+
if (edited) {
|
|
190
|
+
parts.push(`last edited ${edited}`);
|
|
191
|
+
}
|
|
192
|
+
if (classification.kind === 'reqlan-file') {
|
|
193
|
+
const targetDocument = services.shared.workspace.LangiumDocuments.getDocument(
|
|
194
|
+
URI.parse(classification.link.targetUri)
|
|
195
|
+
);
|
|
196
|
+
if (targetDocument) {
|
|
197
|
+
let ideaCount = 0;
|
|
198
|
+
for (const candidate of AstUtils.streamAst(targetDocument.parseResult.value)) {
|
|
199
|
+
if (isIdea(candidate) || isOneLinerIdea(candidate) || isIdeaSet(candidate)) {
|
|
200
|
+
ideaCount++;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
parts.push(`${ideaCount} idea${ideaCount === 1 ? '' : 's'}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return parts;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** @deprecated Prefer {@link buildReferenceCodeLensStats} — kept for existing tests. */
|
|
210
|
+
export function buildReferenceCodeLensTooltip(
|
|
211
|
+
services: ReqlanServices,
|
|
212
|
+
classification: ReferenceCodeLensClassification
|
|
213
|
+
): string | undefined {
|
|
214
|
+
const parts = buildReferenceCodeLensStats(services, classification);
|
|
215
|
+
return parts.length > 0 ? parts.join(' · ') : undefined;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function countOutboundReferences(declaration: ReferencedDeclaration): number {
|
|
219
|
+
let count = 0;
|
|
220
|
+
for (const node of AstUtils.streamAst(declaration)) {
|
|
221
|
+
if (isBracketReference(node) || isWikiLink(node)) {
|
|
222
|
+
count++;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return count;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function fileExtension(targetUri: string): string | undefined {
|
|
229
|
+
const path = URI.parse(targetUri).path;
|
|
230
|
+
const slash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
|
|
231
|
+
const base = slash >= 0 ? path.slice(slash + 1) : path;
|
|
232
|
+
const dot = base.lastIndexOf('.');
|
|
233
|
+
if (dot <= 0 || dot === base.length - 1) {
|
|
234
|
+
return undefined;
|
|
235
|
+
}
|
|
236
|
+
return base.slice(dot + 1).toLowerCase();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export function fileLastEditedLabel(targetUri: string): string | undefined {
|
|
240
|
+
try {
|
|
241
|
+
const uri = URI.parse(targetUri);
|
|
242
|
+
if (uri.scheme !== 'file') {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
const mtime = statSync(uri.fsPath).mtime;
|
|
246
|
+
return mtime.toISOString().slice(0, 10);
|
|
247
|
+
} catch {
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function displayNameForUri(targetUri: string): string {
|
|
253
|
+
const path = URI.parse(targetUri).path;
|
|
254
|
+
const slash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
|
|
255
|
+
return slash >= 0 ? path.slice(slash + 1) : path;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function payloadForClassification(
|
|
259
|
+
services: ReqlanServices,
|
|
260
|
+
classification: ReferenceCodeLensClassification
|
|
261
|
+
): ReferenceCodeLensPayload | undefined {
|
|
262
|
+
const classificationLabel = referenceCodeLensTitle(classification);
|
|
263
|
+
const stats = buildReferenceCodeLensStats(services, classification);
|
|
264
|
+
|
|
265
|
+
if (classification.kind === 'idea') {
|
|
266
|
+
const declaration = classification.declaration;
|
|
267
|
+
const nameNode = GrammarUtils.findNodeForProperty(declaration.$cstNode, 'name');
|
|
268
|
+
const document = AstUtils.getDocument(declaration);
|
|
269
|
+
const summary = isIdea(declaration) || isOneLinerIdea(declaration)
|
|
270
|
+
? truncateSummary(summarizeIdeaDeclaration(declaration), 240)
|
|
271
|
+
: undefined;
|
|
272
|
+
return {
|
|
273
|
+
kind: 'idea',
|
|
274
|
+
classification: classificationLabel,
|
|
275
|
+
displayName: declaration.name,
|
|
276
|
+
targetUri: document.uri.toString(),
|
|
277
|
+
line: nameNode?.range.start.line ?? 0,
|
|
278
|
+
character: nameNode?.range.start.character ?? 0,
|
|
279
|
+
summary: summary || undefined,
|
|
280
|
+
stats
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const link = classification.link;
|
|
285
|
+
const displayName = displayNameForUri(link.targetUri);
|
|
286
|
+
if (classification.kind === 'folder') {
|
|
287
|
+
const folderFiles = link.folderFiles
|
|
288
|
+
?? listFolderFileNames(
|
|
289
|
+
services.shared.workspace.FileSystemProvider,
|
|
290
|
+
URI.parse(link.targetUri)
|
|
291
|
+
);
|
|
292
|
+
return {
|
|
293
|
+
kind: 'folder',
|
|
294
|
+
classification: classificationLabel,
|
|
295
|
+
displayName,
|
|
296
|
+
targetUri: link.targetUri,
|
|
297
|
+
folderFiles,
|
|
298
|
+
summary: folderFiles.slice(0, 8).join(', ') + (folderFiles.length > 8 ? '…' : ''),
|
|
299
|
+
stats
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
kind: classification.kind === 'reqlan-file' ? 'reqlan-file' : 'file',
|
|
304
|
+
classification: classificationLabel,
|
|
305
|
+
displayName,
|
|
306
|
+
targetUri: link.targetUri,
|
|
307
|
+
line: link.targetRange?.start.line ?? 0,
|
|
308
|
+
character: link.targetRange?.start.character ?? 0,
|
|
309
|
+
extension: classification.kind === 'file' ? classification.extension : undefined,
|
|
310
|
+
stats
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function codeLensRange(node: AstNode): Range | undefined {
|
|
315
|
+
const cst = node.$cstNode;
|
|
316
|
+
if (!cst) {
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
start: { line: cst.range.start.line, character: 0 },
|
|
321
|
+
end: cst.range.end
|
|
322
|
+
};
|
|
323
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locate places where a selection or word can become a [reference],
|
|
3
|
+
* and extract surrounding idea text for the search modal preview.
|
|
4
|
+
* rq:["../../../reqlan rq/extension/features-commands.rq".search_code_actions]
|
|
5
|
+
*/
|
|
6
|
+
import type { LangiumDocument } from 'langium';
|
|
7
|
+
import type { Position, Range } from 'vscode-languageserver';
|
|
8
|
+
import {
|
|
9
|
+
findContainingIdea,
|
|
10
|
+
isInMainDescriptionProse
|
|
11
|
+
} from './reqlan-completion-context.js';
|
|
12
|
+
import {
|
|
13
|
+
findIdeaReferenceAtPosition,
|
|
14
|
+
type IdeaReferenceSite
|
|
15
|
+
} from './reqlan-idea-reference-site.js';
|
|
16
|
+
import { isIdea, isOneLinerIdea, type IdeaDeclaration } from './generated/ast.js';
|
|
17
|
+
|
|
18
|
+
export type ReferenceSearchMode = 'replace' | 'wrap';
|
|
19
|
+
|
|
20
|
+
export interface ReferenceSearchContext {
|
|
21
|
+
ideaName: string;
|
|
22
|
+
/** Text before the target within the idea source. */
|
|
23
|
+
before: string;
|
|
24
|
+
/** Selected / reference text that will become (or already is) the reference. */
|
|
25
|
+
target: string;
|
|
26
|
+
/** Text after the target within the idea source. */
|
|
27
|
+
after: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ReferenceSearchSite {
|
|
31
|
+
refText: string;
|
|
32
|
+
range: Range;
|
|
33
|
+
mode: ReferenceSearchMode;
|
|
34
|
+
kind: 'bracket' | 'wikilink' | 'prose';
|
|
35
|
+
context?: ReferenceSearchContext;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Prefer an existing [reference]/[[wikilink]] under the cursor; otherwise a
|
|
40
|
+
* selection or word in idea-body prose that can be wrapped as `[name]`.
|
|
41
|
+
*/
|
|
42
|
+
export function findReferenceSearchSite(
|
|
43
|
+
document: LangiumDocument,
|
|
44
|
+
range: Range
|
|
45
|
+
): ReferenceSearchSite | undefined {
|
|
46
|
+
const existing = findIdeaReferenceAtPosition(document, range.start);
|
|
47
|
+
if (existing) {
|
|
48
|
+
return siteFromExistingReference(document, existing);
|
|
49
|
+
}
|
|
50
|
+
return findWrapSite(document, range);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function siteFromExistingReference(
|
|
54
|
+
document: LangiumDocument,
|
|
55
|
+
existing: IdeaReferenceSite
|
|
56
|
+
): ReferenceSearchSite {
|
|
57
|
+
return {
|
|
58
|
+
refText: existing.refText,
|
|
59
|
+
range: existing.range,
|
|
60
|
+
mode: 'replace',
|
|
61
|
+
kind: existing.kind,
|
|
62
|
+
context: buildContextForRange(document, existing.range)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function findWrapSite(document: LangiumDocument, range: Range): ReferenceSearchSite | undefined {
|
|
67
|
+
const rawRange = isEmptyRange(range)
|
|
68
|
+
? expandToWordAtPosition(document, range.start)
|
|
69
|
+
: normalizeForwardRange(range);
|
|
70
|
+
const wrapRange = rawRange ? trimRangeWhitespace(document, rawRange) : undefined;
|
|
71
|
+
if (!wrapRange || isEmptyRange(wrapRange)) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Both ends must sit in idea-body prose (not imports, attribute keys, refs, etc.)
|
|
76
|
+
const endProbe = document.textDocument.positionAt(
|
|
77
|
+
Math.max(
|
|
78
|
+
document.textDocument.offsetAt(wrapRange.start),
|
|
79
|
+
document.textDocument.offsetAt(wrapRange.end) - 1
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
if (!isAppropriateWrapLocation(document, wrapRange.start)
|
|
83
|
+
|| !isAppropriateWrapLocation(document, endProbe)) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Keep wrap inside a single idea
|
|
88
|
+
const idea = findContainingIdea(document, wrapRange.start);
|
|
89
|
+
if (!idea || findContainingIdea(document, wrapRange.end) !== idea) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const refText = document.textDocument.getText(wrapRange).trim();
|
|
94
|
+
if (!refText || /\n/.test(refText)) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
// Avoid wrapping text that is already bracket-wrapped
|
|
98
|
+
if (/^\[.*\]$/.test(refText) || /^\[\[.*\]\]$/.test(refText)) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
refText,
|
|
104
|
+
range: wrapRange,
|
|
105
|
+
mode: 'wrap',
|
|
106
|
+
kind: 'prose',
|
|
107
|
+
context: buildContextForRange(document, wrapRange, idea)
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function isAppropriateWrapLocation(document: LangiumDocument, position: Position): boolean {
|
|
112
|
+
return isInMainDescriptionProse(document, position);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function buildContextForRange(
|
|
116
|
+
document: LangiumDocument,
|
|
117
|
+
range: Range,
|
|
118
|
+
idea?: IdeaDeclaration
|
|
119
|
+
): ReferenceSearchContext | undefined {
|
|
120
|
+
const containing = idea ?? findContainingIdea(document, range.start);
|
|
121
|
+
if (!containing?.$cstNode) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
const ideaRange = containing.$cstNode.range;
|
|
125
|
+
const ideaText = document.textDocument.getText(ideaRange);
|
|
126
|
+
const ideaStart = document.textDocument.offsetAt(ideaRange.start);
|
|
127
|
+
const targetStart = document.textDocument.offsetAt(range.start) - ideaStart;
|
|
128
|
+
const targetEnd = document.textDocument.offsetAt(range.end) - ideaStart;
|
|
129
|
+
if (targetStart < 0 || targetEnd > ideaText.length || targetStart > targetEnd) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
ideaName: containing.name,
|
|
134
|
+
before: ideaText.slice(0, targetStart),
|
|
135
|
+
target: ideaText.slice(targetStart, targetEnd),
|
|
136
|
+
after: ideaText.slice(targetEnd)
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function expandToWordAtPosition(
|
|
141
|
+
document: LangiumDocument,
|
|
142
|
+
position: Position
|
|
143
|
+
): Range | undefined {
|
|
144
|
+
const line = document.textDocument.getText({
|
|
145
|
+
start: { line: position.line, character: 0 },
|
|
146
|
+
end: { line: position.line + 1, character: 0 }
|
|
147
|
+
});
|
|
148
|
+
// Strip trailing newline for indexing
|
|
149
|
+
const lineText = line.replace(/\r?\n$/, '');
|
|
150
|
+
if (position.character > lineText.length) {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
const isWord = (ch: string | undefined) => !!ch && /[A-Za-z0-9_]/.test(ch);
|
|
154
|
+
let start = position.character;
|
|
155
|
+
let end = position.character;
|
|
156
|
+
while (start > 0 && isWord(lineText[start - 1])) {
|
|
157
|
+
start -= 1;
|
|
158
|
+
}
|
|
159
|
+
while (end < lineText.length && isWord(lineText[end])) {
|
|
160
|
+
end += 1;
|
|
161
|
+
}
|
|
162
|
+
if (start === end) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
start: { line: position.line, character: start },
|
|
167
|
+
end: { line: position.line, character: end }
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function trimRangeWhitespace(document: LangiumDocument, range: Range): Range | undefined {
|
|
172
|
+
const text = document.textDocument.getText(range);
|
|
173
|
+
const lead = /^\s*/.exec(text)?.[0].length ?? 0;
|
|
174
|
+
const trail = /\s*$/.exec(text)?.[0].length ?? 0;
|
|
175
|
+
if (lead + trail >= text.length) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
const startOffset = document.textDocument.offsetAt(range.start) + lead;
|
|
179
|
+
const endOffset = document.textDocument.offsetAt(range.end) - trail;
|
|
180
|
+
return {
|
|
181
|
+
start: document.textDocument.positionAt(startOffset),
|
|
182
|
+
end: document.textDocument.positionAt(endOffset)
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function isEmptyRange(range: Range): boolean {
|
|
187
|
+
return range.start.line === range.end.line && range.start.character === range.end.character;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function normalizeForwardRange(range: Range): Range {
|
|
191
|
+
if (
|
|
192
|
+
range.start.line > range.end.line
|
|
193
|
+
|| (range.start.line === range.end.line && range.start.character > range.end.character)
|
|
194
|
+
) {
|
|
195
|
+
return { start: range.end, end: range.start };
|
|
196
|
+
}
|
|
197
|
+
return range;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function isBlockOrOneLinerIdea(node: unknown): node is IdeaDeclaration {
|
|
201
|
+
return isIdea(node) || isOneLinerIdea(node);
|
|
202
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for the reference target union types.
|
|
3
|
+
*/
|
|
4
|
+
import type { Reference } from 'langium';
|
|
5
|
+
import {
|
|
6
|
+
isFileReference,
|
|
7
|
+
isFileSymbolReference,
|
|
8
|
+
isLocalReference,
|
|
9
|
+
isQualifiedReference,
|
|
10
|
+
type IdeaDeclaration,
|
|
11
|
+
type Import,
|
|
12
|
+
type QualifiedReference,
|
|
13
|
+
type ReferenceTarget
|
|
14
|
+
} from './generated/ast.js';
|
|
15
|
+
import { unquoteReqlanString } from './reqlan-quoted-strings.js';
|
|
16
|
+
|
|
17
|
+
export function referenceImport(target: ReferenceTarget): Reference<Import> | undefined {
|
|
18
|
+
if (isQualifiedReference(target)) {
|
|
19
|
+
return target.path?.ref || target.qualifier?.ref ? (target.path ?? target.qualifier) : undefined;
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function referenceIdea(target: ReferenceTarget): Reference<IdeaDeclaration> | undefined {
|
|
25
|
+
if (isQualifiedReference(target) || isLocalReference(target)) {
|
|
26
|
+
return target.idea;
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function referenceFilePath(target: ReferenceTarget): string | undefined {
|
|
32
|
+
if (isFileReference(target) || isFileSymbolReference(target)) {
|
|
33
|
+
return target.file;
|
|
34
|
+
}
|
|
35
|
+
if (isQualifiedReference(target)) {
|
|
36
|
+
return qualifiedReferenceImportPath(target);
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function qualifiedReferenceImportPath(reference: QualifiedReference): string | undefined {
|
|
42
|
+
if (reference.qualifier?.ref) {
|
|
43
|
+
return reference.qualifier.ref.path;
|
|
44
|
+
}
|
|
45
|
+
if (reference.path?.ref) {
|
|
46
|
+
return reference.path.ref.path;
|
|
47
|
+
}
|
|
48
|
+
if (reference.path?.$refText) {
|
|
49
|
+
return unquoteReqlanString(reference.path.$refText);
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function isAnonymousQualifiedReference(reference: QualifiedReference): boolean {
|
|
55
|
+
return reference.path !== undefined && reference.path.ref === undefined && reference.qualifier === undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { unquoteReqlanString } from './reqlan-quoted-strings.js';
|
|
59
|
+
|
|
60
|
+
export interface ParsedMarkdownLink {
|
|
61
|
+
label: string;
|
|
62
|
+
target: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const MARKDOWN_LINK_PATTERN = /^\[([^\]]+)\]\(([^)]+)\)$/;
|
|
66
|
+
|
|
67
|
+
export function parseMarkdownLink(raw: string): ParsedMarkdownLink | undefined {
|
|
68
|
+
const match = MARKDOWN_LINK_PATTERN.exec(raw);
|
|
69
|
+
if (!match) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
label: match[1]!,
|
|
74
|
+
target: match[2]!
|
|
75
|
+
};
|
|
76
|
+
}
|