private async Task PopulateSnippetCacheOnBackgroundWithForegroundFallback()
        {
            AssertIsBackground();

            try
            {
                IVsExpansionEnumeration expansionEnumerator = await((dynamic)_expansionManager).EnumerateExpansionsAsync(
                    _languageGuidForSnippets,
                    0,                      // shortCutOnly
                    Array.Empty <string>(), // types
                    0,                      // countTypes
                    1,                      // includeNULLTypes
                    1                       // includeDulicates: Allows snippets with the same title but different shortcuts
                    ).ConfigureAwait(false);

                // The rest of the process requires being on the UI thread, see the explanation on
                // PopulateSnippetCacheFromExpansionEnumeration for details
                await Task.Factory.StartNew(() => PopulateSnippetCacheFromExpansionEnumeration(expansionEnumerator),
                                            CancellationToken.None,
                                            TaskCreationOptions.None,
                                            ForegroundTaskScheduler).ConfigureAwait(false);
            }
            catch (RuntimeBinderException)
            {
                // The IExpansionManager.EnumerateExpansionsAsync could not be found. Use
                // IVsExpansionManager.EnumerateExpansions instead, but from the UI thread.
                await Task.Factory.StartNew(() => PopulateSnippetCacheOnForeground(),
                                            CancellationToken.None,
                                            TaskCreationOptions.None,
                                            ForegroundTaskScheduler).ConfigureAwait(false);
            }
        }
Example #2
0
        private void GetSnippets(Guid languageGuid,
                                 ref ArrayList expansionsList)
        {
            IVsTextManager textManager = (IVsTextManager)Package.GetGlobalService(typeof(SVsTextManager));

            if (textManager != null)
            {
                IVsTextManager2 textManager2 = (IVsTextManager2)textManager;
                if (textManager2 != null)
                {
                    IVsExpansionManager expansionManager = null;
                    textManager2.GetExpansionManager(out expansionManager);
                    if (expansionManager != null)
                    {
                        // Tell the environment to fetch all of our snippets.
                        IVsExpansionEnumeration expansionEnumerator = null;
                        expansionManager.EnumerateExpansions(languageGuid,
                                                             0,    // return all info
                                                             null, // return all types
                                                             0,    // return all types
                                                             1,    // include snippets without types
                                                             0,    // do not include duplicates
                                                             out expansionEnumerator);
                        if (expansionEnumerator != null)
                        {
                            // Cache our expansions in a VsExpansion array
                            uint        count          = 0;
                            uint        fetched        = 0;
                            VsExpansion expansionInfo  = new VsExpansion();
                            IntPtr[]    pExpansionInfo = new IntPtr[1];

                            // Allocate enough memory for one VSExpansion structure. This memory is filled in by the Next method.
                            pExpansionInfo[0] = Marshal.AllocCoTaskMem(Marshal.SizeOf(expansionInfo));

                            expansionEnumerator.GetCount(out count);
                            for (uint i = 0; i < count; i++)
                            {
                                expansionEnumerator.Next(1, pExpansionInfo, out fetched);
                                if (fetched > 0)
                                {
                                    // Convert the returned blob of data into a structure that can be read in managed code.
                                    expansionInfo = (VsExpansion)Marshal.PtrToStructure(pExpansionInfo[0], typeof(VsExpansion));

                                    if (!String.IsNullOrEmpty(expansionInfo.shortcut))
                                    {
                                        expansionsList.Add(expansionInfo);
                                    }
                                }
                            }
                            Marshal.FreeCoTaskMem(pExpansionInfo[0]);
                        }
                    }
                }
            }
        }
