Working on Formating DSL completion
This commit is contained in:
172
src/myfasthtml/core/dsl/base_completion.py
Normal file
172
src/myfasthtml/core/dsl/base_completion.py
Normal file
@@ -0,0 +1,172 @@
|
||||
"""
|
||||
Base completion engine for DSL autocompletion.
|
||||
|
||||
Provides an abstract base class that specific DSL implementations
|
||||
can extend to provide context-aware autocompletion.
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any
|
||||
|
||||
from . import utils
|
||||
from .base_provider import BaseMetadataProvider
|
||||
from .types import Position, Suggestion, CompletionResult
|
||||
|
||||
|
||||
class BaseCompletionEngine(ABC):
|
||||
"""
|
||||
Abstract base class for DSL completion engines.
|
||||
|
||||
Subclasses must implement:
|
||||
- detect_scope(): Find the current scope from previous lines
|
||||
- detect_context(): Determine what kind of completion is expected
|
||||
- get_suggestions(): Generate suggestions for the detected context
|
||||
|
||||
The main entry point is get_completions(), which orchestrates the flow.
|
||||
"""
|
||||
|
||||
def __init__(self, provider: BaseMetadataProvider):
|
||||
"""
|
||||
Initialize the completion engine.
|
||||
|
||||
Args:
|
||||
provider: Metadata provider for context-aware suggestions
|
||||
"""
|
||||
self.provider = provider
|
||||
|
||||
def get_completions(self, text: str, cursor: Position) -> CompletionResult:
|
||||
"""
|
||||
Get autocompletion suggestions for the given cursor position.
|
||||
|
||||
This is the main entry point. It:
|
||||
1. Checks if cursor is in a comment (no suggestions)
|
||||
2. Detects the current scope (e.g., which column)
|
||||
3. Detects the completion context (what kind of token is expected)
|
||||
4. Generates and filters suggestions
|
||||
|
||||
Args:
|
||||
text: The full DSL document text
|
||||
cursor: Cursor position
|
||||
|
||||
Returns:
|
||||
CompletionResult with suggestions and replacement range
|
||||
"""
|
||||
# Get the current line up to cursor
|
||||
line = utils.get_line_at(text, cursor.line)
|
||||
line_to_cursor = utils.get_line_up_to_cursor(text, cursor)
|
||||
|
||||
# Check if in comment - no suggestions
|
||||
if utils.is_in_comment(line, cursor.ch):
|
||||
return self._empty_result(cursor)
|
||||
|
||||
# Find word boundaries for replacement range
|
||||
word_range = utils.find_word_boundaries(line, cursor.ch)
|
||||
prefix = line[word_range.start: cursor.ch]
|
||||
|
||||
# Detect scope from previous lines
|
||||
scope = self.detect_scope(text, cursor.line)
|
||||
|
||||
# Detect completion context
|
||||
context = self.detect_context(text, cursor, scope)
|
||||
|
||||
# Get suggestions for this context
|
||||
suggestions = self.get_suggestions(context, scope, prefix)
|
||||
|
||||
# Filter suggestions by prefix
|
||||
if prefix:
|
||||
suggestions = self._filter_suggestions(suggestions, prefix)
|
||||
|
||||
# Build result with correct positions
|
||||
from_pos = Position(line=cursor.line, ch=word_range.start)
|
||||
to_pos = Position(line=cursor.line, ch=word_range.end)
|
||||
|
||||
return CompletionResult(
|
||||
from_pos=from_pos,
|
||||
to_pos=to_pos,
|
||||
suggestions=suggestions,
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def detect_scope(self, text: str, current_line: int) -> Any:
|
||||
"""
|
||||
Detect the current scope by scanning previous lines.
|
||||
|
||||
The scope determines which data context we're in (e.g., which column
|
||||
for column values suggestions).
|
||||
|
||||
Args:
|
||||
text: The full document text
|
||||
current_line: Current line number (0-based)
|
||||
|
||||
Returns:
|
||||
Scope object (type depends on the specific DSL)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def detect_context(self, text: str, cursor: Position, scope: Any) -> Any:
|
||||
"""
|
||||
Detect the completion context at the cursor position.
|
||||
|
||||
Analyzes the current line to determine what kind of token
|
||||
is expected (e.g., keyword, preset name, operator).
|
||||
|
||||
Args:
|
||||
text: The full document text
|
||||
cursor: Cursor position
|
||||
scope: The detected scope
|
||||
|
||||
Returns:
|
||||
Context identifier (type depends on the specific DSL)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_suggestions(self, context: Any, scope: Any, prefix: str) -> list[Suggestion]:
|
||||
"""
|
||||
Generate suggestions for the given context.
|
||||
|
||||
Args:
|
||||
context: The detected completion context
|
||||
scope: The detected scope
|
||||
prefix: The current word prefix (for filtering)
|
||||
|
||||
Returns:
|
||||
List of suggestions
|
||||
"""
|
||||
pass
|
||||
|
||||
def _filter_suggestions(
|
||||
self, suggestions: list[Suggestion], prefix: str
|
||||
) -> list[Suggestion]:
|
||||
"""
|
||||
Filter suggestions by prefix (case-insensitive).
|
||||
|
||||
Args:
|
||||
suggestions: List of suggestions
|
||||
prefix: Prefix to filter by
|
||||
|
||||
Returns:
|
||||
Filtered list of suggestions
|
||||
"""
|
||||
prefix_lower = prefix.lower()
|
||||
return [s for s in suggestions if s.label.lower().startswith(prefix_lower)]
|
||||
|
||||
def _empty_result(self, cursor: Position) -> CompletionResult:
|
||||
"""
|
||||
Return an empty completion result.
|
||||
|
||||
Args:
|
||||
cursor: Cursor position
|
||||
|
||||
Returns:
|
||||
CompletionResult with no suggestions
|
||||
"""
|
||||
return CompletionResult(
|
||||
from_pos=cursor,
|
||||
to_pos=cursor,
|
||||
suggestions=[],
|
||||
)
|
||||
|
||||
def get_id(self):
|
||||
return type(self).__name__
|
||||
Reference in New Issue
Block a user