diff --git a/build.fsx b/build.fsx index b1151fc..20ea5b9 100644 --- a/build.fsx +++ b/build.fsx @@ -95,7 +95,7 @@ Target.create "Clean" (fun _ -> Target.create "Build" (fun _ -> DotNet.build id "./Avalonia.FuncUI.LiveView.sln") -Target.create "PackAnalyzer" (fun _ -> +Target.create "Pack" (fun _ -> for setting in Paket.settings do setting.templateParams @@ -138,7 +138,7 @@ Target.create "Default" ignore "Clean" ==> "Build" ==> "Default" "ClearLocalAnalyzer" -==> "PackAnalyzer" +==> "Pack" ==> "SetLocalAnalyzer" Target.runOrDefault "Default" \ No newline at end of file diff --git a/draft-input.fsx b/draft-input.fsx index 72e64a9..4d3699c 100644 --- a/draft-input.fsx +++ b/draft-input.fsx @@ -21,6 +21,10 @@ type LivePreviewAttribute () = module Store = let num = new State<_> 0 +type Foo = + | Hoge of int + | Fuga + module Counter = open Avalonia.FuncUI open Avalonia.Controls diff --git a/draft.fsx b/draft.fsx index 0c1828c..32568d0 100644 --- a/draft.fsx +++ b/draft.fsx @@ -1,7 +1,10 @@ // #r "nuget: Avalonia.Desktop" // #r "nuget: FSharp.Compiler.Service" #I "tests/Avalonia.FuncUI.LiveView.Core.Tests/bin/Debug/net6.0" +#r "Avalonia" +#r "Avalonia.Base" #r "Avalonia.Desktop" +#r "Avalonia.Skia" #r "Avalonia.Controls" #r "Avalonia.Visuals" #r "Avalonia.FuncUI" @@ -21,8 +24,32 @@ let t = ResizeArray() open Draft AnalysisDraft.references AnalysisDraft.checkProjectResults +let d = AnalysisDraft.parseAndCheckSingleFile InputData.input +d // let input = "DockPanel.background \"Fpp\"" // (AnalysisDraft.parseAndCheckSingleFile InputData.input).AssemblyContents.ImplementationFiles[1].Declarations +d.AssemblyContents.ImplementationFiles[1].Declarations +|> List.iter ( + FuncUIAnalysis.visitDeclaration + { OnLivePreviewFunc = + fun v vs -> + printfn $"{nameof v}:{v}" + printfn $"{nameof vs}:{vs}" + OnInvalidLivePreviewFunc = + fun v vs -> + printfn $"{nameof v}:{v}" + printfn $"{nameof vs}:{vs}" + + OnInvalidStringCall = + fun ex range m typeArgs argExprs -> + [ $"{nameof range}: %A{range}" + $"{nameof m}: {m}" + $"{nameof m}: {m.FullName}" + $"{nameof m}: {m.ReturnParameter}" + $"{nameof typeArgs}: {typeArgs}" + $"{nameof argExprs}: {argExprs}" ] + |> List.iter (printfn "%s") } +) AnalysisDraft.declarations |> List.iter ( FuncUIAnalysis.visitDeclaration @@ -37,7 +64,7 @@ AnalysisDraft.declarations printfn $"{nameof vs}:{vs}" OnInvalidStringCall = - fun range m typeArgs argExprs -> + fun ex range m typeArgs argExprs -> [ $"{nameof range}: %A{range}" $"{nameof m}: {m}" $"{nameof m}: {m.FullName}" diff --git a/src/Sample/Counter.fs b/src/Sample/Sample.fs similarity index 74% rename from src/Sample/Counter.fs rename to src/Sample/Sample.fs index f1068cc..d75f5b7 100644 --- a/src/Sample/Counter.fs +++ b/src/Sample/Sample.fs @@ -10,6 +10,7 @@ module Sample = open Avalonia.Layout open Avalonia.FuncUI.LiveView.Core.Types + let counter numState = Component.create ( "counter", @@ -167,4 +168,64 @@ module Sample = let cmp = Component (fun ctx -> let num = ctx.usePassed Store.num - counter num) \ No newline at end of file + counter num) + +/// 参考:https://github.com/fsprojects/Avalonia.FuncUI/blob/master/src/Avalonia.FuncUI.ControlCatalog/Views/Tabs/TextBoxDemo.fs +module ElmishDemo = + open Avalonia.Controls + open Avalonia.Layout + open Avalonia.FuncUI + open Avalonia.FuncUI.DSL + open Avalonia.FuncUI.Elmish + open Avalonia.FuncUI.Builder + open Avalonia.FuncUI.LiveView.Core.Types + + type State = {watermark:string} + + let init = { watermark = ""} + + /// 判別共用体を含むコードをLivePreviewをするためには値を持たないケースを**1つ以上**入れないといけない. + /// 参考:https://github.com/dotnet/fsharp/issues/8854 + type Msg = + | SetWatermark of string + | UnSetWatermark + + + let update msg state = + match msg with + | SetWatermark test -> {state with watermark = test} + | UnSetWatermark -> {state with watermark = ""} + + let view state dispatch = + StackPanel.create [ + StackPanel.spacing 10.0 + StackPanel.children [ + TextBox.create [ + TextBox.watermark state.watermark + TextBox.horizontalAlignment HorizontalAlignment.Stretch + ] + + Button.create [ + Button.content "Set Watermark" + Button.onClick (fun _ -> dispatch (SetWatermark "test")) + Button.horizontalAlignment HorizontalAlignment.Stretch + ] + + Button.create [ + Button.content "Unset Watermark" + Button.onClick (fun _ -> dispatch (UnSetWatermark )) + Button.horizontalAlignment HorizontalAlignment.Stretch + ] + ] + ] + + type ElmishHost() as this = + inherit Hosts.HostControl() + do + Elmish.Program.mkSimple(fun () -> init) update view + |> Program.withHost this + |> Elmish.Program.run + + [] + let preview () = + ViewBuilder.Create[] \ No newline at end of file diff --git a/src/Sample/Sample.fsproj b/src/Sample/Sample.fsproj index a2bf5a7..d74f572 100644 --- a/src/Sample/Sample.fsproj +++ b/src/Sample/Sample.fsproj @@ -5,7 +5,7 @@ - + diff --git a/tests/Avalonia.FuncUI.LiveView.Core.Tests/FuncUIAnalysisTests.fs b/tests/Avalonia.FuncUI.LiveView.Core.Tests/FuncUIAnalysisTests.fs index e9e9bd4..1411315 100644 --- a/tests/Avalonia.FuncUI.LiveView.Core.Tests/FuncUIAnalysisTests.fs +++ b/tests/Avalonia.FuncUI.LiveView.Core.Tests/FuncUIAnalysisTests.fs @@ -103,8 +103,7 @@ module FuncUIAnalysisTests = open Avalonia.FuncUI.LiveView [] - let ``Should work.`` () = - // let + let ``should work.`` () = let results = Helper.runFuncUIAnalysis """ @@ -154,3 +153,59 @@ module Counter = results.livePreviewFuncs.Count |> shouldEqual 1 results.invalidLivePreviewFuncs.Count |> shouldEqual 1 results.invalidStringCalls.Count |> shouldEqual 1 + + let badCodes : obj[] list = + [ + """ +module SingleCaseUnion + +type Foo = Foo of int + """ + """ +module MultiCaseUnion + +type Bar = + | Hoge of int + | Fuga of string + """ + ] + |> List.map (fun s -> [|box s|]) + + [] + [] + let ``wont work if all union case have value`` badCode = + let ex = + (fun _ -> Helper.runFuncUIAnalysis badCode |> ignore) + |> Assert.Throws + + ex.Message |> shouldContainText "FSharp.Compiler.Service cannot yet return this kind of pattern match at" + + let okCodes : obj[] list = + [ + """ +module SingleCaseUnion + +type Foo = Foo + """ + """ +module MultiCaseUnion + +type Bar = + | Hoge + | Fuga of string + """ + """ +module MultiCaseUnion2 + +type Bar<'t> = + | Hoge + | Fuga of string + | A of {|a:int; b:string; c: bool * string|} + | B of 't -> unit + """ + ] + |> List.map (fun s -> [|box s|]) + [] + [] + let ``should work if there is at least one case label with no union value`` okCode = + Helper.runFuncUIAnalysis okCode |> ignore \ No newline at end of file