Skip to content

Commit 42da876

Browse files
committed
autocomplete: Identify when the user intends a channel link autocomplete
For this commit we temporarily intercept the query at the AutocompleteField widget, to avoid invoking the widgets that are still unimplemented. That lets us defer those widgets' logic to a separate later commit.
1 parent 07de01a commit 42da876

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

lib/model/autocomplete.dart

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ extension ComposeContentAutocomplete on ComposeContentController {
4949
} else if (charAtPos == ':') {
5050
final match = _emojiIntentRegex.matchAsPrefix(textUntilCursor, pos);
5151
if (match == null) continue;
52+
} else if (charAtPos == '#') {
53+
final match = _channelLinkIntentRegex.matchAsPrefix(textUntilCursor, pos);
54+
if (match == null) continue;
5255
} else {
5356
continue;
5457
}
@@ -67,6 +70,10 @@ extension ComposeContentAutocomplete on ComposeContentController {
6770
final match = _emojiIntentRegex.matchAsPrefix(textUntilCursor, pos);
6871
if (match == null) continue;
6972
query = EmojiAutocompleteQuery(match[1]!);
73+
} else if (charAtPos == '#') {
74+
final match = _channelLinkIntentRegex.matchAsPrefix(textUntilCursor, pos);
75+
if (match == null) continue;
76+
query = ChannelLinkAutocompleteQuery(match[1] ?? match[2]!);
7077
} else {
7178
continue;
7279
}
@@ -166,6 +173,32 @@ final RegExp _emojiIntentRegex = (() {
166173
+ r')$');
167174
})();
168175

176+
final RegExp _channelLinkIntentRegex = () {
177+
// Similar reasoning as in _mentionIntentRegex.
178+
const before = r'(?<=^|\s|\p{Punctuation})';
179+
180+
// TODO(upstream): maybe use duplicate-named capture groups for better readability?
181+
// https://github.com/dart-lang/sdk/issues/61337
182+
return RegExp(unicode: true,
183+
before
184+
+ r'#'
185+
// As Web, match both '#channel' and '#**channel'. In both cases, the raw
186+
// query is going to be 'channel'. Matching the second case, '#**channel',
187+
// is useful when user selects a channel from the autocomplete list, but then
188+
// starts pressing "backspace" to edit the query and choose another option,
189+
// instead of clearing the entire query and starting from scratch.
190+
+ r'(?:'
191+
// Case '#channel': right after '#', reject whitespace as well as '**'.
192+
+ r'(?!\s|\*\*)(.*)'
193+
+ r'|'
194+
// Case '#**channel': right after '#**', reject whitespace.
195+
// Also, make sure that the remaining query doesn't contain '**',
196+
// otherwise '#**channel**' (which is a complete channel link syntax) and
197+
// the text followed by that will always match.
198+
+ r'\*\*(?!\s)((?:(?!\*\*).)*)'
199+
+ r')$');
200+
}();
201+
169202
/// The text controller's recognition that the user might want autocomplete UI.
170203
class AutocompleteIntent<QueryT extends AutocompleteQuery> {
171204
AutocompleteIntent({

lib/widgets/autocomplete.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ class _AutocompleteFieldState<QueryT extends AutocompleteQuery, ResultT extends
4545
}
4646

4747
void _handleControllerChange() {
48-
final newQuery = widget.autocompleteIntent()?.query;
48+
var newQuery = widget.autocompleteIntent()?.query;
49+
if (newQuery is ChannelLinkAutocompleteQuery) newQuery = null; // TODO(#124)
4950
// First, tear down the old view-model if necessary.
5051
if (_viewModel != null
5152
&& (newQuery == null

0 commit comments

Comments
 (0)