private bool TryCommitSuggestionIntoDocument(ITextRange range, string displayText, Guid id, ITextCharacterFormat format, bool addTrailingSpace = true) { // We don't want to set text when the display text doesn't change since it may lead to unexpected caret move. range.GetText(TextGetOptions.NoHidden, out var existingText); if (existingText != displayText) { range.SetText(TextSetOptions.Unhide, displayText); } var formatBefore = range.CharacterFormat.GetClone(); range.CharacterFormat.SetClone(format); PadRange(range, formatBefore); range.Link = $"\"{id}\""; // In some rare case, setting Link can fail. Only observed when interacting with Undo/Redo feature. if (range.Link != $"\"{id}\"") { range.Delete(TextRangeUnit.Story, -1); return(false); } if (addTrailingSpace) { var clone = range.GetClone(); clone.Collapse(false); clone.SetText(TextSetOptions.Unhide, " "); clone.Collapse(false); TextDocument.Selection.SetRange(clone.EndPosition, clone.EndPosition); } return(true); }
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; }