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; }
/// <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); } }