Sources/Orgstar/EditorView.swift
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}