Example #3
0
        /// <summary>
        /// Caches expansions returned by IVsExpansionManager for a given language services.
        /// </summary>
        private void CacheLanguageExpansionStructs(IVsExpansionManager expansionManager)
        {
            if (_expansions.Keys.Count > 0)
            {
                return;
            }

            IVsExpansionEnumeration expansionEnumerator = null;

            int hr = expansionManager.EnumerateExpansions(
                RGuidList.RLanguageServiceGuid,
                0,    // return all info
                null, // return all types
                0,    // return all types
                0,    // do not return NULL type
                0,    // do not return duplicates
                out expansionEnumerator
                );

            ErrorHandler.ThrowOnFailure(hr);

            if (expansionEnumerator != null)
            {
                VsExpansion expansion      = new VsExpansion();
                IntPtr[]    pExpansionInfo = new IntPtr[1];
                try {
                    // Allocate enough memory for one VSExpansion structure.
                    // This memory is filled in by the Next method.
                    pExpansionInfo[0] = Marshal.AllocCoTaskMem(Marshal.SizeOf(expansion));

                    uint count = 0;
                    expansionEnumerator.GetCount(out count);
                    for (uint i = 0; i < count; i++)
                    {
                        uint fetched = 0;
                        expansionEnumerator.Next(1, pExpansionInfo, out fetched);
                        if (fetched > 0)
                        {
                            // Convert the returned blob of data into a structure.
                            expansion = (VsExpansion)Marshal.PtrToStructure(pExpansionInfo[0], typeof(VsExpansion));
                            if (!string.IsNullOrEmpty(expansion.shortcut))
                            {
                                _expansions[expansion.shortcut] = expansion;
                            }
                        }
                    }
                } finally {
                    if (pExpansionInfo[0] != null)
                    {
                        Marshal.FreeCoTaskMem(pExpansionInfo[0]);
                    }
                }
            }
        }
