Indentation is important in F#, as it defines the code blocks and the separate code elements. Using Feliz to define a view, in a Fable.React application, the indentation matters just as much, and even more.
Fantomas is a beautiful tool that automatically formats your code and ensures consistency, also in indentation. But using code like with the Feliz library, there some serious drawbacks.
For example this is Feliz code formatted by Fantomas:
let render (state: State) (dispatch: Msg -> unit) =
let filter = createFilter state.Generics state.Indications state.Routes state.Patients dispatch
let details =
match state.Details with
| HasNotStartedYet -> "## Geen generiek gekozen"
| InProgress -> "## Doseringen worden opgehaald ..."
| Resolved s -> s.Trim()
|> markdown.source
|> List.singleton
|> List.append [ markdown.escapeHtml false ]
|> Markdown.markdown
Mui.themeProvider
[ themeProvider.theme defaultTheme
themeProvider.children
[ Html.div
[ [ Fable.MaterialUI.Icons.menuIcon "", (fun _ -> ToggleEdit |> dispatch) ]
|> Components.TitleBar.render (state.Versions |> printTitle)
if state.EditView then
Html.div [
prop.style [ style.marginTop 100 ]
prop.text "Edit view"
]
else
Mui.container
[ prop.style
[ style.marginTop 90
style.padding 10 ]
container.maxWidth.md
prop.children
[ // search
Html.div
[ prop.style [ style.padding 10 ]
paper.children filter ]
match state.Generics with
| Resolved _ ->
// details
Mui.paper
[ prop.style
[ style.padding 10
style.color Colors.indigo.``900`` ]
prop.children [ details ] ]
| _ -> Html.none ] ] ] ] ]
This indentation however has a couple of problems.
- It is very hard to see which are the different elements in the code.
- When you indent pieces of this code, it quickly results in hard to debug indentation errors.
This is because of the following indentation structure:
Mui.themeProvider [ themeProvider.theme defaultTheme
themeProvider.children [ Html.div [ [ Fable.MaterialUI.Icons.menuIcon "",
(fun _ -> ToggleEdit |> dispatch) ]
|> Components.TitleBar.render (state.Versions |> printTitle) ] ] ]
So every list argument starts at the same line as the list opening: i.e.
// fantomas formatted
Html.div [ prop.style [ style.marginTop 40 ]
prop.children [ Mui.typography [ prop.text "the fantomas way" ] ] ]
// easier to extract and indent
Html.div [
prop.style [
style.marginTop 40
]
prop.children [
Mui.typography [
prop.text "easier to extract and indent"
]
]
]
When you reformat the original code to:
let render (state: State) (dispatch: Msg -> unit) =
let filter = createFilter state.Generics state.Indications state.Routes state.Patients dispatch
let details =
match state.Details with
| HasNotStartedYet -> "## Geen generiek gekozen"
| InProgress -> "## Doseringen worden opgehaald ..."
| Resolved s -> s.Trim()
|> markdown.source
|> List.singleton
|> List.append [ markdown.escapeHtml false ]
|> Markdown.markdown
Mui.themeProvider [
themeProvider.theme defaultTheme
themeProvider.children [
Html.div [
[
Fable.MaterialUI.Icons.menuIcon "", (fun _ -> ToggleEdit |> dispatch)
]
|> Components.TitleBar.render (state.Versions |> printTitle)
if state.EditView then
Html.div [
prop.style [ style.marginTop 100 ]
prop.text "Edit view"
]
else
Mui.container [
prop.style [
style.marginTop 90
style.padding 10
]
container.maxWidth.md
prop.children [
// search
Html.div [
prop.style [ style.padding 10 ]
paper.children filter
]
match state.Generics with
| Resolved _ ->
// details
Mui.paper [
prop.style [
style.padding 10
style.color Colors.indigo.``900``
]
prop.children [ details ]
]
| _ -> Html.none
]
]
]
]
]
This is easier to read and identify the different elements. Also, when you need to add indentation, because for example you want to wrap things in an additional div, this is far easier to do.
Even the editor view is much nicer as it allows you to collapse each individual element: