I can validate formatting in editor
This commit is contained in:
@@ -961,7 +961,7 @@ The autocompletion system provides context-aware suggestions for the DSL editor.
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ REST API: /myfasthtml/autocompletion │
|
||||
│ REST API: /myfasthtml/completions │
|
||||
│ Request: { "text": "...", "cursor": {"line": 1, "ch": 15} }│
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
@@ -1024,33 +1024,43 @@ When the engine needs column values for `OPERATOR_VALUE` context, it uses the de
|
||||
|
||||
### DatagridMetadataProvider
|
||||
|
||||
A helper class providing access to DataGrid metadata for context-aware suggestions:
|
||||
A Protocol providing access to DataGrid metadata for context-aware suggestions:
|
||||
|
||||
```python
|
||||
class DatagridMetadataProvider:
|
||||
class DatagridMetadataProvider(Protocol):
|
||||
"""Provides DataGrid metadata for autocompletion."""
|
||||
|
||||
def get_tables(self) -> list[str]:
|
||||
def list_tables(self) -> list[str]:
|
||||
"""List of available DataGrids (namespace.name format)."""
|
||||
...
|
||||
|
||||
def get_columns(self, table_name: str) -> list[str]:
|
||||
def list_columns(self, table_name: str) -> list[str]:
|
||||
"""Column names for a specific DataGrid."""
|
||||
...
|
||||
|
||||
def get_column_values(self, column_name: str) -> list[Any]:
|
||||
def list_column_values(self, table_name: str, column_name: str) -> list[Any]:
|
||||
"""Distinct values for a column in the current scope."""
|
||||
...
|
||||
|
||||
def get_row_count(self, table_name: str) -> int:
|
||||
"""Number of rows in a DataGrid."""
|
||||
...
|
||||
|
||||
def list_style_presets(self) -> list[str]:
|
||||
"""List of available style preset names."""
|
||||
...
|
||||
|
||||
def list_format_presets(self) -> list[str]:
|
||||
"""List of available format preset names."""
|
||||
...
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- `DatagridMetadataProvider` is a Protocol (structural typing), not an abstract base class
|
||||
- DataGrid names follow the pattern `namespace.name` (multi-level namespaces supported)
|
||||
- The provider is passed at initialization, not with each API call
|
||||
- Column values are fetched lazily when the scope is detected
|
||||
- `DataGridsManager` implements this Protocol
|
||||
|
||||
### API Interface
|
||||
|
||||
@@ -1230,24 +1240,35 @@ The following features are excluded from autocompletion for simplicity:
|
||||
|
||||
| Component | Status | Location |
|
||||
|-----------|--------|----------|
|
||||
| **DSL Parser** | | |
|
||||
| DSL Grammar (lark) | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/grammar.py` |
|
||||
| DSL Parser | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/parser.py` |
|
||||
| DSL Transformer | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/transformer.py` |
|
||||
| Scope Dataclasses | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/scopes.py` |
|
||||
| Exceptions | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/exceptions.py` |
|
||||
| Public API (`parse_dsl()`) | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/__init__.py` |
|
||||
| Unit Tests (Parser) | :white_check_mark: ~35 tests | `tests/core/formatting/test_dsl_parser.py` |
|
||||
| Unit Tests (Parser) | :white_check_mark: ~35 tests | `tests/core/formatting/dsl/test_dsl_parser.py` |
|
||||
| **Autocompletion** | | |
|
||||
| DatagridMetadataProvider | :x: Not implemented | `src/myfasthtml/core/formatting/dsl/completion.py` |
|
||||
| Scope Detector | :x: Not implemented | `src/myfasthtml/core/formatting/dsl/completion.py` |
|
||||
| Context Detector | :x: Not implemented | `src/myfasthtml/core/formatting/dsl/completion.py` |
|
||||
| Suggestions Generator | :x: Not implemented | `src/myfasthtml/core/formatting/dsl/completion.py` |
|
||||
| REST Endpoint | :x: Not implemented | `/myfasthtml/autocompletion` |
|
||||
| Unit Tests (Completion) | :x: Not implemented | `tests/core/formatting/test_dsl_completion.py` |
|
||||
| DatagridMetadataProvider | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/completion/provider.py` |
|
||||
| Scope Detector | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/completion/contexts.py` |
|
||||
| Context Detector | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/completion/contexts.py` |
|
||||
| Suggestions Generator | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/completion/suggestions.py` |
|
||||
| Completion Engine | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/completion/engine.py` |
|
||||
| Presets | :white_check_mark: Implemented | `src/myfasthtml/core/formatting/dsl/completion/presets.py` |
|
||||
| Unit Tests (Completion) | :white_check_mark: ~50 tests | `tests/core/formatting/dsl/test_completion.py` |
|
||||
| REST Endpoint | :white_check_mark: Implemented | `src/myfasthtml/core/utils.py` → `/myfasthtml/completions` |
|
||||
| **Client-side** | | |
|
||||
| Lezer Grammar | :x: Not implemented | `static/js/formatrules.grammar` |
|
||||
| CodeMirror Extension | :x: Not implemented | `static/js/formatrules-editor.js` |
|
||||
| DaisyUI Theme | :x: Not implemented | `static/js/daisy-theme.js` |
|
||||
| Lark to Lezer converter | :white_check_mark: Implemented | `src/myfasthtml/core/dsl/lark_to_lezer.py` |
|
||||
| CodeMirror 5 assets | :white_check_mark: Implemented | `assets/codemirror.min.js`, `show-hint.min.js` |
|
||||
| DslEditor control | :white_check_mark: Implemented | `src/myfasthtml/controls/DslEditor.py` |
|
||||
| initDslEditor() JS | :white_check_mark: Implemented | `assets/myfasthtml.js` (static completions only) |
|
||||
| Dynamic completions (server calls) | :white_check_mark: Implemented | `assets/myfasthtml.js` → `/myfasthtml/completions` |
|
||||
| DaisyUI Theme | :o: Deferred | - |
|
||||
| **Syntax Validation (Linting)** | | |
|
||||
| REST Endpoint | :white_check_mark: Implemented | `src/myfasthtml/core/utils.py` → `/myfasthtml/validations` |
|
||||
| CodeMirror lint integration | :white_check_mark: Implemented | `assets/myfasthtml.js` → `dslLint()` |
|
||||
| Lint CSS/JS assets | :white_check_mark: Added | `assets/lint.min.js`, `assets/lint.css` |
|
||||
| Warnings (semantic validation) | :o: Future | Not yet implemented (see note below) |
|
||||
|
||||
---
|
||||
|
||||
@@ -1289,7 +1310,15 @@ src/myfasthtml/core/formatting/dsl/
|
||||
├── parser.py # DSLParser class with Indenter
|
||||
├── transformer.py # AST → dataclass conversion
|
||||
├── scopes.py # ColumnScope, RowScope, CellScope, ScopedRule
|
||||
└── exceptions.py # DSLSyntaxError, DSLValidationError
|
||||
├── exceptions.py # DSLSyntaxError, DSLValidationError
|
||||
├── definition.py # FormattingDSL class for DslEditor
|
||||
└── completion/ # Autocompletion module
|
||||
├── __init__.py
|
||||
├── contexts.py # Context enum, detect_scope(), detect_context()
|
||||
├── suggestions.py # get_suggestions() for each context
|
||||
├── engine.py # FormattingCompletionEngine, get_completions()
|
||||
├── presets.py # Static suggestions (keywords, operators, colors)
|
||||
└── provider.py # DatagridMetadataProvider protocol
|
||||
```
|
||||
|
||||
**Output structure:**
|
||||
@@ -1303,15 +1332,80 @@ class ScopedRule:
|
||||
rule: FormatRule # From core/formatting/dataclasses.py
|
||||
```
|
||||
|
||||
### Syntax Validation (Linting)
|
||||
|
||||
The DSL editor provides real-time syntax validation via CodeMirror's lint addon.
|
||||
|
||||
**Architecture:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ CodeMirror Editor │
|
||||
│ User types invalid syntax │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│ (debounced, 500ms)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ REST API: /myfasthtml/validations │
|
||||
│ Request: { e_id, text, line, ch } │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Python: parse_dsl(text) │
|
||||
│ - If OK: return {"errors": []} │
|
||||
│ - If DSLSyntaxError: return error with line/column/message │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ CodeMirror Lint Display │
|
||||
│ - Gutter marker (error icon) │
|
||||
│ - Underline on error position │
|
||||
│ - Tooltip with error message on hover │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**API Response Format:**
|
||||
|
||||
```json
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"line": 5,
|
||||
"column": 12,
|
||||
"message": "Expected 'column', 'row' or 'cell'",
|
||||
"severity": "error"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** Line and column are 1-based (from lark parser). The JavaScript client converts to 0-based for CodeMirror.
|
||||
|
||||
**Future: Warnings Support**
|
||||
|
||||
Currently, only syntax errors (parse failures) are reported. Semantic warnings are planned for a future release:
|
||||
|
||||
| Warning Type | Example | Status |
|
||||
|--------------|---------|--------|
|
||||
| Unknown style preset | `style("unknown_preset")` | :o: Future |
|
||||
| Unknown format preset | `format("invalid")` | :o: Future |
|
||||
| Unknown parameter | `style(invalid_param=True)` | :o: Future |
|
||||
| Non-existent column reference | `col.nonexistent` | :o: Future |
|
||||
|
||||
These warnings would be non-blocking (DSL still parses) but displayed with a different severity in the editor.
|
||||
|
||||
### Next Steps
|
||||
|
||||
1. ~~**Add `lark` to dependencies** in `pyproject.toml`~~ Done
|
||||
2. **Implement autocompletion API**:
|
||||
- `DatagridMetadataProvider` class
|
||||
- Scope detection (column/row/cell)
|
||||
- Context detection
|
||||
- Suggestions generation
|
||||
- REST endpoint `/myfasthtml/autocompletion`
|
||||
3. **Translate lark grammar to Lezer** for client-side parsing
|
||||
4. **Build CodeMirror extension** with DaisyUI theme
|
||||
2. ~~**Implement autocompletion API**~~ Done
|
||||
3. ~~**Translate lark grammar to Lezer**~~ Done (`lark_to_lezer.py`)
|
||||
4. ~~**Build CodeMirror extension**~~ Done (`DslEditor.py` + `initDslEditor()`)
|
||||
5. ~~**Integrate with DataGrid** - connect DSL output to formatting engine~~ Done
|
||||
6. ~~**Implement dynamic client-side completions**~~ Done
|
||||
- Engine ID: `DSLDefinition.get_id()` passed via `completionEngineId` in JS config
|
||||
- Trigger: Hybrid (Ctrl+Space + auto after `.` `(` `"` and space)
|
||||
- Files modified:
|
||||
- `src/myfasthtml/controls/DslEditor.py:134` - Added `completionEngineId`
|
||||
- `src/myfasthtml/assets/myfasthtml.js:2138-2300` - Async fetch to `/myfasthtml/completions`
|
||||
|
||||
Reference in New Issue
Block a user