SilkyFowl.Avalonia.FuncUI.LiveView.Cli 0.0.4-preview05

This is a prerelease version of SilkyFowl.Avalonia.FuncUI.LiveView.Cli.
dotnet tool install --global SilkyFowl.Avalonia.FuncUI.LiveView.Cli --version 0.0.4-preview05
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest # if you are setting up this repo
dotnet tool install --local SilkyFowl.Avalonia.FuncUI.LiveView.Cli --version 0.0.4-preview05
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=SilkyFowl.Avalonia.FuncUI.LiveView.Cli&version=0.0.4-preview05&prerelease
nuke :add-package SilkyFowl.Avalonia.FuncUI.LiveView.Cli --version 0.0.4-preview05

Avalonia.FuncUI.LiveView

Live fs/fsx previewer for Avalonia.FuncUI.

日本語(Javanese language)

What is this ?

Avalonia.FuncUI.LiveView is an experimental FsAutoComplete extension that aims to provide a real-time preview of the UI of Avalonia.FuncUI. Analyzers.SDK, it displays a real-time preview of the content of the F# file you are editing in the editor. No need to save the file to update the preview.

Demo repositories

How to use

Warning Avalonia.FuncUI.LiveView is incomplete. It has not been fully tested and is not intended for use in a production environment. Please use this tool at your own risk.

The following is a case of using VScode and Paket.

Preliminary Preparation

Network

Use localhost:8080 for communication between Analyzer and LivePreview. Communication method will be improved in the future.

VScode

Install Ionide.Ionide-fsharp in VScode.

install extension

FuncUI Setup

Create a working directory and launch VScode.

mkdir YourFuncUIApp
cd YourFuncUIApp
code .

Create a project.

dotnet new tool-manifest
dotnet new gitignore
dotnet new sln
dotnet new console -o ./src/YourFuncUIApp -lang f#
dotnet sln add ./src/YourFuncUIApp/YourFuncUIApp.fsproj
Setup F# formatter
dotnet tool install fantomas

Create .editorconfig. The contents are as follows:

root = true

[*]
indent_style=space
indent_size=4
charset=utf-8
trim_trailing_whitespace=true
insert_final_newline=false

[*.{fs,fsx}]
fsharp_experimental_elmish=true
Paket Setup
dotnet tool install paket

Create paket.dependencies. The contents are as follows:

source https://api.nuget.org/v3/index.json

storage: none

nuget FSharp.Core content: none
nuget Avalonia.FuncUI 1.1.0
nuget Avalonia.Desktop 11.0.5
nuget Avalonia.Diagnostics 11.0.5
nuget Avalonia.Themes.Fluent 11.0.5
nuget SilkyFowl.Avalonia.FuncUI.LiveView.Attribute 0.0.4-preview05
dotnet paket convert-from-nuget --force --no-install --no-auto-restore
dotnet paket add -p ./src/YourFuncUIApp/YourFuncUIApp.fsproj Avalonia.FuncUI --no-install
dotnet paket add -p ./src/YourFuncUIApp/YourFuncUIApp.fsproj Avalonia.Desktop --no-install
dotnet paket add -p ./src/YourFuncUIApp/YourFuncUIApp.fsproj Avalonia.Diagnostics --no-install
dotnet paket add -p ./src/YourFuncUIApp/YourFuncUIApp.fsproj Avalonia.Themes.Fluent --no-install
dotnet paket add -p ./src/YourFuncUIApp/YourFuncUIApp.fsproj SilkyFowl.Avalonia.FuncUI.LiveView.Attribute --no-install
dotnet paket install
Without Paket

Add a dependency to YourFuncUIApp.fsproj as follows:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="Program.fs" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Avalonia.Desktop" Version="11.0.5" />
    <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5" />
    <PackageReference Include="Avalonia.FuncUI" Version="1.1.0" />
    <PackageReference Include="SilkyFowl.Avalonia.FuncUI.LiveView.Attribute" Version="0.0.4-preview05" />
  </ItemGroup>
</Project>
dotnet restore

Write code

Rewrite Program.fs as follows:

namespace CounterApp

open Avalonia
open Avalonia.Controls.ApplicationLifetimes
open Avalonia.Themes.Fluent
open Avalonia.FuncUI.Hosts
open Avalonia.Controls
open Avalonia.FuncUI
open Avalonia.FuncUI.DSL
open Avalonia.Layout

open Avalonia.FuncUI.LiveView

module Main =
    let view () =
        Component(fun ctx ->
            let state = ctx.useState 0

            DockPanel.create [
                DockPanel.children [
                    Button.create [
                        Button.dock Dock.Bottom
                        Button.onClick (fun _ -> state.Set(state.Current - 1))
                        Button.content "-"
                        Button.horizontalAlignment HorizontalAlignment.Stretch
                        Button.horizontalContentAlignment HorizontalAlignment.Center
                    ]
                    Button.create [
                        Button.dock Dock.Bottom
                        Button.onClick (fun _ -> state.Set(state.Current + 1))
                        Button.content "+"
                        Button.horizontalAlignment HorizontalAlignment.Stretch
                        Button.horizontalContentAlignment HorizontalAlignment.Center
                    ]
                    TextBlock.create [
                        TextBlock.dock Dock.Top
                        TextBlock.fontSize 48.0
                        TextBlock.verticalAlignment VerticalAlignment.Center
                        TextBlock.horizontalAlignment HorizontalAlignment.Center
                        TextBlock.text (string state.Current)
                    ]
                ]
            ])
    
    [<LivePreview>]
    let preview () = view()

