Eugleo / magic-racket

The best coding experience for Racket in VS Code
https://marketplace.visualstudio.com/items?itemName=evzen-wybitul.magic-racket
GNU General Public License v3.0
204 stars 28 forks source link

"enter!: not a module path or #f" on load file in REPL bug #66

Closed CatEricka closed 2 years ago

CatEricka commented 2 years ago

Environment


Error message

code Untitled-1.rkt:

#lang racket

(define foo "hello world")
(display foo)

REPL message:

powershell ~: racket --repl --lib errortrace --eval '(enter! (file "c:/Users/Ericka/sources/racket/Untitled-1.rkt"))'
Welcome to Racket v8.3 [cs].
enter!: not a module path or #f
  at: (file c:/Users/Ericka/sources/racket/Untitled-1.rkt)
  in: (enter! (file c:/Users/Ericka/sources/racket/Untitled-1.rkt))
  errortrace...:
  context...:
   C:\Program Files\Racket\collects\racket\enter.rkt:10:0

Additional context

run (enter! (file "c:/Users/Ericka/sources/racket/Untitled-1.rkt")) in REPL:

powershell ~: racket --repl --lib errortrace --eval '(enter! (file "c:/Users/Ericka/sources/racket/Untitled-1.rkt"))'
Welcome to Racket v8.3 [cs].
enter!: not a module path or #f
  at: (file c:/Users/Ericka/sources/racket/Untitled-1.rkt)
  in: (enter! (file c:/Users/Ericka/sources/racket/Untitled-1.rkt))
  errortrace...:
  context...:
   C:\Program Files\Racket\collects\racket\enter.rkt:10:0                                    
> (enter! (file "c:/Users/Ericka/sources/racket/Untitled-1.rkt"))
hello world
"untitled-1.rkt">

shengjiex98 commented 2 years ago

Having the same issue here. The error occurs when first pressing REPL: Load file in REPL on the menu bar. However, pressing it a second time seems to work fine.

shengjiex98 commented 2 years ago

Upon further investigation, it seems that running racket --repl --eval '(enter! (file "c:/Users/.../file.rkt"))' directly in PowerShell also has this issue, while running (enter! (file "c:/Users/.../file.rkt")) once in the REPL seems to work fine. Maybe it's a racket REPL problem instead of the extension?

CatEricka commented 2 years ago

fixed by #65

The problem seems to be caused by racket 's weird escaping rules for parsing command line arguments on windows.

shocoman commented 2 years ago

Actually, this problem is caused by weird Powershell behaviour. It just strips double-quotes from command line parameters for whatever reason. i.e. in Powershell racket --eval '(displayln "123")' is exactly the same as racket --eval '(displayln 123)'. The solution is to additionally escape the quotes (racket --eval '(displayln \"123\")')

CatEricka commented 2 years ago

Actually, this problem is caused by weird Powershell behaviour. It just strips double-quotes from command line parameters for whatever reason. i.e. in Powershell racket --eval '(displayln "123")' is exactly the same as racket --eval '(displayln 123)'. The solution is to additionally escape the quotes (racket --eval '(displayln \"123\")')

The parsing of double quotes on the command line under Windows is more complicated than I thought. But I don't think it's caused by weird PowerShell behavior: PowerShell doesn't escape double quotes inside single quotes:

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules?view=powershell-7.2#including-quote-characters-in-a-string

...it's not racket's fault either.

In fact, the command line string is processed twice by the PowerShell and c/c++ program:

https://daviddeley.com/autohotkey/parameters/parameters.htm

https://stackoverflow.com/questions/6714165/powershell-stripping-double-quotes-from-command-line-arguments


TL; DR

cmd.exe:

image

How this parameter gets parsed:

parameter string: ^"(enter! (file \^"file_path\^"))^" -> cmd.exe => "(enter! (file \"file_path\"))" -> msvcrt/msvcpprt processed => (enter! (file "file_path")) -> racket get the parameter.

PowerShell:

Same as cmd.exe, just PowerShell call CreateProcess().

How this parameter gets parsed:

parameter string: '(enter! (file \"file_path\"))' -> PowerShell magic => "(enter! (file \"file_path\"))" (I guess) -> msvcrt/msvcpprt processed => (enter! (file "file_path")) -> racket get the parameter.

CatEricka commented 2 years ago

If I understand correctly,

https://github.com/Eugleo/magic-racket/blob/858a6da059f5b3dfb611c4ab2c791ac1b8123e96/src/repl.ts#L77-L78

