mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-13 22:16:23 +00:00
refactor(al): move extract_al_display_name into ALLanguageServer class
Move the AL name extraction pattern and function into the class as a static method since they are only used by the language server. Addresses PR #960 review comment.
This commit is contained in:
1 parent
b9f82774ce
commit
d05d8b765f
2 files changed
+54
-54
No files matched your search
@@ -24,45 +24,6 @@ from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Regex pattern to match AL object names like:
|
||||
# - 'Table 50000 "TEST Customer"' -> captures 'TEST Customer'
|
||||
# - 'Codeunit 50000 CustomerMgt' -> captures 'CustomerMgt'
|
||||
# - 'Interface IPaymentProcessor' -> captures 'IPaymentProcessor'
|
||||
# - 'Enum 50000 CustomerType' -> captures 'CustomerType'
|
||||
# Pattern: <ObjectType> [<ID>] (<QuotedName>|<UnquotedName>)
|
||||
_AL_OBJECT_NAME_PATTERN = re.compile(
|
||||
r"^(?:Table|Page|Codeunit|Enum|Interface|Report|Query|XMLPort|PermissionSet|"
|
||||
r"PermissionSetExtension|Profile|PageExtension|TableExtension|EnumExtension|"
|
||||
r"PageCustomization|ReportExtension|ControlAddin|DotNetPackage)" # Object type
|
||||
r"(?:\s+\d+)?" # Optional object ID
|
||||
r"\s+" # Required space before name
|
||||
r'(?:"([^"]+)"|(\S+))$' # Quoted name (group 1) or unquoted identifier (group 2)
|
||||
)
|
||||
|
||||
|
||||
def extract_al_display_name(full_name: str) -> str:
|
||||
"""
|
||||
Extract the display name from an AL symbol's full name.
|
||||
|
||||
AL Language Server returns symbol names in format:
|
||||
- 'Table 50000 "TEST Customer"' -> 'TEST Customer'
|
||||
- 'Codeunit 50000 CustomerMgt' -> 'CustomerMgt'
|
||||
- 'Interface IPaymentProcessor' -> 'IPaymentProcessor'
|
||||
- 'fields' -> 'fields' (non-AL-object symbols pass through unchanged)
|
||||
|
||||
Args:
|
||||
full_name: The full symbol name as returned by AL Language Server
|
||||
|
||||
Returns:
|
||||
The extracted display name for matching, or the original name if not an AL object
|
||||
|
||||
"""
|
||||
match = _AL_OBJECT_NAME_PATTERN.match(full_name)
|
||||
if match:
|
||||
# Return quoted name (group 1) or unquoted name (group 2)
|
||||
return match.group(1) or match.group(2) or full_name
|
||||
return full_name
|
||||
|
||||
|
||||
class ALLanguageServer(SolidLanguageServer):
|
||||
"""
|
||||
@@ -79,6 +40,45 @@ class ALLanguageServer(SolidLanguageServer):
|
||||
- File opening requirement before symbol retrieval
|
||||
"""
|
||||
|
||||
# Regex pattern to match AL object names like:
|
||||
# - 'Table 50000 "TEST Customer"' -> captures 'TEST Customer'
|
||||
# - 'Codeunit 50000 CustomerMgt' -> captures 'CustomerMgt'
|
||||
# - 'Interface IPaymentProcessor' -> captures 'IPaymentProcessor'
|
||||
# - 'Enum 50000 CustomerType' -> captures 'CustomerType'
|
||||
# Pattern: <ObjectType> [<ID>] (<QuotedName>|<UnquotedName>)
|
||||
_AL_OBJECT_NAME_PATTERN = re.compile(
|
||||
r"^(?:Table|Page|Codeunit|Enum|Interface|Report|Query|XMLPort|PermissionSet|"
|
||||
r"PermissionSetExtension|Profile|PageExtension|TableExtension|EnumExtension|"
|
||||
r"PageCustomization|ReportExtension|ControlAddin|DotNetPackage)" # Object type
|
||||
r"(?:\s+\d+)?" # Optional object ID
|
||||
r"\s+" # Required space before name
|
||||
r'(?:"([^"]+)"|(\S+))$' # Quoted name (group 1) or unquoted identifier (group 2)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _extract_al_display_name(full_name: str) -> str:
|
||||
"""
|
||||
Extract the display name from an AL symbol's full name.
|
||||
|
||||
AL Language Server returns symbol names in format:
|
||||
- 'Table 50000 "TEST Customer"' -> 'TEST Customer'
|
||||
- 'Codeunit 50000 CustomerMgt' -> 'CustomerMgt'
|
||||
- 'Interface IPaymentProcessor' -> 'IPaymentProcessor'
|
||||
- 'fields' -> 'fields' (non-AL-object symbols pass through unchanged)
|
||||
|
||||
Args:
|
||||
full_name: The full symbol name as returned by AL Language Server
|
||||
|
||||
Returns:
|
||||
The extracted display name for matching, or the original name if not an AL object
|
||||
|
||||
"""
|
||||
match = ALLanguageServer._AL_OBJECT_NAME_PATTERN.match(full_name)
|
||||
if match:
|
||||
# Return quoted name (group 1) or unquoted name (group 2)
|
||||
return match.group(1) or match.group(2) or full_name
|
||||
return full_name
|
||||
|
||||
def __init__(self, config: LanguageServerConfig, repository_root_path: str, solidlsp_settings: SolidLSPSettings):
|
||||
"""
|
||||
Initialize the AL Language Server.
|
||||
@@ -1025,7 +1025,7 @@ class ALLanguageServer(SolidLanguageServer):
|
||||
# Normalize names by stripping AL object metadata, storing originals for hover
|
||||
def normalize_name(symbol: UnifiedSymbolInformation) -> None:
|
||||
original_name = symbol["name"]
|
||||
normalized_name = extract_al_display_name(original_name)
|
||||
normalized_name = self._extract_al_display_name(original_name)
|
||||
|
||||
# Store original name if it was normalized (for hover injection)
|
||||
# Only store if we have valid position data to avoid false matches at (0, 0)
|
||||
|
||||
@@ -4,7 +4,7 @@ import pytest
|
||||
|
||||
from serena.symbol import LanguageServerSymbol
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.language_servers.al_language_server import extract_al_display_name
|
||||
from solidlsp.language_servers.al_language_server import ALLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from solidlsp.ls_utils import SymbolUtils
|
||||
from test.conftest import language_tests_enabled
|
||||
@@ -13,49 +13,49 @@ pytestmark = [pytest.mark.al, pytest.mark.skipif(not language_tests_enabled(Lang
|
||||
|
||||
|
||||
class TestExtractALDisplayName:
|
||||
"""Tests for the extract_al_display_name function."""
|
||||
"""Tests for the ALLanguageServer._extract_al_display_name method."""
|
||||
|
||||
def test_table_with_quoted_name(self) -> None:
|
||||
"""Test extraction from Table with quoted name."""
|
||||
assert extract_al_display_name('Table 50000 "TEST Customer"') == "TEST Customer"
|
||||
assert ALLanguageServer._extract_al_display_name('Table 50000 "TEST Customer"') == "TEST Customer"
|
||||
|
||||
def test_page_with_quoted_name(self) -> None:
|
||||
"""Test extraction from Page with quoted name."""
|
||||
assert extract_al_display_name('Page 50001 "TEST Customer Card"') == "TEST Customer Card"
|
||||
assert ALLanguageServer._extract_al_display_name('Page 50001 "TEST Customer Card"') == "TEST Customer Card"
|
||||
|
||||
def test_codeunit_unquoted(self) -> None:
|
||||
"""Test extraction from Codeunit with unquoted name."""
|
||||
assert extract_al_display_name("Codeunit 50000 CustomerMgt") == "CustomerMgt"
|
||||
assert ALLanguageServer._extract_al_display_name("Codeunit 50000 CustomerMgt") == "CustomerMgt"
|
||||
|
||||
def test_enum_unquoted(self) -> None:
|
||||
"""Test extraction from Enum with unquoted name."""
|
||||
assert extract_al_display_name("Enum 50000 CustomerType") == "CustomerType"
|
||||
assert ALLanguageServer._extract_al_display_name("Enum 50000 CustomerType") == "CustomerType"
|
||||
|
||||
def test_interface_no_id(self) -> None:
|
||||
"""Test extraction from Interface (no ID)."""
|
||||
assert extract_al_display_name("Interface IPaymentProcessor") == "IPaymentProcessor"
|
||||
assert ALLanguageServer._extract_al_display_name("Interface IPaymentProcessor") == "IPaymentProcessor"
|
||||
|
||||
def test_table_extension(self) -> None:
|
||||
"""Test extraction from TableExtension."""
|
||||
assert extract_al_display_name('TableExtension 50000 "Ext Customer"') == "Ext Customer"
|
||||
assert ALLanguageServer._extract_al_display_name('TableExtension 50000 "Ext Customer"') == "Ext Customer"
|
||||
|
||||
def test_page_extension(self) -> None:
|
||||
"""Test extraction from PageExtension."""
|
||||
assert extract_al_display_name('PageExtension 50000 "My Page Ext"') == "My Page Ext"
|
||||
assert ALLanguageServer._extract_al_display_name('PageExtension 50000 "My Page Ext"') == "My Page Ext"
|
||||
|
||||
def test_non_al_object_unchanged(self) -> None:
|
||||
"""Test that non-AL-object names pass through unchanged."""
|
||||
assert extract_al_display_name("fields") == "fields"
|
||||
assert extract_al_display_name("CreateCustomer") == "CreateCustomer"
|
||||
assert extract_al_display_name("Name") == "Name"
|
||||
assert ALLanguageServer._extract_al_display_name("fields") == "fields"
|
||||
assert ALLanguageServer._extract_al_display_name("CreateCustomer") == "CreateCustomer"
|
||||
assert ALLanguageServer._extract_al_display_name("Name") == "Name"
|
||||
|
||||
def test_report_with_quoted_name(self) -> None:
|
||||
"""Test extraction from Report."""
|
||||
assert extract_al_display_name('Report 50000 "Sales Invoice"') == "Sales Invoice"
|
||||
assert ALLanguageServer._extract_al_display_name('Report 50000 "Sales Invoice"') == "Sales Invoice"
|
||||
|
||||
def test_query_unquoted(self) -> None:
|
||||
"""Test extraction from Query."""
|
||||
assert extract_al_display_name("Query 50000 CustomerQuery") == "CustomerQuery"
|
||||
assert ALLanguageServer._extract_al_display_name("Query 50000 CustomerQuery") == "CustomerQuery"
|
||||
|
||||
|
||||
@pytest.mark.al
|
||||
|
||||
Reference in new issue
Block a user