fsharp / emacs-fsharp-mode

F# Emacs mode
Apache License 2.0
205 stars 62 forks source link

Trying to include nuget reference breaks inferior buffer #293

Closed elken closed 2 years ago

elken commented 2 years ago

Description

Upon trying to call the #r extension against any nuget package, the entire inferior buffer breaks. I can still navigate around and input characters, so there's no blocking process; however I am unable to interact with the REPL process and all I can really do is kill and reopen the buffer

Repro steps

Please provide the steps required to reproduce the problem

  1. Create an inferior fsharp buffer (run-fsharp)

  2. Run the following snippet

#r "nuget: Newtonsoft.Json";;
open Newtonsoft.Json;;

let o = {| X = 2; Y = "Hello" |};;

printfn "%s" (JsonConvert.SerializeObject o);;

Even just the following breaks:

#r "nuget: Newtonsoft.Json";;

Expected behavior

Output similar to the below screenshot

image

Actual behavior

The buffer no longer becomes interactable.

Known workarounds

None currently, I'm stumped.

Related information

joanimato commented 2 years ago

I'm running into this issue as well. I've tried it on two different macs, and strangely it works on one but not the other. Not sure why. Same versions of dotnet and emacs on both machines.

I wonder if there's something else in my emacs config that breaks it...

elken commented 2 years ago

Good to see I'm not alone!

Did you get anywhere debugging it? @joanimato

juergenhoetzel commented 2 years ago

I have added FSI tests for this fsx file. All tests (also macos) pass: https://github.com/fsharp/emacs-fsharp-mode/pull/309

Would you mind to test it locally:

eldev -d test -f test/fsi-tests.el

Do you load the whole file via C-c C-f (like the test case?)

elken commented 2 years ago

I ran it through run-fsharp in the inferior buffer, just tried on my linux machine (apparently I forgot to also check that...) and it actually works...

I'll re-run on the macbook shortly and report back

elken commented 2 years ago

Nope it does seem specific to macos, maybe it's M1 related? I'll try the command you posted.

elken commented 2 years ago

how irksome....

image

Installed .NET via nix, wondering if that's the issue (desktop installs through rpm)

EDIT: Nope, definitely M1 related

juergenhoetzel commented 2 years ago

Integration tests use

dotnet --version
6.0.200

would you mind to test this setup?

elken commented 2 years ago

Nix uses

image

Is there anything different in that minor release?

EDIT: Seems not

image
juergenhoetzel commented 2 years ago

EDIT: Seems not

Thanks for your feedback: Does it work outside of emacs using:

dotnet fsi --readline-

?

elken commented 2 years ago

Yeah

image
juergenhoetzel commented 2 years ago

just to narrow down the problem: I guess evaluating in the inferior fsharp buffer

(process-coding-system (get-buffer-process (current-buffer)))

returns:

(utf-8-unix . utf-8-unix)

?

elken commented 2 years ago

It does indeed :)

juergenhoetzel commented 2 years ago

Could you please use the following wrapper script:

#!/usr/bin/env bash

exec > >(tee /tmp/fsharpi-stdout.txt)
exec 2> >(tee /tmp/fsharpi-stderr.txt  >&2)
stdbuf -o 0 -e 0 dotnet fsi --readline-

as command instead of dotnet fsi --readline- and upload the resulting files (as attachement).

elken commented 2 years ago

Here you go! :D

fsharpi-stderr.txt fsharpi-stdout.txt

juergenhoetzel commented 2 years ago

Have you killed the interactive/hanging buffer after sending the test code?

[Loading /tmp/nuget/4894--d262e99b-e7fc-4fd4-8ecf-421018e46ec0/Project.fsproj.fsx]
namespace FSI_0002.Project

is missing in your stderr-file.

elken commented 2 years ago

Oh I didn't run anything, I'm dumb...

elken commented 2 years ago

Running with the wrapper script seems to make it work? image

So something else is blocking the buffer?

juergenhoetzel commented 2 years ago

Fascinating. I guess it's related to stdout/stderr buffering. I guess using this wrapper will also work?

#!/usr/bin/env bash

stdbuf -o 0 -e 0 dotnet fsi --readline-
elken commented 2 years ago

Yes that also works. Does this have a potential to be a fix upstream then?

juergenhoetzel commented 2 years ago

Yes that also works. Does this have a potential to be a fix upstream then?

Nope, I guess the root-cause is the emacs-side of the process. It currently uses a pipe (eq process-connection-type nil):

Could you try redefining


(defun fsharp-run-process-if-needed (&optional cmd)
  "Launch fsi if needed, using CMD if supplied."
  (unless (comint-check-proc inferior-fsharp-buffer-name)
    (setq inferior-fsharp-program
          (or cmd (read-from-minibuffer "fsharp toplevel to run: "
                                        inferior-fsharp-program)))
    (let ((cmdlist (inferior-fsharp-args-to-list inferior-fsharp-program))
          (process-connection-type 'pty))
      (with-current-buffer (apply (function make-comint)
                                  inferior-fsharp-buffer-subname
                                  (car cmdlist) nil
                                  (cdr cmdlist))
        (when (eq system-type 'windows-nt)
          (set-process-coding-system (get-buffer-process (current-buffer))
                                     'utf-8 'utf-8))
        (inferior-fsharp-mode))
      (display-buffer inferior-fsharp-buffer-name))))

This should make stdout of dotnet line-buffered.

elken commented 2 years ago

That seems to do it!

elken commented 2 years ago

image LHS has the function redefined, RHS doesn't (and has the code pasted in and RET pressed, still stalls)

juergenhoetzel commented 2 years ago

Should be fixed by #311

elken commented 2 years ago

I'll make a note to test it tomorrow, thanks for a resolution! :D

elken commented 2 years ago

That looks to have done it! Brilliant :D