diff --git a/src/frontend/lib/utils/document_builder.dart b/src/frontend/lib/utils/document_builder.dart index d21db3a9..1f7bcff9 100644 --- a/src/frontend/lib/utils/document_builder.dart +++ b/src/frontend/lib/utils/document_builder.dart @@ -1,3 +1,5 @@ +import 'dart:js_interop'; + import 'package:flutter/material.dart'; import 'package:owlistic/core/theme.dart'; import 'package:owlistic/utils/data_converter.dart'; @@ -28,6 +30,7 @@ class DocumentBuilder { // Plugins late final ActionTagsPlugin _inlineCommandsPlugin; + late final PatternTagPlugin _inlineMetadataPlugin; // Add instance of AttributedTextUtils static final AttributedTextUtils _attributedTextUtils = AttributedTextUtils(); @@ -100,10 +103,18 @@ class DocumentBuilder { createDefaultDocumentEditor(document: _document, composer: _composer); // Add action tags listener for inline commands - _inlineCommandsPlugin = ActionTagsPlugin(); + _inlineCommandsPlugin = ActionTagsPlugin( + tagRule: const TagRule(trigger: "/", excludedCharacters: {" "}) + ); _inlineCommandsPlugin.attach(_editor); _inlineCommandsPlugin.composingActionTag.addListener(_handleInlineCommand); + // Add pattern tags listener for inline metadata (due-date, assignee, etc) + _inlineMetadataPlugin = PatternTagPlugin( + tagRule: const TagRule(trigger: "!", excludedCharacters: {" "}) + ); + _inlineMetadataPlugin.attach(_editor); + _inlineMetadataPlugin.tagIndex.addListener(_handleInlineMetadata); // Create focus node _editorFocusNode = FocusNode(); @@ -116,6 +127,8 @@ class DocumentBuilder { void dispose() { _inlineCommandsPlugin.composingActionTag.removeListener(_handleInlineCommand); _inlineCommandsPlugin.detach(_editor); + _inlineMetadataPlugin.tagIndex.removeListener(_handleInlineMetadata); + _inlineMetadataPlugin.detach(_editor); _editorFocusNode.dispose(); _composer.dispose(); _editor.dispose(); @@ -190,6 +203,30 @@ class DocumentBuilder { } } + void _handleInlineMetadata() { + for (final node in _document) { + if (node is! TextNode) { + continue; + } + + final tags = _inlineMetadataPlugin.tagIndex.getTagsInTextNode(node.id); + + for (final tag in tags) { + final action = node.text.substring(tag.startOffset + 1, tag.endOffset); + final actionText = node.text.substring(tag.endOffset); + switch (action) { + case 'due': + _logger.info("Due Date: ${actionText}"); + break; + case 'at': + case 'assign': + _logger.info("Assignee: ${actionText}"); + break; + } + } + } + } + // Add document structure change listener to detect new/deleted nodes void addDocumentStructureListener(void Function(dynamic) listener) { _document.addListener(listener); @@ -1363,8 +1400,10 @@ class DocumentBuilder { MarkdownInlineUpstreamSyntaxPlugin( parsers: const [ StyleUpstreamMarkdownSyntaxParser() ] ), - // Tasks - _actionTagPlugin, + // Inline Commands + _inlineCommandsPlugin, + // Inline Metadata + _inlineMetadataPlugin, }), ) );