| Hi Chrisitian and everyone, 
 I am currently trying to wrap my head around the refactoring you
    suggested. Although it seemed straight forward at first, the more I
    think about it the more problems arise.
 
 First off, there are 2 different types of information I can gather.
    There is static information where I don't need to know anything
    about loaded modules, local object, etc. Then there is dynamic
    information that needs said knowledge. With static information I can
    only distinguish between an instance , a constructor and a call (and
    string literals). The following table will hopefully explain what I
    mean with instance.
 
 Constructor:
 
 
      Call:Java class constructorConstructor for class from methodConstructor for local class
 
 
      Instance:Local functionClass methodModule method 
      So if I use static analysis on something like:Local objectClass fieldModule fieldClassPackage "foo.replace("\r", "").subString(10).toLow"
 I can tell that "foo" is an instance of some sort and "replace" as
    well as "subString" are calls.
 
 With dynamic analysis it looks a lot better:
 "foo" is an object of type "String" and "replace" as well as
    "subString" are class methods of String.
 
 It is no problem to use dynamic analysis with the script shell
    because I already have all the information there. If I want to reuse
    this for editor autocompletion though I do not have this information
    in the same form.
 
 What I am currently doing is first gather the static information and
    then refine it with the information from the shell. In the end I
    only need the dynamic information about the first item in the chain.
    I want to implement it in a way, that multiple context providers can
    register and are called in order until one of them manages to match
    the item. So for example we have a ModuleContextProvider that can be
    used for loaded (and possibly not loaded) modules, another for local
    variables, and so on. The dynamic analysis will call all of these
    providers in order until it finds a match for "foo".
 
 With this solution it would be possible to reuse most of the code
    and just add different context providers for the editor. It might
    also be possible to also reuse some of the context providers. E.G.:
    If we have a provider for all (unloaded) modules this can be reused
    directly.
 
 Do you understand what I want to do here and if so, do you think
    this would be a good idea?
 
 
 
 Next difficulty:
 You want to get the relevant context for the completion providers.
    This is not a real problem but my current solution can become
    difficult to use.
 
 As I mentioned in previous mails I split the information in a call
    chain and discard everything that is not relevant to the current
    chain. I can also gather information that is not relevant to the
    current chain itself but gives context. I hope some examples will
    help me explain.
 
 foo = "IO 1234";
 include("System." + foo.toLower().subS
 
 In this case the call chain would be [Local object String foo ->
    Java method String.toLower] and the filter would be "subS". I do not
    care about the "System." and for the chain the previous "include" is
    also not of interest. If I gather context information though, I
    would also save [Module method include]. This is very simple and no
    problem to do.
 
 
 My first problem can be seen if we do something like this:
 
 include( new String("system." + foo.toLower().subS
 
 Here the call chain is the same but the context becomes more
    complicated. So the call chain is in the context of [Java
    constructor String] but the String constructor is in the context of
    [Module method include]. For the whole line the context would be
    [Module method include, Java constructor String]. Still not a
    problem to parse, but now we have a lot more context information we
    need to care about.
 
 
 The last problem with this is that the context can also contain a
    call chain.
 include( new StringBuilder().append( foo.toLower().subS
 
 Now the context for the StringBuilder would be [Java constructor
    StringBuilder, Java method StringBuilder.append] and the whole
    context would be [Module method include, [Java constructor
    StringBuilder, Java method StringBuilder.append]].
 
 My current implementation returns a list of call chains for the
    context and this is working fine. I am not sure though this is
    really easy to use for completion providers...
 The current solution is the only one I could come up with that takes
    care of all the mentioned situations. Maybe it's a bit of an
    overkill but if we really want a generic solution I don't see how we
    could do it any other way. Do you have any suggestions?
 
 
 
 Last issue:
 We are currently using
    "org.eclipse.jface.fieldassist.ContentProposalAdapter" to display
    the completion proposals. This adapter class takes care of getting
    the completion proposals and displaying the corresponding popups. If
    we want to use our ICompletionProvider interface with a custom
    getProposals method that takes the gathered context information as a
    parameter, we can't do it directly. If we want to diplay a custom
    pop-up I am not sure we can either.
 
 The problem is that it is not really possible to subclass the
    ContentProposalAdapter and just override the getProposals method
    (and maybe the pop-up) because the methods are private.
 
 The class gets an
    "org.eclipse.jface.fieldassist.IContentProposalProvider" that our
    ICompletionProvider implements but the called interface method is
    defined as "getProposals(String contents, int position)". It would
    be no problem to just stick to the original eclipse interface and
    every ICompletionProvider would have to take care to get the context
    information on its own.
 
 Another solution would be to write a CompeltionProvider class where
    ICompletionProvider objects could register. The created
    CompletionProvider would conform to the eclipse interface and simply
    call our getProposals method with the calculated context
    information. The benefit would be that we could have several
    ICompletionProvider objects registered at once. If we ever come up
    with a new idea for a completion provider we would not have to
    modify the existing code but rather just create a new class and
    register it.
 
 Theoretically the best solution would be to modify the original
    ContentProposalAdapter to allow subclassing and call our own
    ICompletionProviders from that subclass. The problem is that this is
    out of the scope of EASE (I guess).
 
 How should I proceed? Should I create the actual mentioned class and
    wrap the methods accordingly or should every ICompletionProvider get
    the information in the desired form itself.
 
 
 
 I know this was quite a lot, but if we really want a generic well
    thought-through and well working solution these are the things (from
    my perspective) that we need to take care of.
 
 Best regards,
 Martin
 
 
 
 
 Am 2015-07-07 um 16:41 schrieb
      Christian Pontesegger:
 Hi
      Martin,
      
 now that mid term evaluations are passed and you have your first
      deliverable done I would like to do some refactorings on the
      completion code:
 
 I want these proposals to be generic and extensible. Therefore we
      already have an extension point 'completionProcessor' and an
      interface 'ICompletionProvider'.
 In its current form it is very simple and leaves the task to
      decode content information to each completion provider.
 
 The refactoring should provide a helper method capable of parsing
      and understanding the source code left of the cursor position. A
      created context information then could be passed to
      ICompletionProviders. As script code always depends on the script
      language a good place for those helper method(s) would be the
      ModuleWrappers that exist for each script language.
 
 Information that should be gathered:
 content proposal source type (enum): eg when we need proposals for
      a java class then we would need an indicator for this
 content proposal source: the java class to use
 filter: parts of the text that is to be completed.
 context: relevant code left from the cursor
 
 Example:
 Packages.java.io.
 -> source type: java package
 -> source: "java.io"
 -> filter: null/empty
 
 Packages.java.io.Fi
 -> source type: java package
 -> source: "java.io"
 -> filter: "Fi"
 
 include("file://
 -> source type: module function
 -> source: Module Definition instance
 -> filter: "file://"
 
 Together with the context this will allow to create content
      proposals for
 * Java classes
 * java instances
 * methods exported from modules
 * string literals (eg for includes, loadModule, ...)
 
 Getting the relevant context from the cursor position will also
      help Vidura to provide relevant help information. The information
      to be gathered might need some extensions. Please discuss this
      together with Vidura as you both should use the same helper
      methods for this task.
 
 
 
 |