type MainWindow() =
    inherit HostWindow()

    do
        base.Title <- "Counter Example"
        base.Content <- Main.view ()

type App() =
    inherit Application()

    override this.Initialize() =
        this.Styles.Add(FluentTheme())
        this.RequestedThemeVariant <- Styling.ThemeVariant.Dark

    override this.OnFrameworkInitializationCompleted() =
        match this.ApplicationLifetime with
        | :? IClassicDesktopStyleApplicationLifetime as desktopLifetime ->
            desktopLifetime.MainWindow <- MainWindow()
        | _ -> ()

#if DEBUG
        this.AttachDevTools()
#endif

#if !LIVEPREVIEW
module Program =

    [<EntryPoint>]
    let main (args: string[]) =
        AppBuilder
            .Configure<App>()
            .UsePlatformDetect()
            .UseSkia()
            .StartWithClassicDesktopLifetime(args)
#endif

Start the program and check if it works.

dotnet run --project ./src/YourFuncUIApp/YourFuncUIApp.fsproj

vscode settings

  • .vscode/launch.json
{
    "configurations": [
        {
            "name": "FuncUI Launch",
            "type": "coreclr",
            "request": "launch",
            "preLaunchTask": "build",
            "program": "${workspaceFolder}/src/YourFuncUIApp/bin/Debug/net7.0/YourFuncUIApp.dll",
            "args": [],
            "cwd": "${workspaceFolder}",
            "stopAtEntry": false,
            "console": "internalConsole"
        }
    ]
}
  • .vscode/tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "command": "dotnet",
            "type": "shell",
            "args": [
                "build",
            ],
            "problemMatcher": [
                "$msCompile"
            ],
            "group": "build"
        },
    ]
}
  • .vscode/settings.json
{
    "FSharp.enableAnalyzers": true
}

Now start the debugger and make sure it works.

First-Debug

When launched, proceed to the next step.

First-Debug-success

Setting up FuncUI Analyzer

Install Analyzer.

Note Installation of SilkyFowl.Avalonia.FuncUI.LiveView.Analyzer has changed since v0.0.3.

dotnet tool install SilkyFowl.Avalonia.FuncUI.LiveView.Analyzer --version 0.0.4-preview05 --tool-path analyzers

Check if FuncUI Analyzer works

  • FSharp.enableAnalyzers is true
  • Analyzer Dll exists in FSharp.analyzersPath.

With these conditions, editing the F# code recognized in the Solution Explorer of Ionide for F# will start the FuncUi Analyzer.

Active Analyzer

Warning You can analyze fsx scripts, etc. that are not recognized by the Solution Explorer, but you cannot start the FuncUi Analyzer.

fsx-in-explorer

there-is-no-fsx-in-fs-explorer

Setting up FuncUI LivePreview

Install LivePreview
dotnet tool install SilkyFowl.Avalonia.FuncUI.LiveView.Cli --version 0.0.4-preview05

Note Since v0.0.4, recommended to use SilkyFowl.Avalonia.FuncUI.LiveView.Cli from dotnet-tool, but you can also use SilkyFowl.Avalonia.FuncUI.LiveView liblary as it was before.

Check if LivePreview works
dotnet funcui-liveview
Startup settings

Although funcui-liveview requires you to select the project to be previewed, you can set following environment variables to automatically select the project at startup.

  • FUNCUI_LIVEVIEW_WATICHING_PROJECT_INFO_PATH...Path to the project file to be previewed.
  • FUNCUI_LIVEVIEW_WATICHING_PROJECT_INFO_TARGET_FRAMEWORK...TargetFramework of the project to be previewed.

For vscode, you can add task as follows:

        {
            "label": "start funcui-liveview",
            "type": "shell",
            "command": "dotnet",
            "args": [
                "funcui-liveview"
            ],
            "problemMatcher": [],
            "isBackground": true,
            "options": {
                "env": {
                    "FUNCUI_LIVEVIEW_WATICHING_PROJECT_INFO_PATH": "${workspaceFolder}/src/App/App.fsproj",
                    "FUNCUI_LIVEVIEW_WATICHING_PROJECT_INFO_TARGET_FRAMEWORK": "net7.0"
                }
            }
        },
        {
            "label": "watch App project",
            "type": "shell",
            "command": "dotnet",
            "args": [
                "watch",
                "build", // or "run" or "test", etc.
                "--project",
                "${workspaceFolder}/src/App/App.fsproj"
            ],
        },
        {
            "label": "start watch App project and funcui-liveview",
            "dependsOn": [
                "watch App project",
                "start funcui-liveview"
            ],
        }

Plan

→ SilkyFowl/Avalonia.FuncUI.LiveView#4

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last updated
0.0.4-preview05 300 3/10/2024
0.0.4-preview04 115 2/17/2024
0.0.4-preview03 140 2/12/2024
0.0.4-preview02 200 12/20/2023
0.0.4-preview01 412 11/3/2023

* Support FSharp.Analyzers.SDK 0.25.0.
* Support Avalonia.FuncUI 1.3.0.