krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Commit bd76bdbef0

bd76bdbef02dcaa96435b05ce2586c024c56b478

parent: 0cfdac07f7

Verified · cmc

cmc <hello@cleberg.net> · 2026-10-05 20:40 UTC

Fix crash in short windows

The outline pane's HSplitView inside the window's NavigationSplitView
looped on size constraints when the window was short (820×172 after
tiling) and AppKit raised NSGenericException at launch. The pane now
has a set width with a drag divider (160–400 pt, remembered).

Layout: unified · split

Sources/Orgstar/ContentView.swift +29 −3
@@ -44,6 +44,7 @@ struct ContentView: View {
44 /// A file that isn't text, shown as a preview instead of the open document. 44 /// A file that isn't text, shown as a preview instead of the open document.
45 @State private var previewPath: String? 45 @State private var previewPath: String?
46 @AppStorage("outlineShown") private var orgOutlineShown = true 46 @AppStorage("outlineShown") private var orgOutlineShown = true
47 @AppStorage("outlineWidth") private var outlineWidth = 220.0
47 @AppStorage("showMarkup") private var showMarkup = false 48 @AppStorage("showMarkup") private var showMarkup = false
48 @AppStorage("showLineNumbers") private var showLineNumbers = true 49 @AppStorage("showLineNumbers") private var showLineNumbers = true
49 @AppStorage("themeFont") private var themeFont = "" 50 @AppStorage("themeFont") private var themeFont = ""
@@ -136,7 +137,7 @@ struct ContentView: View {
136 Sidebar(workspace: workspace, session: session, selection: $selectedFile) { commands.showingFolderPicker = true } 137 Sidebar(workspace: workspace, session: session, selection: $selectedFile) { commands.showingFolderPicker = true }
137 .navigationSplitViewColumnWidth(min: 200, ideal: 260) 138 .navigationSplitViewColumnWidth(min: 200, ideal: 260)
138 } detail: { 139 } detail: {
139 HSplitView { 140 HStack(spacing: 0) {
140 if outlineShown { 141 if outlineShown {
141 Group { 142 Group {
142 if query.isEmpty { 143 if query.isEmpty {
@@ -149,10 +150,11 @@ struct ContentView: View {
149 } 150 }
150 } 151 }
151 } 152 }
152 .frame(minWidth: 160, idealWidth: 220, maxWidth: 360) 153 .frame(width: CGFloat(outlineWidth))
154 PaneDivider(width: $outlineWidth, range: 160...400)
153 } 155 }
154 detail 156 detail
155 .frame(minWidth: 300, maxWidth: .infinity) 157 .frame(maxWidth: .infinity)
156 } 158 }
157 } 159 }
158 .navigationTitle((previewPath ?? session.path).map { ($0 as NSString).lastPathComponent } ?? "Orgstar") 160 .navigationTitle((previewPath ?? session.path).map { ($0 as NSString).lastPathComponent } ?? "Orgstar")
@@ -642,3 +644,27 @@ struct QuickOpenView: View {
642 .onExitCommand { dismiss() } 644 .onExitCommand { dismiss() }
643 } 645 }
644} 646}
647
648/// A divider that resizes the pane before it by dragging. An `HSplitView` inside the window's
649/// split view loops on its size constraints in short windows, so this sets a width instead.
650struct PaneDivider: View {
651 @Binding var width: Double
652 let range: ClosedRange<Double>
653 @State private var start: Double?
654
655 var body: some View {
656 Rectangle()
657 .fill(Color(nsColor: .separatorColor))
658 .frame(width: 1)
659 .frame(maxHeight: .infinity)
660 .overlay(Color.clear.frame(width: 7).contentShape(Rectangle()).onHover { inside in
661 if inside { NSCursor.resizeLeftRight.push() } else { NSCursor.pop() }
662 }
663 .gesture(DragGesture(minimumDistance: 1).onChanged { drag in
664 let base = start ?? width
665 start = base
666 width = min(max(base + drag.translation.width, range.lowerBound), range.upperBound)
667 }.onEnded { _ in start = nil }))
668 .accessibilityHidden(true)
669 }
670}