/// <summary> /// The same as /// <see cref="LocalContextStateExtensions.ActiveNodeAs{T}(LocalContextState)"/> /// but for getting the virtual node. /// </summary> /// <typeparam name="T">The type of virtual node to get.</typeparam> /// <param name="state"> /// The state from which the <see cref="LocalContextState.ActiveNode"/> /// should be retrieved and casted. /// </param> /// <returns> /// The casted <see cref="LocalContextState.ActiveNode"/> to the specified type. /// </returns> /// <exception cref="InvalidOperationException"> /// Thrown when active node of the <see cref="LocalContextState"/> /// is not initialized or isn't virtual. /// </exception> /// <exception cref="InvalidCastException"> /// Thrown when the <see cref="LocalContextState.ActiveNode"/> cannot be /// casted to the specified type. /// </exception> public static T ActiveNodeAsVirtual <T>(this LocalContextState state) where T : IVirtualSyntaxNode { _ = state ?? throw new ArgumentNullException(nameof(state)); if (state.ActiveNode == null) { throw new InvalidOperationException( "The active node is missing on the provided state."); } if (!state.ActiveNode.Value.IsVirtual) { throw new InvalidOperationException( "The active node of the provided state is not a virtual node."); } if (!(state.ActiveNode.Value.MixedNode is T castedValue)) { throw new InvalidCastException( "The active node type doesn't match the requested one. " + $"The actual type: {state.ActiveNode.Value.MixedNode.GetType()}. " + $"The expected type: {typeof(T)}."); } return(castedValue); }
/// <summary> /// Retrieves the <see cref="LocalContextState.ActiveNode"/> /// for the specified <see cref="LocalContextState"/> and cast it /// to the specified type. /// </summary> /// <typeparam name="T"> /// The type to which <see cref="LocalContextState.ActiveNode"/> /// should be casted. /// </typeparam> /// <param name="state"> /// The state from which the <see cref="LocalContextState.ActiveNode"/> /// should be retrieved and casted. /// </param> /// <returns> /// The casted <see cref="LocalContextState.ActiveNode"/> to the specified type. /// </returns> /// <exception cref="InvalidCastException"> /// Thrown when the <see cref="LocalContextState.ActiveNode"/> cannot be /// casted to the specified type. /// </exception> public static T ActiveNodeAs <T>(this LocalContextState state) where T : SyntaxNode { _ = state ?? throw new ArgumentNullException(nameof(state)); if (!(state.ActiveNode?.BaseNode is T castedValue)) { throw new InvalidCastException("Unable to cast the target node."); } return(castedValue); }
private void UpdateContextAndJump(Action <LocalContextState> jumpAction) { this.operationSemaphorSlim.Wait(); try { IWpfTextView?view = this.viewAccessor?.ActiveView; if (view == null && this.lastView != null) { this.lastView.LayoutChanged -= this.View_LayoutChanged; this.lastView = null; this.lastSnapshot = null; } if (view != null && this.lastActiveView != view) { if (this.adornment != null) { this.adornment.Remove(); } this.adornment = new TextHighlightAdornment(view); this.lastActiveView = view; string text = view.TextSnapshot.GetText(); SyntaxTree tree = CSharpSyntaxTree.ParseText(text); this.localContext = new LocalContext(tree); view.LayoutChanged += View_LayoutChanged; this.lastView = view; } if (this.adornment != null && view != null) { _ = this.localContext ?? throw new NullReferenceException( "The local context should be initialized first."); this.adornment.Remove(); SnapshotPoint caret = view.Caret.Position.BufferPosition; IWpfTextViewLine textViewLine = view.GetTextViewLineContainingBufferPosition(caret); int line = caret.GetContainingLine().LineNumber; int startChar = textViewLine.Start.Difference(caret); Debug.WriteLine( "The state before cursor update:\t" + $"{this.localContext.State.GetType().Name}"); this.localContext.TransitionTo(line, startChar); Debug.WriteLine( "The state after cursor update:\t" + $"{this.localContext.State.GetType().Name}"); jumpAction(this.localContext.State); LocalContextState state = this.localContext.State; Debug.WriteLine( "The state after jump:\t\t\t" + $"{this.localContext.State.GetType().Name}"); if (state.IsJumpTargetSet) { this.adornment.EndorseTextBounds( state.JumpTargetStartLine, state.JumpTargetEndLine, state.JumpTargetStartChar, state.JumpTargetEndChar); ITextSnapshotLine jumpTargetLine = view.TextSnapshot .GetLineFromLineNumber(state.JumpTargetStartLine); SnapshotPoint jumpPoint = jumpTargetLine.Start.Add(state.JumpTargetStartChar); view.Caret.MoveTo(new SnapshotPoint(view.TextSnapshot, jumpPoint)); if (!view.TextViewLines.ContainsBufferPosition(jumpPoint)) { var span = new SnapshotSpan( view.TextSnapshot, Span.FromBounds(jumpTargetLine.Start, jumpTargetLine.End)); view.ViewScroller.EnsureSpanVisible( span, EnsureSpanVisibleOptions.AlwaysCenter); } view.Caret.EnsureVisible(); } } } finally { this.operationSemaphorSlim.Release(); } }