@@ -109,6 +109,23 @@ Uri narrowLink(PerAccountStore store, Narrow narrow, {int? nearMessageId}) {
109109 return result;
110110}
111111
112+ /// The result of parsing some URL within a Zulip realm,
113+ /// when the URL corresponds to some page in this app.
114+ sealed class InternalLink {
115+ InternalLink ({required this .realmUrl});
116+
117+ final Uri realmUrl;
118+ }
119+
120+ /// The result of parsing some URL that points to a narrow on a Zulip realm,
121+ /// when the narrow is of a type that this app understands.
122+ class NarrowLink extends InternalLink {
123+ NarrowLink (this .narrow, this .nearMessageId, {required super .realmUrl});
124+
125+ final Narrow narrow;
126+ final int ? nearMessageId;
127+ }
128+
112129/// A [Narrow] from a given URL, on `store` 's realm.
113130///
114131/// `url` must already be a result from [PerAccountStore.tryResolveUrl]
@@ -124,7 +141,7 @@ Uri narrowLink(PerAccountStore store, Narrow narrow, {int? nearMessageId}) {
124141/// better, but some kinds will be rare, even unheard-of:
125142/// #narrow/stream/1-announce/stream/1-announce (duplicated operator)
126143// TODO(#252): handle all valid narrow links, returning a search narrow
127- Narrow ? parseInternalLink (Uri url, PerAccountStore store) {
144+ InternalLink ? parseInternalLink (Uri url, PerAccountStore store) {
128145 if (! _isInternalLink (url, store.realmUrl)) return null ;
129146
130147 final (category, segments) = _getCategoryAndSegmentsFromFragment (url.fragment);
@@ -155,7 +172,7 @@ bool _isInternalLink(Uri url, Uri realmUrl) {
155172 return (category, segments);
156173}
157174
158- Narrow ? _interpretNarrowSegments (List <String > segments, PerAccountStore store) {
175+ NarrowLink ? _interpretNarrowSegments (List <String > segments, PerAccountStore store) {
159176 assert (segments.isNotEmpty);
160177 assert (segments.length.isEven);
161178
@@ -164,6 +181,7 @@ Narrow? _interpretNarrowSegments(List<String> segments, PerAccountStore store) {
164181 ApiNarrowDm ? dmElement;
165182 ApiNarrowWith ? withElement;
166183 Set <IsOperand > isElementOperands = {};
184+ int ? nearMessageId;
167185
168186 for (var i = 0 ; i < segments.length; i += 2 ) {
169187 final (operator , negated) = _parseOperator (segments[i]);
@@ -201,24 +219,26 @@ Narrow? _interpretNarrowSegments(List<String> segments, PerAccountStore store) {
201219 // It is fine to have duplicates of the same [IsOperand].
202220 isElementOperands.add (IsOperand .fromRawString (operand));
203221
204- case _NarrowOperator .near: // TODO(#82): support for near
205- continue ;
222+ case _NarrowOperator .near:
223+ if (nearMessageId != null ) return null ;
224+ nearMessageId = int .tryParse (operand, radix: 10 );
206225
207226 case _NarrowOperator .unknown:
208227 return null ;
209228 }
210229 }
211230
231+ final Narrow ? narrow;
212232 if (isElementOperands.isNotEmpty) {
213233 if (streamElement != null || topicElement != null || dmElement != null || withElement != null ) {
214234 return null ;
215235 }
216236 if (isElementOperands.length > 1 ) return null ;
217237 switch (isElementOperands.single) {
218238 case IsOperand .mentioned:
219- return const MentionsNarrow ();
239+ narrow = const MentionsNarrow ();
220240 case IsOperand .starred:
221- return const StarredMessagesNarrow ();
241+ narrow = const StarredMessagesNarrow ();
222242 case IsOperand .dm:
223243 case IsOperand .private:
224244 case IsOperand .alerted:
@@ -230,17 +250,20 @@ Narrow? _interpretNarrowSegments(List<String> segments, PerAccountStore store) {
230250 }
231251 } else if (dmElement != null ) {
232252 if (streamElement != null || topicElement != null || withElement != null ) return null ;
233- return DmNarrow .withUsers (dmElement.operand, selfUserId: store.selfUserId);
253+ narrow = DmNarrow .withUsers (dmElement.operand, selfUserId: store.selfUserId);
234254 } else if (streamElement != null ) {
235255 final streamId = streamElement.operand;
236256 if (topicElement != null ) {
237- return TopicNarrow (streamId, topicElement.operand, with_: withElement? .operand);
257+ narrow = TopicNarrow (streamId, topicElement.operand, with_: withElement? .operand);
238258 } else {
239259 if (withElement != null ) return null ;
240- return ChannelNarrow (streamId);
260+ narrow = ChannelNarrow (streamId);
241261 }
262+ } else {
263+ return null ;
242264 }
243- return null ;
265+
266+ return NarrowLink (narrow, nearMessageId, realmUrl: store.realmUrl);
244267}
245268
246269@JsonEnum (fieldRename: FieldRename .kebab, alwaysCreate: true )
0 commit comments