/// <summary> /// Executes QuickFix or ContextAction. Returns post-execute method. /// </summary> /// <returns> /// Action to execute after document and PSI transaction finish. Use to open TextControls, navigate caret, etc. /// </returns> protected override Action <ITextControl> ExecutePsiTransaction(ISolution solution, IProgressIndicator progress) { MissingTokenErrorElement errorElement = _highlighting.AssociatedNode; IFile file = errorElement.GetContainingFile(); Assertion.AssertNotNull(file, "file != null"); TreeTextRange modifiedRange; TextRange hotspotRange; // replace the error token by the missing text using (file.CreateWriteLock()) { modifiedRange = errorElement.GetTreeTextRange(); ITokenNode previousToken = errorElement.GetPreviousToken(); if (previousToken != null && previousToken.GetTokenType() == T4TokenNodeTypes.NewLine) { modifiedRange = modifiedRange.Join(previousToken.GetTreeTextRange()); } Assertion.AssertNotNull(file, "file != null"); Pair <string, TextRange> textWithHotspotRange = GetMissingTextWithHotspotRange(errorElement); hotspotRange = textWithHotspotRange.Second; file.ReParse(modifiedRange, textWithHotspotRange.First); } if (!hotspotRange.IsValid) { return(null); } // create a hotspot around a directive name or value, with basic completion invoked return(textControl => { int startOffset = file.GetDocumentRange(modifiedRange.StartOffset).TextRange.StartOffset; var finalRange = new TextRange(startOffset + hotspotRange.StartOffset, startOffset + hotspotRange.EndOffset); string fieldName = textControl.Document.GetText(finalRange); Shell.Instance .GetComponent <LiveTemplatesManager>() .CreateHotspotSessionAtopExistingText( solution, TextRange.InvalidRange, textControl, LiveTemplatesManager.EscapeAction.LeaveTextAndCaret, new HotspotInfo( new TemplateField(fieldName, new MacroCallExpression(new BasicCompletionMacro()), 0), finalRange)) .Execute(); }); }