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 {
4444 /// A file that isn't text, shown as a preview instead of the open document.
4545 @State private var previewPath: String?
4646 @AppStorage("outlineShown") private var orgOutlineShown = true
47 @AppStorage("outlineWidth") private var outlineWidth = 220.0
4748 @AppStorage("showMarkup") private var showMarkup = false
4849 @AppStorage("showLineNumbers") private var showLineNumbers = true
4950 @AppStorage("themeFont") private var themeFont = ""
@@ -136,7 +137,7 @@ struct ContentView: View {
136137 Sidebar(workspace: workspace, session: session, selection: $selectedFile) { commands.showingFolderPicker = true }
137138 .navigationSplitViewColumnWidth(min: 200, ideal: 260)
138139 } detail: {
139 HSplitView {
140 HStack(spacing: 0) {
140141 if outlineShown {
141142 Group {
142143 if query.isEmpty {
@@ -149,10 +150,11 @@ struct ContentView: View {
149150 }
150151 }
151152 }
152 .frame(minWidth: 160, idealWidth: 220, maxWidth: 360)
153 .frame(width: CGFloat(outlineWidth))
154 PaneDivider(width: $outlineWidth, range: 160...400)
153155 }
154156 detail
155 .frame(minWidth: 300, maxWidth: .infinity)
157 .frame(maxWidth: .infinity)
156158 }
157159 }
158160 .navigationTitle((previewPath ?? session.path).map { ($0 as NSString).lastPathComponent } ?? "Orgstar")
@@ -642,3 +644,27 @@ struct QuickOpenView: View {
642644 .onExitCommand { dismiss() }
643645 }
644646}
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}