Improving completion to support the correct table name for autocompletion and formatting

This commit is contained in:
2026-02-07 18:26:29 +01:00
parent ab4f251f0c
commit 3fc4384251
10 changed files with 49 additions and 58 deletions

View File

@@ -24,7 +24,10 @@ from myfasthtml.controls.helpers import mk, icons
from myfasthtml.core.commands import Command
from myfasthtml.core.constants import ColumnType, ROW_INDEX_ID, FooterAggregation, DATAGRID_PAGE_SIZE, FILTER_INPUT_CID
from myfasthtml.core.dbmanager import DbObject
from myfasthtml.core.dsls import DslsManager
from myfasthtml.core.formatting.dsl.completion.FormattingCompletionEngine import FormattingCompletionEngine
from myfasthtml.core.formatting.dsl.definition import FormattingDSL
from myfasthtml.core.formatting.dsl.parser import DSLParser
from myfasthtml.core.formatting.engine import FormattingEngine
from myfasthtml.core.instances import MultipleInstance
from myfasthtml.core.optimized_ft import OptimizedDiv
@@ -97,6 +100,7 @@ class DatagridSettings(DbObject):
self.open_file_visible: bool = True
self.open_settings_visible: bool = True
self.text_size: str = "sm"
self.enable_formatting: bool = True
class Commands(BaseCommands):
@@ -206,12 +210,20 @@ class DataGrid(MultipleInstance):
self._columns_manager.bind_command("ToggleColumn", self.commands.on_column_changed())
self._columns_manager.bind_command("UpdateColumn", self.commands.on_column_changed())
editor_conf = DslEditorConf()
self._formatting_editor = DataGridFormattingEditor(self,
conf=editor_conf,
dsl=FormattingDSL(),
save_state=self._settings.save_state,
_id="-formatting_editor")
if self._settings.enable_formatting:
completion_engine = FormattingCompletionEngine(self._parent, self.get_table_name())
editor_conf = DslEditorConf(engine_id=completion_engine.get_id())
dsl = FormattingDSL()
self._formatting_editor = DataGridFormattingEditor(self,
conf=editor_conf,
dsl=dsl,
save_state=self._settings.save_state,
_id="-formatting_editor")
# register the auto-completion for the formatter DSL
DslsManager.register(completion_engine,
DSLParser())
else:
self._formatting_editor = None
# other definitions
self._mouse_support = {
@@ -220,7 +232,7 @@ class DataGrid(MultipleInstance):
"shift+click": {"command": self.commands.on_click(), "hx_vals": "js:getCellId()"},
}
logger.debug(f"DataGrid '{self._get_full_name()}' with id='{self._id}' created.")
logger.debug(f"DataGrid '{self.get_table_name()}' with id='{self._id}' created.")
@property
def _df(self):
@@ -298,9 +310,6 @@ class DataGrid(MultipleInstance):
self._state.selection.selected = pos
self._state.save()
def _get_full_name(self):
return f"{self._settings.namespace}.{self._settings.name}" if self._settings.namespace else self._settings.name
def init_from_dataframe(self, df, init_state=True):
def _get_column_type(dtype):
@@ -497,6 +506,9 @@ class DataGrid(MultipleInstance):
def get_settings(self):
return self._settings
def get_table_name(self):
return f"{self._settings.namespace}.{self._settings.name}" if self._settings.namespace else self._settings.name
def mk_headers(self):
resize_cmd = self.commands.set_column_width()
move_cmd = self.commands.move_column()

View File

