Skip to content

Commit 3746b12

Browse files
committed
fix sync with Fesh.Rhino
1 parent 0207fec commit 3746b12

File tree

6 files changed

+96
-117
lines changed

6 files changed

+96
-117
lines changed

.github/workflows/build.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ jobs:
2222
dotnet-version: '9.x'
2323

2424
- name: Run dotnet build ForEditing
25-
run: dotnet build ForEditing.fsproj
25+
run: |
26+
dotnet build ForEditing.fsproj
2627
2728
- name: Run dotnet build ForPublishing
28-
run: dotnet build ForPublishing.fsproj
29+
# build target frameworks net48 and net7.0 separately to avoid race conditions in combineIntoOneFile.fsx
30+
run: |
31+
dotnet build ForPublishing.fsproj --framework net48
32+
dotnet build ForPublishing.fsproj --framework net7.0
2933

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
run: dotnet tool restore
3131

3232
- name: Build code to make xml file
33-
run: dotnet build ForPublishing.fsproj -c Release # see required xml tags: https://fsprojects.github.io/FSharp.Formatting/zero-to-hero.html#Generating-API-documentation
33+
run: dotnet build ForPublishing.fsproj -c Release --framework net48 # see required xml tags: https://fsprojects.github.io/FSharp.Formatting/zero-to-hero.html#Generating-API-documentation
3434

3535
- name: copy README.md to Docs/index.md
3636
run: cp README.md Docs/index.md

.github/workflows/release-nuget.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ jobs:
2525
Set-Content -Path README.md -Value $content
2626
2727
- name: dotnet build
28-
run: dotnet build ForPublishing.fsproj --configuration Release
28+
# build target frameworks net48 and net7.0 separately to avoid race conditions in combineIntoOneFile.fsx
29+
run: |
30+
dotnet build ForPublishing.fsproj -c Release
2931
3032
- name: Check version consistency of git tag and CHANGELOG.md
3133
# needs in fsproj:

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
98
## [Unreleased]
109

10+
## [0.12.0] - 2025-05-25
11+
### Fixed
12+
- fix sync with Fesh.Rhino 0.27.4
13+
1114
## [0.11.0] - 2025-05-24
1215
### Added
1316
- build for net7.0 too

Src/Pretty.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ module PrettySetup =
122122
"-Guid.Empty-"
123123
elif Runtime.HostUtils.RunningInRhino then // because Rhino.Scripting might be referenced from outside of Rhino too
124124
let o = State.Doc.Objects.FindId(g)
125-
if isNull o then sprintf "Guid %O (not in State.Doc.Objects table of this Rhino file)." g
125+
if isNull o then sprintf "Guid %O (not in RhinoDoc.Objects table of this Rhino file)." g
126126
else
127127
let name = o.Attributes.Name // null if unset
128128
if String.IsNullOrWhiteSpace name then

Src/RhinoSync.fs

Lines changed: 81 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -15,87 +15,53 @@ type internal RunOnUiDelegate = delegate of unit -> unit
1515
[<AbstractClass>]
1616
[<Sealed>] //use these attributes to match C# static class and make in visible in C# // https://stackoverflow.com/questions/13101995/defining-static-classes-in-f
1717
type RhinoSync private () =
18+
static let mutable logErrors = true
1819

1920
static let mutable feshRhinoSyncModule:Type = null
2021

2122
static let mutable syncContext: Threading.SynchronizationContext = null //set via reflection below ; from Fesh.Rhino
2223

2324
static let mutable feshRhAssembly : Reflection.Assembly = null //set via reflection below ; from Fesh.Rhino
2425

25-
static let mutable hideEditor : Action = null //set via reflection below ; from Fesh.Rhino
26-
27-
static let mutable showEditor : Action = null //set via reflection below ; from Fesh.Rhino
26+
static let mutable hideEditor = Action(fun ()->()) //set via reflection below ; from Fesh.Rhino
2827

29-
static let mutable isEditorVisible : Func<bool> = null //set via reflection below ; from Fesh.Rhino
28+
static let mutable showEditor = Action(fun ()->()) //set via reflection below ; from Fesh.Rhino
3029

31-
static let mutable logErrors = true
32-
33-
static let mutable prettyFormatters: ResizeArray<obj -> option<string>> = null
30+
static let mutable isEditorVisible = new Func<bool>(fun () -> false) //set via reflection below ; from Fesh.Rhino
3431

