Intellisense question

SyntaxEditor for WPF Forum

Posted 10 years ago by John Dunn
Version: 9.1.0507
Avatar
I'm not sure I'm implementing my Intellisense correctly. My scripting language is lua, and say I have 3 global tables - 'math', 'string' and 'table'. If the user starts typing in empty space, I want to display an Intellisense popup with those 3 options. Once they type a complete global name with a '.', I want to switch to Intellisense specific to that table.

My current solution is to create 4 CompletionSessions, one for the global completion and one for each table. In the DocumentTextChanged event, if the TypedText is '.', I read back and see if it matches one of my specific tables, and if so Open the corresponding session. If a . wasn't typed and IsTypedWordStart is true, I display the global session.

It appears to work, but one thing I'm not happy about is that I need to check to see if any of the other sessions are open before opening the gobal. Is there a better way to solve this problem?

Here's the code for the DocumentTextChangedEvent

switch (e.TypedText)
{
  case ".":
    {
      ITextSnapshotReader reader = _Editor.ActiveView.GetReader();
      reader.ReadCharacterReverseThrough('.');
      IToken token = reader.ReadTokenReverse();
      if (token != null)
      {
        switch (reader.TokenText)
        {
          case "math":
            _MathSession.Open(_Editor.ActiveView);
            break;
          case "string":
            _StringSession.Open(_Editor.ActiveView);
            break;
          case "table":
            _TableSession.Open(_Editor.ActiveView);
            break;
        }
      }
      return;
    }
}
if (e.IsTypedWordStart)
{
  if (!_MathSession.IsOpen&& !_StringSession.IsOpen && !_TableSession.IsOpen)
  {
    _GlobalSession.Open(_Editor.ActiveView);
    return;
  }
}

Comments (4)

Posted 10 years ago by John Dunn
Avatar
There's definitely something wrong with my approach ( or there's a bug in the Editor, but I'm guessing it's more likely my issue ).

With the above code, If I hit a key to bring up the list, then hit backspace, and then another key, an exception is thrown with the following call stack
Uncaught Exception : Exception has been thrown by the target of an invocation.
   at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.Windows.RoutedEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
   at ActiproSoftware.Windows.Controls.SyntaxEditor.SyntaxEditor.a(Object A_0, TextSnapshotChangedEventArgs A_1)
   at ActiproSoftware.Text.Implementation.TextDocumentBase.OnTextChanged(TextSnapshotChangedEventArgs e)
   at ActiproSoftware.Text.Implementation.CodeDocument.OnTextChanged(TextSnapshotChangedEventArgs e)
   at ActiproSoftware.Text.Implementation.TextDocumentBase.a(dx A_0)
   at dx.i()
   at ActiproSoftware.Windows.Controls.SyntaxEditor.Primitives.EditorView.a(ITextChangeType A_0, String A_1, IEditorViewTextChangeOptions A_2)
   at ActiproSoftware.Windows.Controls.SyntaxEditor.Primitives.EditorView.ReplaceSelectedText(ITextChangeType type, String text, IEditorViewTextChangeOptions options)
   at ActiproSoftware.Windows.Controls.SyntaxEditor.EditActions.TypingAction.Execute(IEditorView view)
   at ActiproSoftware.Windows.Controls.SyntaxEditor.Primitives.EditorView.ExecuteEditAction(IEditAction action)
   at ActiproSoftware.Windows.Controls.SyntaxEditor.Primitives.EditorView.a(TextCompositionEventArgs A_0)
   at ActiproSoftware.Windows.Controls.SyntaxEditor.Primitives.EditorView.OnTextInput(TextCompositionEventArgs e)
   at System.Windows.UIElement.OnTextInputThunk(Object sender, TextCompositionEventArgs e)
   at System.Windows.Input.TextCompositionEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.TextCompositionManager.UnsafeCompleteComposition(TextComposition composition)
   at System.Windows.Input.TextCompositionManager.PostProcessInput(Object sender, ProcessInputEventArgs e)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.TextCompositionManager.UnsafeStartComposition(TextComposition composition)
   at System.Windows.Input.TextCompositionManager.PostProcessInput(Object sender, ProcessInputEventArgs e)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndKeyboardInputProvider.ProcessTextInputAction(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at System.Windows.Interop.HwndSource.OnPreprocessMessage(Object param)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi John,

Actually you can use the indexer on editor.IntelliPrompt to see if any IntelliPromptSessionTypes.Completion are already open. That would be easier for checking and the would give you the open instance so you could closed it.

For the exception, please make a simple sample project that shows the issue and email it over and we'll see if we can figure out what is causing it by debugging it. Thanks.


Actipro Software Support

Posted 10 years ago by John Dunn
Avatar
Thanks. I'll email a zip which shows the issue. It appears to be related to not checking if any CompletionSessions are currently open before opening another. Once I implemented the check using your suggested technique the problem went away.

One more question - in the sample code there is a comment that it'd be better to use IToken.Id instead of a string match. Looking at the Lua language in the Language Designer, it appears as though I could set a TokenId for a Classification ( like a LuaFunction ), but not for each LuaFunction. So I could check to see if the token is a LuaFunction, but would still have to compare the string to see if it matches - is this correct?
Posted 10 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi John,

As a side note you should never reference ActiproSoftware.Text.LanguageGeneration.Wpf30.dll. That is just for the Language Designer. I saw you had that ref in your project.

Back to this exception, if you look at the inner exception, you'll see this:
  InnerException: System.InvalidOperationException
       Message="The session is already open."
       Source="ActiproSoftware.SyntaxEditor.Wpf30"
       StackTrace:
            at ActiproSoftware.Windows.Controls.SyntaxEditor.IntelliPrompt.Implementation.IntelliPromptSessionBase.Open(IEditorView view, TextRange textRange) in S:\Code\ActiproSoftware\WPFStudio.v92\Source\SyntaxEditor\Windows.Controls.SyntaxEditor\IntelliPrompt\Implementation\IntelliPromptSessionBase.cs:line 250
            at ActiproSoftware.Windows.Controls.SyntaxEditor.IntelliPrompt.Implementation.CompletionSession.Open(IEditorView view) in S:\Code\ActiproSoftware\WPFStudio.v92\Source\SyntaxEditor\Windows.Controls.SyntaxEditor\IntelliPrompt\Implementation\CompletionSession.cs:line 965
            at EditorCrash.Window1._Editor_DocumentTextChanged(Object sender, EditorSnapshotChangedEventArgs e) in S:\Code\Test\Dunn\EditorCrash\Window1.xaml.cs:line 74
So that is telling you that you must close a session before trying to open it again. In this case your _GlobalSession session is already open from the first time you typed G so you must close it before you can open it again.

As for the tokens, it's always faster to do an integer comparison vs. a string one. And when you are doing reader.TokenText you also incur extra overhead of building a string from the core text storage mechanism. Really it may not make a noticable difference for your application but if you want to maximize performance you should have a lexer that tokenizes the text and assigns a unique ID value to each token type.

Hope that helps.


Actipro Software Support

The latest build of this product (v2019.1 build 0683) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.