locked
Problem with Language Service Walkthrough RRS feed

  • Question

  • Hello,

    I have a question about the walkthrough for creating a language service. (http://msdn.microsoft.com/en-us/library/bb165744%28VS.100%29.aspx)

    I've gone through the process of creating the language service, but when I test it by opening a file in the experimental instance of VS, the language service is not called and the editor is blank.

    (Removing the ProvideLanguageExtensionAttribute attribute from the package class allows the file to be displayed, but then of course, the language service doesn't get loaded either.)

    MyLanguagePackagePackage::Initialize is called, so the language service object is instantiated, but none of the virtual methods of MyLanguageService are called. I overrode all of them, calling the base class in each method to facilitate putting a breakpoint in each of the virtual methods, but none of the breakpoints are reached.

    I noticed someone else had a similar problem (see thread http://social.msdn.microsoft.com/Forums/en/vsx/thread/4372b907-fe73-425e-9767-75016be0f66e) who said they fixed the problem by changing ProvideLanguageServiceAttribute.RequestStockColors to "true". However, this may not have been the right way to fix the problem (see the response), and it doesn't work in my case.

    Below is the source code for my rendition of the package and language service. (Note that the ProvideLanguageCodeExpansionAttribute and ProvideLanguageEditorOptionPageAttribute attributes are not included.)

    Thanks in advance for any help.

    Jim

    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using System.ComponentModel.Design;
    using Microsoft.Win32;
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.Shell.Interop;
    using Microsoft.VisualStudio.OLE.Interop;
    using Microsoft.VisualStudio.Shell;
    
    using Microsoft.VisualStudio.Package;
    using Microsoft.VisualStudio.TextManager.Interop;
    
    namespace HotDocs.MyLanguagePackage
    {
    	[PackageRegistration(UseManagedResourcesOnly = true)]
    	[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
    	[ProvideMenuResource("Menus.ctmenu", 1)]
    	[ProvideEditorFactory(typeof(EditorFactory), 101)]
    	[ProvideEditorExtension(typeof(EditorFactory), ".myext", 32, NameResourceID = 101)]
    	[Guid(GuidList.guidMyLanguagePackagePkgString)]
    	[ProvideServiceAttribute(typeof(MyLanguageService), ServiceName = "My Language Service")]
    	[ProvideLanguageServiceAttribute(typeof(MyLanguageService), "My Language Service",
    		106,       // resource ID of localized language name
    		CodeSense = true,       // Supports IntelliSense
    		RequestStockColors = false,  // Supplies custom colors
    		EnableCommenting = true,   // Supports commenting out code
    		EnableAsyncCompletion = true // Supports background parsing
    		)]
    
    	[ProvideLanguageExtensionAttribute(typeof(MyLanguageService), ".myext")]
    
    	//[ProvideLanguageCodeExpansionAttribute(
    	//     typeof(MyLanguageService),
    	//     "My Language Service", // Name of language used as registry key.
    	//     106,      // Resource ID of localized name of language service.
    	//     "mylanguage", // language key used in snippet templates.
    	//     @"%InstallRoot%\My Language\SnippetsIndex.xml", // Path to snippets index
    	//     SearchPaths = @"%InstallRoot%\My Language\Snippets\%LCID%\Snippets\;" +
    	//            @"%TestDocs%\Code Snippets\My Language\MyLang Code Snippets"
    	//     )]
    
    	public sealed class MyLanguagePackagePackage : Package, IOleComponent
    	{
    		private EditorFactory editorFactory;
    
    		public MyLanguagePackagePackage()
    		{
    			Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString()));
    		}
    
    		/////////////////////////////////////////////////////////////////////////////
    		// Overriden Package Implementation
    		#region Package Members
    
    		protected override void Initialize()
    		{
    			Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString()));
    			base.Initialize();
    
    			// Proffer the service.
    			IServiceContainer serviceContainer = this as IServiceContainer;
    			MyLanguageService langService = new MyLanguageService();
    			langService.SetSite(this);
    			serviceContainer.AddService(typeof(MyLanguageService), langService, true);
    
    			// Add our command handlers for menu (commands must exist in the .vsct file)
    			OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
    			if (null != mcs)
    			{
    				// Create the command for the menu item.
    				CommandID menuCommandID = new CommandID(GuidList.guidMyLanguagePackageCmdSet, (int)PkgCmdIDList.cmdidInsertSnippet);
    				MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
    				mcs.AddCommand(menuItem);
    			}
    
    			// Create our editor factory and register it.
    			this.editorFactory = new EditorFactory(this);
    			base.RegisterEditorFactory(this.editorFactory);
    
    			//Register a timer to call our language service during
    			// idle periods.
    			IOleComponentManager mgr = GetService(typeof(SOleComponentManager)) as IOleComponentManager;
    			if (m_componentID == 0 && mgr != null)
    			{
    				OLECRINFO[] crinfo = new OLECRINFO[1];
    				crinfo[0].cbSize = (uint)Marshal.SizeOf(typeof(OLECRINFO));
    				crinfo[0].grfcrf = (uint)_OLECRF.olecrfNeedIdleTime | (uint)_OLECRF.olecrfNeedPeriodicIdleTime;
    				crinfo[0].grfcadvf = (uint)_OLECADVF.olecadvfModal | (uint)_OLECADVF.olecadvfRedrawOff | (uint)_OLECADVF.olecadvfWarningsOff;
    				crinfo[0].uIdleTimeInterval = 1000;
    				int hr = mgr.FRegisterComponent(this, crinfo, out m_componentID);
    			}
    		}
    
    		protected override void Dispose(bool disposing)
    		{
    			if (m_componentID != 0)
    			{
    				IOleComponentManager mgr = GetService(typeof(SOleComponentManager))
    													as IOleComponentManager;
    				if (mgr != null)
    				{
    					int hr = mgr.FRevokeComponent(m_componentID);
    				}
    				m_componentID = 0;
    			}
    
    			base.Dispose(disposing);
    		}
    
    		#endregion
    
    		private void MenuItemCallback(object sender, EventArgs e)
    		{
    			// Show a Message Box to prove we were here
    			IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
    			Guid clsid = Guid.Empty;
    			int result;
    			Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox(
    						 0,
    						 ref clsid,
    						 "MyLanguagePackage",
    						 string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.ToString()),
    						 string.Empty,
    						 0,
    						 OLEMSGBUTTON.OLEMSGBUTTON_OK,
    						 OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
    						 OLEMSGICON.OLEMSGICON_INFO,
    						 0,    // false
    						 out result));
    		}
    
    		private uint m_componentID;
    
    		#region IOleComponent Members
    
    		public int FDoIdle(uint grfidlef)
    		{
    			bool bPeriodic = (grfidlef & (uint)_OLEIDLEF.oleidlefPeriodic) != 0;
    			// Use typeof(TestLanguageService) because we need to
    			// reference the GUID for our language service.
    			LanguageService service = GetService(typeof(MyLanguageService))
    											 as LanguageService;
    			if (service != null)
    			{
    				service.OnIdle(bPeriodic);
    			}
    			return 0;
    		}
    
    		public int FContinueMessageLoop(uint uReason,
    												 IntPtr pvLoopData,
    												 MSG[] pMsgPeeked)
    		{
    			return 1;
    		}
    
    		public int FPreTranslateMessage(MSG[] pMsg)
    		{
    			return 0;
    		}
    
    		public int FQueryTerminate(int fPromptUser)
    		{
    			return 1;
    		}
    
    		public int FReserved1(uint dwReserved,
    									 uint message,
    									 IntPtr wParam,
    									 IntPtr lParam)
    		{
    			return 1;
    		}
    
    		public IntPtr HwndGetWindow(uint dwWhich, uint dwReserved)
    		{
    			return IntPtr.Zero;
    		}
    
    		public void OnActivationChange(IOleComponent pic,
    												 int fSameComponent,
    												 OLECRINFO[] pcrinfo,
    												 int fHostIsActivating,
    												 OLECHOSTINFO[] pchostinfo,
    												 uint dwReserved)
    		{
    		}
    
    		public void OnAppActivate(int fActive, uint dwOtherThreadID)
    		{
    		}
    
    		public void OnEnterState(uint uStateID, int fEnter)
    		{
    		}
    
    		public void OnLoseActivation()
    		{
    		}
    
    		public void Terminate()
    		{
    		}
    
    		#endregion
    	}
    }
    
    //////////////////////////////////////////////////////////////
    //MyLanguageService.cs
    //////////////////////////////////////////////////////////////
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using Microsoft.VisualStudio;
    using Microsoft.VisualStudio.Package;
    using Microsoft.VisualStudio.TextManager.Interop;
    using Microsoft.VisualStudio.OLE.Interop;
    
    namespace HotDocs.MyLanguagePackage
    {
    	public class MyLanguageService : LanguageService
    	{
    		public MyLanguageService()
    		{
    			int x = 0;
    		}
    		public override string GetFormatFilterList()
    		{
    			throw new NotImplementedException();
    		}
    
    		private LanguagePreferences m_preferences;
    
    		public override LanguagePreferences GetLanguagePreferences()
    		{
    			if (m_preferences == null)
    			{
    				m_preferences = new LanguagePreferences(this.Site, typeof(MyLanguageService).GUID, this.Name);
    				m_preferences.Init();
    			}
    			return m_preferences;
    		}
    
    		private TestScanner m_scanner;
    
    		public override IScanner GetScanner(IVsTextLines buffer)
    		{
    			if (m_scanner == null)
    			{
    				m_scanner = new TestScanner(buffer);
    			}
    			return m_scanner;
    		}
    
    		public override string Name
    		{
    			get { return "My Language Service"; }//Return the name of the language service. MUST NOT BE LOCALIZED.
    		}
    
    		public override AuthoringScope ParseSource(ParseRequest req)
    		{
    			return new TestAuthoringScope();
    		}
    		///////////////////////////////////
    		public override bool CanStopThread(Source src)
    		{
    			return base.CanStopThread(src);
    		}
    		//
    		public override CodeWindowManager CreateCodeWindowManager(IVsCodeWindow codeWindow, Source source)
    		{
    			return base.CreateCodeWindowManager(codeWindow, source);
    		}
    		//
    		public override DocumentProperties CreateDocumentProperties(CodeWindowManager mgr)
    		{
    			return base.CreateDocumentProperties(mgr);
    		}
    		//
    		public override TypeAndMemberDropdownBars CreateDropDownHelper(IVsTextView forView)
    		{
    			return base.CreateDropDownHelper(forView);
    		}
    		//
    		public override ExpansionFunction CreateExpansionFunction(ExpansionProvider provider, string functionName)
    		{
    			return base.CreateExpansionFunction(provider, functionName);
    		}
    		//
    		public override ExpansionProvider CreateExpansionProvider(Source src)
    		{
    			return base.CreateExpansionProvider(src);
    		}
    		//
    		public override ParseRequest CreateParseRequest(Source s, int line, int idx, TokenInfo info, string sourceText, string fname, ParseReason reason, IVsTextView 
    
    view)
    		{
    			return base.CreateParseRequest(s, line, idx, info, sourceText, fname, reason, view);
    		}
    		//
    		public override Source CreateSource(IVsTextLines buffer)
    		{
    			return base.CreateSource(buffer);
    		}
    		//
    		public override ViewFilter CreateViewFilter(CodeWindowManager mgr, IVsTextView newView)
    		{
    			return base.CreateViewFilter(mgr, newView);
    		}
    		//
    		public override int CurFileExtensionFormat(string fileName)
    		{
    			return base.CurFileExtensionFormat(fileName);
    		}
    		///////////////////////////////////
    	}
    
    	internal class TestScanner : IScanner
    	{
    		private IVsTextBuffer m_buffer;
    		string m_source;
    
    		public TestScanner(IVsTextBuffer buffer)
    		{
    			m_buffer = buffer;
    		}
    
    		bool IScanner.ScanTokenAndProvideInfoAboutIt(TokenInfo tokenInfo, ref int state)
    		{
    			tokenInfo.Type = TokenType.Unknown;
    			tokenInfo.Color = TokenColor.Text;
    			return true;
    		}
    
    		void IScanner.SetSource(string source, int offset)
    		{
    			m_source = source.Substring(offset);
    		}
    	}
    
      internal class TestAuthoringScope : AuthoringScope
      {
        public override string GetDataTipText(int line, int col, out TextSpan span)
        {
          span = new TextSpan();
          return null;
        }
    
        public override Declarations GetDeclarations(IVsTextView view,
                               int line,
                               int col,
                               TokenInfo info,
                               ParseReason reason)
        {
          return null;
        }
    
        public override string Goto(VSConstants.VSStd97CmdID cmd, IVsTextView textView, int line, int col, out TextSpan span)
        {
          span = new TextSpan();
          return null;
        }
    
        public override Methods GetMethods(int line, int col, string name)
        {
          return null;
        }
      }
    }
    
    

     

     

    Monday, April 18, 2011 10:44 PM

