Hello Racketeers,

A while ago I announced my MessagePack library here and I mentioned that
I was needing it for a client library for the Neovim text editor. Since
then I have been writing this client library and now I'm at a point
where I need help.

Let me first give you some context: Neovim is a fork of Vim which allows
people to write remote plugins in any language. Remote plugins are run
by a separate process which is a client to the Neovim server. Basically
this means I can write Neovim plugin in Racket (given a Racket host) and
call functions written in Racket from Neovim and use them in Neovim
plugins.

For this to work the functions defined in Racket need to tell Neovim
about themselves, they need to register their specifications. Here is
how the process works: Neovim first searches for paths to remote
plugins, in this case the pattern is "rplugin/racket/*" where "rplugin"
is a directory of a Neovim plugin. This means there are many such paths
that all end in "/rplugin/racket/*". Neovim then passes the list of all
these paths on to the Racket client.

The client then has to load or require all these plugins so that they
can register their specifications. I'll try to capture the sequence of
events in a list:

1) Neovim launches
2) It collects a list of all Racket remote plugins, where a remote
   plugin is either a file ending in ".rkt" or a directory
3) Neovim launches a Racket instance as the client
4) Neovim sends a request to Racket with a list of all the plugin paths
5) Racket has to set up the specifications
6) After Racket responds back Neovim asks for the specifications
7) Racket sends back a hash table containing the specifications

Step 5 is the one that is giving me trouble. Here is how the Racket
client is launched:

  racket -eee '(require (file "autoload/host/bootstrap.rkt"))' \
              '(require neovim)' \
              '(start-host)'

The first instructions requires a bootstrapping module which will get
the host ready to receive the requests in step 4 - 7. It works, I have
tested it. In the bootstrapping module I also want to process the
plugins. A remote plugin has to be required so that its side effects are
performed. A declaration in a remote plugin could look something like
this:

  (require neovim/rpc)

  (define (two) 2)
  (register-function! two #:name "Two" #:sync #t)

Ideally both would be wrapped up in a macro, this is just an idea. The
point is that the Racket function foo is not supposed to leave the
module, but the side effect of registering it in a global table must
happen.

Here is an idea of what a plugin registration function could look like:

  (define (load-plugins paths)
    ;; Process one plugin at a time
    (define (load-plugin path)
      ;; Add the path (or its stem) to the search paths
      ;; Require the plugin (the plugin should register itself)
      )
    (vector-map load-plugin paths)
    "Loaded plugins")

The sequence of paths was received from Nvim as a vector, and I map over
every path, requiring the module/collection. The problem is that I
cannot use (require (file path)) because the require is not a top- or
module level. The question is: what can I do instead? I would like all
the side effects that usually go with "require", but since the
registration happens via RPC request it cannot be at module level. I can
also pass arbitrary arguments to the racket binary, so I don't need to
do all the work in Racket.

I hope this explanation makes it clear what I'm trying to achieve. Of
course if there is a better way of adding a bunch of collections and
modules I am open to that as well.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to