Skip to content

Commit 33f97e6

Browse files
committed
compose: Implement inlineLink, for Markdown "inline link" syntax
And use it in the one place where we've been creating inline links. This is a small amount of code, but drawing it out into a helper gives a convenient place to write down its shortcomings. We'll also use this for zulip#116 quote-and-reply, coming up.
1 parent 48ee5f8 commit 33f97e6

File tree

3 files changed

+32
-2
lines changed

3 files changed

+32
-2
lines changed

lib/model/compose.dart

+22
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,25 @@ Uri narrowLink(PerAccountStore store, Narrow narrow, {int? nearMessageId}) {
182182
String mention(User user, {bool silent = false}) {
183183
return '@${silent ? '_' : ''}**${user.fullName}|${user.userId}**';
184184
}
185+
186+
/// https://spec.commonmark.org/0.30/#inline-link
187+
///
188+
/// The "link text" is made by enclosing [visibleText] in square brackets.
189+
/// If [visibleText] has unexpected features, such as square brackets, the
190+
/// result may be surprising.
191+
///
192+
/// The part between "(" and ")" is just a "link destination" (no "link title").
193+
/// That destination is simply the stringified [destination], if provided.
194+
/// If that has parentheses in it, the result may be surprising.
195+
// TODO: Try harder to guarantee output that creates an inline link,
196+
// and in particular, the intended one. We could help with this by escaping
197+
// square brackets, perhaps with HTML character references:
198+
// https://github.com/zulip/zulip-flutter/pull/201#discussion_r1237951626
199+
// It's also tricky because nearby content can thwart the inline-link syntax.
200+
// From the spec:
201+
// > Backtick code spans, autolinks, and raw HTML tags bind more tightly
202+
// > than the brackets in link text. Thus, for example, [foo`]` could not be
203+
// > a link text, since the second ] is part of a code span.
204+
String inlineLink(String visibleText, Uri? destination) {
205+
return '[$visibleText](${destination?.toString() ?? ''})';
206+
}

lib/widgets/compose_box.dart

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:image_picker/image_picker.dart';
66

77
import '../api/route/messages.dart';
88
import '../model/autocomplete.dart';
9+
import '../model/compose.dart';
910
import '../model/narrow.dart';
1011
import 'dialog.dart';
1112
import 'store.dart';
@@ -135,7 +136,7 @@ class ComposeContentController extends ComposeController<ContentValidationError>
135136
int registerUploadStart(String filename) {
136137
final tag = _nextUploadTag;
137138
_nextUploadTag += 1;
138-
final placeholder = '[Uploading $filename...]()'; // TODO(i18n)
139+
final placeholder = inlineLink('Uploading $filename...', null); // TODO(i18n)
139140
_uploads[tag] = (filename: filename, placeholder: placeholder);
140141
notifyListeners(); // _uploads change could affect validationErrors
141142
value = value.replaced(_insertionIndex(), '$placeholder\n\n');
@@ -157,7 +158,7 @@ class ComposeContentController extends ComposeController<ContentValidationError>
157158

158159
value = value.replaced(
159160
replacementRange,
160-
url == null ? '' : '[$filename](${url.toString()})');
161+
url == null ? '' : inlineLink(filename, url));
161162
_uploads.remove(tag);
162163
notifyListeners(); // _uploads change could affect validationErrors
163164
}

test/model/compose_test.dart

+7
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,11 @@ hello
306306
check(mention(user, silent: false)).equals('@**Full Name|123**');
307307
check(mention(user, silent: true)).equals('@_**Full Name|123**');
308308
});
309+
310+
test('inlineLink', () {
311+
check(inlineLink('CZO', Uri.parse('https://chat.zulip.org/'))).equals('[CZO](https://chat.zulip.org/)');
312+
check(inlineLink('Uploading file.txt…', null)).equals('[Uploading file.txt…]()');
313+
check(inlineLink('IMG_2488.png', Uri.parse('/user_uploads/2/a3/ucEMyjxk90mcNF0y9rmW5XKO/IMG_2488.png')))
314+
.equals('[IMG_2488.png](/user_uploads/2/a3/ucEMyjxk90mcNF0y9rmW5XKO/IMG_2488.png)');
315+
});
309316
}

0 commit comments

Comments
 (0)