Answers

  • Hi Jim,

    It looks like there are a number of problems with that walkthrough, I'll get a documentation bug to the product team to get this fixed up. First off, there is a Guid attribute missing on the LanguageService derived class. I'm guessing you may have already corrected that.

    Second, you'll have to add code to pass back an array of ColorableItems, via the GetItemCount and GetColorableItem methods on your language service, unless you stipulate that you want your language service to use the stock colors, via the RequestStockColors property on the ProvideLanguageServiceAttribute, for example:

        [ProvideLanguageService(typeof(MyLanguageService), "My Language", 0, RequestStockColors=true)]
    

    My suspicion is that this is what was giving you the problem with the blank editor page. I initially repro'd the same behavior, and when debugging, I noticed there was a System.ArgumentException being thrown on the following callstack:

      mscorlib.dll!System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(int errorCode) Line 1028 + 0x1c bytes C#
    > Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontsAndColorsInformation.UpdatePlainTextProperties(Microsoft.VisualStudio.Text.Classification.IClassificationFormatMap classificationFormatMap, Microsoft.VisualStudio.Text.Classification.IEditorFormatMap editorFormatMap, uint autoForeground, uint autoBackground, Microsoft.VisualStudio.Editor.Implementation.IVsColorTable colorTable, Microsoft.VisualStudio.TextManager.Interop.FONTCOLORPREFERENCES2 fontColorPreferences) Line 1088 C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontsAndColorsInformation.UpdatePlainTextProperties() Line 1065 + 0x35 bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontAndColorInformationService.GetFontAndColorInformation(Microsoft.VisualStudio.Editor.FontsAndColorsCategory fontsAndColorsCategory) Line 42 + 0x7 bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsTextViewAdapter.GetOrCreateFontsAndColorsInformation(Microsoft.VisualStudio.Editor.FontsAndColorsCategory category) Line 1239 + 0xa bytes C#
     

    Along with a whole bunch of NullReferenceExceptions on the following stack, after attempting to active the code window:

    > Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontsAndColorsInformation.TryGetIndexForNativeItem(string name, Microsoft.VisualStudio.Editor.Implementation.IVsColorTable colorTable, out int colorTableIndex) Line 1335 + 0x1b bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontsAndColorsInformation.TryGetItemValue(string itemKey, out System.Windows.ResourceDictionary itemValue, System.Collections.Generic.HashSet<System.Guid> visitedCategories) Line 1482 + 0x12 bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontsAndColorsInformation.TryGetItemValue(string itemKey, out System.Windows.ResourceDictionary itemValue) Line 1404 + 0x24 bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Classification.Implementation.EditorFormatMap.CreateResourceDictionaryFromProvision(string key) Line 235 + 0x19 bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Classification.Implementation.EditorFormatMap.GetProperties(string key) Line 60 + 0x5 bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Classification.Implementation.ViewSpecificFormatMap.GetProperties(string key) Line 100 + 0xb bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextSelection.WpfTextSelection(Microsoft.VisualStudio.Text.Editor.IWpfTextView wpfTextView, Microsoft.VisualStudio.Text.Classification.IEditorFormatMap editorFormatMap, Microsoft.VisualStudio.Text.Editor.IEditorOptions selectionOptions, Microsoft.VisualStudio.Text.Utilities.GuardedOperations guardedOperations) Line 124 + 0x55 bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextView.WpfTextView(Microsoft.VisualStudio.Text.Editor.ITextViewModel textViewModel, Microsoft.VisualStudio.Text.Editor.ITextViewRoleSet roles, Microsoft.VisualStudio.Text.Editor.IEditorOptions parentOptions, Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextEditorFactoryService factoryService) Line 264 + 0x30 bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextEditorFactoryService.CreateAndTrackTextView(Microsoft.VisualStudio.Text.Editor.ITextViewModel viewModel, Microsoft.VisualStudio.Text.Editor.ITextViewRoleSet roles, Microsoft.VisualStudio.Text.Editor.IEditorOptions parentOptions) Line 108 + 0x1c bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextEditorFactoryService.CreateAndTrackTextView(Microsoft.VisualStudio.Text.ITextDataModel dataModel, Microsoft.VisualStudio.Text.Editor.ITextViewRoleSet roles, Microsoft.VisualStudio.Text.Editor.IEditorOptions parentOptions) Line 139 + 0xf bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextEditorFactoryService.CreateTextView(Microsoft.VisualStudio.Text.ITextDataModel dataModel, Microsoft.VisualStudio.Text.Editor.ITextViewRoleSet roles, Microsoft.VisualStudio.Text.Editor.IEditorOptions parentOptions) Line 173 + 0x7 bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsTextViewAdapter.Init_InitializeWpfTextView() Line 384 + 0x26 bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsTextViewAdapter.Init_OnActivation() Line 332 C#

    Which seemed to indicate the problem revolved around retrieving the font/color info for the items to be colorized. I then recalled some mention of it being 'required' to provide your own colorable items via the Language Service. But with VS 2010, it seems you can avoid that if you use the stock colors via the attribute property I mentioned above.

    If by chance you have the older VS 2008 SDK on your system, the Example.RegExLanguageService sample is a good place to start. Sadly we revised that sample to utilize the new editor extensions in VS 2010, so there isn't a directly port of that sample to 2010.

    P.S. The code used in that walkthrough is a little 'dated'. It's generally recommended that services by proffered via a ServiceCreatorCallback, so that the individual service(s) are proffered 'on demand'.

    Here's a snippet from my working demo that I used to debug the original problem:

    namespace Microsoft.MyLanguage
    {
        [ProvideService(typeof(MyLanguageService))]
        // Note RequestStockColors==true, otherwise we need to provide our own colorable items
        [ProvideLanguageService(typeof(MyLanguageService), "My Language", 0, RequestStockColors=true)]
        [ProvideLanguageExtension(typeof(MyLanguageService), ".mylang")]
        [PackageRegistration(UseManagedResourcesOnly = true)]
        [InstalledProductRegistration("#110""#112""1.0", IconResourceID = 400)]
        [ProvideMenuResource("Menus.ctmenu", 1)]
        [Guid(GuidList.guidMyLanguagePkgString)]
        public sealed class MyLanguagePackage : Package 
        {
            public MyLanguagePackage() {}
     
            protected override void Initialize()
            {
                base.Initialize();
     
                // Proffer language service on demand
                ServiceCreatorCallback callback = new ServiceCreatorCallback(CreateLanguageService);
                ((IServiceContainer)this).AddService(typeof(MyLanguageService), callback, true);
     
                // Add our command handlers for menu (commands must exist in the .vsct file)
                OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
                if ( null != mcs )
                {
                    // Create the command for the menu item.
                    CommandID menuCommandID = new CommandID(GuidList.guidMyLanguageCmdSet, (int)PkgCmdIDList.cmdidInsertSnippet);
                    MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID );
                    mcs.AddCommand( menuItem );
                }
            }
            
            private void MenuItemCallback(object sender, EventArgs e) { }
            private object CreateLanguageService(IServiceContainer container, Type serviceType)
            {
                if (container == this)
                {
                    if (typeof(MyLanguageService) == serviceType)
                    {
                        MyLanguageService langSvc = new MyLanguageService();
                        langSvc.SetSite(this);
                        return langSvc;
                    }
                }
                return null;
            }
        }
    }
    namespace Microsoft.MyLanguage
    {
        [Guid(GuidList.guidMyLanguageServiceString)]
        internal class MyLanguageService : LanguageService
        {
            private LanguagePreferences preferences = null;
            private MyLangScanner scanner = null;
     
            #region Language Service overrides
     
            public override string GetFormatFilterList()
            {
                return "MyLang File (*.mylang)\n*.mylang";
            }
     
            public override LanguagePreferences GetLanguagePreferences()
            {
                if (preferences == null)
                {
                    preferences = new LanguagePreferences(this.Site, GuidList.guidMyLanguageService, this.Name);
                    preferences.Init();
                }
                return preferences;
            }
     
            public override IScanner GetScanner(IVsTextLines buffer)
            {
                if (scanner == null)
                    scanner = new MyLangScanner();
                return scanner;
            }
     
            public override string Name
            {
                get { return "My Language Service"; }
            }
     
            public override AuthoringScope ParseSource(ParseRequest req)
            {
                throw new NotImplementedException();
            }
     
            public override int GetColorableItem(int index, out IVsColorableItem item)
            {
                return base.GetColorableItem(index, out item);
            }
     
            public override int GetItemCount(out int count)
            {
                return base.GetItemCount(out count);
            }
     
            #endregion
        }
     
        internal class MyLangScanner : IScanner
        {
            private string source;
            private int curPos;
     
            #region IScanner
     
            public bool ScanTokenAndProvideInfoAboutIt(TokenInfo tokenInfo, ref int state)
            {
                int length = source.Length;
                if (curPos < length)
                {
                    // find 'hello'
                    int index = source.IndexOf("hello", curPos, length - curPos, StringComparison.CurrentCultureIgnoreCase);
                    if (index != -1)
                    {
                        // color all instances of 'hello' as keyword
                        tokenInfo.Color = TokenColor.Keyword;
                        tokenInfo.Type = TokenType.Keyword;
                        tokenInfo.StartIndex = index;
                        tokenInfo.EndIndex = index + 4;
                        curPos = index + 5;
                    }
                    else
                    {
                        // otherwise color as text
                        tokenInfo.Color = TokenColor.Text;
                        tokenInfo.Type = TokenType.Text;
                        tokenInfo.StartIndex = curPos;
                        tokenInfo.EndIndex = length;
                        curPos = length;
                    }
                    // scan source for additional tokens
                    return true;
                }
                // no more tokens in current source
                return false;
            }
     
            public void SetSource(string source, int offset)
            {
                this.source = source;
                curPos = offset;
            }
     
            #endregion
        }
    }

    Sincerely,


    Ed Dore
    Monday, May 16, 2011 7:32 PM

