fsharp / fsharp/fslang-suggestions
Possible plain-text formatting improvements
- Dominant language
- No language data
- Stars
- 373
- Forks
- 21
- PR merge metrics
- No merged PRs in 30d
Description
I'd like to start a thread documenting possible improvements to plain-text formatting in F#. This is driven partly my [doing a deep look at getting quality plaintext printing for F# in .NET Interactive Notebooks](https://github.com/dotnet/interactive/issues/642)
The current state of plain-text formatting in F# is documented in these articles:
* `printf` printing - https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/plaintext-formatting
* F# Interactive output - https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/fsharp-interactive-options
The possible adjustments I've spotted are:
1. Be more consistent about using globalization settings (default to InvariantCulture)
In all formatting (both `%A` and F# Interactive), be more consistent about globalization settings for things of type IFormattable. In particular, [arbitrary .NET values](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/plaintext-formatting#net-values) currently format using CurrentCulture settings, where numeric values do not. This is inconsistent
2. Find a way to allow `printf` formatting to use user-defined culture settings. This is partly possible with interpolated strings using FormattableString, but that can't use `%d`, `%A` etc. patterns.
3. Respect `DebuggerBrowsableAttribute` `DebuggerBrowsableState.Never` in F# Interactive printing to automatically suppress the printing of some properties. [.NET Interactive does this](https://github.com/dotnet/interactive/issues/692#issuecomment-670918750)
4. Allow multi-line `%A` printing to respect indentation. So for example `sprintf "fooo %*A goo" v` would put the format of `v` indented 5 spaces if it is multi-line. Currently multiline %A printing doesn't respect indentation (see [here](https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/plaintext-formatting#primitive-values) and this makes outputs look much messier unfortunately).
Further. some limited "break if necessary specifications" may be allowed, so something like `sprintf "tensor [%40*4A]" v` might allow a line break to be inserted if the value hits 40 characters width. These are really useful though not entirely suited to specification in printf strings.
Alternatively we could expose a variation of the box layout code available for us internally in FSharp.Core as an API independent of sprintf.
5. Implement `ToString()` on F# function and other closure values so they do more than print the obscure closure name - as least add some indication the thing is a function
6. Allow `%f`, `%A` and friends to optionally take an additional specifier to force CurrentCulture, e.g. `%$d`, `%$A` (or some other character). There could also be a corresponding option to force InvariantCulture, e.g. `%!d`, `%!A`
```fsharp
// %$f ---> Use the culture from context (UI or FormattableString formatting operation)
// %!f ---> Use invariant culture
// %f == %!f
// %$A ---> For IFormattable, use the culture from context (UI or FormattableString formatting operation)
// %!A ---> For IFormattable, use invariant culture
// %A != %!A
// %A != %$A
// %$O ---> For IFormattable, use the culture from context (UI or FormattableString), otherwise ToString()
// %!O ---> For IFormattable, use invariant culture, otherwise ToString()
// %O == %$O
```
7. Allow `%A` (or some API access point to the same functionality) take a (varying) line width as a parameter, e.g. `%*A` or have `%A` respect Console.WindowWidth by default
8. Allow `%A` (or some API access point to the same functionality) to take a specifier that disables PrintLength for strings and collections.
9. Allow `%A` (or some API access point to the same functionality) to take a specifier that gives colorized output
10. Give a warning when a mix of culture-aware and culture-invariant format specifiers are used in a single interpolated string.
One overall aim may be to allow for the satisfactory implementation of a generic print using
```fsharp
/// Generic unstructured culture-invariant single-line string
let string x = ...
/// Generic structured culture-invariant multi-line colorized
/// output fitting to console width
let print x = ...
/// Generic structured culture-invariant multi-line colorized
/// output fitting to console width with new line
let printn x = ...
```
Plus this:
```fsharp
module CurrentCulture =
/// Generic unstructured culture-aware single-line string
let string x = ...
/// Generic structured culture-aware multi-line colorized
/// output fitting to console width
let print x = ...
/// Generic structured culture-aware multi-line colorized
/// output fitting to console width with new line
let printn x = ... ```
```
This would raise questions about whether `CurrentCulture` module would have functions like `int` and `double` for parsing strings using current culture (the default `int` and `double` parse using invariant culture).
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.