ViewFilter.cs :  » Development » StyleCop » Microsoft » VisualStudio » Package » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Development » StyleCop 
StyleCop » Microsoft » VisualStudio » Package » ViewFilter.cs
//#define TRACE_EXEC
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio;
using System;
using System.Globalization;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell.Interop;
using IOleServiceProviderMicrosoft.VisualStudio.OLE.Interop.IServiceProvider;
using IServiceProviderSystem.IServiceProvider;
using ShellConstantsMicrosoft.VisualStudio.Shell.Interop.Constants;
using OleConstantsMicrosoft.VisualStudio.OLE.Interop.Constants;
using VsCommandsMicrosoft.VisualStudio.VSConstants.VSStd97CmdID;
using VsCommands2KMicrosoft.VisualStudio.VSConstants.VSStd2KCmdID;
using VsShellMicrosoft.VisualStudio.Shell.VsShellUtilities;


namespace Microsoft.VisualStudio.Package{
    /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter"]/*' />
    /// <summary>
    /// ViewFilter provides a default implementation of IVsTextViewFilter providing a
    /// handling of the following VS commands:
    /// 
    /// VsCommands.GotoDefn
    /// VsCommands.GotoDecl
    /// VsCommands.GotoRef
    /// VsCommands2K.COMMENT_BLOCK
    /// VsCommands2K.UNCOMMENT_BLOCK
    /// VsCommands2K.SHOWMEMBERLIST
    /// VsCommands2K.COMPLETEWORD
    /// VsCommands2K.PARAMINFO
    /// VsCommands2K.QUICKINFO
    /// VsCommands2K.OUTLN_STOP_HIDING_ALL
    /// VsCommands2K.OUTLN_START_AUTOHIDING
    /// VsCommands2K.SHOWCONTEXTMENU
    /// 
    /// Most of the work is delegated to the Source object.
    /// </summary>
    [CLSCompliant(false)]
    [System.Runtime.InteropServices.ComVisible(true)]
    public class ViewFilter : IVsTextViewFilter, IVsTextViewEvents, IOleCommandTarget, IDisposable, IVsExpansionEvents {
        private CodeWindowManager mgr;
        private NativeMethods.ConnectionPointCookie textViewEvents;
        private LanguageService service;
        private IVsTextView textView;
        private IOleCommandTarget nextTarget;
        private TextTipData textTipData;
        private Source source;
        // the current dataTipText info...
        private int quickInfoLine;
        private int quickInfoIdx;
        private TextSpan quickInfoSpan;
        private string quickInfoText;
        private bool gotQuickInfo;
        private bool wasCompletionActive;
        private bool commentSupported;
        private bool autoCompleted;
        private bool autoCompletedNothing;
        private bool autoCompleteTypeChar;
        private IntPtr pvaChar;
        private bool gotEnterKey;
        private bool snippetBound;
        private VsCommands gotoCmd;
        private static int execDepth;

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.SnippetBound"]/*' />
        protected bool SnippetBound {
            get { return snippetBound; }
            set { snippetBound = value; }
        }
        private NativeMethods.ConnectionPointCookie expansionEvents;

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.ViewFilter"]/*' />
        public ViewFilter(CodeWindowManager mgr, IVsTextView view) {
            this.pvaChar = IntPtr.Zero;
            this.mgr = mgr;
            this.service = mgr.LanguageService;
            this.source = mgr.Source;
            this.commentSupported = this.service.Preferences.EnableCommenting;
            this.textView = view;
            NativeMethods.ThrowOnFailure(view.AddCommandFilter(this, out nextTarget));

            // Register text view event handlers
            // Delegate to virtual/overridable method
            RegisterTextViewEventHandlers(view);

            if ((this.service != null) && (this.service.Site != null)) {
                IVsExpansionManager emgr = this.service.Site.GetService(typeof(SVsExpansionManager)) as IVsExpansionManager;
                if (emgr != null) {
                    int fBound;
                    emgr.GetSnippetShortCutKeybindingState(out fBound);
                    this.snippetBound = fBound == 0 ? false : true;

                    // Register expansion manager event handlers
                    // Delegate to virtual/overridable method
                    RegisterExpansionManagerEventHandlers(emgr);
                }
            }
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.Finalize"]/*' />
        ~ViewFilter() {
            Dispose();
#if LANGTRACE
            Trace.WriteLine("~ViewFilter");
#endif
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.Dispose"]/*' />
        public virtual void Dispose() {
            this.textView = null;
            this.service = null;
            this.nextTarget = null;
            this.textTipData = null;
            this.mgr = null;
            if (this.pvaChar != IntPtr.Zero) {
                Marshal.FreeCoTaskMem(pvaChar);
                pvaChar = IntPtr.Zero;
            }
            GC.SuppressFinalize(this);
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.Close"]/*' />
        public virtual void Close() {
#if LANGTRACE
            Trace.WriteLine("ViewFilter::Close");
#endif
            if (this.expansionEvents != null) {
                expansionEvents.Dispose();
                expansionEvents = null;
            }
            if (textViewEvents != null) {
                textViewEvents.Dispose();
                textViewEvents = null;
            }

            if (textView == this.service.LastActiveTextView)
                this.service.OnActiveViewChanged(null);

            textView.RemoveCommandFilter(this); // do not care about HRESULT.
            if (textTipData != null) {
                textTipData.Close(textView);
                textTipData = null;
            }

            Dispose();
        }
        const int SizeOfVariant = 16;

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.RegisterTextViewEventHandlers"]/*' />
        public virtual void RegisterTextViewEventHandlers(IVsTextView view)
        {
            this.textViewEvents = new NativeMethods.ConnectionPointCookie(view, this, typeof(IVsTextViewEvents));
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.RegisterTextViewEventHandlers"]/*' />
        public virtual void RegisterExpansionManagerEventHandlers(IVsExpansionManager emgr)
        {
            this.expansionEvents = new NativeMethods.ConnectionPointCookie(emgr, this, typeof(IVsExpansionEvents));
        }

        #region IVsExpansionEvents Members

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.OnAfterSnippetsKeyBindingChange"]/*' />
        public virtual int OnAfterSnippetsKeyBindingChange(uint dwCmdGuid, uint dwCmdId, int fBound) {
            this.snippetBound = fBound == 0 ? false : true;
            return VSConstants.S_OK;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.OnAfterSnippetsUpdate"]/*' />
        public virtual int OnAfterSnippetsUpdate() {
            return VSConstants.S_OK;
        }

        #endregion
        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.CodeWindowManager;"]/*' />
        /// <summary>Returnt the CodeWindowManager that created this view filter.</summary>
        public CodeWindowManager CodeWindowManager {
            get { return this.mgr; }
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.Source;"]/*' />
        /// <summary>Return the Source object encapsulating the text buffer.</summary>
        public Source Source {
            get { return this.source; }
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.TextTipData;"]/*' />
        /// <summary>Get or set the TextTipData object used for displaying tool tips.</summary>
        public TextTipData TextTipData {
            get {
                if (this.textTipData == null) {
                    this.textTipData = this.CreateTextTipData();
                }
                return this.textTipData;
            }
            set { this.textTipData = value; }
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.TextView;"]/*' />
        /// <summary>Return the IVsTextView associated with this filter.</summary>
        public IVsTextView TextView {
            get { return this.textView; }
        }

    /// <include file='doc\ExpansionProvider.uex' path='docs/doc[@for="ViewFilter.IsExpansionUIActive"]/*' />
    public virtual bool IsExpansionUIActive {
      get {
        IVsTextViewEx tve = this.textView as IVsTextViewEx;
        if (tve != null && tve.IsExpansionUIActive() == VSConstants.S_OK) {
          return true;
        }
        return false;
      }
    }

        public static bool IsExecutingCommand {
            get { return execDepth > 0; }
        }

        #region IVsTextViewFilter methods
        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.GetWordExtent"]/*' />
        /// <summary>Returns the result of Source.GetWordExtent.</summary>
        public virtual int GetWordExtent(int line, int index, uint flags, TextSpan[] span) {
            Debug.Assert(line >= 0 && index >= 0);
            if (span == null) NativeHelpers.RaiseComError(NativeMethods.E_INVALIDARG);
            else
                span[0] = new TextSpan();

            span[0].iStartLine = span[0].iEndLine = line;
            span[0].iStartIndex = span[0].iEndIndex = index;

            int start, end;

            if (!this.source.GetWordExtent(line, index, (WORDEXTFLAGS)flags, out start, out end)) {
                return NativeMethods.S_FALSE;
            }

            span[0].iStartIndex = start;
            span[0].iEndIndex = end;
            TextSpanHelper.MakePositive(ref span[0]);
            return NativeMethods.S_OK;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.GetDataTipText"]/*' />
        /// <summary>
        /// If Preferences.EnableQuickInfo is true then this method kicks of a parse with the 
        /// reason ParseReason.QuickInfo to find information about the current token.  If the
        /// parse finds something (returned via the AuthoringScope.GetDataTipText) then it is
        /// displayed using the TextTipData object.  When the asynchronous parse is finished
        /// GetFullDataTipText is called to pop up the tip.
        /// </summary>
        public virtual int GetDataTipText(TextSpan[] aspan, out string textValue) {
            textValue = null;

            TextSpan span = aspan[0];

            if (!service.Preferences.EnableQuickInfo) {
                return NativeMethods.E_FAIL;
            }

            if (span.iEndLine == this.quickInfoLine && span.iEndIndex == this.quickInfoIdx) {
                if (!gotQuickInfo) {
                    // still parsing on the background thread, so return E_PENDING.
                    return (int)NativeMethods.E_PENDING;
                }

                this.quickInfoLine = -1;
                int hr = this.GetFullDataTipText(this.quickInfoText, quickInfoSpan, out textValue);
                aspan[0] = this.quickInfoSpan;
                if (hr != NativeMethods.S_OK)
                    return hr;
            } else {
                // kick off the background parse to get this information...
                this.quickInfoText = null;
                this.gotQuickInfo = false;
                this.quickInfoLine = span.iEndLine;
                this.quickInfoIdx = span.iEndIndex;
                this.source.BeginParse(span.iEndLine, span.iEndIndex, new TokenInfo(), ParseReason.QuickInfo, this.textView, new ParseResultHandler(GetDataTipResponse));
                return (int)NativeMethods.E_PENDING;
            }
            // This return code means that regardless of whether we found any tooltip or not
            // the error associated with a code marker takes precedence (see DocumentTask.cs).
            return (int)TipSuccesses.TIP_S_ONLYIFNOMARKER;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.GetPairExtents"]/*' />
        public virtual int GetPairExtents(int line, int index, TextSpan[] span) {
            Debug.Assert(line >= 0 && index >= 0);
            // This call from VS does not support returning E_PENDING.
            if (span == null) return NativeMethods.E_INVALIDARG;

            this.source.GetPairExtents(this.textView, line, index, out span[0]);
            TextSpanHelper.MakePositive(ref span[0]);
            return NativeMethods.S_OK;
        }
        #endregion

        #region IVsTextViewEvents methods
        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.OnChangeCaretLine"]/*' />
        public virtual void OnChangeCaretLine(IVsTextView view, int line, int col) {
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.OnChangeScrollInfo"]/*' />
        public virtual void OnChangeScrollInfo(IVsTextView view, int iBar, int iMinUnit, int iMaxUnits, int iVisibleUnits, int iFirstVisibleUnit) {
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.OnKillFocus"]/*' />
        public virtual void OnKillFocus(IVsTextView view) {
            this.mgr.OnKillFocus(view);
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.OnSetBuffer"]/*' />
        public virtual void OnSetBuffer(IVsTextView view, IVsTextLines buffer) {
            Debug.Assert(buffer == this.mgr.Source.GetTextLines());
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.OnSetFocus"]/*' />
        public virtual void OnSetFocus(IVsTextView view) {
            this.service.OnActiveViewChanged(view);
            if (this.mgr != null) this.mgr.OnSetFocus(view); // is null during shutdown.
        }
        #endregion

        internal void GetDataTipResponse(ParseRequest req) {
            if (req.Line == this.quickInfoLine && req.Col == this.quickInfoIdx) {
                if (req.Scope == null) {
                    this.quickInfoText = null;
                } else {
                    this.quickInfoText = req.Scope.GetDataTipText(req.Line, req.Col, out this.quickInfoSpan);
                }
                this.gotQuickInfo = true;
            }
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.QueryCommandStatus"]/*' />
        /// <summary>
        /// Override this method to intercept the IOleCommandTarget::QueryStatus call.
        /// </summary>
        /// <param name="guidCmdGroup"></param>
        /// <param name="nCmdId"></param>
        /// <returns>Usually returns a combination of OLECMDF flags, for example
        /// OLECMDF_ENABLED | OLECMDF_SUPPORTED.  
        /// Return E_FAIL if want to delegate to the next command target.
        /// </returns>
        protected virtual int QueryCommandStatus(ref Guid guidCmdGroup, uint nCmdId) {
            ExpansionProvider ep = GetExpansionProvider();
            if (ep != null && ep.InTemplateEditingMode) {
                int hr = 0;
                if (ep.HandleQueryStatus(ref guidCmdGroup, nCmdId, out hr))
                    return hr;
            }
            if (guidCmdGroup == Microsoft.VisualStudio.VSConstants.GUID_VSStandardCommandSet97) {
                VsCommands cmd = (VsCommands)nCmdId;

                switch (cmd) {
                    case VsCommands.GotoDefn:
                    case VsCommands.GotoDecl:
                    case VsCommands.GotoRef:
                        return (int)OLECMDF.OLECMDF_SUPPORTED | (int)OLECMDF.OLECMDF_ENABLED;
                }
            } else if (guidCmdGroup == Microsoft.VisualStudio.Shell.VsMenus.guidStandardCommandSet2K) {
                VsCommands2K cmd = (VsCommands2K)nCmdId;

                switch (cmd) {
                    case VsCommands2K.FORMATDOCUMENT:
                        if (this.CanReformat())
                            return (int)OLECMDF.OLECMDF_SUPPORTED | (int)OLECMDF.OLECMDF_ENABLED;
                        break;
                    case VsCommands2K.FORMATSELECTION:
                        if (this.CanReformat())
                            return (int)OLECMDF.OLECMDF_SUPPORTED | (int)OLECMDF.OLECMDF_ENABLED;
                        break;

                    case VsCommands2K.COMMENT_BLOCK:
                    case VsCommands2K.UNCOMMENT_BLOCK:
                        if (this.commentSupported)
                            return (int)OLECMDF.OLECMDF_SUPPORTED | (int)OLECMDF.OLECMDF_ENABLED;
                        break;

                    case VsCommands2K.SHOWMEMBERLIST:
                    case VsCommands2K.COMPLETEWORD:
                    case VsCommands2K.PARAMINFO:
                        return (int)OLECMDF.OLECMDF_SUPPORTED | (int)OLECMDF.OLECMDF_ENABLED;

                    case VsCommands2K.QUICKINFO:
                        if (this.service.Preferences.EnableQuickInfo) {
                            return (int)OLECMDF.OLECMDF_SUPPORTED | (int)OLECMDF.OLECMDF_ENABLED;
                        }
                        break;

                    case VsCommands2K.OUTLN_START_AUTOHIDING:
                        if (!this.source.OutliningEnabled)
                        {
                            return (int)OLECMDF.OLECMDF_SUPPORTED | (int)OLECMDF.OLECMDF_ENABLED;
                        }
                        break;

                    //                    case VsCommands2K.HANDLEIMEMESSAGE:
                    //                        return 0;

                    // Let the core editor handle this.  Stop outlining also removes user
                    // defined hidden sections so it is handy to keep this enabled.
                    //                    case VsCommands2K.OUTLN_STOP_HIDING_ALL: 
                    //                        int rc = (int)OLECMDF.OLECMDF_SUPPORTED;
                    //                        if (this.source.OutliningEnabled) {
                    //                            rc |= (int)OLECMDF.OLECMDF_ENABLED;
                    //                        }
                    //                        return rc;
                }
            }

            return (int)NativeMethods.E_FAIL; // delegate to next command target.
        }

        /// <include file='doc\EditorView.uex' path='docs/doc[@for="SimpleEditorView.QueryParameterList"]/*' />
        /// <summary>
        /// The parameter list of a command is queried by calling Exec with the LOWORD
        /// of nCmdexecopt set to OLECMDEXECOPT_SHOWHELP (instead of the more usual
        /// OLECMDEXECOPT_DODEFAULT), the HIWORD of nCmdexecopt set to
        /// VSCmdOptQueryParameterList, pvaIn set to NULL, and pvaOut pointing to an
        /// empty VARIANT ready to receive the result BSTR.  This should be done only
        /// for commands that are marked with the ALLOWPARAMS flags in the command
        /// table.        
        /// </summary>
        /// <returns>Usually returns 0 if ok, or OLECMDERR_E_NOTSUPPORTED</returns>
        protected virtual int QueryParameterList(ref Guid guidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) {
#if LANGTRACE
            Trace.WriteLine(String.Format("QueryParameterList({0},{1})", guidCmdGroup.ToString(), nCmdId));
#endif
            return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.HandlePreExec"]/*' />
        public virtual bool HandlePreExec(ref Guid guidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) {
            
            this.wasCompletionActive = this.Source.IsCompletorActive;
            this.gotEnterKey = false;

            if (guidCmdGroup == typeof(VsCommands).GUID) {
                VsCommands cmd = (VsCommands)nCmdId;
#if TRACE_EXEC
                if (cmd != VsCommands.SolutionCfg && cmd != VsCommands.SearchCombo) {
                    Trace.WriteLine(String.Format("ExecCommand: {0}", cmd.ToString()));
                }
#endif
                switch (cmd) {
                    case VsCommands.GotoDefn:
                    case VsCommands.GotoDecl:
                    case VsCommands.GotoRef:
                        HandleGoto(cmd);
                        return true;
                }
            } else if (guidCmdGroup == typeof(VsCommands2K).GUID) {

                VsCommands2K cmd = (VsCommands2K)nCmdId;
                switch (cmd) {
                    case VsCommands2K.FORMATDOCUMENT:
                        this.ReformatDocument();
                        return true;

                    case VsCommands2K.FORMATSELECTION:
                        this.ReformatSelection();
                        return true;

                    case VsCommands2K.COMMENT_BLOCK:
                        this.CommentSelection();
                        return true;

                    case VsCommands2K.UNCOMMENT_BLOCK:
                        this.UncommentSelection();
                        return true;

                    case VsCommands2K.COMPLETEWORD: {
                            int line, col;
                            NativeMethods.ThrowOnFailure(this.textView.GetCaretPos(out line, out col));
                            this.source.Completion(this.textView, this.source.GetTokenInfo(line, col), ParseReason.CompleteWord);
                            return true;
                        }
                    case VsCommands2K.SHOWMEMBERLIST: {
                            int line, col;
                            NativeMethods.ThrowOnFailure(this.textView.GetCaretPos(out line, out col));
                            this.source.Completion(this.textView, this.source.GetTokenInfo(line, col), ParseReason.DisplayMemberList);
                            return true;
                        }
                    case VsCommands2K.PARAMINFO: {
                            int line;
                            int col;
                            NativeMethods.ThrowOnFailure(this.textView.GetCaretPos(out line, out col));
                            this.source.MethodTip(this.textView, line, col, this.source.GetTokenInfo(line, col));
                            return true;
                        }

                    case VsCommands2K.QUICKINFO: {
                            HandleQuickInfo();
                            return true;
                        }

                    case VsCommands2K.SHOWCONTEXTMENU: {
                        int vsize = Marshal.SizeOf(typeof(Variant));
                        Variant x = Variant.ToVariant(pvaIn);
                        Variant y = Variant.ToVariant(new IntPtr((long)pvaIn + vsize)); 

                        this.ShowContextMenu(VsMenus.IDM_VS_CTXT_CODEWIN, VsMenus.guidSHLMainMenu, TextView as IOleCommandTarget, (int)x.Value, (int)y.Value);
                        return true;
                    }

                    case VsCommands2K.OUTLN_STOP_HIDING_ALL:
                        this.source.DisableOutlining();
                        return true;

                    case VsCommands2K.OUTLN_START_AUTOHIDING:
                        this.source.OutliningEnabled = true;
                        // subtle way of calling this.source.ProcessHiddenRegions(..);
                        this.source.IsDirty = true;
                        return true;
                    case VsCommands2K.ECMD_LEFTCLICK:
                        // check general trigger characters for intellisense
                        Source.OnCommand(TextView, cmd, '\0');
                        break;
                }
            }
            return false;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.HanelPostExec"]/*' />
        /// <summary>This method hooks up HandleSmartIndent and Source.OnCommand.  </summary>
        public virtual void HandlePostExec(ref Guid guidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut, bool bufferWasChanged) {

            if (guidCmdGroup == typeof(VsCommands2K).GUID) {
                VsCommands2K cmd = (VsCommands2K)nCmdId;
                char ch = '\0';
                if (cmd == VsCommands2K.TYPECHAR && pvaIn != IntPtr.Zero) {
                    Variant v = Variant.ToVariant(pvaIn);
                    ch = v.ToChar();

#if TRACE_EXEC
                    Trace.WriteLine(String.Format("ExecCommand: {0}, '{1}', {2}", cmd.ToString(), ch.ToString(), (int)ch));
#endif
                }

                switch (cmd) {
                    case VsCommands2K.RETURN:
                        gotEnterKey = true;
                        // Handle smart-indentation after core text editor has
                        // actually performed the newline operation.
                        if (bufferWasChanged && !this.wasCompletionActive && this.service.Preferences.IndentStyle == IndentingStyle.Smart) {
                            if (HandleSmartIndent())
                                break;
                        }
                        break;

                    case VsCommands2K.TYPECHAR:
                    case VsCommands2K.BACKSPACE:
                    case VsCommands2K.TAB:
                    case VsCommands2K.BACKTAB:
                    case VsCommands2K.DELETE:
                        // check general trigger characters for intellisense
                        if (bufferWasChanged) {
                            this.source.OnCommand(this.textView, cmd, ch);
                        }
                        break;
                    case VsCommands2K.UP:
                    case VsCommands2K.UP_EXT:
                    case VsCommands2K.UP_EXT_COL:
                    case VsCommands2K.DOWN:
                    case VsCommands2K.DOWN_EXT:
                    case VsCommands2K.DOWN_EXT_COL:
                    case VsCommands2K.HOME:
                    case VsCommands2K.HOME_EXT:
                    case VsCommands2K.END:
                    case VsCommands2K.END_EXT:
                    case VsCommands2K.BOL:
                    case VsCommands2K.BOL_EXT:
                    case VsCommands2K.BOL_EXT_COL:
                    case VsCommands2K.FIRSTCHAR:
                    case VsCommands2K.FIRSTCHAR_EXT:
                    case VsCommands2K.EOL:
                    case VsCommands2K.EOL_EXT:
                    case VsCommands2K.EOL_EXT_COL:
                    case VsCommands2K.LASTCHAR:
                    case VsCommands2K.LASTCHAR_EXT:
                    case VsCommands2K.PAGEUP:
                    case VsCommands2K.PAGEUP_EXT:
                    case VsCommands2K.PAGEDN:
                    case VsCommands2K.PAGEDN_EXT:
                    case VsCommands2K.LEFT:
                    case VsCommands2K.LEFT_EXT:
                    case VsCommands2K.LEFT_EXT_COL:
                    case VsCommands2K.RIGHT:
                    case VsCommands2K.RIGHT_EXT:
                    case VsCommands2K.RIGHT_EXT_COL:
                    case VsCommands2K.WORDNEXT:
                    case VsCommands2K.WORDNEXT_EXT:
                    case VsCommands2K.WORDNEXT_EXT_COL:
                    case VsCommands2K.WORDPREV:
                    case VsCommands2K.WORDPREV_EXT:
                    case VsCommands2K.WORDPREV_EXT_COL:
                    case VsCommands2K.BOTTOMLINE:
                    case VsCommands2K.BOTTOMLINE_EXT:
                    case VsCommands2K.TOPLINE:
                    case VsCommands2K.TOPLINE_EXT:
                        // check general trigger characters for intellisense
                        this.source.OnCommand(this.textView, cmd, ch);
                        break;
                }
            }
            return;
        }

        [DllImport("oleaut32", PreserveSig = false)]
        static extern void VariantInit(IntPtr pObject);
        [DllImport("oleaut32", PreserveSig = false)]
        static extern void VariantClear(IntPtr pObject);

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.ExecCommand"]/*' />
        /// <summary>
        /// Override this method to intercept the IOleCommandTarget::Exec call.
        /// </summary>
        /// <returns>Usually returns 0 if ok, or OLECMDERR_E_NOTSUPPORTED</returns>
        protected virtual int ExecCommand(ref Guid guidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) {
            int rc = 0;
            execDepth++; // only on UI thread, so this should be safe.
            try {
                this.autoCompleted = false;
                if (this.IsExpansionUIActive) {
                    // Pass it along to the expansion UI picker.
                    return this.InnerExec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut);
                }

                ExpansionProvider ep = GetExpansionProvider();
                if (ep != null && ep.InTemplateEditingMode) {
                    if (ep.HandlePreExec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut))
                        return rc;
                }

                if (!HandlePreExec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut) &&
                    this.nextTarget != null) {

                    // Pass it along the chain.
                    int count = this.source.ChangeCount;
                    rc = this.InnerExec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut);
                    if (!ErrorHandler.Succeeded(rc))
                        return rc;

                    bool bufferWasChanged = count != source.ChangeCount;

                    if (this.autoCompleted) {
                        this.autoCompleted = false;
                        // See if completion set just completed, so we can do auto-completion synchronously.
                        CompletionSet cset = this.source.CompletionSet;
                        if (cset != null) {
                            if (this.autoCompletedNothing &&
                                this.wasCompletionActive && guidCmdGroup == typeof(VsCommands2K).GUID &&
                                nCmdId == (uint)VsCommands2K.RETURN) {
                                // This happens if the user typed ENTER while the CompletionSet was active,
                                // but selected nothing from the list.  In this case the ENTER key was gobbled up
                                // by the CompletionSet, and we want the ENTER key inserted into the buffer instead.
                                this.wasCompletionActive = false;
                                this.InnerExec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut);
                            }
                        }
                        if (this.autoCompleteTypeChar) {
                            // Auto-complete typed a different char so we skip HandlePostExec in this case.
                            return rc;
                        }
                    }

                    if (ep != null && ep.InTemplateEditingMode) {
                        if (ep.HandlePostExec(ref guidCmdGroup, nCmdId, nCmdexecopt, gotEnterKey, pvaIn, pvaOut))
                            return rc;
                    }
                    HandlePostExec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut, bufferWasChanged);
                }
            } finally {
                execDepth--;
            }
            return rc;
        }

        protected virtual int InnerExec(ref Guid guidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) {
            return this.nextTarget.Exec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut);
        }

        /// <include file='doc\Source.uex' path='docs/doc[@for="ViewFilter.OnAutoComplete"]/*' />
        public virtual void OnAutoComplete() {
            this.autoCompletedNothing = false;
            this.autoCompleteTypeChar = false;
            CompletionSet cset = this.source.CompletionSet;
            if (cset != null) {
                char ch = cset.OnAutoComplete();
                if (ch != '\0') {
                    if (ch <= 0x1f) {
                        Debug.Assert(false, cset.GetType().FullName + ".OnAutoComplete returned an illegal control character which will not be inserted into the buffer.");
                    } else {
                        this.autoCompleteTypeChar = true;
                        bool wca = this.wasCompletionActive;
                        TypeChar(ch);
                        this.wasCompletionActive = wca;
                    }
                } else {
                    this.autoCompletedNothing = string.IsNullOrEmpty(cset.OnCommitText);
                }
            }
            // This must be placed after the above TypeChar because TypeChar re-enters
            // ExecCommand and we do not want to do the autoCompleted block until after
            // this method returns.
            this.autoCompleted = true;
        }

        /// <include file='doc\Source.uex' path='docs/doc[@for="ViewFilter.TypeChar"]/*' />
        // Executes a VsCommands2K.TYPECHAR command on the current command chain.
        public int TypeChar(char ch) {

            if (this.pvaChar == IntPtr.Zero) {
                this.pvaChar = Marshal.AllocCoTaskMem(SizeOfVariant);
            }
            if (pvaChar == IntPtr.Zero)
                return NativeMethods.E_OUTOFMEMORY;

            VariantInit(pvaChar);
            Marshal.GetNativeVariantForObject(ch, pvaChar);
            int rc = 0;
            try {
        Guid cmdGroup = typeof(VsCommands2K).GUID;
                rc = ExecCommand(ref cmdGroup, (uint)VsCommands2K.TYPECHAR, 0, pvaChar, IntPtr.Zero);
            } finally {
                VariantClear(pvaChar);
            }
            return rc;
        }

        /// <include file='doc\Source.uex' path='docs/doc[@for="ViewFilter.HandleSmartIndent"]/*' />
        /// Override this method if you want to support smart indenting.
        /// This will only be called if Preferences.Indenting == IndentingStyle.Smart which is
        /// only available if you set your language service registry key ShowSmartIndent to 1.
        public virtual bool HandleSmartIndent() {
            return false;
        }

        #region IOleCommandTarget methods
        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.IOleCommandTarget.QueryStatus"]/*' />
        /// <internalonly/>
        int IOleCommandTarget.QueryStatus(ref Guid guidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) {
            for (uint i = 0; i < cCmds; i++) {
                int rc = QueryCommandStatus(ref guidCmdGroup, (uint)prgCmds[i].cmdID);

                if (rc == NativeMethods.E_FAIL) {
                    if (nextTarget != null) {
                        try {
                            return this.nextTarget.QueryStatus(ref guidCmdGroup, cCmds, prgCmds, pCmdText);
                        } catch (Exception) {
                            // We are going to return the failed return code below
                        }
                    }

                    return rc;
                }

                prgCmds[i].cmdf = (uint)rc;
            }

            return NativeMethods.S_OK;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.IOleCommandTarget.Exec"]/*' />
        /// <internalonly/>
        int IOleCommandTarget.Exec(ref Guid guidCmdGroup, uint nCmdId, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) {

            ushort lo = (ushort)(nCmdexecopt & (uint)0xffff);
            ushort hi = (ushort)(nCmdexecopt >> 16);
            switch (lo) {
                case (ushort)OLECMDEXECOPT.OLECMDEXECOPT_SHOWHELP:
                    if ((nCmdexecopt >> 16) == VsMenus.VSCmdOptQueryParameterList) {
                        int hr = QueryParameterList(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut);
                        if (hr != (int)OleConstants.OLECMDERR_E_NOTSUPPORTED)
                        {
                            return hr;
                        }
                        return this.InnerExec(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut);
                    }
                    break;
                default:
                    // On every command, update the tip window if it's active.
                    if (this.textTipData != null && this.textTipData.IsActive())
                        textTipData.CheckCaretPosition(this.textView);

                    int rc = 0;
                    try {
                        rc = ExecCommand(ref guidCmdGroup, nCmdId, nCmdexecopt, pvaIn, pvaOut);
                    } catch (COMException e) {
                        int hr = e.ErrorCode;
                        // We silently fail on the following errors because the user has
                        // most likely already been prompted with things like source control checkout
                        // dialogs and so forth.
                        if (hr != (int)TextBufferErrors.BUFFER_E_LOCKED &&
                            hr != (int)TextBufferErrors.BUFFER_E_READONLY &&
                            hr != (int)TextBufferErrors.BUFFER_E_READONLY_REGION &&
                            hr != (int)TextBufferErrors.BUFFER_E_SCC_READONLY) {
                            throw;
                        }
                    }

                    return rc;
            }
            return (int)OleConstants.OLECMDERR_E_NOTSUPPORTED;
        }
        #endregion

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.HandleQuickInfo"]/*' />
        /// <summary>This method is called to handle the VsCommands2K.QUICKINFO command.</summary>
        public virtual void HandleQuickInfo() {
            int line, col;

            // Get the caret position
            NativeMethods.ThrowOnFailure(this.textView.GetCaretPos(out line, out col));

            // Get the tip text at that location. 
            this.source.BeginParse(line, col, new TokenInfo(), ParseReason.Autos, this.textView, 
                new ParseResultHandler(HandleQuickInfoResponse));
        }

        void HandleQuickInfoResponse(ParseRequest req){

            int line;
            int col;
            // Get the caret position
            NativeMethods.ThrowOnFailure(this.textView.GetCaretPos(out line, out col));

            string text = null;
            AuthoringScope scope = req.Scope;
            if (scope != null) {
                TextSpan span;
                text = scope.GetDataTipText(req.Line, req.Col, out span);
                if (text == null || !TextSpanHelper.ContainsInclusive(span, line, col)) {
                    return; // caret has moved.
                }
            } else {
                return;
            }

            string fullText;
            TextSpan ts = new TextSpan();
            ts.iStartLine = ts.iEndLine = line;
            ts.iStartIndex = ts.iEndIndex = col;
            NativeMethods.ThrowOnFailure(GetFullDataTipText(text, ts, out fullText));

            if (fullText == null) {
                return;
            }

            int iPos, iPosEnd, iSpace, iLength;

            // Calculate the stream position
            NativeMethods.ThrowOnFailure(textView.GetNearestPosition(ts.iStartLine, ts.iStartIndex, out iPos, out iSpace));
            NativeMethods.ThrowOnFailure(textView.GetNearestPosition(ts.iEndLine, ts.iEndIndex, out iPosEnd, out iSpace));
            iLength = Math.Max(iPosEnd - iPos, 1);

            // Tear down the method tip window if it's there
            this.source.DismissCompletor();

            // Update the text tip window
            TextTipData textTipData = this.TextTipData;

            textTipData.Update(fullText, iPos, iLength, this.textView);
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.GetFullDataTipText"]/*' />
        /// <summary>This method checks to see if the IVsDebugger is running, and if so, 
        /// calls it to get additional information about the current token and returns a combined result.
        /// You can return an HRESULT here like TipSuccesses2.TIP_S_NODEFAULTTIP.</summary>
        public virtual int GetFullDataTipText(string textValue, TextSpan ts, out string fullTipText) {
            IVsTextLines textLines;
            fullTipText = textValue;

            NativeMethods.ThrowOnFailure(this.textView.GetBuffer(out textLines));

            // Now, check if the debugger is running and has anything to offer
            try {
                Microsoft.VisualStudio.Shell.Interop.IVsDebugger debugger = this.service.GetIVsDebugger();
                if (debugger != null && this.mgr.LanguageService.IsDebugging) {
                    TextSpan[] tsdeb = new TextSpan[1] { new TextSpan() };
                    if (!TextSpanHelper.IsEmpty(ts)) {
                        // While debugging we always want to evaluate the expression user is hovering over
                        if (NativeMethods.S_OK == textView.GetWordExtent(ts.iStartLine, ts.iStartIndex, (uint)WORDEXTFLAGS.WORDEXT_FINDEXPRESSION, tsdeb)) {
                            // If it failed to find something, then it means their is no expression so return S_FALSE
                            if (TextSpanHelper.IsEmpty(tsdeb[0])) {
                                return NativeMethods.S_FALSE;
                            }
                        }
                    }
                    string debugTextTip = null;
                    int hr = debugger.GetDataTipValue(textLines, tsdeb, null, out debugTextTip);
                    fullTipText = debugTextTip;
                    if (hr == (int)TipSuccesses2.TIP_S_NODEFAULTTIP) {
                        return hr;
                    }
                    if (!string.IsNullOrEmpty(debugTextTip) && debugTextTip != textValue) {
                        // The debugger in this case returns "=value [type]" which we can
                        // append to the variable name so we get "x=value[type]" as the full tip.
                        int i = debugTextTip.IndexOf('=');
                        if (i >= 0) {
                            string spacer = (i < debugTextTip.Length - 1 && debugTextTip[i + 1] == ' ') ? " " : "";
                            fullTipText = textValue + spacer + debugTextTip.Substring(i);
                        }
                    }
                }
#if LANGTRACE
            } catch (COMException e) {
                Trace.WriteLine("COMException: GetDataTipValue, errorcode=" + e.ErrorCode);
#else
            } catch (COMException) {
#endif
            }
            if (string.IsNullOrEmpty(fullTipText)) {
                fullTipText = textValue;
            }
            return NativeMethods.S_OK;

        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.GetTextTipData"]/*' />
        /// <summary>Creates the TextTipData object and returns it</summary>
        public virtual TextTipData CreateTextTipData() {
            // create it 
            return new TextTipData(this.service.Site);

        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.HandleGoto"]/*' />
        /// <summary>Handles VsCommands.GotoDefn, VsCommands.GotoDecl and VsCommands.GotoRef by
        /// calling OnSyncGoto on the Source object and opening the text editor on the resulting
        /// URL, then scrolling to the resulting span.</summary>
        public virtual void HandleGoto(VsCommands cmd) {
            int line, col;

            // Get the caret position
            NativeMethods.ThrowOnFailure(this.textView.GetCaretPos(out line, out col));

            // Get the tip text at that location. 
            this.gotoCmd = cmd;
            this.source.BeginParse(line, col, new TokenInfo(), ParseReason.Goto, this.textView, 
                new ParseResultHandler(HandleGotoResponse));
        }

        void HandleGotoResponse(ParseRequest req) {
            // Make sure caret hasn't moved since we kicked this off.
            TextSpan[] aSpan = new TextSpan[1];
            int line, col;
            NativeMethods.ThrowOnFailure(this.textView.GetCaretPos(out line, out col));
            if (req.Line != line || req.Col != col)
                return; // caret has moved.

            string url = null;
            TextSpan span;
            AuthoringScope scope = req.Scope;            
            if (scope != null) {
                url = scope.Goto(this.gotoCmd, textView, line, col, out span);
            } else {
                return;
            }
            if (url == null || url.Trim().Length == 0) { // nothing to show
                return;
            }

            // Open the referenced document, and scroll to the given location.
            IVsUIHierarchy hierarchy;
            uint itemID;
            IVsWindowFrame frame;
            IVsTextView view;

            VsShell.OpenDocument(this.service.Site, url, NativeMethods.LOGVIEWID_Code, out hierarchy, out itemID, out frame, out view);
            if (view != null) {
                TextSpanHelper.MakePositive(ref span);
                NativeMethods.ThrowOnFailure(view.EnsureSpanVisible(span));
                NativeMethods.ThrowOnFailure(view.SetSelection(span.iStartLine, span.iStartIndex, span.iEndLine, span.iEndIndex));
            }
        }
        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.GetExpansionProvider"]/*' />
        public virtual ExpansionProvider GetExpansionProvider() {
            return this.source.GetExpansionProvider();
        }

        /// <include file='doc\LanguageService.uex' path='docs/doc[@for="ViewFilter.ShowContextMenu"]/*' />
        public virtual void ShowContextMenu(int menuId, Guid groupGuid, IOleCommandTarget target, int x, int y) {
            IVsUIShell uiShell = this.service.GetService(typeof(SVsUIShell)) as IVsUIShell;
            if (uiShell != null && !this.service.IsMacroRecordingOn()) { // disable context menu while recording macros.
                POINTS[] pnts = new POINTS[1];
                pnts[0].x = (short)x;
                pnts[0].y = (short)y;
                int hr = uiShell.ShowContextMenu(0, ref groupGuid, menuId, pnts, target);
                if (!NativeMethods.Succeeded(hr)) {
                    Debug.Assert(false, "uiShell.ShowContextMenu returned " + hr);
                }
            }
            uiShell = null;
        }

        #region CommentSelection

        // Special View filter command handling.
        /// <include file='doc\Source.uex' path='docs/doc[@for="ViewFilter.CommentSelection"]/*' />
        public virtual void CommentSelection() {
            if (this.service == null) return;

            TextSpan span = GetSelection();
            span = this.source.CommentSpan(span);

            NativeMethods.ThrowOnFailure(this.textView.SetSelection(span.iStartLine, span.iStartIndex, span.iEndLine, span.iEndIndex));
        }

        /// <include file='doc\Source.uex' path='docs/doc[@for="ViewFilter.GetSelection"]/*' />
        /// <summary>Returns the current selection, adjusted to become a positive text span</summary>
        public TextSpan GetSelection() {
            //get text range
            TextSpan[] aspan = new TextSpan[1];
            NativeMethods.ThrowOnFailure(this.textView.GetSelectionSpan(aspan));
            if (!TextSpanHelper.IsPositive(aspan[0])) {
                TextSpanHelper.MakePositive(ref aspan[0]);
            }
            return aspan[0];
        }

        /// <include file='doc\Source.uex' path='docs/doc[@for="ViewFilter.UncommentSelection"]/*' />
        public virtual void UncommentSelection() {
            //get text range
            TextSpan span = GetSelection();
            
            TextSpan uncommentedSpan = this.source.UncommentSpan(span);
            span = TextSpanHelper.Merge(uncommentedSpan, span);
            //union the start position, trimmed position on the end
            NativeMethods.ThrowOnFailure(textView.SetSelection(span.iStartLine, span.iStartIndex, uncommentedSpan.iEndLine, uncommentedSpan.iEndIndex));

        }
        #endregion


        #region Reformat

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.ReformatDocument;"]/*' />
        public virtual void ReformatDocument() {
            if (this.CanReformat()) {
                Debug.Assert(this.source != null);
                if (this.source != null) {
                    TextSpan span = this.source.GetDocumentSpan();
                    using (EditArray mgr = new EditArray(this.source, this.TextView, true, SR.GetString(SR.FormatSpan))) {
                        this.source.ReformatSpan(mgr, span);
                        mgr.ApplyEdits();
                    }
                }
            }
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="ViewFilter.ReformatSelection;"]/*' />
        public virtual void ReformatSelection() {
            if (this.CanReformat()) {
                Debug.Assert(this.source != null);
                if (this.source != null) {
                    TextSpan ts = GetSelection();
                    if (TextSpanHelper.IsEmpty(ts)) {
                        // format just this current line.
                        ts.iStartIndex = 0;
                        ts.iEndLine = ts.iStartLine;
                        ts.iEndIndex = this.source.GetLineLength(ts.iStartLine);
                    }
                    using (EditArray mgr = new EditArray(this.source, this.TextView, true, SR.GetString(SR.FormatSpan))) {
                        this.source.ReformatSpan(mgr, ts);
                        mgr.ApplyEdits();
                    }
                }
            }
        }

        /// <include file='doc\LanguageService.uex' path='docs/doc[@for="ViewFilter.CanReformat"]/*' />
        /// <summary>This method returns true if the FormatDocument and FormatSelection commands
        /// are to be enabled.  Default returns false if debugging, otherwise it returns
        /// the result for Preferences.EnableFormatSelection.</summary>
        public virtual bool CanReformat() {
            if (this.service == null) return false;
            if (this.service.IsDebugging) return false;
            return this.service.Preferences.EnableFormatSelection;
        }

        #endregion

    }

    /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData"]/*' />
    /// <summary>This class provides a default implementation of IVsTextTipData for
    /// use in the IVsTextTipWindow for displaying tool tips.</summary>
    [CLSCompliant(false)]
    [System.Runtime.InteropServices.ComVisible(true)]
    public class TextTipData : IVsTextTipData {
        IVsTextTipWindow textTipWindow;
        int pos;
        int len;
        string text;
        bool isWindowUp;

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.TextTipData"]/*' />
        public TextTipData(IServiceProvider site) {
            if (site == null)
                throw new System.ArgumentNullException("site");

            //this.textView = view;
            // Create our method tip window (through the local registry)
            Type t = typeof(IVsTextTipWindow);
            Guid riid = t.GUID;

            Guid clsid = typeof(VsTextTipWindowClass).GUID;
            Microsoft.VisualStudio.Shell.Package pkg = (Microsoft.VisualStudio.Shell.Package)site.GetService(typeof(Microsoft.VisualStudio.Shell.Package));
            if (pkg == null) {
                throw new NullReferenceException(typeof(Microsoft.VisualStudio.Shell.Package).FullName);
            }
            this.textTipWindow = (IVsTextTipWindow)pkg.CreateInstance(ref clsid, ref riid, t);
            if (this.textTipWindow == null)
                NativeHelpers.RaiseComError(NativeMethods.E_FAIL);

            NativeMethods.ThrowOnFailure(textTipWindow.SetTextTipData(this));
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.Close"]/*' />
        public void Close(IVsTextView textView) {
            if (this.textTipWindow != null) {
                if (this.isWindowUp)
                    NativeMethods.ThrowOnFailure(textView.UpdateTipWindow(this.textTipWindow, (uint)TipWindowFlags.UTW_DISMISS));

                this.textTipWindow = null;
            }
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.IsActive"]/*' />
        public bool IsActive() { return this.isWindowUp; }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.Update"]/*' />
        public void Update(string textValue, int pos, int len, IVsTextView textView) {
            if (textView == null) return;

            this.pos = pos;
            this.len = len;
            this.text = textValue;
            if (textValue == null || textValue.Length == 0)
                NativeHelpers.RaiseComError(NativeMethods.E_FAIL);

            int hr = textView.UpdateTipWindow(textTipWindow, (uint)TipWindowFlags.UTW_CONTEXTCHANGED | (uint)TipWindowFlags.UTW_CONTENTCHANGED);
            Debug.Assert(NativeMethods.Succeeded(hr), "UpdateTipWindow");
            this.isWindowUp = true;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.CheckCaretPosition"]/*' />
        public void CheckCaretPosition(IVsTextView textView) {
            if (textView == null) return;

            int line, col, pos, space;

            NativeMethods.ThrowOnFailure(textView.GetCaretPos(out line, out col));
            NativeMethods.ThrowOnFailure(textView.GetNearestPosition(line, col, out pos, out space));
            if (pos < this.pos || pos > this.pos + this.len) {
                NativeMethods.ThrowOnFailure(textView.UpdateTipWindow(this.textTipWindow, (uint)TipWindowFlags.UTW_DISMISS));
            }
        }

        ////////////////////////////////////////////////////////////////////////////////
        #region IVsTextTipData
        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.GetTipText"]/*' />
        public virtual int GetTipText(string[] pbstrText, out int pfFontData) {
            pfFontData = 0; 
            if (pbstrText == null || pbstrText.Length == 0)
                return NativeMethods.E_INVALIDARG;

            pfFontData = 0; 
            pbstrText[0] = this.text;
            return NativeMethods.S_OK;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.GetTipFontInfo"]/*' />
        public virtual int GetTipFontInfo(int iChars, uint[] pdwFontInfo) {
            return NativeMethods.E_NOTIMPL;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.GetContextStream"]/*' />
        public virtual int GetContextStream(out int piPos, out int piLen) {
            piPos = this.pos;
            piLen = this.len;
            return NativeMethods.S_OK;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.OnDismiss"]/*' />
        public virtual void OnDismiss() {
            this.isWindowUp = false;
        }

        /// <include file='doc\ViewFilter.uex' path='docs/doc[@for="TextTipData.UpdateView"]/*' />
        public virtual void UpdateView() {
        }
        #endregion
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.