private void ValidateTokenFromRange(ITextRange range)
        {
            if (range.Length == 0 || !TryGetTokenFromRange(range, out var token))
            {
                return;
            }

            // Check for duplicate tokens. This can happen if the user copies and pastes the token multiple times.
            if (token.Active && token.RangeStart != range.StartPosition && token.RangeEnd != range.EndPosition)
            {
                var guid = Guid.NewGuid();
                if (TryCommitSuggestionIntoDocument(range, token.DisplayText, guid, CreateTokenFormat(range), false))
                {
                    token = new RichSuggestToken(guid, token.DisplayText)
                    {
                        Active = true, Item = token.Item
                    };
                    token.UpdateTextRange(range);
                    _tokens.Add(range.Link, token);
                }

                return;
            }

            if (token.ToString() != range.Text)
            {
                range.Delete(TextRangeUnit.Story, 0);
                token.Active = false;
                return;
            }

            token.UpdateTextRange(range);
            token.Active = true;
        }
Example #2
0
        /// <summary>
        /// Try getting the token associated with a text range.
        /// </summary>
        /// <param name="range">The range of the token to get.</param>
        /// <param name="token">When this method returns, contains the token associated with the specified range; otherwise, it is null.</param>
        /// <returns>true if there is a token associated with the text range; otherwise false.</returns>
        public bool TryGetTokenFromRange(ITextRange range, out RichSuggestToken token)
        {
            token = null;
            range = range.GetClone();
            if (range != null && !string.IsNullOrEmpty(range.Link))
            {
                lock (_tokensLock)
                {
                    return(_tokens.TryGetValue(range.Link, out token));
                }
            }

            return(false);
        }
        internal async Task CommitSuggestionAsync(object selectedItem)
        {
            var currentQuery = _currentQuery;
            var range        = currentQuery?.Range.GetClone();
            var id           = Guid.NewGuid();
            var prefix       = currentQuery?.Prefix;
            var query        = currentQuery?.QueryText;

            // range has length of 0 at the end of the commit.
            // Checking length == 0 to avoid committing twice.
            if (prefix == null || query == null || range == null || range.Length == 0)
            {
                return;
            }

            var textBefore = range.Text;
            var format     = CreateTokenFormat(range);
            var eventArgs  = new SuggestionChosenEventArgs
            {
                Id           = id,
                Prefix       = prefix,
                QueryText    = query,
                SelectedItem = selectedItem,
                DisplayText  = query,
                Format       = format
            };

            if (SuggestionChosen != null)
            {
                await SuggestionChosen.InvokeAsync(this, eventArgs);
            }

            var text = eventArgs.DisplayText;

            // Since this operation is async, the document may have changed at this point.
            // Double check if the range still has the expected query.
            if (string.IsNullOrEmpty(text) || textBefore != range.Text ||
                !TryExtractQueryFromRange(range, out var testPrefix, out var testQuery) ||
                testPrefix != prefix || testQuery != query)
            {
                return;
            }

            var displayText = prefix + text;

            void RealizeToken()
            {
                if (TryCommitSuggestionIntoDocument(range, displayText, id, eventArgs.Format ?? format, true))
                {
                    var token = new RichSuggestToken(id, displayText)
                    {
                        Active = true, Item = selectedItem
                    };
                    token.UpdateTextRange(range);
                    _tokens.Add(range.Link, token);
                }
            }

            lock (_tokensLock)
            {
                this.CreateSingleEdit(RealizeToken);
            }
        }