Skip to content

Commit

Permalink
Config documentation (fsprojects#1956)
Browse files Browse the repository at this point in the history
* Add documentation attribute

* Expose documentation attributes via Fantomas Daemon.

Co-authored-by: Asti <rahul.ramakumar@walmart.com>
  • Loading branch information
2 people authored and jindraivanek committed Mar 30, 2022
1 parent f7608b4 commit 7b72f37
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 20 deletions.
36 changes: 26 additions & 10 deletions src/Fantomas.CoreGlobalTool/Daemon.fs
Original file line number Diff line number Diff line change
Expand Up @@ -106,33 +106,49 @@ type FantomasDaemon(sender: Stream, reader: Stream) as this =
Reflection.getRecordFields FormatConfig.FormatConfig.Default
|> Array.toList
|> List.choose
(fun (name, defaultValue) ->
(fun (recordField, defaultValue) ->
let optionalField key value =
value
|> Option.toList
|> List.map (fun v -> key, Encode.string v)

let meta =
List.concat [| optionalField "category" recordField.Category
optionalField "displayName" recordField.DisplayName
optionalField "description" recordField.Description |]

let type' =
match defaultValue with
| :? bool as b ->
Some(
Encode.object [ "type", Encode.string "boolean"
"defaultValue", Encode.string (if b then "true" else "false") ]
Encode.object [ yield "type", Encode.string "boolean"
yield "defaultValue", Encode.string (if b then "true" else "false")
yield! meta ]
)
| :? int as i ->
Some(
Encode.object [ "type", Encode.string "number"
"defaultValue", Encode.string (string i) ]
Encode.object [ yield "type", Encode.string "number"
yield "defaultValue", Encode.string (string i)
yield! meta ]
)
| :? MultilineFormatterType as m ->
Some(
Encode.object [ "type", Encode.string "multilineFormatterType"
"defaultValue", Encode.string (MultilineFormatterType.ToConfigString m) ]
Encode.object [ yield "type", Encode.string "multilineFormatterType"
yield
"defaultValue",
Encode.string (MultilineFormatterType.ToConfigString m)
yield! meta ]
)
| :? EndOfLineStyle as e ->
Some(
Encode.object [ "type", Encode.string "endOfLineStyle"
"defaultValue", Encode.string (EndOfLineStyle.ToConfigString e) ]
Encode.object [ yield "type", Encode.string "endOfLineStyle"
yield "defaultValue", Encode.string (EndOfLineStyle.ToConfigString e)
yield! meta ]
)
| _ -> None

type'
|> Option.map (fun t -> toEditorConfigName name, t))
|> Option.map (fun t -> toEditorConfigName recordField.PropertyName, t))
|> Encode.object

let enumOptions =
Expand Down
43 changes: 36 additions & 7 deletions src/Fantomas.Extras/EditorConfig.fs
Original file line number Diff line number Diff line change
@@ -1,15 +1,37 @@
module Fantomas.Extras.EditorConfig

open System.Collections.Generic
open System.ComponentModel
open Fantomas.FormatConfig

module Reflection =
open System
open System.Reflection
open FSharp.Reflection

type FSharpRecordField =
{ PropertyName: string
Category: string option
DisplayName: string option
Description: string option }

let inline private getCustomAttribute<'t, 'v when 't :> Attribute and 't: null>
(projection: 't -> 'v)
(property: PropertyInfo)
: 'v option =
property.GetCustomAttribute<'t>()
|> Option.ofObj
|> Option.map projection

let inline getRecordFields x =
let names =
FSharpType.GetRecordFields(x.GetType())
|> Seq.map (fun x -> x.Name)
|> Seq.map
(fun x ->
{ PropertyName = x.Name
Category = getCustomAttribute<CategoryAttribute, string> (fun a -> a.Category) x
DisplayName = getCustomAttribute<DisplayNameAttribute, string> (fun a -> a.DisplayName) x
Description = getCustomAttribute<DescriptionAttribute, string> (fun a -> a.Description) x })

let values = FSharpValue.GetRecordFields x
Seq.zip names values |> Seq.toArray
Expand Down Expand Up @@ -38,8 +60,10 @@ let toEditorConfigName value =
let private fantomasFields =
Reflection.getRecordFields FormatConfig.Default
|> Array.map
(fun (propertyName, defaultValue) ->
let editorConfigName = toEditorConfigName propertyName
(fun (recordField, defaultValue) ->
let editorConfigName =
toEditorConfigName recordField.PropertyName

(editorConfigName, defaultValue))

let private (|Number|_|) d =
Expand Down Expand Up @@ -74,14 +98,19 @@ let parseOptionsFromEditorConfig (editorConfigProperties: IReadOnlyDictionary<st
let configToEditorConfig (config: FormatConfig) : string =
Reflection.getRecordFields config
|> Array.choose
(fun (k, v) ->
(fun (recordField, v) ->
match v with
| :? System.Boolean as b ->
sprintf "%s=%s" (toEditorConfigName k) (if b then "true " else "false")
sprintf "%s=%s" (toEditorConfigName recordField.PropertyName) (if b then "true " else "false")
|> Some
| :? System.Int32 as i ->
sprintf "%s=%d" (toEditorConfigName recordField.PropertyName) i
|> Some
| :? System.Int32 as i -> sprintf "%s=%d" (toEditorConfigName k) i |> Some
| :? MultilineFormatterType as mft ->
sprintf "%s=%s" (toEditorConfigName k) (MultilineFormatterType.ToConfigString mft)
sprintf
"%s=%s"
(toEditorConfigName recordField.PropertyName)
(MultilineFormatterType.ToConfigString mft)
|> Some
| _ -> None)
|> String.concat "\n"
Expand Down
126 changes: 123 additions & 3 deletions src/Fantomas/FormatConfig.fs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Fantomas.FormatConfig

open System
open System.ComponentModel

let satSolveMaxStepsMaxSteps = 100

Expand Down Expand Up @@ -56,47 +57,166 @@ type EndOfLineStyle =

// NOTE: try to keep this list below in sync with the docs (e.g. Documentation.md)
type FormatConfig =
{ /// Number of spaces for each indentation
{ [<Category("Indentation")>]
[<DisplayName("Indent spaces")>]
[<Description("Number of spaces to use for indentation")>]
IndentSize: Num
/// The column where we break to new lines

[<Category("Boundaries")>]
[<DisplayName("Maximum line length")>]
[<Description("The column where we break to new lines")>]
MaxLineLength: Num

[<Category("Convention")>]
[<DisplayName("Semicolon at end-of-line")>]
[<Description("Forces a semicolon to be added to the end of a line")>]
SemicolonAtEndOfLine: bool

[<Category("Spacing")>]
[<DisplayName("Before parameter")>]
SpaceBeforeParameter: bool

[<Category("Spacing")>]
[<DisplayName("Before lowercase invocation")>]
SpaceBeforeLowercaseInvocation: bool

[<Category("Spacing")>]
[<DisplayName("Before uppercase invocation")>]
SpaceBeforeUppercaseInvocation: bool

[<Category("Spacing")>]
[<DisplayName("Before class constructor")>]
SpaceBeforeClassConstructor: bool

[<Category("Spacing")>]
[<DisplayName("Before member")>]
SpaceBeforeMember: bool

[<Category("Spacing")>]
[<DisplayName("Before colon")>]
SpaceBeforeColon: bool

[<Category("Spacing")>]
[<DisplayName("After comma")>]
SpaceAfterComma: bool

[<Category("Spacing")>]
[<DisplayName("Before semicolon")>]
SpaceBeforeSemicolon: bool

[<Category("Spacing")>]
[<DisplayName("After semicolon")>]
SpaceAfterSemicolon: bool

[<Category("Indentation")>]
[<DisplayName("Indent try-with")>]
IndentOnTryWith: bool

[<Category("Spacing")>]
[<DisplayName("Around delimiter")>]
SpaceAroundDelimiter: bool

[<Category("Boundaries")>]
[<DisplayName("Maximum if-then-else width")>]
MaxIfThenElseShortWidth: Num

[<Category("Boundaries")>]
[<DisplayName("Maximum infix-operator expression")>]
MaxInfixOperatorExpression: Num

[<Category("Boundaries")>]
[<DisplayName("Maximum record width")>]
MaxRecordWidth: Num

[<Category("Boundaries")>]
[<DisplayName("Maximum items in a record")>]
MaxRecordNumberOfItems: Num

[<Category("Boundaries")>]
[<DisplayName("Multi-line formatter for records")>]
RecordMultilineFormatter: MultilineFormatterType

[<Category("Boundaries")>]
[<DisplayName("Maximum array or list width")>]
MaxArrayOrListWidth: Num

[<Category("Boundaries")>]
[<DisplayName("Maximum number of items in array/list")>]
MaxArrayOrListNumberOfItems: Num

[<Category("Boundaries")>]
[<DisplayName("Multi-line formatter for array/list")>]
ArrayOrListMultilineFormatter: MultilineFormatterType

[<Category("Boundaries")>]
[<DisplayName("Maximum value-binding width")>]
MaxValueBindingWidth: Num

[<Category("Boundaries")>]
[<DisplayName("Maximum function-binding width")>]
MaxFunctionBindingWidth: Num

[<Category("Boundaries")>]
[<DisplayName("Maximum dot get expression width")>]
MaxDotGetExpressionWidth: Num

[<Category("Boundaries")>]
[<DisplayName("Multiline-block brackets on same column")>]
MultilineBlockBracketsOnSameColumn: bool

[<Category("Convention")>]
[<DisplayName("Newline between type definition and members")>]
NewlineBetweenTypeDefinitionAndMembers: bool

[<Category("Convention")>]
[<DisplayName("Keep If-Then in same line")>]
[<Description("Obsolete setting, this no longer has any effect and will be removed in the next major version.")>]
KeepIfThenInSameLine: bool

[<Category("Elmish")>]
[<DisplayName("Maximum width for elmish syntax")>]
MaxElmishWidth: Num

[<Category("Elmish")>]
[<DisplayName("Single-argument web mode")>]
SingleArgumentWebMode: bool

[<Category("Convention")>]
[<DisplayName("Align function signature to indentation")>]
AlignFunctionSignatureToIndentation: bool

[<Category("Convention")>]
[<DisplayName("Alternative long member definitions")>]
AlternativeLongMemberDefinitions: bool

[<Category("Boundaries")>]
[<DisplayName("MultiLine-lambda has closing newline")>]
MultiLineLambdaClosingNewline: bool

[<Category("Elmish")>]
[<DisplayName("Disable support for elmish syntax")>]
DisableElmishSyntax: bool

[<Category("Boundaries")>]
[<DisplayName("Line-ending style")>]
EndOfLine: EndOfLineStyle

[<Category("Indentation")>]
[<DisplayName("Keep indent in branch")>]
[<Description("Experimental feature, use at your own risk.")>]
KeepIndentInBranch: bool

[<Category("Convention")>]
[<DisplayName("Keep empty lines around nested multi-line expressions")>]
BlankLinesAroundNestedMultilineExpressions: bool

[<Category("Convention")>]
[<DisplayName("Add a bar before Discriminated Union declarations")>]
BarBeforeDiscriminatedUnionDeclaration: bool
/// Pretty printing based on ASTs only

[<Category("Convention")>]
[<DisplayName("Strict mode")>]
[<Description("Pretty printing based on ASTs only.\nPlease do not use this setting for formatting hand written code!")>]
StrictMode: bool }

static member Default =
Expand Down

0 comments on commit 7b72f37

Please sign in to comment.