Skip to content

Commit

Permalink
Comments reviewed & rebase on master
Browse files Browse the repository at this point in the history
  • Loading branch information
amantoux committed Dec 7, 2023
1 parent 4c22640 commit 5dc6d9b
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 55 deletions.
114 changes: 60 additions & 54 deletions packages/fleather/lib/src/widgets/autoformats.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,26 @@ import 'package:flutter/services.dart';
import 'package:intl/intl.dart' as intl;
import 'package:quill_delta/quill_delta.dart';

/// An [AutoFormat] is responsible for looking back for a pattern and apply a
/// formatting suggestion.
/// An [AutoFormat] is responsible for looking backwards for a pattern and
/// applying a formatting suggestion to a document.
///
/// For example, identify a link a automatically wrap it with a link attribute or
/// apply formatting using Markdown shortcuts
/// For example, identifying a link and automatically wrapping it with a link
/// attribute or applying block formats using Markdown shortcuts
abstract class AutoFormat {
const AutoFormat();

/// Indicates whether character trigger auto format is kept in document
/// Indicates whether the character triggering the auto format is kept in
/// document
///
/// E.g: for link detections, '[space]' is kept whereas for Markdown block
/// shortcuts, the '[space]' is not added to document, it only serves to
/// E.g: for link detections, [space] is kept whereas for Markdown block
/// shortcuts, the [space] is not added to document, it only serves to
/// trigger the block formatting
bool get keepTriggerCharacter;

/// Upon upon insertion of a space or new line run format detection and apply
/// Upon insertion of a trigger character, run format detection and apply
/// formatting to document
/// Returns a [ActiveFormatResult].
///
/// Returns a [AutoFormatResult].
AutoFormatResult? apply(
ParchmentDocument document, int position, String data);
}
Expand All @@ -48,21 +50,22 @@ class AutoFormats {
/// The selection override of the active formatting suggestion
TextSelection? get selection => _activeSuggestion!.selection;

/// The position at with the active suggestion can be deactivated
/// The position at which the active suggestion can be deactivated
int get undoPosition => _activeSuggestion!.undoPositionCandidate;

/// `true` if the active suggestion auto format keeps trigger character in
/// `true` if the active suggestion [AutoFormat] keeps trigger character in
/// document; `false` otherwise
bool get activeSuggestionKeepTriggerCharacter =>
_activeSuggestion!.keepTriggerCharacter;

/// `true` if there is an active auto format suggestion; `false` otherwise
/// `true` if there is an active suggestion; `false` otherwise
bool get hasActiveSuggestion => _activeSuggestion != null;

/// Perform detection of auto formats and apply changes to [document]
/// Perform detection of auto formats and apply changes to [document].
///
/// Inserted data must be of type [String].
///
/// Inserted data must be of type [String]
/// Returns `true` if auto format was activated
/// Returns `true` if auto format was activated; `false` otherwise
bool run(ParchmentDocument document, int position, Object data) {
if (data is! String || data.isEmpty) {
return false;
Expand All @@ -77,22 +80,23 @@ class AutoFormats {
return false;
}

/// Remove auto format from [document] and de-activate current suggestion
/// It will throw if [_activeSuggestion] is null.
/// Remove auto format from [document] and de-activate current suggestion.
///
/// This will throw if [_activeSuggestion] is null.
TextSelection? undoActive(ParchmentDocument document) {
final undoSelection = _activeSuggestion!.undoSelection;
document.compose(_activeSuggestion!.undo, ChangeSource.local);
_activeSuggestion = null;
return undoSelection;
}

/// Cancel active auto format
/// Cancel active suggestion
void cancelActive() {
_activeSuggestion = null;
}
}

/// An auto format result
/// The result of a [AutoFormat.apply] that has detected a pattern
class AutoFormatResult {
AutoFormatResult({
this.selection,
Expand All @@ -103,15 +107,17 @@ class AutoFormatResult {
required this.keepTriggerCharacter,
});

/// The selection after applying the auto format
/// Optional
/// *Optional* [TextSelection] after applying the auto format.
///
/// Useful for Markdown shortcuts for example
final TextSelection? selection;

/// The change that was applied
final Delta change;

/// The selection after undoing the formatting
/// Optional
/// *Optional* [TextSelection] after undoing the formatting
///
/// Useful for Markdown shortcuts for example
final TextSelection? undoSelection;

/// The changes to undo the formatting
Expand Down Expand Up @@ -204,6 +210,37 @@ class _MarkdownShortCuts extends AutoFormat {
return prefixOps.map((e) => e.data).cast<String>().join();
}

// Skips to the beginning of line containing position at specified [length]
// and returns contents of the line skipped so far.
List<Operation> skipToLineAt(DeltaIterator iter, int length) {
if (length == 0) {
return List.empty(growable: false);

Check warning on line 217 in packages/fleather/lib/src/widgets/autoformats.dart

View check run for this annotation

Codecov / codecov/patch

packages/fleather/lib/src/widgets/autoformats.dart#L217

Added line #L217 was not covered by tests
}

final prefix = <Operation>[];

var skipped = 0;
while (skipped < length && iter.hasNext) {
final opLength = iter.peekLength();
final skip = math.min(length - skipped, opLength);
final op = iter.next(skip);
if (op.data is! String) {
prefix.add(op);

Check warning on line 228 in packages/fleather/lib/src/widgets/autoformats.dart

View check run for this annotation

Codecov / codecov/patch

packages/fleather/lib/src/widgets/autoformats.dart#L228

Added line #L228 was not covered by tests
} else {
var text = op.data as String;
var pos = text.lastIndexOf('\n');
if (pos == -1) {
prefix.add(op);
} else {
prefix.clear();
prefix.add(Operation.insert(text.substring(pos + 1), op.attributes));
}
}
skipped += op.length;
}
return prefix;
}

(TextSelection, Delta)? _formatLine(
DeltaIterator iter, int index, String prefix, ParchmentAttribute attr) {
/// First, delete the shortcut prefix itself.
Expand Down Expand Up @@ -311,37 +348,6 @@ class _MarkdownShortCuts extends AutoFormat {
}
}

// Skips to the beginning of line containing position at specified [length]
// and returns contents of the line skipped so far.
List<Operation> skipToLineAt(DeltaIterator iter, int length) {
if (length == 0) {
return List.empty(growable: false);
}

final prefix = <Operation>[];

var skipped = 0;
while (skipped < length && iter.hasNext) {
final opLength = iter.peekLength();
final skip = math.min(length - skipped, opLength);
final op = iter.next(skip);
if (op.data is! String) {
prefix.add(op);
} else {
var text = op.data as String;
var pos = text.lastIndexOf('\n');
if (pos == -1) {
prefix.add(op);
} else {
prefix.clear();
prefix.add(Operation.insert(text.substring(pos + 1), op.attributes));
}
}
skipped += op.length;
}
return prefix;
}

// Infers text direction from the input when happens in the beginning of a line.
// This rule also removes alignment and sets it based on inferred direction.
class _AutoTextDirection extends AutoFormat {
Expand Down
2 changes: 1 addition & 1 deletion packages/fleather/lib/src/widgets/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class FleatherController extends ChangeNotifier {
_autoFormats.activeSuggestionKeepTriggerCharacter;
final isDeletionOfOneChar = data is String && data.isEmpty && length == 1;
if (isDeletionOfOneChar) {
// Undo if deleting 1 character after retain of autoformat
// Undo if deleting 1 character after retain of auto-format
if (position == _autoFormats.undoPosition) {
final undoSelection = _autoFormats.undoActive(document);
if (undoSelection != null) {
Expand Down

0 comments on commit 5dc6d9b

Please sign in to comment.