From 76362bfb7659285a180bd5ccbe4fbd07c34691bf Mon Sep 17 00:00:00 2001 From: Davide Rutigliano Date: Tue, 27 May 2025 20:40:33 +0200 Subject: [PATCH 1/4] Add due-date/assignee plugins --- src/frontend/lib/utils/document_builder.dart | 33 +++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/frontend/lib/utils/document_builder.dart b/src/frontend/lib/utils/document_builder.dart index d21db3a9..f1a7537c 100644 --- a/src/frontend/lib/utils/document_builder.dart +++ b/src/frontend/lib/utils/document_builder.dart @@ -28,6 +28,8 @@ class DocumentBuilder { // Plugins late final ActionTagsPlugin _inlineCommandsPlugin; + late final PatternTagPlugin _dueDatesPlugin; + late final PatternTagPlugin _assigneesPlugin; // Add instance of AttributedTextUtils static final AttributedTextUtils _attributedTextUtils = AttributedTextUtils(); @@ -104,6 +106,19 @@ class DocumentBuilder { _inlineCommandsPlugin.attach(_editor); _inlineCommandsPlugin.composingActionTag.addListener(_handleInlineCommand); + // Add pattern tags listener for due dates + _dueDatesPlugin = PatternTagPlugin( + tagRule: const TagRule(trigger: "!", excludedCharacters: {" "}) + ); + _dueDatesPlugin.attach(_editor); + _dueDatesPlugin.tagIndex.addListener(_handleDueDateCommand); + + // Add action tags listener for inline commands + _assigneesPlugin = PatternTagPlugin( + tagRule: const TagRule(trigger: "@", excludedCharacters: {" ", "."}) + ); + _assigneesPlugin.attach(_editor); + _assigneesPlugin.tagIndex.addListener(_handleAssigneeCommand); // Create focus node _editorFocusNode = FocusNode(); @@ -116,6 +131,10 @@ class DocumentBuilder { void dispose() { _inlineCommandsPlugin.composingActionTag.removeListener(_handleInlineCommand); _inlineCommandsPlugin.detach(_editor); + _dueDatesPlugin.tagIndex.removeListener(_handleDueDateCommand); + _dueDatesPlugin.detach(_editor); + _assigneesPlugin.tagIndex.removeListener(_handleAssigneeCommand); + _assigneesPlugin.detach(_editor); _editorFocusNode.dispose(); _composer.dispose(); _editor.dispose(); @@ -190,6 +209,14 @@ class DocumentBuilder { } } + void _handleDueDateCommand() { + + } + + void _handleAssigneeCommand() { + + } + // Add document structure change listener to detect new/deleted nodes void addDocumentStructureListener(void Function(dynamic) listener) { _document.addListener(listener); @@ -1364,7 +1391,11 @@ class DocumentBuilder { parsers: const [ StyleUpstreamMarkdownSyntaxParser() ] ), // Tasks - _actionTagPlugin, + _inlineCommandsPlugin, + // Due Dates + _dueDatesPlugin, + // Assignees + _assigneesPlugin, }), ) ); From c52fd21869a47fcd6d479ffd602acfd8c55bb5ad Mon Sep 17 00:00:00 2001 From: Davide Rutigliano Date: Tue, 27 May 2025 21:46:47 +0200 Subject: [PATCH 2/4] Replace pattern tags with action tags (more stable and fitting) --- src/frontend/lib/utils/document_builder.dart | 24 +++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/frontend/lib/utils/document_builder.dart b/src/frontend/lib/utils/document_builder.dart index f1a7537c..ab7e2f79 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,8 +30,8 @@ class DocumentBuilder { // Plugins late final ActionTagsPlugin _inlineCommandsPlugin; - late final PatternTagPlugin _dueDatesPlugin; - late final PatternTagPlugin _assigneesPlugin; + late final ActionTagsPlugin _dueDatesPlugin; + late final ActionTagsPlugin _assigneesPlugin; // Add instance of AttributedTextUtils static final AttributedTextUtils _attributedTextUtils = AttributedTextUtils(); @@ -107,18 +109,18 @@ class DocumentBuilder { _inlineCommandsPlugin.composingActionTag.addListener(_handleInlineCommand); // Add pattern tags listener for due dates - _dueDatesPlugin = PatternTagPlugin( + _dueDatesPlugin = ActionTagsPlugin( tagRule: const TagRule(trigger: "!", excludedCharacters: {" "}) ); _dueDatesPlugin.attach(_editor); - _dueDatesPlugin.tagIndex.addListener(_handleDueDateCommand); + _dueDatesPlugin.composingActionTag.addListener(_handleDueDateCommand); // Add action tags listener for inline commands - _assigneesPlugin = PatternTagPlugin( - tagRule: const TagRule(trigger: "@", excludedCharacters: {" ", "."}) + _assigneesPlugin = ActionTagsPlugin( + tagRule: const TagRule(trigger: "@", excludedCharacters: {" "}) ); _assigneesPlugin.attach(_editor); - _assigneesPlugin.tagIndex.addListener(_handleAssigneeCommand); + _assigneesPlugin.composingActionTag.addListener(_handleAssigneeCommand); // Create focus node _editorFocusNode = FocusNode(); @@ -131,9 +133,9 @@ class DocumentBuilder { void dispose() { _inlineCommandsPlugin.composingActionTag.removeListener(_handleInlineCommand); _inlineCommandsPlugin.detach(_editor); - _dueDatesPlugin.tagIndex.removeListener(_handleDueDateCommand); + _dueDatesPlugin.composingActionTag.removeListener(_handleDueDateCommand); _dueDatesPlugin.detach(_editor); - _assigneesPlugin.tagIndex.removeListener(_handleAssigneeCommand); + _assigneesPlugin.composingActionTag.removeListener(_handleAssigneeCommand); _assigneesPlugin.detach(_editor); _editorFocusNode.dispose(); _composer.dispose(); @@ -210,11 +212,11 @@ class DocumentBuilder { } void _handleDueDateCommand() { - + _logger.info("Due Date: ${_dueDatesPlugin.composingActionTag}"); } void _handleAssigneeCommand() { - + _logger.info("Assignee: ${_assigneesPlugin.composingActionTag}"); } // Add document structure change listener to detect new/deleted nodes From 03888916fe5365414b403a1e9bd8f6db819b2cc3 Mon Sep 17 00:00:00 2001 From: Davide Rutigliano Date: Tue, 27 May 2025 21:47:38 +0200 Subject: [PATCH 3/4] Aling plugin names --- src/frontend/lib/utils/document_builder.dart | 32 ++++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/frontend/lib/utils/document_builder.dart b/src/frontend/lib/utils/document_builder.dart index ab7e2f79..186cb775 100644 --- a/src/frontend/lib/utils/document_builder.dart +++ b/src/frontend/lib/utils/document_builder.dart @@ -30,8 +30,8 @@ class DocumentBuilder { // Plugins late final ActionTagsPlugin _inlineCommandsPlugin; - late final ActionTagsPlugin _dueDatesPlugin; - late final ActionTagsPlugin _assigneesPlugin; + late final ActionTagsPlugin _inlineTaskDueDatePlugin; + late final ActionTagsPlugin _inlineTaskAssigneePlugin; // Add instance of AttributedTextUtils static final AttributedTextUtils _attributedTextUtils = AttributedTextUtils(); @@ -109,18 +109,18 @@ class DocumentBuilder { _inlineCommandsPlugin.composingActionTag.addListener(_handleInlineCommand); // Add pattern tags listener for due dates - _dueDatesPlugin = ActionTagsPlugin( + _inlineTaskDueDatePlugin = ActionTagsPlugin( tagRule: const TagRule(trigger: "!", excludedCharacters: {" "}) ); - _dueDatesPlugin.attach(_editor); - _dueDatesPlugin.composingActionTag.addListener(_handleDueDateCommand); + _inlineTaskDueDatePlugin.attach(_editor); + _inlineTaskDueDatePlugin.composingActionTag.addListener(_handleDueDateCommand); // Add action tags listener for inline commands - _assigneesPlugin = ActionTagsPlugin( + _inlineTaskAssigneePlugin = ActionTagsPlugin( tagRule: const TagRule(trigger: "@", excludedCharacters: {" "}) ); - _assigneesPlugin.attach(_editor); - _assigneesPlugin.composingActionTag.addListener(_handleAssigneeCommand); + _inlineTaskAssigneePlugin.attach(_editor); + _inlineTaskAssigneePlugin.composingActionTag.addListener(_handleAssigneeCommand); // Create focus node _editorFocusNode = FocusNode(); @@ -133,10 +133,10 @@ class DocumentBuilder { void dispose() { _inlineCommandsPlugin.composingActionTag.removeListener(_handleInlineCommand); _inlineCommandsPlugin.detach(_editor); - _dueDatesPlugin.composingActionTag.removeListener(_handleDueDateCommand); - _dueDatesPlugin.detach(_editor); - _assigneesPlugin.composingActionTag.removeListener(_handleAssigneeCommand); - _assigneesPlugin.detach(_editor); + _inlineTaskDueDatePlugin.composingActionTag.removeListener(_handleDueDateCommand); + _inlineTaskDueDatePlugin.detach(_editor); + _inlineTaskAssigneePlugin.composingActionTag.removeListener(_handleAssigneeCommand); + _inlineTaskAssigneePlugin.detach(_editor); _editorFocusNode.dispose(); _composer.dispose(); _editor.dispose(); @@ -212,11 +212,11 @@ class DocumentBuilder { } void _handleDueDateCommand() { - _logger.info("Due Date: ${_dueDatesPlugin.composingActionTag}"); + _logger.info("Due Date: ${_inlineTaskDueDatePlugin.composingActionTag}"); } void _handleAssigneeCommand() { - _logger.info("Assignee: ${_assigneesPlugin.composingActionTag}"); + _logger.info("Assignee: ${_inlineTaskAssigneePlugin.composingActionTag}"); } // Add document structure change listener to detect new/deleted nodes @@ -1395,9 +1395,9 @@ class DocumentBuilder { // Tasks _inlineCommandsPlugin, // Due Dates - _dueDatesPlugin, + _inlineTaskDueDatePlugin, // Assignees - _assigneesPlugin, + _inlineTaskAssigneePlugin, }), ) ); From f7c491fa834308bf342d2b1648cd534f83ab9d43 Mon Sep 17 00:00:00 2001 From: Davide Rutigliano Date: Tue, 27 May 2025 22:28:27 +0200 Subject: [PATCH 4/4] Use single metadata plugin with "!" prefix --- src/frontend/lib/utils/document_builder.dart | 62 +++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/frontend/lib/utils/document_builder.dart b/src/frontend/lib/utils/document_builder.dart index 186cb775..1f7bcff9 100644 --- a/src/frontend/lib/utils/document_builder.dart +++ b/src/frontend/lib/utils/document_builder.dart @@ -30,8 +30,7 @@ class DocumentBuilder { // Plugins late final ActionTagsPlugin _inlineCommandsPlugin; - late final ActionTagsPlugin _inlineTaskDueDatePlugin; - late final ActionTagsPlugin _inlineTaskAssigneePlugin; + late final PatternTagPlugin _inlineMetadataPlugin; // Add instance of AttributedTextUtils static final AttributedTextUtils _attributedTextUtils = AttributedTextUtils(); @@ -104,23 +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 due dates - _inlineTaskDueDatePlugin = ActionTagsPlugin( + // Add pattern tags listener for inline metadata (due-date, assignee, etc) + _inlineMetadataPlugin = PatternTagPlugin( tagRule: const TagRule(trigger: "!", excludedCharacters: {" "}) ); - _inlineTaskDueDatePlugin.attach(_editor); - _inlineTaskDueDatePlugin.composingActionTag.addListener(_handleDueDateCommand); - - // Add action tags listener for inline commands - _inlineTaskAssigneePlugin = ActionTagsPlugin( - tagRule: const TagRule(trigger: "@", excludedCharacters: {" "}) - ); - _inlineTaskAssigneePlugin.attach(_editor); - _inlineTaskAssigneePlugin.composingActionTag.addListener(_handleAssigneeCommand); + _inlineMetadataPlugin.attach(_editor); + _inlineMetadataPlugin.tagIndex.addListener(_handleInlineMetadata); // Create focus node _editorFocusNode = FocusNode(); @@ -133,10 +127,8 @@ class DocumentBuilder { void dispose() { _inlineCommandsPlugin.composingActionTag.removeListener(_handleInlineCommand); _inlineCommandsPlugin.detach(_editor); - _inlineTaskDueDatePlugin.composingActionTag.removeListener(_handleDueDateCommand); - _inlineTaskDueDatePlugin.detach(_editor); - _inlineTaskAssigneePlugin.composingActionTag.removeListener(_handleAssigneeCommand); - _inlineTaskAssigneePlugin.detach(_editor); + _inlineMetadataPlugin.tagIndex.removeListener(_handleInlineMetadata); + _inlineMetadataPlugin.detach(_editor); _editorFocusNode.dispose(); _composer.dispose(); _editor.dispose(); @@ -211,12 +203,28 @@ class DocumentBuilder { } } - void _handleDueDateCommand() { - _logger.info("Due Date: ${_inlineTaskDueDatePlugin.composingActionTag}"); - } + void _handleInlineMetadata() { + for (final node in _document) { + if (node is! TextNode) { + continue; + } + + final tags = _inlineMetadataPlugin.tagIndex.getTagsInTextNode(node.id); - void _handleAssigneeCommand() { - _logger.info("Assignee: ${_inlineTaskAssigneePlugin.composingActionTag}"); + 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 @@ -1392,12 +1400,10 @@ class DocumentBuilder { MarkdownInlineUpstreamSyntaxPlugin( parsers: const [ StyleUpstreamMarkdownSyntaxParser() ] ), - // Tasks + // Inline Commands _inlineCommandsPlugin, - // Due Dates - _inlineTaskDueDatePlugin, - // Assignees - _inlineTaskAssigneePlugin, + // Inline Metadata + _inlineMetadataPlugin, }), ) );