the argument that racket gets are actually (enter! (file "file/path)), and I think it's pure coincidence that it works

cmd.exe:

C:\Users\Ericka\test>argv_echo.exe racket --repl --eval "(enter! (file ""c:/Users/Ericka/Untitled-1.rkt""))"
argv 0: argv_echo.exe
argv 1: racket
argv 2: --repl
argv 3: --eval
argv 4: (enter! (file "c:/Users/Ericka/Untitled-1.rkt))

C:\Users\Ericka\test>argv_echo.exe racket --repl --eval ^"(enter! (file \^"c:/Users/Ericka/Untitled-1.rkt\^"))^"
argv 0: argv_echo.exe
argv 1: racket
argv 2: --repl
argv 3: --eval
argv 4: (enter! (file "c:/Users/Ericka/Untitled-1.rkt"))

code of argv_echo.exe:

#include <iostream>
using namespace std;
int main(int argc, char*argv[])
{
    for (int i = 0; i < argc; i++)
    {
        cout << "argv " << i << ": " << argv[i] << endl;
    }
    return 0;
}
shocoman commented 2 years ago

Interesting! I agree with you that this should be changed just to be safe. But here is the thing: 1) If racket actually gets (enter! (file "file/path)) then why doesn't it show an error? Because when I try explicitly import file in REPL it throws one at me (I use Git Bash in this example) image 2) I wrote a similar "program" in Python and ran it from cmd.exe

import sys
print("\n".join(sys.argv))

And here what I got. The quote is present image Although it probably depends on how various programs treat (parse?) cmd params individually. Both Python's and Racket's runtimes do it right

CatEricka commented 2 years ago

If racket actually gets (enter! (file "file/path)) then why doesn't it show an error?

It occurred to me that how the main function gets arguments is up to the compiler.

Same code, different compiler:

Code:

#include <stdio.h>
int main(int argc, char*argv[])
{
    for (int i = 0; i < argc; i++)
    {
        printf("argv %d: %s\n", i, argv[i]);
    }
    return 0;
}

Msys2 mingw-w64-x86_64-gcc 10.3.0:

cmd > args.exe "(enter! (file ""c:/test/test.rkt""))"
argv 0: args.exe
argv 1: (enter! (file "c:/test/test.rkt))

Visual Studio 2017 (v141), windows sdk 10.0.17763.0

cmd > args.exe "(enter! (file ""c:/test/test.rkt""))"
0: Project1.exe
1: (enter! (file "c:/test/test.rkt"))

So, it seems that different c runtimes have different understanding of command line argument escaping.

In any case, programs should not rely on the behavior of the c runtime, I think using \" escaping is the correct thing to do.

An incident

I checked the header of Racket.exe using dumpbin.exe:

OPTIONAL HEADER VALUES
            ...
            2.35 linker version
            ...

... it doesn't seem to be compiled by visual studio, and then I searched for the keyword mingw

000000000040CF80: 4D 69 6E 67 77 2D 77 36 34 20 72 75 6E 74 69 6D  Mingw-w64 runtim
000000000040CF90: 65 20 66 61 69 6C 75 72 65 3A 0A 00 00 00 00 00  e failure:......
000000000040CFA0: 41 64 64 72 65 73 73 20 25 70 20 68 61 73 20 6E  Address %p has n
000000000040CFB0: 6F 20 69 6D 61 67 65 2D 73 65 63 74 69 6F 6E 00  o image-section.

I can only think there’s some magic in it.

shengjiex98 commented 2 years ago

Thanks for investing the issue guys. Wish I could help--I just started taking a course in racket last week and wanted to report issues so that people more competent than me could take a shot fixing them! cheers

Eugleo commented 2 years ago

Should be fixed in 0.6.3. Made sure to package the correct code this time. Please, test this and then close the issue if everything is ok.

CatEricka commented 2 years ago

Version 0.6.3 still packs the wrong files, same as 0.6.2.

$ diff evzen-wybitul.magic-racket-0.6.2 evzen-wybitul.magic-racket-0.6.3
diff evzen-wybitul.magic-racket-0.6.2/extension.vsixmanifest evzen-wybitul.magic-racket-0.6.3/extension.vsixmanifest
4c4
<                       <Identity Language="en-US" Id="magic-racket" Version="0.6.2" Publisher="evzen-wybitul" />
---
>                       <Identity Language="en-US" Id="magic-racket" Version="0.6.3" Publisher="evzen-wybitul" />

evzen-wybitul.magic-racket-0.6.3.vsix/extension/out/repl.js#L23-L38

exports.executeSelectionInRepl = executeSelectionInRepl;
function runFileInTerminal(command, filePath, terminal) {
    terminal.show();
    terminal.sendText(`clear`);
    terminal.sendText((0, shell_quote_1.quote)([...command, filePath]));
    // Leaving this here if we ever need to fix cmd.exe again
    // const shell: string | undefined = vscode.workspace
    //   .getConfiguration("terminal.integrated.shell")
    //   .get("windows");
    // if (process.platform === "win32" && shell && /cmd\.exe$/.test(shell)) {
    //   // cmd.exe doesn't recognize single quotes
    //   terminal.sendText(`${racket} "${filePath}"`);
    // } else {
    //   terminal.sendText(`${racket} '${filePath}'`);
    // }
}

current master branch

https://github.com/Eugleo/magic-racket/blob/54f66ab58a1a4409e0ad149520cea4504c7f2f21/src/repl.ts#L24-L40

Eugleo commented 2 years ago

Should be fixed. I manually downloaded the 0.6.4 from the marketplace and checked that the repl.js file is the correct one. Sorry everyone for the mishaps!

octocorvus commented 2 years ago

This is also an issue with powershell on linux.

mijhaels commented 1 year ago

Still not fixed.

jryans commented 1 year ago

Please create a new issue to track whatever remains, rather than reviving this old closed one. Include more info in the new issue with your system details and versions along what you tried, and then we'll take a look.