graphql-mode icon indicating copy to clipboard operation
graphql-mode copied to clipboard

Support field autocompletion by GraphQL introspection

Open davazp opened this issue 9 years ago • 21 comments

Using GraphQL introspection we can get the fields, what could be used to autocomplete the fields at point.

davazp avatar Oct 15 '16 12:10 davazp

Hey David, Which completion package (auto-complete, company, or any) are you going to use? Thanks for your time

timoweave avatar Sep 12 '17 05:09 timoweave

Hopefully any. I would do a basic integration with the built-in mechanism of Emacs, so hopefully all the fancy packages can work on top of it.

davazp avatar Sep 12 '17 08:09 davazp

I am new to completion (ac, company, helm, ...). Is any the same thing as helm (anything.el) that you are referring?

timoweave avatar Sep 12 '17 16:09 timoweave

I'm not fully familiar with completion either, but this link

https://www.gnu.org/software/emacs/manual/html_node/elisp/Completion-in-Buffers.html

this the relevant standard way to implement completion in-buffers in Emacs.

The packages you mention ac,company,helm are able to read this normally, so every standard completion in emacs work for them. Although they then extend that with more custom functionality.

I would like to support first the standard emacs functionality I mentioned, and then optionally and if it is worthy, we can support other extensions.

davazp avatar Sep 12 '17 20:09 davazp

I am not familiar with completion either. Are we referring

  1. keywords only completion (static) or
  2. user field and user type, query, mutation, fragment, variables (dynamic),

timoweave avatar Sep 12 '17 22:09 timoweave

I was thinking mostly about fields, specially useful for queries.

But the more the better. We have to start somewhere.

davazp avatar Sep 12 '17 22:09 davazp

Yeah, you are right: start with the first standard and then extend later on. I need to read/experiment a bit more about completion to get some idea how to develop this feature.

timoweave avatar Sep 13 '17 00:09 timoweave

would these introspection good enough for fields?

query get_schema_info {
  __schema {
    types {
      name
      fields {
        name
        type {
          name
          kind
          ofType {name}
        }
      }
    }
  }
}

timoweave avatar Sep 28 '17 06:09 timoweave

I am not sure right now.

I looks like it. I guess it's a bit trickier to "parse" the query, so we have a path field1 > field2 > ... and we can infer the type at that point. But it should work :-)

davazp avatar Sep 28 '17 07:09 davazp

Yeah, we need a proper parser.

  1. that parser can parse the query file, the __schema type buffer (from server),
    which we resolve the type back into graphql file.
  2. then we use graphql schema language as intermedia language as well, and we
    can treat query or type buffer the same to create lookup table.
  3. so that and turn that whatever syntax tree into child-type field lookup table with
    the parent-type field.
  4. also take care of the sytnax. for example if one split "query hello {...}" into "query\n hello\n {...}"
    the "query", "hello" would pick up the syntax color as in one-liner.

Do you have any recommendation about how to approach the parser?

  1. c/c++ lex/yacc parser/codgen that bind it to elisp?
  2. all elisp parser/codegen, similar to js2-mode?

timoweave avatar Sep 28 '17 14:09 timoweave

I don't think we actually need a full parser. It's quite easy to go upward in the elisp parser state levels . ({}). For example

query {
  alias: field1 () {
     alias2: field2 () {
         |
     }
  }
}

going upward in the sexprs would take us to the parent fields, so we only need to find the field name (not alias), by skipping over the parenthesis and reading a word.

However, having a full parser would be probably great for other functionality. If you want, we can go in that direction. We can write our own parser, using any of the well known techniques, or we can try to translate the official parser from js to elisp more literally.

davazp avatar Sep 29 '17 07:09 davazp

  1. first dynamic and context sensitive completion with query.
screen shot 2017-10-02 at 12 59 18 am

timoweave avatar Oct 02 '17 07:10 timoweave

Looks awesome. Is it using introspection then?

davazp avatar Oct 02 '17 19:10 davazp

Yeah, the completion use introspection, whatever the __schema response from the server. Right now, I just save the __schema response to a file, hook up the algorithm, and get draft going. That __Schema is not very useful. Instead, I extend root ("") that make it easier to lookup scope.

Here is the 2nd draft, a separated package company-graphql.el.

out2

timoweave avatar Oct 03 '17 03:10 timoweave

I wrote few parsers in the past. It is not hard in C/C++, or python, but I am not sure in elisp.... but elisp is an excellent language to handle recursive parser itself without grammar... For now, I will put this parser idea on the side... and get other stuff going.

timoweave avatar Oct 03 '17 03:10 timoweave

I will try if I have some time.

davazp avatar Oct 03 '17 13:10 davazp

This looks awesome. Would love an update on where this stands.

danrasmuson avatar Jan 15 '18 07:01 danrasmuson

@timoweave do you have any update of this? or can you share a branch with your changes? perhaps we can merge a initial version and leave the proper parsing for later. 👍

davazp avatar Jan 15 '18 08:01 davazp

Yeah, David!

We have new participant!

It will be really fully functional like graphiql-mode using language server, for completion, indentation, and color (the last two was not part of the Microsoft language server spec)

Interested in working on it together? I’ve also like good peer like David, good cider, to keep my motivation going.

timoweave avatar Jan 15 '18 13:01 timoweave

Hi, folks! Any update on this? I've tried company-graphql but it's not on MELPA, @timoweave.

viniciussbs avatar Apr 14 '18 20:04 viniciussbs

With graphql-language-service and lsp-mode, you can get auto-completion with this snippet:

(lsp-register-client
 (make-lsp-client :new-connection (lsp-tcp-connection (lambda (port) `("graphql" "server" "-m" "socket" "-p" ,(number-to-string port))))
                  :major-modes '(graphql-mode)
                  :initialization-options (lambda () `())
                  :server-id 'graphql))
(add-to-list 'lsp-language-id-configuration '(graphql-mode . "graphql"))

I'll look in to getting this upstreamed into lsp-mode.

TOTBWF avatar Oct 16 '19 20:10 TOTBWF