public virtual void GetWordExtent( int line, int index, uint flags, TextSpan[] span){ Debug.Assert(line>=0 && index >=0); if (span == null) NativeHelpers.RaiseComError(HResult.E_INVALIDARG); else span[0] = new TextSpan(); span[0].iStartLine = span[0].iEndLine = line; span[0].iStartIndex = index; int start, end; if (!this.source.GetWordExtent( line, index, (WORDEXTFLAGS)flags, out start, out end)) { NativeHelpers.RaiseComError(HResult.S_FALSE); } span[0].iStartIndex = start; span[0].iEndIndex = end; }
public virtual void GetDataTipText( TextSpan[] aspan, out string text ) { text = null; TextSpan span = aspan[0]; if (!service.Preferences.EnableQuickInfo) { NativeHelpers.RaiseComError(HResult.E_FAIL); } if (span.iEndLine == this.quickInfoLine && span.iEndIndex == this.quickInfoIdx) { if (this.quickInfoText == null) { // still parsing on the background thread, so return E_PENDING. Trace.WriteLine("ViewFilter::GetDataTipText - E_PENDING"); NativeHelpers.RaiseComError(HResult.E_PENDING); } this.quickInfoLine = -1; if (this.quickInfoText == "") { // then the parser found nothing to display. NativeHelpers.RaiseComError(HResult.E_FAIL); } text = this.GetFullDataTipText(this.quickInfoText, span); aspan[0] = this.quickInfoSpan; this.quickInfoText = null; Trace.WriteLine("ViewFilter::GetDataTipText - '"+text+"'"); } else { // kick off the background parse to get this information... Trace.WriteLine("ViewFilter::GetDataTipText - OnQuickInfo - E_PENDING"); this.quickInfoText = null; this.quickInfoLine = span.iEndLine; this.quickInfoIdx = span.iEndIndex; this.source.BeginParse(span.iEndLine, span.iEndIndex, new TokenInfo(), ParseReason.QuickInfo, this.textView, new ParseResultHandler(HandleQuickInfoResponse)); NativeHelpers.RaiseComError(HResult.E_PENDING); } // bugbug: cannot return COM errors AND return out arguments. //NativeHelpers.RaiseComError((HResult)TipSuccesses.TIP_S_ONLYIFNOMARKER); }
public virtual string OnSyncGoto(VsCommands cmd, IVsTextView textView, int line, int col, out TextSpan span) { // synchronous parse and return definition location. string text = this.GetTextUpToLine(line+1); string fname = this.GetFilePath(); ParseReason reason = ParseReason.Autos; AuthoringSink sink = new AuthoringSink(reason, line, col); AuthoringScope scope = this.service.ParseSource(text, line, col, fname, sink, reason); if (scope != null) { return scope.Goto(cmd, textView, line, col, out span); } else { span = new TextSpan(); } return null; }
public virtual void UnCommentSelection(IVsTextView textView) { CCITracing.TraceCall(); //get text range TextSpan[] aspan = new TextSpan[1]; textView.GetSelectionSpan(aspan); TextSpan span = aspan[0]; //check bounds if (span.iEndIndex == 0) span.iEndLine--; //get line lengths int startLen,endLen; this.textLines.GetLengthOfLine( span.iStartLine, out startLen ); this.textLines.GetLengthOfLine( span.iEndLine, out endLen ); // adjust end index if necessary if (span.iEndIndex == 0) span.iEndIndex = endLen; int adjustment = 0; // is block comment selected? if (this.commentInfo.blockStart != null && this.commentInfo.blockEnd != null) { // TODO: this doesn't work if the selection contains a mix of code and block comments // or multiple block comments!! We should use our parse tree to find the embedded // comments and uncomment the resulting comment spans only. string startText = null; this.textLines.GetLineText( span.iStartLine, span.iStartIndex, span.iStartLine, span.iStartIndex+this.commentInfo.blockStart.Length, out startText ); if (startText == this.commentInfo.blockStart) { string endText = null; this.textLines.GetLineText( span.iEndLine, span.iEndIndex- this.commentInfo.blockEnd.Length, span.iEndLine, span.iEndIndex, out endText ); if (endText == this.commentInfo.blockEnd) { //yes, block comment selected; remove it this.textLines.ReplaceLines( span.iEndLine, span.iEndIndex-this.commentInfo.blockEnd.Length, span.iEndLine, span.iEndIndex, null, 0, null); this.textLines.ReplaceLines( span.iStartLine, span.iStartIndex, span.iStartLine, span.iStartIndex+this.commentInfo.blockStart.Length, null, 0, null); adjustment = - commentInfo.blockEnd.Length; if (span.iStartLine == span.iEndLine) adjustment -= commentInfo.blockStart.Length; goto end; } } } //if no line comment possible, we are done if (!this.commentInfo.useLineComments) NativeHelpers.RaiseComError(HResult.S_FALSE); // try if we can remove line comments, using the scanner to find them for (int line = span.iStartLine; line <= span.iEndLine; line++) { TokenInfo[] lineInfo = this.colorizer.GetLineInfo(line, this.colorState); for (int i = 0, n = lineInfo.Length; i<n; i++) { if (lineInfo[i].type == TokenType.LineComment) { this.textLines.ReplaceLines(line, lineInfo[i].startIndex, line, lineInfo[i].startIndex+this.commentInfo.lineStart.Length, null, 0, null); if (line == span.iEndLine) { adjustment = - this.commentInfo.lineStart.Length; } } } } end: if (TextSpanHelper.TextSpanPositive(span)) textView.SetSelection( span.iStartLine, span.iStartIndex, span.iEndLine, span.iEndIndex + adjustment ); else textView.SetSelection( span.iEndLine, span.iEndIndex + adjustment, span.iStartLine, span.iStartIndex ); }
internal void HandleMethodTipResponse(ParseRequest req) { try { CallInfo call = req.Sink.MethodCalls.GetCurrentMethodCall(); if (call == null) goto fail; IdentifierList names = call.names; if (names.Length == 0) goto fail; Identifier name = names[names.Length-1]; SourceContext ctx = name.SourceContext; Methods methods = req.Scope.GetMethods(ctx.StartLine-1, ctx.StartColumn-1, name); if (methods == null) goto fail; TextSpan span = new TextSpan(); span.iStartLine = ctx.StartLine-1; span.iStartIndex = ctx.StartColumn-1; span.iEndLine = ctx.EndLine-1; span.iEndIndex = ctx.EndColumn-1; int currentParameter = call.currentParameter; this.methodData.Refresh(req.View, methods, currentParameter, span ); return; fail: DismissMethodTip(); } catch (Exception e) { CCITracing.Trace("HandleMethodTipResponse exception: " + e.Message); } }
// helper methods. public TaskItem CreateErrorTaskItem(TextSpan span, string message, Severity severity) { //normalize text span TextSpanHelper.TextSpanNormalize(ref span, textLines); //remove control characters StringBuilder sb = new StringBuilder(); for (int i = 0, n = message.Length; i<n; i++) { char ch = message[i]; sb.Append( System.Convert.ToInt32(ch) < 0x20 ? ' ' : ch); } message = sb.ToString(); //set options VsShellInterop.VSTASKPRIORITY priority = VsShellInterop.VSTASKPRIORITY.TP_NORMAL; VsShellInterop._vstaskbitmap bitmap = VsShellInterop._vstaskbitmap.BMP_SQUIGGLE; VsShellInterop.VSTASKCATEGORY category = VsShellInterop.VSTASKCATEGORY.CAT_CODESENSE; MARKERTYPE markerType = MARKERTYPE.MARKER_CODESENSE_ERROR; if (severity == Severity.SevFatal) { priority = VsShellInterop.VSTASKPRIORITY.TP_HIGH; } else if (severity == Severity.SevHint) { if (this.taskProvider != null) { if (!taskProvider.IsTaskToken(message, out priority )) return null; } bitmap = VsShellInterop._vstaskbitmap.BMP_COMMENT; category = VsShellInterop.VSTASKCATEGORY.CAT_COMMENTS; markerType = MARKERTYPE.MARKER_INVISIBLE; } // create marker so task item navigation works even after file is edited. IVsTextLineMarker textLineMarker = TextMarkerClient.CreateMarker(textLines, span, markerType, message); string fileName = this.GetFilePath(); // create task item TaskItem taskItem = new TaskItem(this.service.site, textLineMarker, fileName, message, true, category, priority, bitmap, null ); return taskItem; }
// Special View filter command handling. public virtual void CommentSelection(IVsTextView textView) { CCITracing.TraceCall(); //get text range TextSpan[] aspan = new TextSpan[1]; textView.GetSelectionSpan(aspan); TextSpan span = aspan[0]; //check bounds if (span.iEndIndex == 0) span.iEndLine--; //get line lengths int startLen,endLen; this.textLines.GetLengthOfLine( span.iStartLine, out startLen ); this.textLines.GetLengthOfLine( span.iEndLine, out endLen ); // adjust end index if necessary if (span.iEndIndex == 0) span.iEndIndex = endLen; int adjustment = 0; //try to use line comments first, if we can. if (this.commentInfo.useLineComments && span.iStartIndex == 0 && span.iEndIndex == endLen) { //comment each line for (int line = span.iStartLine; line <= span.iEndLine; line++) { this.textLines.ReplaceLines( line, 0, line, 0, this.commentInfo.lineStart, this.commentInfo.lineStart.Length, null); } adjustment = this.commentInfo.lineStart.Length; span.iStartIndex = 0; } // otherwise try to use block comments else if (this.commentInfo.blockStart != null && this.commentInfo.blockEnd != null) { //add end comment this.textLines.ReplaceLines( span.iEndLine, span.iEndIndex, span.iEndLine, span.iEndIndex , this.commentInfo.blockEnd, this.commentInfo.blockEnd.Length, null); //add start comment this.textLines.ReplaceLines( span.iStartLine, span.iStartIndex, span.iStartLine, span.iStartIndex , this.commentInfo.blockStart, this.commentInfo.blockStart.Length, null); adjustment = this.commentInfo.blockEnd.Length; if (span.iStartLine == span.iEndLine) adjustment += this.commentInfo.blockStart.Length; } else NativeHelpers.RaiseComError(HResult.E_FAIL); if (TextSpanHelper.TextSpanPositive(span)) textView.SetSelection( span.iStartLine, span.iStartIndex, span.iEndLine, span.iEndIndex + adjustment ); else textView.SetSelection( span.iEndLine, span.iEndIndex + adjustment, span.iStartLine, span.iStartIndex ); }
public void Refresh( IVsTextView textView, Methods methods, int currentParameter, TextSpan context ) { this.methods = methods; this.context = context; // Apparently this Refresh() method is called as a result of event notification // after the currentMethod is changed, so we do not want to Dismiss anything or // reset the currentMethod here. This fixes bug #235 //Dismiss(); this.textView = textView; this.methods = methods; // TODO: We could do so much better since we have a full parse tree available // we could intelligently select the best matching method based on what the user // has already typed in !! // m_currentMethod = 0; this.currentParameter = currentParameter; this.AdjustCurrentParameter( 0 ); }
// IVsFinalTextChangeCommitEvents public virtual void OnChangesCommitted( uint reason, TextSpan[] changedArea) { SetDirty(); }
public virtual void GetPairExtents( int line, int col, out TextSpan span ) { span = new TextSpan(); // Synchronously return the matching brace location. string text = this.GetTextUpToLine(0); // Might be matching forwards so we have to search the whole file. string fname = this.GetFilePath(); ParseReason reason = ParseReason.MatchBraces; AuthoringSink sink = new AuthoringSink(reason, line, col); AuthoringScope scope = this.service.ParseSource(text, line, col, fname, sink, reason); if (sink.Spans.Count == 0) return; //transform spanList into an array of spans TextSpan[] spans = (TextSpan[])sink.Spans.ToArray(typeof(TextSpan)); int spanCount = spans.Length; //called from ViewFilter::GetPairExtents if (spans[0].iStartLine < spans[spanCount-1].iStartLine || (spans[0].iStartLine == spans[spanCount-1].iStartLine && spans[0].iStartIndex <= spans[spanCount-1].iStartIndex )) { span.iStartLine = spans[0].iStartLine; span.iStartIndex = spans[0].iStartIndex; span.iEndLine = spans[spanCount-1].iStartLine; span.iEndIndex = spans[spanCount-1].iStartIndex; } else { span.iStartLine = spans[spanCount-1].iStartLine; span.iStartIndex = spans[spanCount-1].iStartIndex; span.iEndLine = spans[0].iStartLine; span.iEndIndex = spans[0].iStartIndex; } if (span.iStartLine == span.iEndLine && span.iStartIndex == span.iEndIndex) NativeHelpers.RaiseComError(HResult.S_FALSE); return; }
public static bool TextSpanEndsBeforeAt(TextSpan span1, TextSpan span2) { return(span1.iEndLine < span2.iEndLine || (span1.iEndLine == span2.iEndLine && span1.iEndIndex <= span2.iEndIndex)); }
public virtual string GetFullDataTipText(string text, TextSpan ts) { IVsTextLines textLines; this.textView.GetBuffer(out textLines); // Now, check if the debugger is running and has anything to offer string debugDataTip = null; try { Microsoft.VisualStudio.Shell.Interop.IVsDebugger debugger = this.service.GetIVsDebugger(); if (debugger != null) { TextSpan[] tsdeb = new TextSpan[1] { ts }; bool selection = ( (ts.iStartLine != ts.iEndLine) || (ts.iStartIndex != ts.iEndIndex) ); if (!selection) { // The debugger can't determine the current word by itself. // Do it for them... textView.GetWordExtent(ts.iStartLine, ts.iStartIndex, (uint)WORDEXTFLAGS.WORDEXT_FINDWORD | (uint)WORDEXTFLAGS.WORDEXT_CURRENT, tsdeb); } // What a royal pain! // Microsoft.VisualStudio.Shell.Interop.TextSpan[] tsa = new Microsoft.VisualStudio.Shell.Interop.TextSpan[1]; // tsa[0].iEndIndex = tsdeb[0].iEndIndex; // tsa[0].iEndLine = tsdeb[0].iEndLine; // tsa[0].iStartIndex = tsdeb[0].iStartIndex; // tsa[0].iStartLine = tsdeb[0].iStartLine; debugger.GetDataTipValue(textLines, tsdeb, null, out debugDataTip); } } catch (COMException e) { Trace.WriteLine("GetDataTipValue="+e.ErrorCode); } if (debugDataTip == null || debugDataTip == "") { return text ; } int i = debugDataTip.IndexOf('='); if (i < 0) { return text; } else { string spacer = (i < debugDataTip.Length-1 && debugDataTip[i+1] == ' ') ? " " : ""; return text + spacer + debugDataTip.Substring(i); } }
public virtual void HandleGoto(VsCommands cmd) { TextSpan ts = new TextSpan(); // Get the caret position this.textView.GetCaretPos(out ts.iStartLine, out ts.iStartIndex); ts.iEndLine = ts.iStartLine; ts.iEndIndex = ts.iStartIndex; // Get the tip text at that location. // Wait, since the user specifically requested this one... TextSpan span; string url = this.source.OnSyncGoto(cmd, this.textView, ts.iEndLine, ts.iEndIndex, out span); if (url == null || url.Trim() == "") { // nothing to show return; } // Open the referenced document, and scroll to the given location. VsShellInterop.IVsUIHierarchy hierarchy; uint itemID; VsShellInterop.IVsWindowFrame frame; IVsTextView view; VsShell.OpenDocument(this.service.site, url, out hierarchy, out itemID, out frame, out view); if (view != null) { view.EnsureSpanVisible(span); view.SetSelection(span.iStartLine, span.iStartIndex, span.iEndLine, span.iEndIndex); } }
public virtual void HandleQuickInfo() { TextSpan ts = new TextSpan(); // Get the caret position this.textView.GetCaretPos(out ts.iStartLine, out ts.iStartIndex); ts.iEndLine = ts.iStartLine; ts.iEndIndex = ts.iStartIndex; // Get the tip text at that location. // Wait, since the user specifically requested this one... string text = this.source.OnSyncQuickInfo(this.textView, ts.iEndLine, ts.iEndIndex); if (text == null) { // nothing to show return; } string fullText = GetFullDataTipText(text, ts); if (fullText == null) { return; } int iPos, iPosEnd, iSpace, iLength; // Calculate the stream position textView.GetNearestPosition(ts.iStartLine, ts.iStartIndex, out iPos, out iSpace); textView.GetNearestPosition (ts.iEndLine, ts.iEndIndex, out iPosEnd, out iSpace); iLength = Math.Max(iPosEnd - iPos, 1); // Tear down the method tip if it's there this.source.DismissMethodTip(); // Update the text tip window TextTipData textTipData = GetTextTipData(); textTipData.Update(fullText, iPos, iLength, this.textView); }
public virtual void GetPairExtents(int line, int index, TextSpan[] span) { Trace.WriteLine("ViewFilter::GetWordExtent"); Debug.Assert(line>=0 && index >=0); if (span == null) NativeHelpers.RaiseComError(HResult.E_INVALIDARG); this.source.GetPairExtents( line, index, out span[0] ); }
public static bool TextSpanIsEmpty(TextSpan span) { return(span.iStartLine < 0 || span.iEndLine < 0 || span.iStartIndex < 0 || span.iEndIndex < 0); }
public static void ClearTextSpan(ref TextSpan span) { span.iStartLine = span.iEndLine = -1; span.iStartIndex = span.iEndIndex = -1; }
public static bool TextSpanPositive(TextSpan span) { return(span.iStartLine < span.iEndLine || (span.iStartLine == span.iEndLine && span.iStartIndex <= span.iEndIndex)); }
internal void ReportErrors(ErrorNodeList errors) { TextSpan firstError = new TextSpan(); int errorMax = this.service.Preferences.MaxErrorMessages; this.taskProvider.ClearErrors(); for (int i = 0, n = errors.Length; i < n; i++ ) { ErrorNode enode = errors[i]; SourceContext ctx = enode.SourceContext; Severity severity = enode.Severity > 0 ? Severity.SevError : Severity.SevWarning; string message = enode.GetMessage(this.service.culture); if (message == null) return; //set error TextSpan span; span.iStartLine = ctx.StartLine-1; span.iStartIndex = ctx.StartColumn-1; span.iEndLine = ctx.EndLine-1; span.iEndIndex = ctx.EndColumn-1; // Don't do multi-line squiggles, instead just squiggle to the // end of the first line. if (span.iEndLine > span.iStartLine) { span.iEndLine = span.iStartLine; this.textLines.GetLengthOfLine(span.iStartLine, out span.iEndIndex); } if (TextSpanHelper.TextSpanIsEmpty( firstError) && (severity > Severity.SevWarning)) { firstError = span; } this.taskProvider.AddTask(this.CreateErrorTaskItem(span, message, severity)); //check error count if (i == errorMax) { string maxMsg = UIStrings.GetString(UIStringNames.MaxErrorsReached); TaskItem error = this.CreateErrorTaskItem(span, maxMsg, Severity.SevWarning); this.taskProvider.AddTask(error); break; } } this.taskProvider.RefreshTaskWindow(); }
public static bool TextSpanAfterAt(TextSpan span1, TextSpan span2) { return(span1.iStartLine > span2.iStartLine || (span1.iStartLine == span2.iStartLine && span1.iStartIndex >= span2.iStartIndex)); }