Strange characters in VSCode FSharp Interactive terminal - f#

I try to play with fsharp under Ubuntu (and yes, I slowly figure out that it is more pain than fun), I already installed Mono, VSCode and Ionide extension and I can create and build F# projects. Unfortunately when I run simple F# script via F# Interactive:
printfn "bar"
In terminal window I get:
>
- printfn "bar"
-
- ;;
bar
val it : unit = () F# 4.0 (Open Source Edition)
> ^?^?414;3R^?^?^?^?^?^? the Apache 2.0 Open Source License
The strange sequence ^?^? looks like unrecognized terminal escape codes, but when I use bash from within VSCode there is nothing like this.
What's more the strange sequence reappears after every command executed in FSI:
> let j = 9;;
val j : int = 9
> printfn "foo";;
foo
val it : unit = ()
> ^?^?
Does anyone have the same problem and knows a solution (or maybe just knows a solution)?
EDIT: Problem occurs mostly when I execute commands via Ionide Alt+Enter shortcut

This looks like the https://github.com/Microsoft/vscode/issues/19766 bug. VS Code 1.9 introduced a new setting, terminal.integrated.flowControl, that defaults to true. The ^? characters you're seeing (and any ^S and ^Q characters that might show up) come from this "flow control" feature, which doesn't play well with F# Interactive. Change your VS Code settings to set terminal.integrated.flowControl to false and your problem should go away.

Related

Fake Glob operator (!!) not expanding directory paths

I have a situation where in a Fake script I am trying to grab all the unit test dll's from a path using the Glob (!!) operator.
The issue is that on my machine the glob expansion doesn't work, on other similar Windows 10 machines at work, its fine and finds the dlls.
Below is an example:
let path = [function to generate path]
trace path [would look something like "c:\git\project\src\**\*UnitTest*"]
!! path.ToLower()
|> Seq.iter (fun file -> trace file ) [this would not output anything]
I've tried numerous things:
uninstalling older versions of F#
reinstalling the lastest version
ensuring F# is in my Path
The versions of software I am using are:
Fake v4.63.2
Windows 10
F#4.1
No errors or exceptions are thrown.
Whats the best way to trouble shoot if its an F# or a Fake issue?
How could I work out what version of F# Fake is using?
Update
I've reinstalled F# 4.1 and performed a test using fsi.exe with the following command:
Microsoft (R) F# Interactive version 4.1
<snip>
#r #"packages/FAKE/tools/FakeLib.dll";;
open Fake;;
!! "**\*UnitTests.dll" |> Seq.iter (fun x -> trace x);;
C:\git\project1\bin\Debug\project1.UnitTests.dll
C:\git\project2\bin\Debug\project2.UnitTests.dll
!! "**\*UnitTests.dll".ToLower() |> Seq.iter (fun x -> trace x);;
C:\git\project1\bin\Debug\project1.UnitTests.dll
C:\git\project2\bin\Debug\project2.UnitTests.dll
All the test dlls were found, both with and without the call to ToLower().
When I remove the ToLower() from the script, it now works on my machine.
However, on other peoples machines removing ToLower() on the path causes them not to find any files.
So, is Fake using a different version of the fsi.exe?
I've opened a github issue to see if that sheds any light on it: https://github.com/fsharp/FAKE/issues/1772
In F# as in all .NET languages, the backslash is used for escape sequences in strings.
You need to escape the backslash or use a verbatim string, eg :
let path = "c:\\git\\project\\src\\**\\*UnitTest*"
or
let path = #"c:\git\project\src\**\*UnitTest*"
Fake can work with forward slashes as well :
let path = "c:/git/project/src/**/*UnitTest*"
You'll have to use forward slashes anyway if you want your build script to run on Linux.
An even better option is to use relative paths. Your build script most likely is stored in your project folder. You can write
let path = "src/**/*UnitTest*"
Using the following script, I was able to reproduce the issue and work out that the issue was due to how Windows 10 handles the original casing of the company name, in the path.
I confirmed this by changing company name to ** in the file path expression, the operator worked and found all the dlls.
I remember changing the capitalisation of the company name, from all caps to lower case. If I remove the ToLower() on the path, then the script works fine and finds all the dlls.
This hidden issue, combined with how FAKE does a case sensitive search, doesn't help either.
Powershell
packages\FAKE\tools\FAKE.exe glob.test.fsx
glob.test.fsx
#r #"packages/FAKE/tools/FakeLib.dll"
open Fake
let thePath = """C:\git\company/projectname/**/bin/Debug/*UnitTests.dll"""
sprintf "the path is %s" thePath |> trace
!! thePath.ToLower() |> Seq.iter (fun f -> trace f)
I had a look at the process executing in ProcMon and did not see the original casing of the directory. The NTFS file system is still see this directory as its original casing (see comments below).
I re-image my machine every few months, so this will disappear soon but it was good to understand what was going on.
Thanks to all those that helped narrow the issue down.