3532
/// Red green blue text
36-
static let mutable printColor : int * int * int * string -> unit= //changed via reflection below from Fesh.Rhino
37-
fun (_,_,_, s) -> Console.Write s
33+
static let mutable printFeshLogColor = //changed via reflection below from Fesh.Rhino
34+
new Action<int,int,int,string>(fun r g b s -> Console.Write s)
3835

3936
/// Red green blue text
40-
static let mutable printNewLineColor : int * int * int * string -> unit = //changed via reflection below from Fesh.Rhino
41-
fun (_,_,_, s) -> Console.WriteLine s
37+
static let mutable printnFeshLogColor = //changed via reflection below from Fesh.Rhino
38+
new Action<int,int,int,string>(fun r g b s -> Console.WriteLine s)
4239

43-
static let mutable clear : unit -> unit = // changed via reflection below from Fesh
44-
fun () -> ()
45-
46-
static let initFeshPrint() =
47-
let allAss = AppDomain.CurrentDomain.GetAssemblies()
48-
match allAss |> Array.tryFind (fun a -> a.GetName().Name = "Fesh") with
49-
| Some feshAssembly ->
50-
try
51-
let printModule = feshAssembly.GetType "Fesh.Model.IFeshLogModule"
52-
if notNull printModule then
53-
let cl = printModule.GetProperty("clear").GetValue(feshAssembly)
54-
if notNull cl then
55-
let clt = cl :?> unit -> unit
56-
clear <- clt
57-
58-
try
59-
let pc = printModule.GetProperty( "printColorTupled" ).GetValue(feshAssembly)
60-
if notNull pc then
61-
let pct = pc :?> int * int * int * string -> unit
62-
printColor <- pct
63-
64-
let pnc = printModule.GetProperty("printnColorTupled").GetValue(feshAssembly)
65-
if notNull pnc then
66-
let pct = pnc :?> int * int * int * string -> unit
67-
printNewLineColor <- pct
68-
69-
with ex ->
70-
eprintfn "The Fesh.Model.IFeshLogModule.clear was found but printColorTupled failed. The Error was: %A" ex
71-
72-
with ex ->
73-
eprintfn "The Fesh was found but setting up color printing failed. The Error was: %A" ex
74-
|None -> ()
75-
76-
match allAss |> Array.tryFind (fun a -> a.GetName().Name = "Pretty") with
77-
| Some prettyAssembly ->
78-
try
79-
let prettySettings = prettyAssembly.GetType "Pretty.PrettySettings"
80-
if notNull prettySettings then
81-
let formatters = prettySettings.GetProperty("Formatters").GetValue(prettyAssembly) :?> ResizeArray<obj -> option<string>>
82-
if notNull formatters then
83-
prettyFormatters <- formatters
84-
85-
86-
with ex ->
87-
eprintfn "An Assembly 'Pretty' was found but setting up color printing failed. The Error was: %A" ex
88-
|None -> ()
40+
static let mutable clearFeshLog = Action(fun ()->()) // changed via reflection below from Fesh
8941

42+
static let mutable prettyFormatters: ResizeArray<obj -> option<string>> = null
9043

44+
// static let initFeshPrint() =
45+
// let allAss = AppDomain.CurrentDomain.GetAssemblies()
46+
// match allAss |> Array.tryFind (fun a -> a.GetName().Name = "Pretty") with
47+
// | Some prettyAssembly ->
48+
// try
49+
// let prettySettings = prettyAssembly.GetType "Pretty.PrettySettings"
50+
// if notNull prettySettings then
51+
// let formatters = prettySettings.GetProperty("Formatters").GetValue(prettyAssembly) :?> ResizeArray<obj -> option<string>>
52+
// if notNull formatters then
53+
// prettyFormatters <- formatters
54+
// with ex ->
55+
// eprintfn "An Assembly 'Pretty' was found but setting up color printing failed. The Error was: %A" ex
56+
// |None -> ()
9157

9258

9359
static let log msg = Printf.kprintf(fun s -> if logErrors then (RhinoApp.WriteLine s ; eprintfn "%s" s)) msg
9460

9561
static let mutable initIsPending = true
9662

