0

I have found two ways of proffering a language service on the internet.

The first way involves using a IOleComponentManager and registering a timer to call my service during idle times.

The second way involves casing my service as an IServiceContainer and adding a ServiceCreatorCallback to "proffer the service on demand".

Supposedly the second way is now the "preferred way" of doing things. Unfortunately, when I use this method, OnSynchronizeDropdowns never gets called on my TypeAndMembersDropdownBars implementation.

In addition, when my LanguageService finds errors in the file, it uses ParseRequest.Sink.AddError() to add errors to the error list. When proffering "On Demand", these errors don't show up in the GUI, even though I see them being added when I debug through the code.

I know that my language service is being registered, because syntax highlighting, "Go to Defintion", and "Find All References" still work.

Here is the code I'm using to "proffer my service on demand":

IServiceContainer serviceContainer = this as IServiceContainer;
ServiceCreatorCallback callback = new ServiceCreatorCallback(CreateLanguageService);
serviceContainer.AddService(typeof(MyLanguageService), callback, true);

Can anyone tell me why some functionality of my LanguageService does not work when proffering it on demand? Am I missing something, or is that way just not meant for a fully functional language service?

Jon Senchyna
  • 7,867
  • 2
  • 26
  • 46
  • What is the question? –  Feb 27 '14 at 10:11
  • @Amy The question is about how to proffer a custom language service the right way, so that Visual Studio interacts with it as expected... the problem is, that there are various ways to do the language service registration, but not all ways of doing it lead to the correct behavior. – Matze Feb 27 '14 at 10:56
  • @Amy I updated my question with a clear summary of what I'm asking. – Jon Senchyna Feb 27 '14 at 12:18
  • Can someone tell me what is wrong with my question? – Jon Senchyna Mar 04 '14 at 16:56

1 Answers1

1

It looks like at least the missing functionality requires using the IOleComponentManager method that registers a timer to call the language service during idle periods.

Using dotPeek, I found that OnSynchronizeDropdowns() gets called from OnCaretMoved() for synchronizing the selected item when you click around in the editor. OnCaretMoved() itself appears to only be called from the LanguageService.OnIdle() method, which I believe requires the use of the idle timer.

After digging some more, I also found that the error list requires that the ParseRequest.Reason be set to ParseReason.Check, otherwise it ignores the call. Digging through the code some more, the only place I found that parse reason being used was in Source.OnIdle().

Update: I believe I have confirmed that registering an idle timer is required for these two pieces of functionality. From MSDN on LanguageService.OnIdle:

Note This method is not called unless you set up your own timer and call this method from the timer handler.

The base method calls OnCaretMoved if the caret has moved since last time OnIdle was called. The base method then calls the OnIdle method on the Source object for the current view. If the current Source object cannot be obtained, the base method does nothing at all, including not calling OnCaretMoved.

Community
  • 1
  • 1
Jon Senchyna
  • 7,867
  • 2
  • 26
  • 46
  • For an MPF language service, this is correct. Proffering the language service instance is a separate operation from performing background updates within that instance. My [LangSvcV2](https://github.com/tunnelvisionlabs/LangSvcV2/) project does not base its language services on MPF. In that code, an [event listener is added to `ITextCaret.PositionChanged`](https://github.com/tunnelvisionlabs/LangSvcV2/blob/master/Tvl.VisualStudio.Text.Implementation/Navigation/EditorNavigationDropdownBar.cs#L114) in order to synchronize the drop downs. – Sam Harwell Oct 28 '14 at 10:39
  • Note that the latter strategy will also be used in the [VSBase service implementation](https://github.com/tunnelvisionlabs/vsbase/issues/9) of this feature, since it requires fewer steps for the user to remember. – Sam Harwell Oct 28 '14 at 10:41
  • "The latter strategy" being the event listener mentioned in your comment, the second method mentioned in my question, or a combination of both (my current assumption)? (I'd take a look at your GitHub repository to see for myself, but I don't have the time at the moment.) – Jon Senchyna Oct 28 '14 at 11:46
  • The LangSvcV2 project is not structured in a way that works with other language implementations. The VSBase project will initially use an implementation of this feature similar to the one in LangSvcV2, but it will be refactored into new assemblies in a way that allows it to be reliably used by a variety of other extensions. – Sam Harwell Oct 28 '14 at 11:51