Example #4
0
        /// <remarks>
        /// This method must be called on the UI thread because it eventually calls into
        /// IVsExpansionEnumeration.Next, which must be called on the UI thread due to an issue
        /// with how the call is marshalled.
        ///
        /// The second parameter for IVsExpansionEnumeration.Next is defined like this:
        ///    [ComAliasName("Microsoft.VisualStudio.TextManager.Interop.VsExpansion")] IntPtr[] rgelt
        ///
        /// We pass a pointer for rgelt that we expect to be populated as the result. This
        /// eventually calls into the native CExpansionEnumeratorShim::Next method, which has the
        /// same contract of expecting a non-null rgelt that it can drop expansion data into. When
        /// we call from the UI thread, this transition from managed code to the
        /// CExpansionEnumeratorShim goes smoothly and everything works.
        ///
        /// When we call from a background thread, the COM marshaller has to move execution to the
        /// UI thread, and as part of this process it uses the interface as defined in the idl to
        /// set up the appropriate arguments to pass. The same parameter from the idl is defined as
        ///    [out, size_is(celt), length_is(*pceltFetched)] VsExpansion **rgelt
        ///
        /// Because rgelt is specified as an <c>out</c> parameter, the marshaller is discarding the
        /// pointer we passed and substituting the null reference. This then causes a null
        /// reference exception in the shim. Calling from the UI thread avoids this marshaller.
        /// </remarks>
        private void PopulateSnippetCacheFromExpansionEnumeration(IVsExpansionEnumeration expansionEnumerator)
        {
            AssertIsForeground();

            var updatedSnippets         = ExtractSnippetInfo(expansionEnumerator);
            var updatedSnippetShortcuts = GetShortcutsHashFromSnippets(updatedSnippets);

            lock (cacheGuard)
            {
                snippets         = updatedSnippets;
                snippetShortcuts = updatedSnippetShortcuts;
            }
        }
        public static VsExpansion[] EnumerateExpansions(this IVsExpansionManager expansionManager, Guid language, string[] snippetTypes, bool shortcutsOnly)
        {
            Contract.Requires <ArgumentNullException>(expansionManager != null, "expansionManager");
            Contract.Ensures(Contract.Result <VsExpansion[]>() != null);

            bool includeNullType   = false;
            bool includeDuplicates = false;

            IVsExpansionEnumeration expEnum = null;

            if (ErrorHandler.Succeeded(ErrorHandler.CallWithCOMConvention(() => expansionManager.EnumerateExpansions(language, shortcutsOnly ? 1 : 0, snippetTypes, snippetTypes.Length, includeNullType ? 1 : 0, includeDuplicates ? 1 : 0, out expEnum))))
            {
                uint count;
                ErrorHandler.ThrowOnFailure(expEnum.GetCount(out count));

                IntPtr[] raw = new IntPtr[count];
                try
                {
                    for (int i = 0; i < raw.Length; i++)
                    {
                        raw[i] = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(VsExpansion)));
                    }

                    uint fetched;
                    ErrorHandler.ThrowOnFailure(expEnum.Next(count, raw, out fetched));

                    VsExpansion[] results = new VsExpansion[fetched];
                    for (int i = 0; i < results.Length; i++)
                    {
                        if (raw[i] != IntPtr.Zero)
                        {
                            results[i] = (VsExpansion)Marshal.PtrToStructure(raw[i], typeof(VsExpansion));
                        }
                    }

                    return(results);
                }
                finally
                {
                    foreach (IntPtr p in raw)
                    {
                        Marshal.FreeCoTaskMem(p);
                    }
                }
            }

            return(new VsExpansion[0]);
        }
        /// <remarks>
        /// Changes to the <see cref="IVsExpansionManager.EnumerateExpansions"/> invocation
        /// should also be made to the IExpansionManager.EnumerateExpansionsAsync
        /// invocation in <see cref="PopulateSnippetCacheAsync(IExpansionManager)"/>.
        /// </remarks>
        private void PopulateSnippetCacheOnForeground(IVsExpansionManager expansionManager)
        {
            AssertIsForeground();

            IVsExpansionEnumeration expansionEnumerator = null;

            expansionManager.EnumerateExpansions(
                _languageGuidForSnippets,
                fShortCutOnly: 0,
                bstrTypes: null,
                iCountTypes: 0,
                fIncludeNULLType: 1,
                fIncludeDuplicates: 1, // Allows snippets with the same title but different shortcuts
                pEnum: out expansionEnumerator);

            PopulateSnippetCacheFromExpansionEnumeration(expansionEnumerator);
        }
        private bool TryGetVsSnippets(out IVsExpansionEnumeration expansionEnumerator)
        {
            expansionEnumerator = null;
            if (_expansionManager != null)
            {
                _expansionManager.EnumerateExpansions(
                    _languageGuidForSnippets,
                    fShortCutOnly: 0,
                    bstrTypes: null,
                    iCountTypes: 0,
                    fIncludeNULLType: 1,
                    fIncludeDuplicates: 1, // Allows snippets with the same title but different shortcuts
                    pEnum: out expansionEnumerator);
            }

            return(expansionEnumerator != null);
        }
        private ImmutableArray <SnippetInfo> ExtractSnippetInfo(IVsExpansionEnumeration expansionEnumerator)
        {
            AssertIsForeground();

            var snippetListBuilder = ImmutableArray.CreateBuilder <SnippetInfo>();

            uint        count       = 0;
            uint        fetched     = 0;
            VsExpansion snippetInfo = new VsExpansion();

            IntPtr[] pSnippetInfo = new IntPtr[1];

            try
            {
                // Allocate enough memory for one VSExpansion structure. This memory is filled in by the Next method.
                pSnippetInfo[0] = Marshal.AllocCoTaskMem(Marshal.SizeOf(snippetInfo));
                expansionEnumerator.GetCount(out count);

                for (uint i = 0; i < count; i++)
                {
                    expansionEnumerator.Next(1, pSnippetInfo, out fetched);
                    if (fetched > 0)
                    {
                        // Convert the returned blob of data into a structure that can be read in managed code.
                        snippetInfo = ConvertToVsExpansionAndFree(pSnippetInfo[0]);

                        if (!string.IsNullOrEmpty(snippetInfo.shortcut))
                        {
                            snippetListBuilder.Add(new SnippetInfo(snippetInfo.shortcut, snippetInfo.title, snippetInfo.description, snippetInfo.path));
                        }
                    }
                }
            }
            finally
            {
                Marshal.FreeCoTaskMem(pSnippetInfo[0]);
            }

            return(snippetListBuilder.ToImmutable());
        }
        private ImmutableArray<SnippetInfo> ExtractSnippetInfo(IVsExpansionEnumeration expansionEnumerator)
        {
            AssertIsForeground();

            var snippetListBuilder = ImmutableArray.CreateBuilder<SnippetInfo>();

            uint count = 0;
            uint fetched = 0;
            VsExpansion snippetInfo = new VsExpansion();
            IntPtr[] pSnippetInfo = new IntPtr[1];

            try
            {
                // Allocate enough memory for one VSExpansion structure. This memory is filled in by the Next method.
                pSnippetInfo[0] = Marshal.AllocCoTaskMem(Marshal.SizeOf(snippetInfo));
                expansionEnumerator.GetCount(out count);

                for (uint i = 0; i < count; i++)
                {
                    expansionEnumerator.Next(1, pSnippetInfo, out fetched);
                    if (fetched > 0)
                    {
                        // Convert the returned blob of data into a structure that can be read in managed code.
                        snippetInfo = ConvertToVsExpansionAndFree(pSnippetInfo[0]);

                        if (!string.IsNullOrEmpty(snippetInfo.shortcut))
                        {
                            snippetListBuilder.Add(new SnippetInfo(snippetInfo.shortcut, snippetInfo.title, snippetInfo.description, snippetInfo.path));
                        }
                    }
                }
            }
            finally
            {
                Marshal.FreeCoTaskMem(pSnippetInfo[0]);
            }

            return snippetListBuilder.ToImmutable();
        }
        /// <remarks>
        /// This method must be called on the UI thread because it eventually calls into
        /// IVsExpansionEnumeration.Next, which must be called on the UI thread due to an issue
        /// with how the call is marshalled.
        /// 
        /// The second parameter for IVsExpansionEnumeration.Next is defined like this:
        ///    [ComAliasName("Microsoft.VisualStudio.TextManager.Interop.VsExpansion")] IntPtr[] rgelt
        ///
        /// We pass a pointer for rgelt that we expect to be populated as the result. This
        /// eventually calls into the native CExpansionEnumeratorShim::Next method, which has the
        /// same contract of expecting a non-null rgelt that it can drop expansion data into. When
        /// we call from the UI thread, this transition from managed code to the
        /// CExpansionEnumeratorShim` goes smoothly and everything works.
        ///
        /// When we call from a background thread, the COM marshaller has to move execution to the
        /// UI thread, and as part of this process it uses the interface as defined in the idl to
        /// set up the appropriate arguments to pass. The same parameter from the idl is defined as
        ///    [out, size_is(celt), length_is(*pceltFetched)] VsExpansion **rgelt
        ///
        /// Because rgelt is specified as an `out` parameter, the marshaller is discarding the
        /// pointer we passed and substituting the null reference. This then causes a null
        /// reference exception in the shim. Calling from the UI thread avoids this marshaller.
        /// </remarks>
        void PopulateSnippetCacheFromExpansionEnumeration(IVsExpansionEnumeration expansionEnumerator)
        {
            AssertIsForeground();

            var updatedSnippets = ExtractSnippetInfo(expansionEnumerator);
            var updatedSnippetShortcuts = GetShortcutsHashFromSnippets(updatedSnippets);

            lock (cacheGuard)
            {
                snippets = updatedSnippets;
                snippetShortcuts = updatedSnippetShortcuts;
            }
        }
