Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[ease-dev] Autocompletion feature sum-up

Hi,

since the Google Summer of Code program ends next Friday I decided to freeze the features for auto-completion and use the rest of the time to fix last issues and clean up the code.
This mail should give you a quick overview on what the actual auto-completion features are and what might be some open topics.

General (why I believe my implementation is a good thing):
  • EASE now uses a generic interface for completion providers:
    • The class CompletionProviderDispatcher handles all registered providers and dispatches the code for completion calculation.
    • The CompletionProviderDispatcher is used for both the script shell and the _javascript_ editor (other editors possible but not implemented).
    • Different CompletionProviders can be registered using the completionProcessor extension point.
    • CompletionProviders can be generic or language specific. Language specific providers must set the language in the extension.
    • Each scripting language that wants to have auto-completion must implement the ICompletionAnalyzer interface. This interface is used to parse code to a more easily usable format. 
  • New completion providers can be added very fast
    • CompletionProviders must implement the ICompletionProvider interface and set up the completionProcessor extension.
    • Everything else is handled by the CompletionProviderDispatcher
  • Completion providers can be reused
    • for different languages (e.g.: available modules completion provider)
    • for both script shell and the editor
  • Completion for new languages can be implemented fast
    • Language must implement ICompletionAnalyzer interface and set extension (script shell only)
  • Code can be used to detect type of object
    • Necessary for completion calculation
    • Helpful for other utility functionality (e.g. hover tool-tips)


To help everyone understand what is actually happening I will quickly try to outline the flow for completion calculation.

Flow ScriptShell:

  • The ScriptShell instantiates the CompletionProviderDispatcher when it starts up (this includes keybindings, etc.)
  • The ScriptShell sets the completion providers matching the currently selected scripting language.
    • The ScriptShell sets the ICompletionAnalyzer for the currently selected engine.
    • The ScriptShell uses the getProviders utility method to query for matching providers.
    • The ScriptShell sets the script engine for all providers.
    • The providers, engine and analyzer are reset when the script engine changes.
  • Each line entered in the ScriptShell will be passed to all registered CompletionProviders.
    • If a completion provider parses information this information must be stored for later use.
    • Completion providers may choose to ignore all given code (e.g.: Keyword completion provider needs no information about code).
  • Once the user presses the completion keybinding (default: CTRL+SPACE) the CompletionProviderDispatcher is started.
  • The given line will be analyzed using the ICompletionAnalyzer interface.
    • All unnecessary code is removed.
    • The necessary code will be split into a call chain and a filter.
    • A first basic ICompletionContext will be created.
  • The created context will be refined using all registered completion providers.
    • Context needs refinement if call chain is not empty.
    • Only information about first item in call chain necessary (rest are simple class look-ups).
    • Refined context also stores information about type of element in call chain (e.g. module method, local variable, ...).
  • The refined context is used to calculate the actual proposals.
    • All registered completion providers use refined context to calculate matches.
    • Since script engine is available completion providers might choose to not calculate proposals (available anyways).
    • The matches are calculated based on the filter and call-chain of the given context.
  • The calculated proposals are transformed to the correct type.
    • Since not all completion mechanisms need the same type of proposals a generic intermediate list is calculated.
    • This list is then used to calculate the proposals with the corresponding message for the ScriptShell.
  • The calculated proposals are displayed using Vidura's updated ContentProposalModifier.


The flow for the _javascript_ editor looks very similar:

  • The _javascript_ completion provider is instantiated the first time the user presses the completion keybinding (default: CTRL+SPACE)
    • Note that this completion provider is of the type IJavaCompletionProposalComputer so it can be used with the existing mechanisms
  • Internally the provider creates a CompletionProviderDispatcher and sets the _javascript_CompletionAnalyzer as well as all matching EASE completion providers.
  • The _javascript_ completion interface receives an IDocument that will be parsed.
    • First the actual content of the document is read.
    • Then the completion analyzer creates a string with the document's content as well as the included files.
      • Instead of each include the content of the included file will be put into the contents string.
      • This will be called until no more includes available.
      • Circular imports are detected and ignored.
        • The first time a file gets included it will be marked as loaded.
        • If at a later point the same file is included again the include statement will be discarded.
  • The created code will be given to all completion providers (see Script-Shell flow)
  • The code will then be analyzed and the proposals calculated.
    • Same flow as in Script-Shell.
    • This time the other way around, no script engine available so some providers might not calculate proposals while others do now.
  • The calculated proposals are again parsed to correct format for _javascript_ editor.
  • The proposals are displayed using the _javascript_ editor's internal mechanism.


I implemented some ICompletionProviders to have the most important proposals available. The following list will give an overview on what providers are currently implemented:

  • LoadedModuleCompletionProvider
    • Detects when a module has been loaded.
    • Offers information about methods and fields of said module.
    • Used for both script shell and editor as well as for all languages.
  • AvailableModuleCompletionProvider
    • Holds list of all available modules (not just loaded)
    • Otherwise same as LoadedModuleCompletionProvider.
  • ScriptShellCompletionProvider
    • Simple completion provider to query given script engine (if available)
    • Can be used for local variables, etc.
    • Used for all languages but only when script engine available -> ScriptShell only.
  • SourceStackCompletionProvider
    • Used for non-empty call chain.
    • Simply follows call chain and calculates all matches based on class of last element and filter.
    • Needs a refined context to work.
    • Used for all languages and both script shell and editor.
  • KeywordCompletionProvider
    • Simple completion provider holding a list of keywords for selected language.
    • Used for all languages (with different list of keywords) and both script shell and editor.
  • CustomAnnotationCompletionProvider
    • Used in script only.
    • Offers custom annotation to declare type of object.
    • Syntax: @type varName varClass
    • Will be explained in detail once it is upstream


There are still some open points that do not have the highest priority and will (probably) not be implemented as part of the GSOC program:

  • All code is single-threaded:
    • Calculations might take too long and UI responsiveness could decrease.
    • All registered completion providers called sequentially, would be faster if called in parallel.
    • At the moment not a problem but might be once more providers are registered.
  • No caching mechanism:
    • Code might be unchanged but will still be parsed.
    • Especially bad for editors because lots of code might need to be parsed.
  • No mechanism to detect duplicates:
    • The same suggestion might be proposed several times (e.g. from loaded module and from available module)
  • No scalable recursion mechanism for e.g. included files:
    • Each language can define the getIncludedCode method in the ICompletionAnalyzer method.
    • Not possible to dynamically add completion providers that also add code during proposal calculation.


I know the e-mail is quite overwhelming but that's probably a good thing because you have lots of cool new features available in EASE ;-)

Best regards,
Martin


Back to the top