9763
//only called when actually needed in DoSync methods below.
98-
static let init() =
64+
static let initSync() =
9965
initIsPending <- false
10066
if isNull feshRhAssembly then
10167
// it s ok to log errors here since we check 'if notNull feshRh then'
@@ -107,47 +73,39 @@ type RhinoSync private () =
10773
if notNull feshRh then
10874
feshRhAssembly <- feshRh.Assembly
10975
feshRhinoSyncModule <- feshRhAssembly.GetType "Fesh.Rhino.Sync"
110-
initFeshPrint()
11176
with e ->
11277
log "Rhino.Scripting.dll could not get feshRhinoSyncModule from Fesh Assembly via Reflection: %A" e
11378

11479
if notNull feshRhinoSyncModule then
11580
// it s ok to log errors here since feshRhinoSyncModule is not null and we expect to find those all:
116-
try
117-
hideEditor <- feshRhinoSyncModule.GetProperty("hideEditor").GetValue(feshRhAssembly) :?> Action
118-
//if isNull hideEditor then
119-
//log "Rhino.Scripting.dll: Fesh.Rhino.Sync.hideEditor is null" // null is expected when the Fesh plugin is loaded but the editor is not running.
120-
with e ->
121-
log "Rhino.Scripting.dll: Fesh.Rhino.Sync.hideEditor failed with: %O" e
81+
try hideEditor <- feshRhinoSyncModule.GetProperty("hideEditor").GetValue(feshRhAssembly) :?> Action
82+
with e -> log "Rhino.Scripting.dll: loading Fesh.Rhino.Sync.hideEditor via reflection failed with: %O" e
12283

123-
try
124-
showEditor <- feshRhinoSyncModule.GetProperty("showEditor").GetValue(feshRhAssembly) :?> Action
125-
// if isNull showEditor then
126-
// log "Rhino.Scripting.dll: Fesh.Rhino.Sync showEditor is null" // null is expected when the Fesh plugin is loaded but the editor is not running.
127-
with e ->
128-
log "Rhino.Scripting.dll: Fesh.Rhino.Sync.showEditor failed with: %O" e
84+
try showEditor <- feshRhinoSyncModule.GetProperty("showEditor").GetValue(feshRhAssembly) :?> Action
85+
with e -> log "Rhino.Scripting.dll: loading Fesh.Rhino.Sync.showEditor via reflection failed with: %O" e
12986

130-
try
131-
isEditorVisible <- feshRhinoSyncModule.GetProperty("isEditorVisible").GetValue(feshRhAssembly) :?> Func<bool>
132-
//if isNull isEditorVisible then
133-
// log "Rhino.Scripting.dll: Fesh.Rhino.Sync isEditorVisible is null" // null is expected when the Fesh plugin is loaded but the editor is not running.
134-
with e ->
135-
log "Rhino.Scripting.dll: Fesh.Rhino.Sync.isEditorVisible failed with: %O" e
87+
try isEditorVisible <- feshRhinoSyncModule.GetProperty("isEditorVisible").GetValue(feshRhAssembly) :?> Func<bool>
88+
with e -> log "Rhino.Scripting.dll: loading Fesh.Rhino.Sync.isEditorVisible via reflection failed with: %O" e
13689

137-
try
138-
syncContext <- feshRhinoSyncModule.GetProperty("syncContext").GetValue(feshRhAssembly) :?> Threading.SynchronizationContext
139-
//if isNull syncContext then
140-
//log "Rhino.Scripting.dll: Fesh.Rhino.Sync.syncContext is null"// null is expected when the Fesh plugin is loaded but the editor is not running.
90+
try syncContext <- feshRhinoSyncModule.GetProperty("syncContext").GetValue(feshRhAssembly) :?> Threading.SynchronizationContext
91+
with e -> log "Rhino.Scripting.dll: loading Fesh.Rhino.Sync.syncContext via reflection failed with: %O" e
14192