Example #11
0
 public int EnumerateExpansions(Guid guidLang, int fShortCutOnly, string[] bstrTypes, int iCountTypes, int fIncludeNULLType, int fIncludeDuplicates, out IVsExpansionEnumeration pEnum) {
     pEnum = new VsExpansionEnumerationMock();
     return VSConstants.S_OK;
 }
 public int EnumerateExpansions(Guid guidLang, int fShortCutOnly, string[] bstrTypes, int iCountTypes, int fIncludeNULLType, int fIncludeDuplicates, out IVsExpansionEnumeration pEnum)
 {
     throw new NotImplementedException();
 }
Example #13
0
 public int EnumerateExpansions(Guid guidLang, int fShortCutOnly, string[] bstrTypes, int iCountTypes, int fIncludeNULLType, int fIncludeDuplicates, out IVsExpansionEnumeration pEnum)
 {
     pEnum = new VsExpansionEnumerationMock();
     return(VSConstants.S_OK);
 }
Example #14
0
        /// <summary>
        /// Executes a specified command or displays help for a command.
        /// </summary>
        /// <param name="pguidCmdGroupRef">Pointer to unique identifier of the command group; can be NULL to specify the standard group.</param>
        /// <param name="nCmdID">The command to be executed. This command must belong to the group specified with pguidCmdGroup.</param>
        /// <param name="nCmdexecopt">Values taken from the OLECMDEXECOPT enumeration, which describe how the object should execute the command.</param>
        /// <param name="pvaIn">Pointer to a VARIANTARG structure containing input arguments. Can be NULL.</param>
        /// <param name="pvaOut">Pointer to a VARIANTARG structure to receive command output. Can be NULL.</param>
        /// <returns>This method supports the standard return values E_FAIL and E_UNEXPECTED, as well as the following:
        ///            S_OK
        ///                The command was executed successfully.
        ///            OLECMDERR_E_UNKNOWNGROUP
        ///                The pguidCmdGroup parameter is not NULL but does not specify a recognized command group.
        ///            OLECMDERR_E_NOTSUPPORTED
        ///                The nCmdID parameter is not a valid command in the group identified by pguidCmdGroup.
        ///            OLECMDERR_E_DISABLED
        ///                The command identified by nCmdID is currently disabled and cannot be executed.
        ///            OLECMDERR_E_NOHELP
        ///                The caller has asked for help on the command identified by nCmdID, but no help is available.
        ///            OLECMDERR_E_CANCELED
        ///                The user canceled the execution of the command.</returns>
        public int Exec(ref Guid pguidCmdGroupRef, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
        {
            //the snippet picker code starts here
            if (nCmdID == (uint)VSConstants.VSStd2KCmdID.INSERTSNIPPET)
            {
                IVsTextManager2 textManager = (IVsTextManager2)languageService.GetService(typeof(SVsTextManager));

                textManager.GetExpansionManager(out m_exManager);

                IVsExpansionEnumeration expansionEnumerator = null;
                int ret = m_exManager.EnumerateExpansions(Guids.LuaLanguageService,
                                                          0,          // return all info
                                                          null,       // return all types
                                                          0,          // return all types
                                                          1,          // include snippets without types
                                                          0,          // do not include duplicates
                                                          out expansionEnumerator);

                uint count = 0;
                if (expansionEnumerator != null)
                {
                    expansionEnumerator.GetCount(out count);
                }
                if (count == 0)
                {
                    RegisterCodeSnippets();
                    return(VSConstants.S_OK);
                }
                m_exManager.InvokeInsertionUI(
                    m_vsTextView,
                    this,          //the expansion client
                    Guids.LuaLanguageService,
                    null,          //use all snippet types
                    0,             //number of types (0 for all)
                    0,             //ignored if iCountTypes == 0
                    null,          //use all snippet kinds
                    0,             //use all snippet kinds
                    0,             //ignored if iCountTypes == 0
                    "Lua",         //the text to show in the prompt
                    string.Empty); //only the ENTER key causes insert

                return(VSConstants.S_OK);
            }
            //the expansion insertion is handled in OnItemChosen
            //if the expansion session is still active, handle tab/backtab/return/cancel
            if (m_exSession != null)
            {
                if (nCmdID == (uint)VSConstants.VSStd2KCmdID.BACKTAB)
                {
                    m_exSession.GoToPreviousExpansionField();
                    return(VSConstants.S_OK);
                }
                else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB)
                {
                    m_exSession.GoToNextExpansionField(0); //false to support cycling through all the fields
                    return(VSConstants.S_OK);
                }
                else if (nCmdID == (uint)VSConstants.VSStd2KCmdID.RETURN || nCmdID == (uint)VSConstants.VSStd2KCmdID.CANCEL)
                {
                    if (m_exSession.EndCurrentExpansion(0) == VSConstants.S_OK)
                    {
                        m_exSession = null;
                        return(VSConstants.S_OK);
                    }
                }
            }
            //neither an expansion session nor a completion session is open, but we got a tab, so check whether the last word typed is a snippet shortcut
            //if (m_exSession == null && nCmdID == (uint)VSConstants.VSStd2KCmdID.TAB)
            //{
            //    //get the word that was just added
            //    CaretPosition pos = m_vsTextView.Caret.Position;
            //    TextExtent word = languageService.NavigatorService.GetTextStructureNavigator(m_textView.TextBuffer).GetExtentOfWord(pos.BufferPosition - 1); //use the position 1 space back
            //    string textString = word.Span.GetText(); //the word that was just added
            //                                             //if it is a code snippet, insert it, otherwise carry on
            //    if (InsertAnyExpansion(textString, null, null))
            //        return VSConstants.S_OK;
            //}

#if SUPPORT_REFACTOR
            string commandId = VSIDECommands.GetCommandId(pguidCmdGroupRef, nCmdID);

            if (!string.IsNullOrEmpty(commandId))
            {
                // refactor and undo are not working anyway.
                {
                    //Refactor command
                    if (VSIDECommands.IsRightClick(pguidCmdGroupRef, nCmdID))
                    {
                        SetRefactorMenuBars();
                        return(ExecVsHandler(ref pguidCmdGroupRef, nCmdID, nCmdexecopt, pvaIn, pvaOut));
                    }

                    //Undo command
                    if (commandId == "cmdidUndo")
                    {
                        var luaUndoService = languageService.GetService(typeof(ILuaUndoService)) as ILuaUndoService;
                        if (luaUndoService != null)
                        {
                            luaUndoService.Undo();
                        }

                        return(ExecVsHandler(ref pguidCmdGroupRef, nCmdID, nCmdexecopt, pvaIn, pvaOut));
                    }
                }
            }
#endif
            return(ExecVsHandler(ref pguidCmdGroupRef, nCmdID, nCmdexecopt, pvaIn, pvaOut));
        }
        private bool TryGetVsSnippets(out IVsExpansionEnumeration expansionEnumerator)
        {
            expansionEnumerator = null;
            if (_expansionManager != null)
            {
                _expansionManager.EnumerateExpansions(
                    _languageGuidForSnippets,
                    fShortCutOnly: 0,
                    bstrTypes: null,
                    iCountTypes: 0,
                    fIncludeNULLType: 1,
                    fIncludeDuplicates: 1, // Allows snippets with the same title but different shortcuts
                    pEnum: out expansionEnumerator);
            }

            return expansionEnumerator != null;
        }
Example #16
0
 public int EnumerateExpansions(Guid guidLang, int fShortCutOnly, string[] bstrTypes, int iCountTypes, int fIncludeNULLType, int fIncludeDuplicates, out IVsExpansionEnumeration pEnum) {
     throw new NotImplementedException();
 }