Commit 8847b010a7
Verified · cmc
Layout: unified · split
Sources/Orgstar/ContentView.swift +10 −1
| @@ -12,6 +12,14 @@ struct ContentView: View { | |||
| 12 | @AppStorage("keymap") private var preset = KeymapPreset.emacs | 12 | @AppStorage("keymap") private var preset = KeymapPreset.emacs |
| 13 | @AppStorage("optionAsMeta") private var optionAsMeta = OptionAsMeta.left.rawValue | 13 | @AppStorage("optionAsMeta") private var optionAsMeta = OptionAsMeta.left.rawValue |
| 14 | @State private var keymap = KeymapPreset.emacs.keymap | 14 | @State private var keymap = KeymapPreset.emacs.keymap |
| 15 | @AppStorage("tagsColumn") private var tagsColumn = -77 | ||
| 16 | @AppStorage("headingAfterSubtree") private var headingAfterSubtree = true | ||
| 17 | @AppStorage("splitLine") private var splitLine = false | ||
| 18 | @AppStorage("alphabeticalLists") private var alphabeticalLists = true | ||
| 19 | |||
| 20 | private var options: EditingOptions { | ||
| 21 | Preferences.options(tagsColumn: tagsColumn, headingAfterSubtree: headingAfterSubtree, splitLine: splitLine, alphabeticalLists: alphabeticalLists) | ||
| 22 | } | ||
| 15 | @State private var selectedFile: String? | 23 | @State private var selectedFile: String? |
| 16 | @State private var query = "" | 24 | @State private var query = "" |
| 17 | @FocusState private var searchFocused: Bool | 25 | @FocusState private var searchFocused: Bool |
| @@ -35,7 +43,7 @@ struct ContentView: View { | |||
| 35 | .navigationSplitViewColumnWidth(min: 160, ideal: 220, max: 360) | 43 | .navigationSplitViewColumnWidth(min: 160, ideal: 220, max: 360) |
| 36 | } detail: { | 44 | } detail: { |
| 37 | if session.path != nil { | 45 | if session.path != nil { |
| 38 | EditorView(session: session, commands: commands, keymap: keymap, optionAsMeta: OptionAsMeta(rawValue: optionAsMeta), onAppCommand: perform) | 46 | EditorView(session: session, commands: commands, keymap: keymap, optionAsMeta: OptionAsMeta(rawValue: optionAsMeta), options: options, onAppCommand: perform) |
| 39 | .safeAreaInset(edge: .bottom, spacing: 0) { EchoArea(commands: commands) } | 47 | .safeAreaInset(edge: .bottom, spacing: 0) { EchoArea(commands: commands) } |
| 40 | } else { | 48 | } else { |
| 41 | ContentUnavailableView( | 49 | ContentUnavailableView( |
| @@ -65,6 +73,7 @@ struct ContentView: View { | |||
| 65 | } | 73 | } |
| 66 | } | 74 | } |
| 67 | .onChange(of: saveMode, initial: true) { _, mode in session.saveMode = mode } | 75 | .onChange(of: saveMode, initial: true) { _, mode in session.saveMode = mode } |
| 76 | .onChange(of: options, initial: true) { _, options in session.options = options } | ||
| 68 | .onChange(of: preset, initial: true) { loadKeymap() } | 77 | .onChange(of: preset, initial: true) { loadKeymap() } |
| 69 | .sheet(isPresented: $commands.showingPalette) { | 78 | .sheet(isPresented: $commands.showingPalette) { |
| 70 | PaletteView(keymap: keymap) { id in | 79 | PaletteView(keymap: keymap) { id in |
Sources/Orgstar/EditorView.swift +2
| @@ -11,6 +11,7 @@ struct EditorView: NSViewRepresentable { | |||
| 11 | let commands: AppCommands | 11 | let commands: AppCommands |
| 12 | let keymap: Keymap | 12 | let keymap: Keymap |
| 13 | let optionAsMeta: OptionAsMeta | 13 | let optionAsMeta: OptionAsMeta |
| 14 | let options: EditingOptions | ||
| 14 | let onAppCommand: (String) -> Void | 15 | let onAppCommand: (String) -> Void |
| 15 | 16 | ||
| 16 | final class Coordinator { | 17 | final class Coordinator { |
| @@ -54,6 +55,7 @@ struct EditorView: NSViewRepresentable { | |||
| 54 | if let editor = coordinator.editor { | 55 | if let editor = coordinator.editor { |
| 55 | if editor.keymap != keymap { editor.keymap = keymap } | 56 | if editor.keymap != keymap { editor.keymap = keymap } |
| 56 | editor.optionAsMeta = optionAsMeta | 57 | editor.optionAsMeta = optionAsMeta |
| 58 | editor.options = options | ||
| 57 | } | 59 | } |
| 58 | container.window?.isDocumentEdited = session.isDirty | 60 | container.window?.isDocumentEdited = session.isDirty |
| 59 | if let request = session.revealRequest, request.id != coordinator.revealID { | 61 | if let request = session.revealRequest, request.id != coordinator.revealID { |
Sources/Orgstar/OrgstarApp.swift +26 −3
| @@ -90,9 +90,15 @@ enum UnsavedChanges { | |||
| 90 | @main | 90 | @main |
| 91 | struct OrgstarApp: App { | 91 | struct OrgstarApp: App { |
| 92 | @NSApplicationDelegateAdaptor private var delegate: AppDelegate | 92 | @NSApplicationDelegateAdaptor private var delegate: AppDelegate |
| 93 | @State private var workspace = Result { try WorkspaceModel(directory: WorkspaceModel.defaultDirectory) } | 93 | @State private var workspace = Result { |
| 94 | try WorkspaceModel(directory: WorkspaceModel.defaultDirectory, settings: .with(todoKeywords: Preferences.orgSettings)) | ||
| 95 | } | ||
| 94 | @State private var commands = AppCommands() | 96 | @State private var commands = AppCommands() |
| 95 | @State private var session = DocumentSession() | 97 | @State private var session: DocumentSession = { |
| 98 | let session = DocumentSession() | ||
| 99 | session.defaults = Preferences.orgSettings | ||
| 100 | return session | ||
| 101 | }() | ||
| 96 | 102 | ||
| 97 | var body: some Scene { | 103 | var body: some Scene { |
| 98 | Window("Orgstar", id: "main") { | 104 | Window("Orgstar", id: "main") { |
| @@ -144,6 +150,11 @@ struct SettingsView: View { | |||
| 144 | @AppStorage("saveMode") private var saveMode = SaveMode.automatic | 150 | @AppStorage("saveMode") private var saveMode = SaveMode.automatic |
| 145 | @AppStorage("keymap") private var preset = KeymapPreset.emacs | 151 | @AppStorage("keymap") private var preset = KeymapPreset.emacs |
| 146 | @AppStorage("optionAsMeta") private var optionAsMeta = OptionAsMeta.left.rawValue | 152 | @AppStorage("optionAsMeta") private var optionAsMeta = OptionAsMeta.left.rawValue |
| 153 | @AppStorage("tagsColumn") private var tagsColumn = -77 | ||
| 154 | @AppStorage("headingAfterSubtree") private var headingAfterSubtree = true | ||
| 155 | @AppStorage("splitLine") private var splitLine = false | ||
| 156 | @AppStorage("alphabeticalLists") private var alphabeticalLists = true | ||
| 157 | @AppStorage("todoKeywords") private var todoKeywords = Preferences.defaultTodoKeywords | ||
| 147 | 158 | ||
| 148 | var body: some View { | 159 | var body: some View { |
| 149 | Form { | 160 | Form { |
| @@ -165,8 +176,20 @@ struct SettingsView: View { | |||
| 165 | .font(.caption) | 176 | .font(.caption) |
| 166 | .foregroundStyle(.secondary) | 177 | .foregroundStyle(.secondary) |
| 167 | .textSelection(.enabled) | 178 | .textSelection(.enabled) |
| 179 | Divider() | ||
| 180 | Picker("Tags:", selection: $tagsColumn) { | ||
| 181 | Text("Aligned to end at column 77").tag(-77) | ||
| 182 | Text("One space after the title").tag(0) | ||
| 183 | } | ||
| 184 | Toggle("M-RET adds the new heading after the subtree", isOn: $headingAfterSubtree) | ||
| 185 | Toggle("M-RET splits the line at the caret", isOn: $splitLine) | ||
| 186 | Toggle("Lists can use letters (a. b. c.)", isOn: $alphabeticalLists) | ||
| 187 | TextField("Default TODO keywords:", text: $todoKeywords) | ||
| 188 | Text("For files without #+TODO, in #+TODO syntax. Takes effect when Orgstar restarts.") | ||
| 189 | .font(.caption) | ||
| 190 | .foregroundStyle(.secondary) | ||
| 168 | } | 191 | } |
| 169 | .padding(20) | 192 | .padding(20) |
| 170 | .frame(width: 420) | 193 | .frame(width: 480) |
| 171 | } | 194 | } |
| 172 | } | 195 | } |
Sources/Orgstar/Preferences.swift added +20
| @@ -0,0 +1,20 @@ | |||
| 1 | import Foundation | ||
| 2 | import OrgCore | ||
| 3 | |||
| 4 | /// Org preferences, stored in user defaults by the Settings window. | ||
| 5 | enum Preferences { | ||
| 6 | static let defaultTodoKeywords = "TODO PROJ LOOP STRT WAIT HOLD IDEA | DONE KILL" | ||
| 7 | |||
| 8 | /// TODO keywords for files without `#+TODO`, read at launch. | ||
| 9 | static var orgSettings: OrgSettings { | ||
| 10 | let line = UserDefaults.standard.string(forKey: "todoKeywords") ?? defaultTodoKeywords | ||
| 11 | return OrgSettings.default.withTodoKeywords(line) ?? .default | ||
| 12 | } | ||
| 13 | |||
| 14 | static func options(tagsColumn: Int, headingAfterSubtree: Bool, splitLine: Bool, alphabeticalLists: Bool) -> EditingOptions { | ||
| 15 | EditingOptions( | ||
| 16 | tagsColumn: tagsColumn, insertHeadingRespectContent: headingAfterSubtree, | ||
| 17 | metaReturnMaySplitLine: splitLine, listAllowAlphabetical: alphabeticalLists | ||
| 18 | ) | ||
| 19 | } | ||
| 20 | } | ||