How to turn off Ionide Lint warnings

I have written a F# script in FSI using Ionide in VS Code. It's a great tool, but I am getting a warning from Ionide Lint suggesting a code improvement:
'Lint: Seq.map f (Seq.map g x) might be able to be refactored into Seq.map (g >> f) x.'
I have about 6 Seq.map functions all piped together with |> which I am happy with.
There is also a green wiggly line that is annoying me. I don't agree with the suggestion, and want the wiggly line to go away. How can I tell Ionide to stop making this suggestion?
I have turned off Lint globally in the VS Code settings
"FSharp.linter": false,
I think Ionide uses FsharpLint: http://fsprojects.github.io/FSharpLint/
This supports suppressing of lint messages like this:
[<SuppressMessage("NameConventions", "InterfaceNamesMustBeginWithI")>]
type Printable =
abstract member Print : unit -> unit
Something like that might work for you as well. I just turned it off.
This is the directive to disable this particular message in code:
open System.Diagnostics.CodeAnalysis
[<SuppressMessage("Hints", "") >]
Place above the block that is producing this 'error'.

Why does the Visual Studio 2010 debugger not pick up debug symbols for handling exception in F# sequence?

In Visual Studio 2010, the following F# sequence works as expected in Release mode (ignores UnauthorizedAccessException), but does not work correctly in Debug mode (breaks on UnauthorizedAccessException, even if I have set "Common Language Runtime Exceptions: Thrown = false, User-Unhandled = true").
open System
open System.IO
module private MyTestModule =
let rec private getAllFiles dir = seq {
if String.IsNullOrWhiteSpace dir |> not then
let getAuthorizedItems getItems dir =
try getItems dir
with :? UnauthorizedAccessException -> [||]
// Debugger stops here on UnauthorizedAccessException, but shouldn't...
yield! getAuthorizedItems Directory.GetFiles dir
for subDir in getAuthorizedItems Directory.GetDirectories dir do
yield! getAllFiles subDir }
// etc.
However, if I do not nest the getAuthorizedItems function inside the sequence, but place it at module level instead, the debugger works correctly.
Note:
I have looked at the generated IL code, and the exception handler is where it should be in both cases (is not modified/optimized in any way);
I know that System.Core must be preloaded in order for sequences to be displayed correctly in the debugger, but that is not related to my issue.
Are there any special rules for handling exceptions in sequences at debug time in F#?
Edit
After my reporting the issue, the F# team very quickly started to track it. It seems to be a minor bug related to the fact that, in Debug mode, some of the generated code is marked as ‘External Code’, even though it is user code. For the time being, one can use the workarounds suggested in pad's answer. Another workaround ist to turn off "Enable Just My Code" in the VS debugging options.
I'm able to reproduce the bug on my machine using F# 2.0/.NET 4.0 without VS2010 SP1 installed. It could be the case that this bug has been fixed in VS2010 SP1 as #svick couldn't reproduce it. It turns out this bug is still present after VS2010 SP1 update.
I think it's a bug of handling exception in nested functions inside sequence expression, changing the nested function to catch any exception doesn't affect the behaviour:
let getAuthorizedItems getItems dir =
try getItems dir
with ex -> [||]
This is a minor bug; you can bypass it in many ways:
It works in Release mode, inside fsi and even runs in Debug mode outside Visual Studio.
Declaring the nested function as inline makes it work in Debug mode.
Turning on Optimize code option makes it work again.
Not using nested functions inside seq also helps.
If it hasn't been fixed, I suggest you file a bug report at fsbugs at microsoft dot com.

