krz/orgstar

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

Sources/Orgstar/EditorView.swift

85c633a83a4744bef9dde8b52462f9c2a1c037e4
orgstar/Sources/Orgstar/EditorView.swift history · blame · raw

64 lines · 2568 bytes

 1import AppKit
 2import OrgApp
 3import OrgCore
 4import OrgEditorAppKit
 5import SwiftUI
 6
 7/// The TextKit 2 editor for the session's file. A new file gets a new editor, which becomes the
 8/// session's buffer; reveal requests go to the existing one.
 9struct EditorView: NSViewRepresentable {
10    let session: DocumentSession
11    let commands: AppCommands
12    let keymap: Keymap
13    let optionAsMeta: OptionAsMeta
14    let onAppCommand: (String) -> Void
15
16    final class Coordinator {
17        var editor: OrgEditor?
18        var path: String?
19        var revealID = 0
20    }
21
22    func makeCoordinator() -> Coordinator { Coordinator() }
23
24    func makeNSView(context: Context) -> NSView {
25        NSView()
26    }
27
28    func updateNSView(_ container: NSView, context: Context) {
29        let coordinator = context.coordinator
30        if coordinator.path != session.path {
31            coordinator.path = session.path
32            container.subviews.forEach { $0.removeFromSuperview() }
33            coordinator.editor = nil
34            if let document = session.document {
35                let editor = OrgEditor(document: document, frame: container.bounds, editable: document.isEditable)
36                editor.onChange = { [weak session] in session?.bufferChanged() }
37                editor.onMessage = { [weak commands] in commands?.show($0) }
38                editor.onKeysPending = { [weak commands] keys, next in
39                    commands?.pendingKeys = keys
40                    commands?.keyHints = next.map { KeyHint(key: $0.key, title: $0.title) }
41                }
42                editor.onAppCommand = onAppCommand
43                editor.onPrompt = { [weak commands] prompt, reply in commands?.ask(prompt, reply: reply) }
44                commands.editor = editor
45                let scroll = editor.makeScrollView()
46                scroll.frame = container.bounds
47                scroll.autoresizingMask = [.width, .height]
48                container.addSubview(scroll)
49                container.window?.makeFirstResponder(editor.textView)
50                coordinator.editor = editor
51                session.attach(editor)
52            }
53        }
54        if let editor = coordinator.editor {
55            if editor.keymap != keymap { editor.keymap = keymap }
56            editor.optionAsMeta = optionAsMeta
57        }
58        container.window?.isDocumentEdited = session.isDirty
59        if let request = session.revealRequest, request.id != coordinator.revealID {
60            coordinator.revealID = request.id
61            coordinator.editor?.reveal(request.offset)
62        }
63    }
64}