Skip to content

decoders for geiser-con--tq-filter?

I'm trying to add a script-fu (by GIMP) implementation for Geiser.

Due to the nature of script-fu and my inability, I am facing some problems that I need help with.

About script-fu:

  1. GIMP's scheme server uses a specific protocol that requires messages to be encoded and decoded
  2. It is served over a port. There is no command-line REPL for it

Features I got working:

  • I can (geiser-connect 'gimp-fu "localhost" 10008) to get an interactive buffer.
  • I have evaluations, completions and autodocs working

Problem 1. geiser-con--tq-filter

The incoming messages need to be decoded.

(define-minor-mode gimp-fu-mode
 "This mode *only* exists to toggle the behaviour of the geiser-con--tq-filter")

(provide 'gimp-fu)

;; ...

(defun gimp-fu.geiser::tq-filter (orig-fun tq str)
 (if gimp-fu-mode
     (let ((decoded (gimp-fu::decode str)))
       ;; incomplete messages are accumulated inside the tq buffer until they are ready
       (when (complete?)
	 (funcall orig-fun tq decoded)))
  (funcall orig-fun tq str)))

;; ...
;; ...

(add-function :around (symbol-function#'geiser-con--tq-filter)
   #'gimp-fu.geiser::tq-filter)

Because geiser just overwrites the process filter repeatedly, this is the best way I found to decode the incoming payload.

I find this approach to be highly unpleasant.

I think geiser should allow me to pass in message decoders, and let me pass in a lambda to check if the response in tq-buffer is ready. The regexp is not sufficient.

Problem 2. M-x geiser vs M-x geiser-connect

It seems like M-x geiser is the default way to start geiser. the -run commands, the scheme switchers all prefer it by default and I couldn't override that behaviour.

(progn
 (define-geiser-implementation
  gimp-fu
  (binary (lambda () "sh"))
  (arglist (lambda ()
            (let* ((xs '("echo cannot start gimp-fu this way"
                         "echo"
                         "echo use:"
                         "echo ' `M-x geiser-connect`"
                         "echo"
                         "echo bye."
                         "false"))
                   (code (string-join xs "; ")))
             (list "-c" code))))
  (prompt-regexp ""))
 
 (add-function :override (symbol-function 'geiser-gimp-fu)
  #'gimp-fu.geiser:run))

Is there some way I can make it so M-x geiser or other ways of starting geiser within a file buffer or a REPL buffer use the hostname & port number for connection?

Problem 3. "" prompt and assuming "\n"

script-fu doesn't have a prompt. Its :eot is where the message headers say it is. They are also don't end in newlines. These don't stop my code from working but I'm having to add linebreaks in my decoder for geiser's tq-filter regexp to be happy.

geiser likes to add a \n to messages it is sending. I am offsetting my headers to leave room for geiser's additional linebreaks but it'd be nice to be able to control that behaviour.

Problem 4. cannot (quit)

(defun gimp-fu.geiser::exit-cmd ()
 "(geiser.quit)")
(define-geiser-implementation
  gimp-fu
  ;; ...
  (exit-command gimp-fu.geiser:exit-cmd))

There isn't a way to ask the server to terminate the connection. script-fu's (quit) won't end the connection but the current evaluation only.

I implemented a procedure on the scheme side to display user some info about why they cannot quit. I can map C-c C-q to a new interactive command but I'm not sure if that's the best way




Would you be able to advise me on what the better solutions could be?

Would you be open for me to submit a patch to introduce a variable/methods to control encoding/decoding and the response-completeness check?

I would eventually like to be able to share my work so I appreciate your help in getting there.