142-
with e ->
143-
log "Rhino.Scripting.dll: Fesh.Rhino.Sync.syncContext failed with: %O" e
93+
try printFeshLogColor <- feshRhinoSyncModule.GetProperty("printFeshLogColor").GetValue(feshRhAssembly) :?> Action<int,int,int,string>
94+
with e -> log "Rhino.Scripting.dll: loading Fesh.Rhino.Sync.printFeshLogColor via reflection failed with: %O" e
95+
96+
try printnFeshLogColor <- feshRhinoSyncModule.GetProperty("printnFeshLogColor").GetValue(feshRhAssembly) :?> Action<int,int,int,string>
97+
with e -> log "Rhino.Scripting.dll: loading Fesh.Rhino.Sync.printnFeshLogColor via reflection failed with: %O" e
98+
99+
try clearFeshLog <- feshRhinoSyncModule.GetProperty("clearFeshLog").GetValue(feshRhAssembly) :?> Action
100+
with e -> log "Rhino.Scripting.dll: loading Fesh.Rhino.Sync.clearFeshLog via reflection failed with: %O" e
144101

145102
else
146103
// Fesh syncContext not found via reflection,
147104
// The code is not used from within Fesh.Rhino plugin
148105
// let just use AsyncInvoke from Eto.Forms.Application
149106
// https://pages.picoe.ca/docs/api/html/M_Eto_Forms_Application_AsyncInvoke.htm#!
150-
syncContext <- null
107+
// syncContext <- null
108+
syncContext <- Threading.SynchronizationContext.Current
151109

152110
//
153111
// // try to get just the sync context from Windows form ( that works on Mac.Mono) (WPF is not anymore referenced by this project)
@@ -162,7 +120,7 @@ type RhinoSync private () =
162120
// should be called via reflection from Fesh.Rhino in case Rhino.Scripting is loaded already by another plugin.
163121
// Reinitialize Rhino.Scripting just in case it is loaded already in the current AppDomain:
164122
// to have showEditor and hideEditor actions setup correctly.
165-
new Action(init)
123+
new Action(initSync)
166124

167125

168126
// An alternative to do! Async.SwitchToContext syncContext
@@ -187,59 +145,63 @@ type RhinoSync private () =
187145
/// Set to false to disable the logging off errors to
188146
/// RhinoApp.WriteLine and the error stream (eprintfn).
189147
static member LogErrors
190-
with get() = logErrors
191-
and set v = logErrors <- v
148+
with get() : bool = logErrors
149+
and set v : unit = logErrors <- v
192150

193151
/// The SynchronizationContext of the currently Running Rhino Instance,
194152
/// This SynchronizationContext is loaded via reflection from the Fesh.Rhino plugin
195153
static member SyncContext
196-
with get() =
154+
with get() : Threading.SynchronizationContext =
197155
if isNull syncContext then
198-
initialize.Invoke() // init()
156+
initialize.Invoke() // this is the same as init()
199157
syncContext
200-
and set v =
158+
and set v : unit =
201159
syncContext <- v
202160

203161
/// Hide the WPF Window of currently running Fesh Editor.
204162
/// Or do nothing if not running in Fesh Editor.
205-
static member HideEditor() = if notNull hideEditor then hideEditor.Invoke()
163+
static member HideEditor() = hideEditor.Invoke() //Action
206164

207165
/// Show the WPF Window of currently running Fesh Editor.
208166
/// Or do nothing if not running in Fesh Editor.
209-
static member ShowEditor() = if notNull showEditor then showEditor.Invoke()
167+
static member ShowEditor() = showEditor.Invoke() //Action
210168

211169
// The Assembly currently running Fesh Editor Window.
212170
// Or 'null' if not running in Fesh Editor.
213171
// static member FeshRhinoAssembly :Reflection.Assembly = feshRhAssembly
214172

215173
//static member Initialize() = init() // not called in ActiveDocument module anymore , only called when actually needed in DoSync methods below.
216-
static member PrettyFormatters = prettyFormatters
174+
175+
176+
/// This is a collection of pretty formatters that the libray Pretty is using if present. Needs to be set via reflection !!
177+
static member PrettyFormatters : ResizeArray<obj -> option<string>> =
178+
prettyFormatters
217179

218180
/// Prints in both RhinoApp.WriteLine and Console.WriteLine, or Fesh Editor with color if running.
219181
/// Red green blue text , NO new line
220182
static member PrintColor r g b s =
221-
printColor (r, g, b, s)
183+
printFeshLogColor.Invoke(r, g, b, s)
222184
RhinoApp.Write s
223185
RhinoApp.Wait()
224186