All replies

  • Hi jfjerstad ,

     

    Thanks for your post.

    I tried the walkthrough and can reproduce your issue.

    When debugging the ironpython language service provided in VS2008 SDK,

    I noticed that all .py extension files are mapped to standard XML editor, but your extension

    .myext doesn't map with any editor, which means, if you use "Open with" to open such file with a

    specific editor, the language service should work.

    To map a extension to editor, you can try Tools->Options->Text Editor->File Extension,

    or register a custom editor for that extension.

    If I misunderstand your issue, be free to let me know.

    Best Regards,

    Ziwei Chen

     

     

     

     

     


    Ziwei Chen [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, April 19, 2011 7:58 AM
  • Ziwei,

    Thanks for your response.

    I don't think this is a file extension mapping issue, (although maybe I haven't mapped it properly). In response to your suggestion, I mapped the .myext to the script editor using Tools>Options>Text Editor>File Extension in the experimental instance of VS. That didn't work. In addition, I had also previously tried using a custom editor. Both my custom editor and the default text editor work fine if I simply remove the ProvideLanguageExtensionAttribute attribute from the MyLanguagePackagePackage class. But of course if I do that, the Language Service is not not loaded when I open a .myext file.

    Thanks again for your help and for replicating the issue. Hopefully we'll get this solved.

    Jim

    Tuesday, April 19, 2011 3:39 PM
  • Hello Jim,

     

    Thank you for your question.

     

    I am currently looking into this issue and will give you an update as soon as possible.

     

    Thank you for your understanding and support.

    Best Regards,


    Ziwei Chen [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, April 20, 2011 9:59 AM
  • Hi Jim,

    It looks like there are a number of problems with that walkthrough, I'll get a documentation bug to the product team to get this fixed up. First off, there is a Guid attribute missing on the LanguageService derived class. I'm guessing you may have already corrected that.

    Second, you'll have to add code to pass back an array of ColorableItems, via the GetItemCount and GetColorableItem methods on your language service, unless you stipulate that you want your language service to use the stock colors, via the RequestStockColors property on the ProvideLanguageServiceAttribute, for example:

        [ProvideLanguageService(typeof(MyLanguageService), "My Language", 0, RequestStockColors=true)]
    

    My suspicion is that this is what was giving you the problem with the blank editor page. I initially repro'd the same behavior, and when debugging, I noticed there was a System.ArgumentException being thrown on the following callstack:

      mscorlib.dll!System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(int errorCode) Line 1028 + 0x1c bytes C#
    > Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontsAndColorsInformation.UpdatePlainTextProperties(Microsoft.VisualStudio.Text.Classification.IClassificationFormatMap classificationFormatMap, Microsoft.VisualStudio.Text.Classification.IEditorFormatMap editorFormatMap, uint autoForeground, uint autoBackground, Microsoft.VisualStudio.Editor.Implementation.IVsColorTable colorTable, Microsoft.VisualStudio.TextManager.Interop.FONTCOLORPREFERENCES2 fontColorPreferences) Line 1088 C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontsAndColorsInformation.UpdatePlainTextProperties() Line 1065 + 0x35 bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontAndColorInformationService.GetFontAndColorInformation(Microsoft.VisualStudio.Editor.FontsAndColorsCategory fontsAndColorsCategory) Line 42 + 0x7 bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsTextViewAdapter.GetOrCreateFontsAndColorsInformation(Microsoft.VisualStudio.Editor.FontsAndColorsCategory category) Line 1239 + 0xa bytes C#
     

    Along with a whole bunch of NullReferenceExceptions on the following stack, after attempting to active the code window:

    > Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontsAndColorsInformation.TryGetIndexForNativeItem(string name, Microsoft.VisualStudio.Editor.Implementation.IVsColorTable colorTable, out int colorTableIndex) Line 1335 + 0x1b bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontsAndColorsInformation.TryGetItemValue(string itemKey, out System.Windows.ResourceDictionary itemValue, System.Collections.Generic.HashSet<System.Guid> visitedCategories) Line 1482 + 0x12 bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsFontsAndColorsInformation.TryGetItemValue(string itemKey, out System.Windows.ResourceDictionary itemValue) Line 1404 + 0x24 bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Classification.Implementation.EditorFormatMap.CreateResourceDictionaryFromProvision(string key) Line 235 + 0x19 bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Classification.Implementation.EditorFormatMap.GetProperties(string key) Line 60 + 0x5 bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Classification.Implementation.ViewSpecificFormatMap.GetProperties(string key) Line 100 + 0xb bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextSelection.WpfTextSelection(Microsoft.VisualStudio.Text.Editor.IWpfTextView wpfTextView, Microsoft.VisualStudio.Text.Classification.IEditorFormatMap editorFormatMap, Microsoft.VisualStudio.Text.Editor.IEditorOptions selectionOptions, Microsoft.VisualStudio.Text.Utilities.GuardedOperations guardedOperations) Line 124 + 0x55 bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextView.WpfTextView(Microsoft.VisualStudio.Text.Editor.ITextViewModel textViewModel, Microsoft.VisualStudio.Text.Editor.ITextViewRoleSet roles, Microsoft.VisualStudio.Text.Editor.IEditorOptions parentOptions, Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextEditorFactoryService factoryService) Line 264 + 0x30 bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextEditorFactoryService.CreateAndTrackTextView(Microsoft.VisualStudio.Text.Editor.ITextViewModel viewModel, Microsoft.VisualStudio.Text.Editor.ITextViewRoleSet roles, Microsoft.VisualStudio.Text.Editor.IEditorOptions parentOptions) Line 108 + 0x1c bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextEditorFactoryService.CreateAndTrackTextView(Microsoft.VisualStudio.Text.ITextDataModel dataModel, Microsoft.VisualStudio.Text.Editor.ITextViewRoleSet roles, Microsoft.VisualStudio.Text.Editor.IEditorOptions parentOptions) Line 139 + 0xf bytes C#
      Microsoft.VisualStudio.Platform.VSEditor.dll!Microsoft.VisualStudio.Text.Editor.Implementation.WpfTextEditorFactoryService.CreateTextView(Microsoft.VisualStudio.Text.ITextDataModel dataModel, Microsoft.VisualStudio.Text.Editor.ITextViewRoleSet roles, Microsoft.VisualStudio.Text.Editor.IEditorOptions parentOptions) Line 173 + 0x7 bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsTextViewAdapter.Init_InitializeWpfTextView() Line 384 + 0x26 bytes C#
      Microsoft.VisualStudio.Editor.Implementation.dll!Microsoft.VisualStudio.Editor.Implementation.VsTextViewAdapter.Init_OnActivation() Line 332 C#

    Which seemed to indicate the problem revolved around retrieving the font/color info for the items to be colorized. I then recalled some mention of it being 'required' to provide your own colorable items via the Language Service. But with VS 2010, it seems you can avoid that if you use the stock colors via the attribute property I mentioned above.

    If by chance you have the older VS 2008 SDK on your system, the Example.RegExLanguageService sample is a good place to start. Sadly we revised that sample to utilize the new editor extensions in VS 2010, so there isn't a directly port of that sample to 2010.

    P.S. The code used in that walkthrough is a little 'dated'. It's generally recommended that services by proffered via a ServiceCreatorCallback, so that the individual service(s) are proffered 'on demand'.

    Here's a snippet from my working demo that I used to debug the original problem:

    namespace Microsoft.MyLanguage
    {
        [ProvideService(typeof(MyLanguageService))]
        // Note RequestStockColors==true, otherwise we need to provide our own colorable items
        [ProvideLanguageService(typeof(MyLanguageService), "My Language", 0, RequestStockColors=true)]
        [ProvideLanguageExtension(typeof(MyLanguageService), ".mylang")]
        [PackageRegistration(UseManagedResourcesOnly = true)]
        [InstalledProductRegistration("#110""#112""1.0", IconResourceID = 400)]
        [ProvideMenuResource("Menus.ctmenu", 1)]
        [Guid(GuidList.guidMyLanguagePkgString)]
        public sealed class MyLanguagePackage : Package 
        {
            public MyLanguagePackage() {}
     
            protected override void Initialize()
            {
                base.Initialize();
     
                // Proffer language service on demand
                ServiceCreatorCallback callback = new ServiceCreatorCallback(CreateLanguageService);
                ((IServiceContainer)this).AddService(typeof(MyLanguageService), callback, true);
     
                // Add our command handlers for menu (commands must exist in the .vsct file)
                OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
                if ( null != mcs )
                {
                    // Create the command for the menu item.
                    CommandID menuCommandID = new CommandID(GuidList.guidMyLanguageCmdSet, (int)PkgCmdIDList.cmdidInsertSnippet);
                    MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID );
                    mcs.AddCommand( menuItem );
                }
            }
            
            private void MenuItemCallback(object sender, EventArgs e) { }
            private object CreateLanguageService(IServiceContainer container, Type serviceType)
            {
                if (container == this)
                {
                    if (typeof(MyLanguageService) == serviceType)
                    {
                        MyLanguageService langSvc = new MyLanguageService();
                        langSvc.SetSite(this);
                        return langSvc;
                    }
                }
                return null;
            }
        }
    }
    namespace Microsoft.MyLanguage
    {
        [Guid(GuidList.guidMyLanguageServiceString)]
        internal class MyLanguageService : LanguageService
        {
            private LanguagePreferences preferences = null;
            private MyLangScanner scanner = null;
     
            #region Language Service overrides
     
            public override string GetFormatFilterList()
            {
                return "MyLang File (*.mylang)\n*.mylang";
            }
     
            public override LanguagePreferences GetLanguagePreferences()
            {
                if (preferences == null)
                {
                    preferences = new LanguagePreferences(this.Site, GuidList.guidMyLanguageService, this.Name);
                    preferences.Init();
                }
                return preferences;
            }
     
            public override IScanner GetScanner(IVsTextLines buffer)
            {
                if (scanner == null)
                    scanner = new MyLangScanner();
                return scanner;
            }
     
            public override string Name
            {
                get { return "My Language Service"; }
            }
     
            public override AuthoringScope ParseSource(ParseRequest req)
            {
                throw new NotImplementedException();
            }
     
            public override int GetColorableItem(int index, out IVsColorableItem item)
            {
                return base.GetColorableItem(index, out item);
            }
     
            public override int GetItemCount(out int count)
            {
                return base.GetItemCount(out count);
            }
     
            #endregion
        }
     
        internal class MyLangScanner : IScanner
        {
            private string source;
            private int curPos;
     
            #region IScanner
     
            public bool ScanTokenAndProvideInfoAboutIt(TokenInfo tokenInfo, ref int state)
            {
                int length = source.Length;
                if (curPos < length)
                {
                    // find 'hello'
                    int index = source.IndexOf("hello", curPos, length - curPos, StringComparison.CurrentCultureIgnoreCase);
                    if (index != -1)
                    {
                        // color all instances of 'hello' as keyword
                        tokenInfo.Color = TokenColor.Keyword;
                        tokenInfo.Type = TokenType.Keyword;
                        tokenInfo.StartIndex = index;
                        tokenInfo.EndIndex = index + 4;
                        curPos = index + 5;
                    }
                    else
                    {
                        // otherwise color as text
                        tokenInfo.Color = TokenColor.Text;
                        tokenInfo.Type = TokenType.Text;
                        tokenInfo.StartIndex = curPos;
                        tokenInfo.EndIndex = length;
                        curPos = length;
                    }
                    // scan source for additional tokens
                    return true;
                }
                // no more tokens in current source
                return false;
            }
     
            public void SetSource(string source, int offset)
            {
                this.source = source;
                curPos = offset;
            }
     
            #endregion
        }
    }

    Sincerely,


    Ed Dore
    Monday, May 16, 2011 7:32 PM