import SwiftUI import ObjectiveC.runtime #if canImport(FoundationModels) import FoundationModels #endif #if os(macOS) import AppKit #endif #if os(iOS) import UIKit #endif /// MARK: - Types private var runtimeLanguageBundleAssociationKey: UInt8 = 0 private final class RuntimeLanguageBundle: Bundle, @unchecked Sendable { override func localizedString(forKey key: String, value: String?, table tableName: String?) -> String { if let languageBundle = objc_getAssociatedObject(self, &runtimeLanguageBundleAssociationKey) as? Bundle { return languageBundle.localizedString(forKey: key, value: value, table: tableName) } return super.localizedString(forKey: key, value: value, table: tableName) } } private enum RuntimeLanguageOverride { private static var didInstallBundleOverride = false static func apply(languageCode: String) { installBundleOverrideIfNeeded() let bundle = languageBundle(for: languageCode) objc_setAssociatedObject( Bundle.main, &runtimeLanguageBundleAssociationKey, bundle, .OBJC_ASSOCIATION_RETAIN_NONATOMIC ) } private static func installBundleOverrideIfNeeded() { guard !didInstallBundleOverride else { return } object_setClass(Bundle.main, RuntimeLanguageBundle.self) didInstallBundleOverride = true } private static func languageBundle(for languageCode: String) -> Bundle? { guard languageCode != "system" else { return nil } if let exact = Bundle.main.path(forResource: languageCode, ofType: "lproj").flatMap(Bundle.init(path:)) { return exact } let fallbackCode = languageCode.split(separator: "-").first.map(String.init) ?? languageCode return Bundle.main.path(forResource: fallbackCode, ofType: "lproj").flatMap(Bundle.init(path:)) } } #if os(macOS) final class AppDelegate: NSObject, NSApplicationDelegate { weak var viewModel: EditorViewModel? { didSet { guard let viewModel else { return } Task { @MainActor in self.flushPendingURLs(into: viewModel) } } } weak var appUpdateManager: AppUpdateManager? private var pendingOpenURLs: [URL] = [] func application(_ application: NSApplication, open urls: [URL]) { Task { @MainActor in for url in urls { if let existing = WindowViewModelRegistry.shared.viewModel(containing: url) { _ = existing.viewModel.focusTabIfOpen(for: url) if let window = NSApp.window(withWindowNumber: existing.windowNumber) { window.makeKeyAndOrderFront(nil) NSApp.activate(ignoringOtherApps: true) } continue } let target = WindowViewModelRegistry.shared.activeViewModel() ?? self.viewModel if let target { target.openFile(url: url) } else { self.pendingOpenURLs.append(url) } } } } func applicationShouldOpenUntitledFile(_ sender: NSApplication) -> Bool { return NSApp.windows.isEmpty && pendingOpenURLs.isEmpty } func applicationWillTerminate(_ notification: Notification) { appUpdateManager?.applicationWillTerminate() RuntimeReliabilityMonitor.shared.markGracefulTermination() } @MainActor private func flushPendingURLs(into viewModel: EditorViewModel) { guard !pendingOpenURLs.isEmpty else { return } let urls = pendingOpenURLs pendingOpenURLs.removeAll() urls.forEach { viewModel.openFile(url: $0) } } } private struct DetachedWindowContentView: View { @State private var viewModel = EditorViewModel() @ObservedObject var supportPurchaseManager: SupportPurchaseManager @ObservedObject var appUpdateManager: AppUpdateManager @Binding var showGrokError: Bool @Binding var grokErrorMessage: String var body: some View { ContentView(startupBehavior: .forceBlankDocument) .environment(viewModel) .environmentObject(supportPurchaseManager) .environmentObject(appUpdateManager) .environment(\.showGrokError, $showGrokError) .environment(\.grokErrorMessage, $grokErrorMessage) .frame(minWidth: 600, minHeight: 400) } } #endif @main struct NeonVisionEditorApp: App { @State private var viewModel = EditorViewModel() @StateObject private var supportPurchaseManager = SupportPurchaseManager() @StateObject private var appUpdateManager = AppUpdateManager() @AppStorage("SettingsAppearance") private var appearance: String = "system" @AppStorage("SettingsAppLanguageCode") private var appLanguageCode: String = "system" @Environment(\.scenePhase) private var scenePhase private let mainStartupBehavior: ContentView.StartupBehavior private let startupSafeModeMessage: String? @State private var didMarkLaunchCompleted: Bool = false #if os(macOS) @Environment(\.openWindow) private var openWindow @State private var useAppleIntelligence: Bool = true @State private var appleAIStatus: String = "Apple Intelligence: Checking…" @State private var appleAIRoundTripMS: Double? = nil @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate #endif @State private var showGrokError: Bool = false @State private var grokErrorMessage: String = "" private var preferredAppearance: ColorScheme? { ReleaseRuntimePolicy.preferredColorScheme(for: appearance) } private var preferredLocale: Locale { appLanguageCode == "system" ? .autoupdatingCurrent : Locale(identifier: appLanguageCode) } private func applyRuntimeLanguageOverride() { RuntimeLanguageOverride.apply(languageCode: appLanguageCode) } private func completeLaunchReliabilityTrackingIfNeeded() { guard !didMarkLaunchCompleted else { return } didMarkLaunchCompleted = true RuntimeReliabilityMonitor.shared.markLaunchCompleted() } #if os(macOS) private var appKitAppearance: NSAppearance? { switch appearance { case "light": return NSAppearance(named: .aqua) case "dark": return NSAppearance(named: .darkAqua) default: return nil } } private func applyGlobalAppearanceOverride() { let override = appKitAppearance NSApp.appearance = override for window in NSApp.windows { window.appearance = override window.invalidateShadow() window.displayIfNeeded() } } private func applyMacWindowTabbingPolicy() { // Use app-native file tab pills only; disable NSWindow tab bar to avoid duplicate tab systems. NSWindow.allowsAutomaticWindowTabbing = false for window in NSApp.windows { window.tabbingMode = .disallowed } hideNativeTabBarMenuItems() } private func hideNativeTabBarMenuItems() { guard let mainMenu = NSApp.mainMenu else { return } let targets = ["Show Tab Bar", "Hide Tab Bar", "Move Tab to New Window", "Merge All Windows"] func filter(menu: NSMenu) { for item in menu.items { if let submenu = item.submenu { filter(menu: submenu) } } menu.items.removeAll { item in targets.contains(item.title) } } filter(menu: mainMenu) } #endif #if os(iOS) private var userInterfaceStyle: UIUserInterfaceStyle { switch appearance { case "light": return .light case "dark": return .dark default: return .unspecified } } private func applyIOSAppearanceOverride() { let style = userInterfaceStyle UIApplication.shared.connectedScenes .compactMap { $0 as? UIWindowScene } .forEach { scene in scene.windows.forEach { window in if window.overrideUserInterfaceStyle != style { window.overrideUserInterfaceStyle = style } } } } #endif init() { let defaults = UserDefaults.standard let launchCountKey = "AppLaunchCountV1" defaults.set(defaults.integer(forKey: launchCountKey) + 1, forKey: launchCountKey) // Default editor behavior: // - keep line numbers on // - keep style/space visualization toggles off unless user enables them in Settings defaults.register(defaults: [ "SettingsShowLineNumbers": true, "SettingsHighlightCurrentLine": false, "SettingsHighlightMatchingBrackets": false, "SettingsShowScopeGuides": false, "SettingsHighlightScopeBackground": false, "SettingsLineWrapEnabled": false, "SettingsShowInvisibleCharacters": false, "SettingsUseSystemFont": false, "SettingsIndentStyle": "spaces", "SettingsIndentWidth": 4, "SettingsAutoIndent": true, "SettingsAutoCloseBrackets": false, "SettingsTrimTrailingWhitespace": false, "SettingsTrimWhitespaceForSyntaxDetection": false, "SettingsCompletionEnabled": false, "SettingsCompletionFromDocument": false, "SettingsCompletionFromSyntax": false, "SettingsReopenLastSession": true, "SettingsOpenWithBlankDocument": false, "SettingsAppLanguageCode": "system", "SettingsDefaultNewFileLanguage": "plain", "SettingsConfirmCloseDirtyTab": true, "SettingsConfirmClearEditor": true, "SettingsRemoteSessionsEnabled": false, "SettingsRemoteHost": "", "SettingsRemoteUsername": "", "SettingsRemotePort": 22, "SettingsRemotePreparedTarget": "", "SettingsAutoCheckForUpdates": true, "SettingsUpdateCheckInterval": AppUpdateCheckInterval.daily.rawValue, "SettingsAutoDownloadUpdates": false ]) let vimResetMigrationKey = "SettingsMigrationVimModeResetV1" if !defaults.bool(forKey: vimResetMigrationKey) { // One-time safety reset: avoid stale NORMAL-mode state making editor appear non-editable. defaults.set(false, forKey: "EditorVimModeEnabled") defaults.set(true, forKey: vimResetMigrationKey) } let whitespaceMigrationKey = "SettingsMigrationWhitespaceGlyphResetV1" if !defaults.bool(forKey: whitespaceMigrationKey) { defaults.set(false, forKey: "SettingsShowInvisibleCharacters") defaults.set(false, forKey: "NSShowAllInvisibles") defaults.set(false, forKey: "NSShowControlCharacters") defaults.set(true, forKey: whitespaceMigrationKey) } RuntimeReliabilityMonitor.shared.markLaunch() let safeModeDecision = RuntimeReliabilityMonitor.shared.consumeSafeModeLaunchDecision() self.mainStartupBehavior = safeModeDecision.isEnabled ? .safeMode : .standard self.startupSafeModeMessage = safeModeDecision.message RuntimeReliabilityMonitor.shared.startMainThreadWatchdog() EditorPerformanceMonitor.shared.markLaunchConfigured() RuntimeLanguageOverride.apply( languageCode: defaults.string(forKey: "SettingsAppLanguageCode") ?? "system" ) } #if os(macOS) private var activeWindowNumber: Int? { NSApp.keyWindow?.windowNumber ?? NSApp.mainWindow?.windowNumber } private var activeEditorViewModel: EditorViewModel { WindowViewModelRegistry.shared.activeViewModel() ?? viewModel } private func postWindowCommand(_ name: Notification.Name, object: Any? = nil) { var userInfo: [AnyHashable: Any] = [:] if let activeWindowNumber { userInfo[EditorCommandUserInfo.windowNumber] = activeWindowNumber } NotificationCenter.default.post( name: name, object: object, userInfo: userInfo.isEmpty ? nil : userInfo ) } #endif var body: some Scene { #if os(macOS) WindowGroup { ContentView( startupBehavior: mainStartupBehavior, safeModeMessage: startupSafeModeMessage ) .environment(viewModel) .environmentObject(supportPurchaseManager) .environmentObject(appUpdateManager) .onAppear { appDelegate.viewModel = viewModel appDelegate.appUpdateManager = appUpdateManager } .onAppear { applyGlobalAppearanceOverride() } .onAppear { applyMacWindowTabbingPolicy() } .onChange(of: appearance) { _, _ in applyGlobalAppearanceOverride() } .onAppear { applyRuntimeLanguageOverride() } .onChange(of: appLanguageCode) { _, _ in applyRuntimeLanguageOverride() } .environment(\.showGrokError, $showGrokError) .environment(\.grokErrorMessage, $grokErrorMessage) .environment(\.locale, preferredLocale) .tint(.blue) .preferredColorScheme(preferredAppearance) .onChange(of: scenePhase) { _, newPhase in guard newPhase == .active else { return } completeLaunchReliabilityTrackingIfNeeded() } .frame(minWidth: 600, minHeight: 400) .task { completeLaunchReliabilityTrackingIfNeeded() guard mainStartupBehavior != .safeMode else { return } if ReleaseRuntimePolicy.isUpdaterEnabledForCurrentDistribution { appUpdateManager.startAutomaticChecks() } #if USE_FOUNDATION_MODELS && canImport(FoundationModels) do { let start = Date() _ = try await AppleFM.appleFMHealthCheck() let end = Date() appleAIStatus = "Apple Intelligence: Ready" appleAIRoundTripMS = end.timeIntervalSince(start) * 1000.0 AIActivityLog.record( "Startup AI health check succeeded (\(String(format: "%.1f", appleAIRoundTripMS ?? 0)) ms).", source: "Startup" ) } catch { appleAIStatus = "Apple Intelligence: Error — \(error.localizedDescription)" appleAIRoundTripMS = nil AIActivityLog.record( "Startup AI health check failed: \(error.localizedDescription)", level: .error, source: "Startup" ) } #else appleAIStatus = "Apple Intelligence: Unavailable (build without USE_FOUNDATION_MODELS)" AIActivityLog.record( "Startup AI health check unavailable (built without USE_FOUNDATION_MODELS).", level: .warning, source: "Startup" ) #endif } } .defaultSize(width: 1000, height: 600) .handlesExternalEvents(matching: ["*"]) WindowGroup("New Window", id: "blank-window") { DetachedWindowContentView( supportPurchaseManager: supportPurchaseManager, appUpdateManager: appUpdateManager, showGrokError: $showGrokError, grokErrorMessage: $grokErrorMessage ) .onAppear { applyGlobalAppearanceOverride() } .onAppear { applyMacWindowTabbingPolicy() } .onChange(of: appearance) { _, _ in applyGlobalAppearanceOverride() } .onAppear { applyRuntimeLanguageOverride() } .onChange(of: appLanguageCode) { _, _ in applyRuntimeLanguageOverride() } .environment(\.locale, preferredLocale) .tint(.blue) .preferredColorScheme(preferredAppearance) } .defaultSize(width: 1000, height: 600) .handlesExternalEvents(matching: []) Settings { ConfiguredSettingsView( supportsOpenInTabs: false, supportsTranslucency: true, editorViewModel: activeEditorViewModel, supportPurchaseManager: supportPurchaseManager, appUpdateManager: appUpdateManager ) .onAppear { applyGlobalAppearanceOverride() } .onAppear { applyMacWindowTabbingPolicy() } .onChange(of: appearance) { _, _ in applyGlobalAppearanceOverride() } .onAppear { applyRuntimeLanguageOverride() } .onChange(of: appLanguageCode) { _, _ in applyRuntimeLanguageOverride() } .environment(\.locale, preferredLocale) .tint(.blue) .preferredColorScheme(preferredAppearance) } Window("AI Activity Log", id: "ai-logs") { AIActivityLogView() .frame(minWidth: 720, minHeight: 420) .onAppear { applyRuntimeLanguageOverride() } .onChange(of: appLanguageCode) { _, _ in applyRuntimeLanguageOverride() } .environment(\.locale, preferredLocale) .preferredColorScheme(preferredAppearance) .tint(.blue) } .defaultSize(width: 860, height: 520) .handlesExternalEvents(matching: []) MenuBarExtra("Welcome Tour", systemImage: "sparkles.rectangle.stack") { Button { postWindowCommand(.showWelcomeTourRequested) } label: { Label("Show Welcome Tour", systemImage: "sparkles.rectangle.stack") } Button { postWindowCommand(.showEditorHelpRequested) } label: { Label("Editor Help…", systemImage: "questionmark.circle") } Button { postWindowCommand(.showSupportPromptRequested) } label: { Label("Support Neon Vision Editor…", systemImage: "heart.circle.fill") } Divider() SettingsLink { Label("Settings…", systemImage: "gearshape") } if ReleaseRuntimePolicy.isUpdaterEnabledForCurrentDistribution { Button { postWindowCommand(.showUpdaterRequested, object: true) } label: { Label("Check for Updates…", systemImage: "arrow.triangle.2.circlepath.circle") } } } .commands { NeonVisionMacAppCommands( activeEditorViewModel: { activeEditorViewModel }, hasActiveEditorWindow: { WindowViewModelRegistry.shared.activeViewModel() != nil }, openNewWindow: { openWindow(id: "blank-window") }, openAIDiagnosticsWindow: { openWindow(id: "ai-logs") }, postWindowCommand: { name, object in postWindowCommand(name, object: object) }, isUpdaterEnabled: ReleaseRuntimePolicy.isUpdaterEnabledForCurrentDistribution, recentFilesProvider: { RecentFilesStore.items(limit: 10) }, clearRecentFiles: { RecentFilesStore.clearUnpinned() }, useAppleIntelligence: $useAppleIntelligence, appleAIStatus: $appleAIStatus, appleAIRoundTripMS: $appleAIRoundTripMS, showGrokError: $showGrokError, grokErrorMessage: $grokErrorMessage ) } #else WindowGroup { ContentView( startupBehavior: mainStartupBehavior, safeModeMessage: startupSafeModeMessage ) .environment(viewModel) .environmentObject(supportPurchaseManager) .environmentObject(appUpdateManager) .environment(\.showGrokError, $showGrokError) .environment(\.grokErrorMessage, $grokErrorMessage) .environment(\.locale, preferredLocale) .onAppear { applyRuntimeLanguageOverride() } .onChange(of: appLanguageCode) { _, _ in applyRuntimeLanguageOverride() } .tint(.blue) .onAppear { applyIOSAppearanceOverride() } .onChange(of: scenePhase) { _, newPhase in guard newPhase == .active else { return } completeLaunchReliabilityTrackingIfNeeded() } .onReceive(NotificationCenter.default.publisher(for: UIApplication.willTerminateNotification)) { _ in RuntimeReliabilityMonitor.shared.markGracefulTermination() } .onChange(of: appearance) { _, _ in applyIOSAppearanceOverride() } .preferredColorScheme(preferredAppearance) .task { completeLaunchReliabilityTrackingIfNeeded() } } .commands { CommandGroup(replacing: .undoRedo) { Button("Undo") { UIApplication.shared.sendAction(Selector(("undo:")), to: nil, from: nil, for: nil) } .keyboardShortcut("z", modifiers: .command) Button("Redo") { UIApplication.shared.sendAction(Selector(("redo:")), to: nil, from: nil, for: nil) } .keyboardShortcut("z", modifiers: [.command, .shift]) } } #endif } } struct ShowGrokErrorKey: EnvironmentKey { static let defaultValue: Binding = .constant(false) } struct GrokErrorMessageKey: EnvironmentKey { static let defaultValue: Binding = .constant("") } extension EnvironmentValues { var showGrokError: Binding { get { self[ShowGrokErrorKey.self] } set { self[ShowGrokErrorKey.self] = newValue } } var grokErrorMessage: Binding { get { self[GrokErrorMessageKey.self] } set { self[GrokErrorMessageKey.self] = newValue } } }