225187
/// Prints in both RhinoApp.WriteLine and Console.WriteLine, or Fesh Editor with color if running.
226188
/// Red green blue text , with new line
227189
static member PrintnColor r g b s =
228-
printNewLineColor (r, g, b, s)
190+
printnFeshLogColor.Invoke(r, g, b, s)
229191
RhinoApp.WriteLine s
230192
RhinoApp.Wait()
231193

232194
/// Clears the Fesh log window
233195
/// and the Rhino command history window.
234196
static member ClearLog() =
235-
clear()
197+
clearFeshLog.Invoke() //Action
236198
RhinoApp.ClearCommandHistoryWindow()
237199
RhinoApp.Wait()
238200

239201
/// Evaluates a function on UI Thread.
240202
static member DoSync (func:unit->'T) : 'T =
241203
if RhinoApp.InvokeRequired then
242-
if initIsPending then init()
204+
if initIsPending then initSync()
243205
if isNull syncContext then
244206
Eto.Forms.Application.Instance.Invoke func
245207

@@ -262,7 +224,7 @@ type RhinoSync private () =
262224
static member DoSyncRedraw (func:unit->'T) : 'T =
263225
let redraw = RhinoDoc.ActiveDoc.Views.RedrawEnabled
264226
if RhinoApp.InvokeRequired then
265-
if initIsPending then init()
227+
if initIsPending then initSync()
266228
if isNull syncContext then
267229
Eto.Forms.Application.Instance.Invoke func
268230

@@ -291,7 +253,7 @@ type RhinoSync private () =
291253
let redraw = RhinoDoc.ActiveDoc.Views.RedrawEnabled
292254

293255
if RhinoApp.InvokeRequired then
294-
if initIsPending then init() // do first
256+
if initIsPending then initSync() // do first
295257
if isNull syncContext then
296258
Eto.Forms.Application.Instance.Invoke func
297259

@@ -303,23 +265,31 @@ type RhinoSync private () =
303265
else
304266
async{
305267
do! Async.SwitchToContext syncContext
306-
let isWinVis = if isNull isEditorVisible then false else isEditorVisible.Invoke() // do after init
268+
let isWinVis = isEditorVisible.Invoke() // do after init
307269
//eprintfn "Hiding Fesh async..isWinVis:%b" isWinVis
308-
if isWinVis && notNull hideEditor then hideEditor.Invoke()
309-
if not redraw then RhinoDoc.ActiveDoc.Views.RedrawEnabled <- true
310-
RhinoApp.SetFocusToMainWindow()
270+
if isWinVis then
271+
hideEditor.Invoke() //Action
272+
if not redraw then
273+
RhinoDoc.ActiveDoc.Views.RedrawEnabled <- true
274+
RhinoApp.SetFocusToMainWindow() //Action
311275
let res = func()
312-
if not redraw then RhinoDoc.ActiveDoc.Views.RedrawEnabled <- false
313-
if isWinVis && notNull showEditor then showEditor.Invoke()
276+
if not redraw then
277+
RhinoDoc.ActiveDoc.Views.RedrawEnabled <- false
278+
if isWinVis then
279+
showEditor.Invoke() //Action
314280
return res
315281
} |> Async.RunSynchronously
316282
else
317-
if initIsPending then init() // because even when we are in sync we still need to see if the Fesh window is showing or not.
318-
let isWinVis = if isNull isEditorVisible then false else isEditorVisible.Invoke() // do after init
283+
if initIsPending then initSync() // because even when we are in sync we still need to see if the Fesh window is showing or not.
284+
let isWinVis = isEditorVisible.Invoke() // do after init
319285
//eprintfn "Hiding Fesh sync..isWinVis:%b" isWinVis
320-
if isWinVis && notNull hideEditor then hideEditor.Invoke()
321-
if not redraw then RhinoDoc.ActiveDoc.Views.RedrawEnabled <- true
286+
if isWinVis then
287+
hideEditor.Invoke() //Action
288+
if not redraw then
289+
RhinoDoc.ActiveDoc.Views.RedrawEnabled <- true
322290
let res = func()
323-
if not redraw then RhinoDoc.ActiveDoc.Views.RedrawEnabled <- false
324-
if isWinVis && notNull showEditor then showEditor.Invoke()
291+
if not redraw then
292+
RhinoDoc.ActiveDoc.Views.RedrawEnabled <- false
293+
if isWinVis then
294+
showEditor.Invoke() //Action
325295
res

0 commit comments

Comments
 (0)