mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-13 20:15:20 +00:00
Minor simplification of sourcekit_lsp.py, added sleeping at startup
This commit is contained in:
1 parent
5236ffe2b6
commit
6d28c7d722
2 files changed
+125
-342
No files matched your search
@@ -3,17 +3,16 @@ import os
|
|||||||
import pathlib
|
import pathlib
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
from overrides import override
|
from overrides import override
|
||||||
|
|
||||||
from solidlsp.ls import SolidLanguageServer
|
from solidlsp.ls import SolidLanguageServer
|
||||||
from solidlsp.ls_config import LanguageServerConfig
|
from solidlsp.ls_config import LanguageServerConfig
|
||||||
from solidlsp.ls_logger import LanguageServerLogger
|
from solidlsp.ls_logger import LanguageServerLogger
|
||||||
from solidlsp.lsp_protocol_handler import lsp_types
|
|
||||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||||
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
|
||||||
from solidlsp.settings import SolidLSPSettings
|
from solidlsp.settings import SolidLSPSettings
|
||||||
from solidlsp.lsp_protocol_handler import lsp_types as LSPTypes
|
|
||||||
|
|
||||||
|
|
||||||
class SourceKitLSP(SolidLanguageServer):
|
class SourceKitLSP(SolidLanguageServer):
|
||||||
@@ -31,53 +30,25 @@ class SourceKitLSP(SolidLanguageServer):
|
|||||||
return super().is_ignored_dirname(dirname) or dirname in [".build", ".swiftpm", "node_modules", "dist", "build"]
|
return super().is_ignored_dirname(dirname) or dirname in [".build", ".swiftpm", "node_modules", "dist", "build"]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_swift_version():
|
def _get_sourcekit_lsp_version() -> str:
|
||||||
"""Get the installed Swift version or None if not found."""
|
"""Get the installed sourcekit-lsp version or raise error if sourcekit was not found."""
|
||||||
try:
|
|
||||||
result = subprocess.run(["swift", "--version"], capture_output=True, text=True, check=False)
|
|
||||||
if result.returncode == 0:
|
|
||||||
return result.stdout.strip()
|
|
||||||
except FileNotFoundError:
|
|
||||||
return None
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_sourcekit_lsp_version():
|
|
||||||
"""Get the installed sourcekit-lsp version or None if not found."""
|
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(["sourcekit-lsp", "-h"], capture_output=True, text=True, check=False)
|
result = subprocess.run(["sourcekit-lsp", "-h"], capture_output=True, text=True, check=False)
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
return result.stdout.strip()
|
return result.stdout.strip()
|
||||||
except FileNotFoundError:
|
else:
|
||||||
return None
|
raise Exception(f"`sourcekit-lsp -h` resulted in: {result}")
|
||||||
return None
|
except Exception as e:
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _setup_runtime_dependency():
|
|
||||||
"""
|
|
||||||
Check if required Swift runtime dependencies are available.
|
|
||||||
Raises RuntimeError with helpful message if dependencies are missing.
|
|
||||||
"""
|
|
||||||
swift_version = SourceKitLSP._get_swift_version()
|
|
||||||
if not swift_version:
|
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Swift is not installed. Please install Swift from https://swift.org/download/ and make sure it is added to your PATH."
|
"Could not find sourcekit-lsp, please install it as described in https://github.com/apple/sourcekit-lsp#installation"
|
||||||
)
|
"And make sure it is available on your PATH."
|
||||||
|
) from e
|
||||||
sourcekit_lsp_version = SourceKitLSP._get_sourcekit_lsp_version()
|
|
||||||
if not sourcekit_lsp_version:
|
|
||||||
raise RuntimeError(
|
|
||||||
"Found a Swift version but sourcekit-lsp is not installed.\n"
|
|
||||||
"Please install sourcekit-lsp as described in https://github.com/apple/sourcekit-lsp#installation\n\n"
|
|
||||||
"After installation, make sure it is added to your PATH."
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
self, config: LanguageServerConfig, logger: LanguageServerLogger, repository_root_path: str, solidlsp_settings: SolidLSPSettings
|
||||||
):
|
):
|
||||||
self._setup_runtime_dependency()
|
sourcekit_version = self._get_sourcekit_lsp_version()
|
||||||
|
logger.log(f"Starting sourcekit lsp with version: {sourcekit_version}", logging.INFO)
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
config,
|
config,
|
||||||
@@ -96,40 +67,25 @@ class SourceKitLSP(SolidLanguageServer):
|
|||||||
Returns the initialize params for the Swift Language Server.
|
Returns the initialize params for the Swift Language Server.
|
||||||
"""
|
"""
|
||||||
root_uri = pathlib.Path(repository_absolute_path).as_uri()
|
root_uri = pathlib.Path(repository_absolute_path).as_uri()
|
||||||
|
|
||||||
initialize_params = {
|
initialize_params = {
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"general": {
|
"general": {
|
||||||
"markdown": {
|
"markdown": {"parser": "marked", "version": "1.1.0"},
|
||||||
"parser": "marked",
|
"positionEncodings": ["utf-16"],
|
||||||
"version": "1.1.0"
|
"regularExpressions": {"engine": "ECMAScript", "version": "ES2020"},
|
||||||
},
|
|
||||||
"positionEncodings": [
|
|
||||||
"utf-16"
|
|
||||||
],
|
|
||||||
"regularExpressions": {
|
|
||||||
"engine": "ECMAScript",
|
|
||||||
"version": "ES2020"
|
|
||||||
},
|
|
||||||
"staleRequestSupport": {
|
"staleRequestSupport": {
|
||||||
"cancel": True,
|
"cancel": True,
|
||||||
"retryOnContentModified": [
|
"retryOnContentModified": [
|
||||||
"textDocument/semanticTokens/full",
|
"textDocument/semanticTokens/full",
|
||||||
"textDocument/semanticTokens/range",
|
"textDocument/semanticTokens/range",
|
||||||
"textDocument/semanticTokens/full/delta"
|
"textDocument/semanticTokens/full/delta",
|
||||||
]
|
],
|
||||||
}
|
|
||||||
},
|
|
||||||
"notebookDocument": {
|
|
||||||
"synchronization": {
|
|
||||||
"dynamicRegistration": True,
|
|
||||||
"executionSummarySupport": True
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"textDocument": {
|
|
||||||
"callHierarchy": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
"notebookDocument": {"synchronization": {"dynamicRegistration": True, "executionSummarySupport": True}},
|
||||||
|
"textDocument": {
|
||||||
|
"callHierarchy": {"dynamicRegistration": True},
|
||||||
"codeAction": {
|
"codeAction": {
|
||||||
"codeActionLiteralSupport": {
|
"codeActionLiteralSupport": {
|
||||||
"codeActionKind": {
|
"codeActionKind": {
|
||||||
@@ -141,7 +97,7 @@ class SourceKitLSP(SolidLanguageServer):
|
|||||||
"refactor.inline",
|
"refactor.inline",
|
||||||
"refactor.rewrite",
|
"refactor.rewrite",
|
||||||
"source",
|
"source",
|
||||||
"source.organizeImports"
|
"source.organizeImports",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -150,193 +106,85 @@ class SourceKitLSP(SolidLanguageServer):
|
|||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"honorsChangeAnnotations": True,
|
"honorsChangeAnnotations": True,
|
||||||
"isPreferredSupport": True,
|
"isPreferredSupport": True,
|
||||||
"resolveSupport": {
|
"resolveSupport": {"properties": ["edit"]},
|
||||||
"properties": [
|
|
||||||
"edit"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"codeLens": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
|
||||||
"colorProvider": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
},
|
||||||
|
"codeLens": {"dynamicRegistration": True},
|
||||||
|
"colorProvider": {"dynamicRegistration": True},
|
||||||
"completion": {
|
"completion": {
|
||||||
"completionItem": {
|
"completionItem": {
|
||||||
"commitCharactersSupport": True,
|
"commitCharactersSupport": True,
|
||||||
"deprecatedSupport": True,
|
"deprecatedSupport": True,
|
||||||
"documentationFormat": [
|
"documentationFormat": ["markdown", "plaintext"],
|
||||||
"markdown",
|
|
||||||
"plaintext"
|
|
||||||
],
|
|
||||||
"insertReplaceSupport": True,
|
"insertReplaceSupport": True,
|
||||||
"insertTextModeSupport": {
|
"insertTextModeSupport": {"valueSet": [1, 2]},
|
||||||
"valueSet": [
|
|
||||||
1,
|
|
||||||
2
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"labelDetailsSupport": True,
|
"labelDetailsSupport": True,
|
||||||
"preselectSupport": True,
|
"preselectSupport": True,
|
||||||
"resolveSupport": {
|
"resolveSupport": {"properties": ["documentation", "detail", "additionalTextEdits"]},
|
||||||
"properties": [
|
|
||||||
"documentation",
|
|
||||||
"detail",
|
|
||||||
"additionalTextEdits"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"snippetSupport": True,
|
"snippetSupport": True,
|
||||||
"tagSupport": {
|
"tagSupport": {"valueSet": [1]},
|
||||||
"valueSet": [
|
|
||||||
1
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"completionItemKind": {
|
"completionItemKind": {
|
||||||
"valueSet": [
|
"valueSet": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"completionList": {
|
|
||||||
"itemDefaults": [
|
|
||||||
"commitCharacters",
|
|
||||||
"editRange",
|
|
||||||
"insertTextFormat",
|
|
||||||
"insertTextMode",
|
|
||||||
"data"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
|
"completionList": {"itemDefaults": ["commitCharacters", "editRange", "insertTextFormat", "insertTextMode", "data"]},
|
||||||
"contextSupport": True,
|
"contextSupport": True,
|
||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"insertTextMode": 2
|
"insertTextMode": 2,
|
||||||
},
|
|
||||||
"declaration": {
|
|
||||||
"dynamicRegistration": True,
|
|
||||||
"linkSupport": True
|
|
||||||
},
|
|
||||||
"definition": {
|
|
||||||
"dynamicRegistration": True,
|
|
||||||
"linkSupport": True
|
|
||||||
},
|
|
||||||
"diagnostic": {
|
|
||||||
"dynamicRegistration": True,
|
|
||||||
"relatedDocumentSupport": False
|
|
||||||
},
|
|
||||||
"documentHighlight": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
|
||||||
"documentLink": {
|
|
||||||
"dynamicRegistration": True,
|
|
||||||
"tooltipSupport": True
|
|
||||||
},
|
},
|
||||||
|
"declaration": {"dynamicRegistration": True, "linkSupport": True},
|
||||||
|
"definition": {"dynamicRegistration": True, "linkSupport": True},
|
||||||
|
"diagnostic": {"dynamicRegistration": True, "relatedDocumentSupport": False},
|
||||||
|
"documentHighlight": {"dynamicRegistration": True},
|
||||||
|
"documentLink": {"dynamicRegistration": True, "tooltipSupport": True},
|
||||||
"documentSymbol": {
|
"documentSymbol": {
|
||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"hierarchicalDocumentSymbolSupport": True,
|
"hierarchicalDocumentSymbolSupport": True,
|
||||||
"labelSupport": True,
|
"labelSupport": True,
|
||||||
"symbolKind": {
|
"symbolKind": {
|
||||||
"valueSet": [
|
"valueSet": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tagSupport": {
|
"tagSupport": {"valueSet": [1]},
|
||||||
"valueSet": [
|
|
||||||
1
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"foldingRange": {
|
"foldingRange": {
|
||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"foldingRange": {
|
"foldingRange": {"collapsedText": False},
|
||||||
"collapsedText": False
|
"foldingRangeKind": {"valueSet": ["comment", "imports", "region"]},
|
||||||
},
|
|
||||||
"foldingRangeKind": {
|
|
||||||
"valueSet": [
|
|
||||||
"comment",
|
|
||||||
"imports",
|
|
||||||
"region"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lineFoldingOnly": True,
|
"lineFoldingOnly": True,
|
||||||
"rangeLimit": 5000
|
"rangeLimit": 5000,
|
||||||
},
|
|
||||||
"formatting": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
|
||||||
"hover": {
|
|
||||||
"contentFormat": [
|
|
||||||
"markdown",
|
|
||||||
"plaintext"
|
|
||||||
],
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
|
||||||
"implementation": {
|
|
||||||
"dynamicRegistration": True,
|
|
||||||
"linkSupport": True
|
|
||||||
},
|
},
|
||||||
|
"formatting": {"dynamicRegistration": True},
|
||||||
|
"hover": {"contentFormat": ["markdown", "plaintext"], "dynamicRegistration": True},
|
||||||
|
"implementation": {"dynamicRegistration": True, "linkSupport": True},
|
||||||
"inlayHint": {
|
"inlayHint": {
|
||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"resolveSupport": {
|
"resolveSupport": {"properties": ["tooltip", "textEdits", "label.tooltip", "label.location", "label.command"]},
|
||||||
"properties": [
|
|
||||||
"tooltip",
|
|
||||||
"textEdits",
|
|
||||||
"label.tooltip",
|
|
||||||
"label.location",
|
|
||||||
"label.command"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"inlineValue": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
|
||||||
"linkedEditingRange": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
|
||||||
"onTypeFormatting": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
},
|
||||||
|
"inlineValue": {"dynamicRegistration": True},
|
||||||
|
"linkedEditingRange": {"dynamicRegistration": True},
|
||||||
|
"onTypeFormatting": {"dynamicRegistration": True},
|
||||||
"publishDiagnostics": {
|
"publishDiagnostics": {
|
||||||
"codeDescriptionSupport": True,
|
"codeDescriptionSupport": True,
|
||||||
"dataSupport": True,
|
"dataSupport": True,
|
||||||
"relatedInformation": True,
|
"relatedInformation": True,
|
||||||
"tagSupport": {
|
"tagSupport": {"valueSet": [1, 2]},
|
||||||
"valueSet": [
|
"versionSupport": False,
|
||||||
1,
|
|
||||||
2
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"versionSupport": False
|
|
||||||
},
|
|
||||||
"rangeFormatting": {
|
|
||||||
"dynamicRegistration": True,
|
|
||||||
"rangesSupport": True
|
|
||||||
},
|
|
||||||
"references": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
},
|
||||||
|
"rangeFormatting": {"dynamicRegistration": True, "rangesSupport": True},
|
||||||
|
"references": {"dynamicRegistration": True},
|
||||||
"rename": {
|
"rename": {
|
||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"honorsChangeAnnotations": True,
|
"honorsChangeAnnotations": True,
|
||||||
"prepareSupport": True,
|
"prepareSupport": True,
|
||||||
"prepareSupportDefaultBehavior": 1
|
"prepareSupportDefaultBehavior": 1,
|
||||||
},
|
|
||||||
"selectionRange": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
},
|
||||||
|
"selectionRange": {"dynamicRegistration": True},
|
||||||
"semanticTokens": {
|
"semanticTokens": {
|
||||||
"augmentsSyntaxTokens": True,
|
"augmentsSyntaxTokens": True,
|
||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"formats": [
|
"formats": ["relative"],
|
||||||
"relative"
|
|
||||||
],
|
|
||||||
"multilineTokenSupport": False,
|
"multilineTokenSupport": False,
|
||||||
"overlappingTokenSupport": False,
|
"overlappingTokenSupport": False,
|
||||||
"requests": {
|
"requests": {"full": {"delta": True}, "range": True},
|
||||||
"full": {
|
|
||||||
"delta": True
|
|
||||||
},
|
|
||||||
"range": True
|
|
||||||
},
|
|
||||||
"serverCancelSupport": True,
|
"serverCancelSupport": True,
|
||||||
"tokenModifiers": [
|
"tokenModifiers": [
|
||||||
"declaration",
|
"declaration",
|
||||||
@@ -348,7 +196,7 @@ class SourceKitLSP(SolidLanguageServer):
|
|||||||
"async",
|
"async",
|
||||||
"modification",
|
"modification",
|
||||||
"documentation",
|
"documentation",
|
||||||
"defaultLibrary"
|
"defaultLibrary",
|
||||||
],
|
],
|
||||||
"tokenTypes": [
|
"tokenTypes": [
|
||||||
"namespace",
|
"namespace",
|
||||||
@@ -373,67 +221,35 @@ class SourceKitLSP(SolidLanguageServer):
|
|||||||
"number",
|
"number",
|
||||||
"regexp",
|
"regexp",
|
||||||
"operator",
|
"operator",
|
||||||
"decorator"
|
"decorator",
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
"signatureHelp": {
|
"signatureHelp": {
|
||||||
"contextSupport": True,
|
"contextSupport": True,
|
||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"signatureInformation": {
|
"signatureInformation": {
|
||||||
"activeParameterSupport": True,
|
"activeParameterSupport": True,
|
||||||
"documentationFormat": [
|
"documentationFormat": ["markdown", "plaintext"],
|
||||||
"markdown",
|
"parameterInformation": {"labelOffsetSupport": True},
|
||||||
"plaintext"
|
},
|
||||||
],
|
|
||||||
"parameterInformation": {
|
|
||||||
"labelOffsetSupport": True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"synchronization": {
|
"synchronization": {"didSave": True, "dynamicRegistration": True, "willSave": True, "willSaveWaitUntil": True},
|
||||||
"didSave": True,
|
"typeDefinition": {"dynamicRegistration": True, "linkSupport": True},
|
||||||
"dynamicRegistration": True,
|
"typeHierarchy": {"dynamicRegistration": True},
|
||||||
"willSave": True,
|
|
||||||
"willSaveWaitUntil": True
|
|
||||||
},
|
|
||||||
"typeDefinition": {
|
|
||||||
"dynamicRegistration": True,
|
|
||||||
"linkSupport": True
|
|
||||||
},
|
|
||||||
"typeHierarchy": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"window": {
|
"window": {
|
||||||
"showDocument": {
|
"showDocument": {"support": True},
|
||||||
"support": True
|
"showMessage": {"messageActionItem": {"additionalPropertiesSupport": True}},
|
||||||
},
|
"workDoneProgress": True,
|
||||||
"showMessage": {
|
|
||||||
"messageActionItem": {
|
|
||||||
"additionalPropertiesSupport": True
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"workDoneProgress": True
|
|
||||||
},
|
},
|
||||||
"workspace": {
|
"workspace": {
|
||||||
"applyEdit": True,
|
"applyEdit": True,
|
||||||
"codeLens": {
|
"codeLens": {"refreshSupport": True},
|
||||||
"refreshSupport": True
|
|
||||||
},
|
|
||||||
"configuration": True,
|
"configuration": True,
|
||||||
"diagnostics": {
|
"diagnostics": {"refreshSupport": True},
|
||||||
"refreshSupport": True
|
"didChangeConfiguration": {"dynamicRegistration": True},
|
||||||
},
|
"didChangeWatchedFiles": {"dynamicRegistration": True, "relativePatternSupport": True},
|
||||||
"didChangeConfiguration": {
|
"executeCommand": {"dynamicRegistration": True},
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
|
||||||
"didChangeWatchedFiles": {
|
|
||||||
"dynamicRegistration": True,
|
|
||||||
"relativePatternSupport": True
|
|
||||||
},
|
|
||||||
"executeCommand": {
|
|
||||||
"dynamicRegistration": True
|
|
||||||
},
|
|
||||||
"fileOperations": {
|
"fileOperations": {
|
||||||
"didCreate": True,
|
"didCreate": True,
|
||||||
"didDelete": True,
|
"didDelete": True,
|
||||||
@@ -441,70 +257,38 @@ class SourceKitLSP(SolidLanguageServer):
|
|||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"willCreate": True,
|
"willCreate": True,
|
||||||
"willDelete": True,
|
"willDelete": True,
|
||||||
"willRename": True
|
"willRename": True,
|
||||||
},
|
|
||||||
"foldingRange": {
|
|
||||||
"refreshSupport": True
|
|
||||||
},
|
|
||||||
"inlayHint": {
|
|
||||||
"refreshSupport": True
|
|
||||||
},
|
|
||||||
"inlineValue": {
|
|
||||||
"refreshSupport": True
|
|
||||||
},
|
|
||||||
"semanticTokens": {
|
|
||||||
"refreshSupport": False
|
|
||||||
},
|
},
|
||||||
|
"foldingRange": {"refreshSupport": True},
|
||||||
|
"inlayHint": {"refreshSupport": True},
|
||||||
|
"inlineValue": {"refreshSupport": True},
|
||||||
|
"semanticTokens": {"refreshSupport": False},
|
||||||
"symbol": {
|
"symbol": {
|
||||||
"dynamicRegistration": True,
|
"dynamicRegistration": True,
|
||||||
"resolveSupport": {
|
"resolveSupport": {"properties": ["location.range"]},
|
||||||
"properties": [
|
|
||||||
"location.range"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"symbolKind": {
|
"symbolKind": {
|
||||||
"valueSet": [
|
"valueSet": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tagSupport": {
|
"tagSupport": {"valueSet": [1]},
|
||||||
"valueSet": [
|
|
||||||
1
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"workspaceEdit": {
|
"workspaceEdit": {
|
||||||
"changeAnnotationSupport": {
|
"changeAnnotationSupport": {"groupsOnLabel": True},
|
||||||
"groupsOnLabel": True
|
|
||||||
},
|
|
||||||
"documentChanges": True,
|
"documentChanges": True,
|
||||||
"failureHandling": "textOnlyTransactional",
|
"failureHandling": "textOnlyTransactional",
|
||||||
"normalizesLineEndings": True,
|
"normalizesLineEndings": True,
|
||||||
"resourceOperations": [
|
"resourceOperations": ["create", "rename", "delete"],
|
||||||
"create",
|
|
||||||
"rename",
|
|
||||||
"delete"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"workspaceFolders": True
|
"workspaceFolders": True,
|
||||||
}
|
},
|
||||||
},
|
|
||||||
"clientInfo": {
|
|
||||||
"name": "Visual Studio Code",
|
|
||||||
"version": "1.102.2"
|
|
||||||
},
|
},
|
||||||
|
"clientInfo": {"name": "Visual Studio Code", "version": "1.102.2"},
|
||||||
"initializationOptions": {
|
"initializationOptions": {
|
||||||
"backgroundIndexing": True,
|
"backgroundIndexing": True,
|
||||||
"backgroundPreparationMode": "enabled",
|
"backgroundPreparationMode": "enabled",
|
||||||
"textDocument/codeLens": {
|
"textDocument/codeLens": {"supportedCommands": {"swift.debug": "swift.debug", "swift.run": "swift.run"}},
|
||||||
"supportedCommands": {
|
|
||||||
"swift.debug": "swift.debug",
|
|
||||||
"swift.run": "swift.run"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"window/didChangeActiveDocument": True,
|
"window/didChangeActiveDocument": True,
|
||||||
"workspace/getReferenceDocument": True,
|
"workspace/getReferenceDocument": True,
|
||||||
"workspace/peekDocuments": True
|
"workspace/peekDocuments": True,
|
||||||
},
|
},
|
||||||
"locale": "en",
|
"locale": "en",
|
||||||
"processId": os.getpid(),
|
"processId": os.getpid(),
|
||||||
@@ -517,7 +301,7 @@ class SourceKitLSP(SolidLanguageServer):
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
return initialize_params
|
return initialize_params
|
||||||
|
|
||||||
def _start_server(self):
|
def _start_server(self):
|
||||||
@@ -549,13 +333,18 @@ class SourceKitLSP(SolidLanguageServer):
|
|||||||
|
|
||||||
capabilities = init_response["capabilities"]
|
capabilities = init_response["capabilities"]
|
||||||
self.logger.log(f"SourceKit LSP capabilities: {list(capabilities.keys())}", logging.INFO)
|
self.logger.log(f"SourceKit LSP capabilities: {list(capabilities.keys())}", logging.INFO)
|
||||||
|
|
||||||
assert "textDocumentSync" in capabilities, "textDocumentSync capability missing"
|
assert "textDocumentSync" in capabilities, "textDocumentSync capability missing"
|
||||||
assert "definitionProvider" in capabilities, "definitionProvider capability missing"
|
assert "definitionProvider" in capabilities, "definitionProvider capability missing"
|
||||||
|
|
||||||
self.server.notify.initialized({})
|
self.server.notify.initialized({})
|
||||||
self.completions_available.set()
|
self.completions_available.set()
|
||||||
|
|
||||||
# sourcekit-lsp server is typically ready immediately after initialization
|
|
||||||
self.server_ready.set()
|
self.server_ready.set()
|
||||||
self.server_ready.wait()
|
self.server_ready.wait()
|
||||||
|
|
||||||
|
# SourceKit LSP needs a short initialization period after startup
|
||||||
|
# before it can provide accurate reference information. This sleep
|
||||||
|
# prevents race conditions where references might not be available yet.
|
||||||
|
# Unfortunately, sourcekit doesn't send a signal when it's really ready
|
||||||
|
time.sleep(5)
|
||||||
@@ -6,8 +6,6 @@ like request_references using the Swift test repository.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -17,30 +15,31 @@ from serena.text_utils import LineType
|
|||||||
from solidlsp import SolidLanguageServer
|
from solidlsp import SolidLanguageServer
|
||||||
from solidlsp.ls_config import Language
|
from solidlsp.ls_config import Language
|
||||||
|
|
||||||
|
|
||||||
# Skip Swift tests on Windows due to complex GitHub Actions configuration
|
# Skip Swift tests on Windows due to complex GitHub Actions configuration
|
||||||
WINDOWS_SKIP = platform.system() == "Windows"
|
WINDOWS_SKIP = platform.system() == "Windows"
|
||||||
WINDOWS_SKIP_REASON = "GitHub Actions configuration for Swift on Windows is complex, skipping for now."
|
WINDOWS_SKIP_REASON = "GitHub Actions configuration for Swift on Windows is complex, skipping for now."
|
||||||
|
|
||||||
pytestmark = [pytest.mark.swift, pytest.mark.skipif(WINDOWS_SKIP, reason=WINDOWS_SKIP_REASON)]
|
pytestmark = [pytest.mark.swift, pytest.mark.skipif(WINDOWS_SKIP, reason=WINDOWS_SKIP_REASON)]
|
||||||
|
|
||||||
|
|
||||||
class TestSwiftLanguageServerBasics:
|
class TestSwiftLanguageServerBasics:
|
||||||
"""Test basic functionality of the Swift language server."""
|
"""Test basic functionality of the Swift language server."""
|
||||||
|
|
||||||
@pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True)
|
@pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True)
|
||||||
def test_goto_definition_calculator_class(self, language_server: SolidLanguageServer) -> None:
|
def test_goto_definition_calculator_class(self, language_server: SolidLanguageServer) -> None:
|
||||||
"""Test goto_definition on Calculator class usage."""
|
"""Test goto_definition on Calculator class usage."""
|
||||||
file_path = os.path.join("src", "main.swift")
|
file_path = os.path.join("src", "main.swift")
|
||||||
|
|
||||||
# Find the Calculator usage at line 5: let calculator = Calculator()
|
# Find the Calculator usage at line 5: let calculator = Calculator()
|
||||||
# Position should be at the "Calculator()" call
|
# Position should be at the "Calculator()" call
|
||||||
definitions = language_server.request_definition(file_path, 4, 23) # Position at Calculator() call
|
definitions = language_server.request_definition(file_path, 4, 23) # Position at Calculator() call
|
||||||
assert isinstance(definitions, list), "Definitions should be a list"
|
assert isinstance(definitions, list), "Definitions should be a list"
|
||||||
assert len(definitions) > 0, "Should find definition for Calculator class"
|
assert len(definitions) > 0, "Should find definition for Calculator class"
|
||||||
|
|
||||||
# Verify the definition points to the Calculator class definition
|
# Verify the definition points to the Calculator class definition
|
||||||
calculator_def = definitions[0]
|
calculator_def = definitions[0]
|
||||||
assert calculator_def.get("uri", "").endswith("main.swift"), "Definition should be in main.swift"
|
assert calculator_def.get("uri", "").endswith("main.swift"), "Definition should be in main.swift"
|
||||||
|
|
||||||
# The Calculator class is defined starting at line 16
|
# The Calculator class is defined starting at line 16
|
||||||
start_line = calculator_def.get("range", {}).get("start", {}).get("line")
|
start_line = calculator_def.get("range", {}).get("start", {}).get("line")
|
||||||
assert start_line == 15, f"Calculator class definition should be at line 16, got {start_line + 1}"
|
assert start_line == 15, f"Calculator class definition should be at line 16, got {start_line + 1}"
|
||||||
@@ -49,17 +48,17 @@ class TestSwiftLanguageServerBasics:
|
|||||||
def test_goto_definition_user_struct(self, language_server: SolidLanguageServer) -> None:
|
def test_goto_definition_user_struct(self, language_server: SolidLanguageServer) -> None:
|
||||||
"""Test goto_definition on User struct usage."""
|
"""Test goto_definition on User struct usage."""
|
||||||
file_path = os.path.join("src", "main.swift")
|
file_path = os.path.join("src", "main.swift")
|
||||||
|
|
||||||
# Find the User usage at line 9: let user = User(name: "Alice", age: 30)
|
# Find the User usage at line 9: let user = User(name: "Alice", age: 30)
|
||||||
# Position should be at the "User(...)" call
|
# Position should be at the "User(...)" call
|
||||||
definitions = language_server.request_definition(file_path, 8, 18) # Position at User(...) call
|
definitions = language_server.request_definition(file_path, 8, 18) # Position at User(...) call
|
||||||
assert isinstance(definitions, list), "Definitions should be a list"
|
assert isinstance(definitions, list), "Definitions should be a list"
|
||||||
assert len(definitions) > 0, "Should find definition for User struct"
|
assert len(definitions) > 0, "Should find definition for User struct"
|
||||||
|
|
||||||
# Verify the definition points to the User struct definition
|
# Verify the definition points to the User struct definition
|
||||||
user_def = definitions[0]
|
user_def = definitions[0]
|
||||||
assert user_def.get("uri", "").endswith("main.swift"), "Definition should be in main.swift"
|
assert user_def.get("uri", "").endswith("main.swift"), "Definition should be in main.swift"
|
||||||
|
|
||||||
# The User struct is defined starting at line 26
|
# The User struct is defined starting at line 26
|
||||||
start_line = user_def.get("range", {}).get("start", {}).get("line")
|
start_line = user_def.get("range", {}).get("start", {}).get("line")
|
||||||
assert start_line == 25, f"User struct definition should be at line 26, got {start_line + 1}"
|
assert start_line == 25, f"User struct definition should be at line 26, got {start_line + 1}"
|
||||||
@@ -68,16 +67,16 @@ class TestSwiftLanguageServerBasics:
|
|||||||
def test_goto_definition_calculator_method(self, language_server: SolidLanguageServer) -> None:
|
def test_goto_definition_calculator_method(self, language_server: SolidLanguageServer) -> None:
|
||||||
"""Test goto_definition on Calculator method usage."""
|
"""Test goto_definition on Calculator method usage."""
|
||||||
file_path = os.path.join("src", "main.swift")
|
file_path = os.path.join("src", "main.swift")
|
||||||
|
|
||||||
# Find the add method usage at line 6: let result = calculator.add(5, 3)
|
# Find the add method usage at line 6: let result = calculator.add(5, 3)
|
||||||
# Position should be at the "add" method call
|
# Position should be at the "add" method call
|
||||||
definitions = language_server.request_definition(file_path, 5, 28) # Position at add method call
|
definitions = language_server.request_definition(file_path, 5, 28) # Position at add method call
|
||||||
assert isinstance(definitions, list), "Definitions should be a list"
|
assert isinstance(definitions, list), "Definitions should be a list"
|
||||||
|
|
||||||
# Verify the definition points to the add method definition
|
# Verify the definition points to the add method definition
|
||||||
add_def = definitions[0]
|
add_def = definitions[0]
|
||||||
assert add_def.get("uri", "").endswith("main.swift"), "Definition should be in main.swift"
|
assert add_def.get("uri", "").endswith("main.swift"), "Definition should be in main.swift"
|
||||||
|
|
||||||
# The add method is defined starting at line 17
|
# The add method is defined starting at line 17
|
||||||
start_line = add_def.get("range", {}).get("start", {}).get("line")
|
start_line = add_def.get("range", {}).get("start", {}).get("line")
|
||||||
assert start_line == 16, f"add method definition should be at line 17, got {start_line + 1}"
|
assert start_line == 16, f"add method definition should be at line 17, got {start_line + 1}"
|
||||||
@@ -86,42 +85,38 @@ class TestSwiftLanguageServerBasics:
|
|||||||
def test_goto_definition_cross_file(self, language_server: SolidLanguageServer) -> None:
|
def test_goto_definition_cross_file(self, language_server: SolidLanguageServer) -> None:
|
||||||
"""Test goto_definition across files - Utils struct."""
|
"""Test goto_definition across files - Utils struct."""
|
||||||
utils_file = os.path.join("src", "utils.swift")
|
utils_file = os.path.join("src", "utils.swift")
|
||||||
|
|
||||||
# First, let's check if Utils is used anywhere (it might not be in this simple test)
|
# First, let's check if Utils is used anywhere (it might not be in this simple test)
|
||||||
# We'll test goto_definition on Utils struct itself
|
# We'll test goto_definition on Utils struct itself
|
||||||
symbols = language_server.request_document_symbols(utils_file)
|
symbols = language_server.request_document_symbols(utils_file)
|
||||||
utils_symbol = next((s for s in symbols[0] if s.get("name") == "Utils"), None)
|
utils_symbol = next((s for s in symbols[0] if s.get("name") == "Utils"), None)
|
||||||
|
|
||||||
sel_start = utils_symbol["selectionRange"]["start"]
|
sel_start = utils_symbol["selectionRange"]["start"]
|
||||||
definitions = language_server.request_definition(utils_file, sel_start["line"], sel_start["character"])
|
definitions = language_server.request_definition(utils_file, sel_start["line"], sel_start["character"])
|
||||||
assert isinstance(definitions, list), "Definitions should be a list"
|
assert isinstance(definitions, list), "Definitions should be a list"
|
||||||
|
|
||||||
# Should find the Utils struct definition itself
|
# Should find the Utils struct definition itself
|
||||||
utils_def = definitions[0]
|
utils_def = definitions[0]
|
||||||
assert utils_def.get("uri", "").endswith("utils.swift"), "Definition should be in utils.swift"
|
assert utils_def.get("uri", "").endswith("utils.swift"), "Definition should be in utils.swift"
|
||||||
|
|
||||||
@pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True)
|
@pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True)
|
||||||
def test_request_references_calculator_class(self, language_server: SolidLanguageServer) -> None:
|
def test_request_references_calculator_class(self, language_server: SolidLanguageServer) -> None:
|
||||||
# SourceKit LSP needs a short initialization period after startup
|
|
||||||
# before it can provide accurate reference information. This sleep
|
|
||||||
# prevents race conditions where references might not be available yet.
|
|
||||||
time.sleep(5)
|
|
||||||
"""Test request_references on the Calculator class."""
|
"""Test request_references on the Calculator class."""
|
||||||
# Get references to the Calculator class in main.swift
|
# Get references to the Calculator class in main.swift
|
||||||
file_path = os.path.join("src", "main.swift")
|
file_path = os.path.join("src", "main.swift")
|
||||||
symbols = language_server.request_document_symbols(file_path)
|
symbols = language_server.request_document_symbols(file_path)
|
||||||
|
|
||||||
calculator_symbol = next((s for s in symbols[0] if s.get("name") == "Calculator"), None)
|
calculator_symbol = next((s for s in symbols[0] if s.get("name") == "Calculator"), None)
|
||||||
|
|
||||||
sel_start = calculator_symbol["selectionRange"]["start"]
|
sel_start = calculator_symbol["selectionRange"]["start"]
|
||||||
references = language_server.request_references(file_path, sel_start["line"], sel_start["character"])
|
references = language_server.request_references(file_path, sel_start["line"], sel_start["character"])
|
||||||
assert isinstance(references, list), "References should be a list"
|
assert isinstance(references, list), "References should be a list"
|
||||||
assert len(references) > 0, "Calculator class should be referenced"
|
assert len(references) > 0, "Calculator class should be referenced"
|
||||||
|
|
||||||
# Validate that Calculator is referenced in the main function
|
# Validate that Calculator is referenced in the main function
|
||||||
calculator_refs = [ref for ref in references if ref.get("uri", "").endswith("main.swift")]
|
calculator_refs = [ref for ref in references if ref.get("uri", "").endswith("main.swift")]
|
||||||
assert len(calculator_refs) > 0, "Calculator class should be referenced in main.swift"
|
assert len(calculator_refs) > 0, "Calculator class should be referenced in main.swift"
|
||||||
|
|
||||||
# Check that one reference is at line 5 (let calculator = Calculator())
|
# Check that one reference is at line 5 (let calculator = Calculator())
|
||||||
line_5_refs = [ref for ref in calculator_refs if ref.get("range", {}).get("start", {}).get("line") == 4]
|
line_5_refs = [ref for ref in calculator_refs if ref.get("range", {}).get("start", {}).get("line") == 4]
|
||||||
assert len(line_5_refs) > 0, "Calculator should be referenced at line 5"
|
assert len(line_5_refs) > 0, "Calculator should be referenced at line 5"
|
||||||
@@ -132,17 +127,17 @@ class TestSwiftLanguageServerBasics:
|
|||||||
# Get references to the User struct in main.swift
|
# Get references to the User struct in main.swift
|
||||||
file_path = os.path.join("src", "main.swift")
|
file_path = os.path.join("src", "main.swift")
|
||||||
symbols = language_server.request_document_symbols(file_path)
|
symbols = language_server.request_document_symbols(file_path)
|
||||||
|
|
||||||
user_symbol = next((s for s in symbols[0] if s.get("name") == "User"), None)
|
user_symbol = next((s for s in symbols[0] if s.get("name") == "User"), None)
|
||||||
|
|
||||||
sel_start = user_symbol["selectionRange"]["start"]
|
sel_start = user_symbol["selectionRange"]["start"]
|
||||||
references = language_server.request_references(file_path, sel_start["line"], sel_start["character"])
|
references = language_server.request_references(file_path, sel_start["line"], sel_start["character"])
|
||||||
assert isinstance(references, list), "References should be a list"
|
assert isinstance(references, list), "References should be a list"
|
||||||
|
|
||||||
# Validate that User is referenced in the main function
|
# Validate that User is referenced in the main function
|
||||||
user_refs = [ref for ref in references if ref.get("uri", "").endswith("main.swift")]
|
user_refs = [ref for ref in references if ref.get("uri", "").endswith("main.swift")]
|
||||||
assert len(user_refs) > 0, "User struct should be referenced in main.swift"
|
assert len(user_refs) > 0, "User struct should be referenced in main.swift"
|
||||||
|
|
||||||
# Check that one reference is at line 9 (let user = User(...))
|
# Check that one reference is at line 9 (let user = User(...))
|
||||||
line_9_refs = [ref for ref in user_refs if ref.get("range", {}).get("start", {}).get("line") == 8]
|
line_9_refs = [ref for ref in user_refs if ref.get("range", {}).get("start", {}).get("line") == 8]
|
||||||
assert len(line_9_refs) > 0, "User should be referenced at line 9"
|
assert len(line_9_refs) > 0, "User should be referenced at line 9"
|
||||||
@@ -160,17 +155,16 @@ class TestSwiftLanguageServerBasics:
|
|||||||
references = language_server.request_references(file_path, sel_start["line"], sel_start["character"])
|
references = language_server.request_references(file_path, sel_start["line"], sel_start["character"])
|
||||||
assert isinstance(references, list), "References should be a list"
|
assert isinstance(references, list), "References should be a list"
|
||||||
assert len(references) > 0, "Utils struct should be referenced"
|
assert len(references) > 0, "Utils struct should be referenced"
|
||||||
|
|
||||||
# Validate that Utils is referenced in main.swift
|
# Validate that Utils is referenced in main.swift
|
||||||
utils_refs = [ref for ref in references if ref.get("uri", "").endswith("main.swift")]
|
utils_refs = [ref for ref in references if ref.get("uri", "").endswith("main.swift")]
|
||||||
assert len(utils_refs) > 0, "Utils struct should be referenced in main.swift"
|
assert len(utils_refs) > 0, "Utils struct should be referenced in main.swift"
|
||||||
|
|
||||||
# Check that one reference is at line 12 (Utils.calculateArea call)
|
# Check that one reference is at line 12 (Utils.calculateArea call)
|
||||||
line_12_refs = [ref for ref in utils_refs if ref.get("range", {}).get("start", {}).get("line") == 11]
|
line_12_refs = [ref for ref in utils_refs if ref.get("range", {}).get("start", {}).get("line") == 11]
|
||||||
assert len(line_12_refs) > 0, "Utils should be referenced at line 12"
|
assert len(line_12_refs) > 0, "Utils should be referenced at line 12"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestSwiftProjectBasics:
|
class TestSwiftProjectBasics:
|
||||||
@pytest.mark.parametrize("project", [Language.SWIFT], indirect=True)
|
@pytest.mark.parametrize("project", [Language.SWIFT], indirect=True)
|
||||||
def test_retrieve_content_around_line(self, project: Project) -> None:
|
def test_retrieve_content_around_line(self, project: Project) -> None:
|
||||||
@@ -187,7 +181,7 @@ class TestSwiftProjectBasics:
|
|||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
assert calculator_line is not None, "Calculator class not found"
|
assert calculator_line is not None, "Calculator class not found"
|
||||||
line_calc = project.retrieve_content_around_line(file_path, calculator_line)
|
line_calc = project.retrieve_content_around_line(file_path, calculator_line)
|
||||||
assert len(line_calc.lines) == 1
|
assert len(line_calc.lines) == 1
|
||||||
@@ -209,7 +203,7 @@ class TestSwiftProjectBasics:
|
|||||||
user_matches = [m for m in matches if "User" in str(m)]
|
user_matches = [m for m in matches if "User" in str(m)]
|
||||||
assert len(user_matches) > 0, "Should find User struct"
|
assert len(user_matches) > 0, "Should find User struct"
|
||||||
|
|
||||||
# Scenario 4: Search for class definitions
|
# Scenario 4: Search for class definitions
|
||||||
class_pattern = r"class\s+\w+"
|
class_pattern = r"class\s+\w+"
|
||||||
matches = project.search_source_files_for_pattern(class_pattern)
|
matches = project.search_source_files_for_pattern(class_pattern)
|
||||||
assert len(matches) > 0, "Should find class definitions"
|
assert len(matches) > 0, "Should find class definitions"
|
||||||
@@ -225,4 +219,4 @@ class TestSwiftProjectBasics:
|
|||||||
assert len(matches) > 0, "Should find enum definitions"
|
assert len(matches) > 0, "Should find enum definitions"
|
||||||
# Should find Status enum
|
# Should find Status enum
|
||||||
status_matches = [m for m in matches if "Status" in str(m)]
|
status_matches = [m for m in matches if "Status" in str(m)]
|
||||||
assert len(status_matches) > 0, "Should find Status enum"
|
assert len(status_matches) > 0, "Should find Status enum"
|
||||||
Reference in new issue
Block a user