Help embedding FSI

Starting here - Embedding F# interactive - I've been trying to embed FSI in my application.
However, I'm getting weird stuff back from StandardOutput.
for example, in standard FSI, if I send this:
let a = 3;;
I get this back:
[empty line here]
val a : int = 3
[empty line here]
> |
(with Pipe representing the input position)
But if I send let a = 3;; to StandardInput, I get this back on StandardOutput:
>
val a : int = 3
|
Has anyone else tried this? Is there something I'm doing wrong, and if not is there any way to work around this? None of the things I've tried so far work, and before I try the 'worse' thing I can think of (set a timer after sending stuff, add the > myself on timeout), I'd like to know if there is a better way!
When embedding F# Interactive, Visual Studio uses the --fsi-server:<some value> parameter.
As far as I know, this does two things:
Changes the way output is printed (instead of printing >, it prints SERVER-PROMPT> on a separate line, so it should be easier to remove it from the output and detect state when input is expected)
It also starts some .NET Remoting channel that you can use to stop execution of commands in F# Interactive (e.g. if it runs into an infinite loop) and it can also provide some completion information.
The F# Interactive pad in MonoDevelop F# plugin uses the flag (see source code on GitHub). I think it works mostly right, but I believe it sometimes prints additional \n in the output.

Why doesn't Console.Readline work but Console.Readline() does?

How do you use Console.Readline in F#? Unlike Console.Writeline, it isn't being honored when I call it.
If you use
let s = Console.ReadLine
you are only building a delegate that points to the ReadLine function. You need to say
let s = Console.ReadLine()
to actually execute the function. This is just like C# syntax, except type inference means you don't get a compiler warning.
What do you mean by "it isn't being honored"? Here's a small console app I've just written in VS2010b1, and it works fine:
open System
let line = Console.ReadLine()
Console.WriteLine("You wrote {0}", line)
// Just to make it pause
let unused = Console.ReadLine()
Are you trying to run the code from F# Interactive within Visual Studio? If so, that may be the issue, as Brian's post explains.
However, I haven't seen the same problem when using F# Interactive from the command line. Here's a complete transcript of a session:
Microsoft F# Interactive, (c) Microsoft Corporation, All Rights Reserved
F# Version 1.9.6.16, compiling for .NET Framework Version v4.0.20506
Please send bug reports to fsbugs#microsoft.com
For help type #help;;
> open System;;
> let line = Console.ReadLine();;
Hello world
val line : string = "Hello world"
Running Brian's looping code from F# Interactive didn't show the same problem.
Bottom line: It seems like this is broken in F# Interactive in Visual Studio, but not when running interactively from the command line or in a full console app.
I don't have a Beta1 box handy, but I know that in the past we've had a bug where ReadLine() would see the background commands that communicate between the interactive UI and the background process that runs your F# code. It may be interesting to investigate what
let Foo max =
let rec Loop i =
if i < max then
let line = System.Console.ReadLine()
printfn "line = %s" line
Loop (i+1)
Loop 1
Foo 12
prints when you highlight it and 'Send to Interactive'. I think possibly you'll see a few unexpected interesting lines, followed by lines you type into the window.
// is the right way if you're not wanting to use a return of anything typed into readline
Console.ReadLine() |> ignore

Resources