@@ -14,11 +14,7 @@ from myfasthtml.controls.helpers import mk
from myfasthtml.core.DataGridsRegistry import DataGridsRegistry
from myfasthtml.core.commands import Command
from myfasthtml.core.dbmanager import DbObject
from myfasthtml.core.dsls import DslsManager
from myfasthtml.core.formatting.dsl.completion.engine import FormattingCompletionEngine
from myfasthtml.core.formatting.dsl.completion.provider import DatagridMetadataProvider
from myfasthtml.core.formatting.dsl.definition import FormattingDSL
from myfasthtml.core.formatting.dsl.parser import DSLParser
from myfasthtml.core.formatting.presets import DEFAULT_STYLE_PRESETS, DEFAULT_FORMATTER_PRESETS
from myfasthtml.core.instances import InstancesManager, SingleInstance
from myfasthtml.icons.fluent_p1 import table_add20_regular
@@ -94,11 +90,6 @@ class DataGridsManager(SingleInstance, DatagridMetadataProvider):
# Global presets shared across all DataGrids
self.style_presets: dict = DEFAULT_STYLE_PRESETS.copy()
self.formatter_presets: dict = DEFAULT_FORMATTER_PRESETS.copy()
# register the auto-completion for the formatter DSL
DslsManager.register(FormattingDSL().get_id(),
FormattingCompletionEngine(self),
DSLParser())
def upload_from_source(self):
file_upload = FileUpload(self)
@@ -112,7 +103,7 @@ class DataGridsManager(SingleInstance, DatagridMetadataProvider):
namespace = file_upload.get_file_basename()
name = file_upload.get_sheet_name()
dg_conf = DatagridConf(namespace=namespace, name=name)
dg = DataGrid(self._tabs_manager, conf=dg_conf, save_state=True) # first time the Datagrid is created
dg = DataGrid(self, conf=dg_conf, save_state=True) # first time the Datagrid is created
dg.init_from_dataframe(df)
self._registry.put(namespace, name, dg.get_id())
document = DocumentDefinition(
@@ -133,7 +124,7 @@ class DataGridsManager(SingleInstance, DatagridMetadataProvider):
document_id = self._tree.get_bag(node_id)
try:
document = next(filter(lambda x: x.document_id == document_id, self._state.elements))
dg = DataGrid(self._tabs_manager, _id=document.datagrid_id) # reload the state & settings
dg = DataGrid(self, _id=document.datagrid_id) # reload the state & settings
return self._tabs_manager.show_or_create_tab(document.tab_id, document.name, dg)
except StopIteration:
# the selected node is not a document (it's a folder)
@@ -157,7 +148,7 @@ class DataGridsManager(SingleInstance, DatagridMetadataProvider):
raise ValueError(f"No document found for tab {tab_id}")
# Recreate the DataGrid with its saved state
dg = DataGrid(self._tabs_manager, _id=document.datagrid_id) # reload the state & settings
dg = DataGrid(self, _id=document.datagrid_id) # reload the state & settings
return dg
def clear_tree(self):

View File

@@ -32,6 +32,7 @@ class DslEditorConf:
linting: bool = True
placeholder: str = ""
readonly: bool = False
engine_id: str = None # id of the DSL engine to use for autocompletion
class DslEditorState(DbObject):
@@ -141,7 +142,7 @@ class DslEditor(MultipleInstance):
simple_mode_config = None
if hasattr(self._dsl, 'simple_mode_config'):
simple_mode_config = self._dsl.simple_mode_config
config = {
"elementId": str(self._id),
"textareaId": f"ta_{self._id}",
@@ -151,7 +152,7 @@ class DslEditor(MultipleInstance):
"placeholder": self.conf.placeholder,
"readonly": self.conf.readonly,
"updateCommandId": str(self.commands.update_content().id),
"dslId": self._dsl.get_id(),
"dslId": self.conf.engine_id,
"dsl": {
"name": self._dsl.name,
"completions": self._dsl.completions,

View File

@@ -33,6 +33,7 @@ class BaseCompletionEngine(ABC):
provider: Metadata provider for context-aware suggestions
"""
self.provider = provider
self._id = type(self).__name__
def get_completions(self, text: str, cursor: Position) -> CompletionResult:
"""
@@ -169,4 +170,4 @@ class BaseCompletionEngine(ABC):
)
def get_id(self):
return type(self).__name__
return self._id

View File

@@ -19,7 +19,7 @@ class BaseMetadataProvider(Protocol):
can extend this with additional methods.
"""
def get_style_presets(self) -> list[str]:
def list_style_presets(self) -> list[str]:
"""
Return the list of available style preset names.
@@ -28,7 +28,7 @@ class BaseMetadataProvider(Protocol):
"""
...
def get_format_presets(self) -> list[str]:
def list_format_presets(self) -> list[str]:
"""
Return the list of available format preset names.

View File

@@ -14,9 +14,9 @@ class DslsManager:
dsls: dict[str, DslDefinition] = {}
@staticmethod
def register(dsl_id: str, completion: BaseCompletionEngine, validation: DSLParser):
def register(completion: BaseCompletionEngine, validation: DSLParser):
# then engine_id is actually the DSL id
DslsManager.dsls[dsl_id] = DslDefinition(completion, validation)
DslsManager.dsls[completion.get_id()] = DslDefinition(completion, validation)
@staticmethod
def get_completion_engine(engine_id) -> BaseCompletionEngine:

View File

@@ -3,8 +3,10 @@ Completion engine for the formatting DSL.
Implements the BaseCompletionEngine for DataGrid formatting rules.
"""
from myfasthtml.core.dsl.base_completion import BaseCompletionEngine
from myfasthtml.core.dsl.types import Position, Suggestion, CompletionResult
from myfasthtml.core.utils import make_safe_id
from . import suggestions as suggestions_module
from .contexts import Context, DetectedScope, detect_scope, detect_context
from .provider import DatagridMetadataProvider
@@ -21,7 +23,7 @@ class FormattingCompletionEngine(BaseCompletionEngine):
- Conditions with operators and values
"""
def __init__(self, provider: DatagridMetadataProvider):
def __init__(self, provider: DatagridMetadataProvider, table_name: str):
"""
Initialize the completion engine.
@@ -30,6 +32,8 @@ class FormattingCompletionEngine(BaseCompletionEngine):
"""
super().__init__(provider)
self.provider: DatagridMetadataProvider = provider
self.table_name: str = table_name # current table name
self._id = "formatting_completion_engine#" + make_safe_id(table_name)
def detect_scope(self, text: str, current_line: int) -> DetectedScope:
"""

View File

@@ -5,10 +5,12 @@ Provides access to DataGrid metadata (columns, values, row counts)
for context-aware autocompletion.
"""
from typing import Protocol, Any
from typing import Any
from myfasthtml.core.dsl.base_provider import BaseMetadataProvider
class DatagridMetadataProvider(Protocol):
class DatagridMetadataProvider(BaseMetadataProvider):
"""
Protocol for providing DataGrid metadata to the autocompletion engine.
@@ -70,25 +72,3 @@ class DatagridMetadataProvider(Protocol):
Number of rows
"""
...
def list_style_presets(self) -> list[str]:
"""
Return the list of available style preset names.
Includes default presets (primary, error, etc.) and custom presets.
Returns:
List of style preset names
"""
...
def list_format_presets(self) -> list[str]:
"""
Return the list of available format preset names.
Includes default presets (EUR, USD, etc.) and custom presets.
Returns:
List of format preset names
"""
...

View File

@@ -375,7 +375,7 @@ def post(session, b_id: str, values: dict):
:param values:
:return:
"""
logger.debug(f"Entering {Routes.Bindings} with {session=}, {b_id=}, {values=}")
logger.debug(f"Entering {Routes.Bindings} with session='{debug_session(session)}', {b_id=}, {values=}")
from myfasthtml.core.bindings import BindingsManager
binding = BindingsManager.get_binding(b_id)
if binding:
@@ -396,7 +396,8 @@ def get(session, e_id: str, text: str, line: int, ch: int):
:param ch:
:return:
"""
logger.debug(f"Entering {Routes.Completions} with {session=}, {e_id=}, {text=}, {line=}, {ch}")
logger.debug(
f"Entering {Routes.Completions} with session='{debug_session(session)}', {e_id=}, text={len(text)} char(s), {line=}, {ch=}")
completion = DslsManager.get_completion_engine(e_id)
result = completion.get_completions(text, Position(line, ch))
return result.to_dict()
@@ -413,7 +414,8 @@ def get(session, e_id: str, text: str, line: int, ch: int):
:param ch:
:return:
"""
logger.debug(f"Entering {Routes.Validations} with {session=}, {e_id=}, {text=}, {line=}, {ch}")
logger.debug(
f"Entering {Routes.Validations} with session='{debug_session(session)}', {e_id=}, text={len(text)} char(s), {line=}, {ch=}")
validation = DslsManager.get_validation_parser(e_id)
try:
validation.parse(text)