Adjustments for the rewrite code. Text field adjustments

This commit is contained in:
Rodric Krogh 2025-09-25 11:01:45 +02:00
parent d9d424878e
commit 39ce3f3443
24 changed files with 935 additions and 721 deletions

View file

@ -7,25 +7,12 @@
objects = {
/* Begin PBXBuildFile section */
983EEA302E5F22DA00E19094 /* SwiftData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98EAE6592E5F1E890050E579 /* SwiftData.framework */; };
983EEA312E5F22DA00E19094 /* SwiftData.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 98EAE6592E5F1E890050E579 /* SwiftData.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9825C2092ED77CF3007D8698 /* SwiftData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9825C2082ED77CF3007D8698 /* SwiftData.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
983EEA322E5F22DA00E19094 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
dstPath = "";
dstSubfolder = Frameworks;
files = (
983EEA312E5F22DA00E19094 /* SwiftData.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
9825C2082ED77CF3007D8698 /* SwiftData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftData.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS26.1.sdk/System/Library/Frameworks/SwiftData.framework; sourceTree = DEVELOPER_DIR; };
98EAE6332E5F15E80050E579 /* Neon Vision Editor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Neon Vision Editor.app"; sourceTree = BUILT_PRODUCTS_DIR; };
98EAE6592E5F1E890050E579 /* SwiftData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftData.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS26.0.sdk/System/Library/Frameworks/SwiftData.framework; sourceTree = DEVELOPER_DIR; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
@ -40,7 +27,7 @@
98EAE6302E5F15E80050E579 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
files = (
983EEA302E5F22DA00E19094 /* SwiftData.framework in Frameworks */,
9825C2092ED77CF3007D8698 /* SwiftData.framework in Frameworks */,
);
};
/* End PBXFrameworksBuildPhase section */
@ -66,7 +53,7 @@
98EAE6532E5F175B0050E579 /* Frameworks */ = {
isa = PBXGroup;
children = (
98EAE6592E5F1E890050E579 /* SwiftData.framework */,
9825C2082ED77CF3007D8698 /* SwiftData.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -81,7 +68,6 @@
98EAE62F2E5F15E80050E579 /* Sources */,
98EAE6302E5F15E80050E579 /* Frameworks */,
98EAE6312E5F15E80050E579 /* Resources */,
983EEA322E5F22DA00E19094 /* Embed Frameworks */,
);
buildRules = (
);
@ -101,7 +87,7 @@
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 2600;
LastUpgradeCheck = 2600;
LastUpgradeCheck = 2610;
TargetAttributes = {
98EAE6322E5F15E80050E579 = {
CreatedOnToolsVersion = 26.0;
@ -178,6 +164,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = CS727NF72U;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -201,6 +188,7 @@
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
@ -240,6 +228,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = CS727NF72U;
ENABLE_NS_ASSERTIONS = NO;
@ -256,6 +245,7 @@
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_COMPILATION_MODE = wholemodule;
};
name = Release;
@ -265,15 +255,29 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
AUTOMATION_APPLE_EVENTS = NO;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = CS727NF72U;
ENABLE_APP_SANDBOX = YES;
ENABLE_FILE_ACCESS_DOWNLOADS_FOLDER = readwrite;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
ENABLE_PREVIEWS = YES;
ENABLE_USER_SELECTED_FILES = readonly;
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
ENABLE_RESOURCE_ACCESS_CALENDARS = NO;
ENABLE_RESOURCE_ACCESS_CAMERA = NO;
ENABLE_RESOURCE_ACCESS_CONTACTS = NO;
ENABLE_RESOURCE_ACCESS_LOCATION = NO;
ENABLE_RESOURCE_ACCESS_PHOTO_LIBRARY = NO;
ENABLE_RESOURCE_ACCESS_PRINTING = NO;
ENABLE_RESOURCE_ACCESS_USB = NO;
ENABLE_USER_SELECTED_FILES = readwrite;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "Neon Vision Editor";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
@ -297,6 +301,12 @@
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
REGISTER_APP_GROUPS = YES;
RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES = NO;
RUNTIME_EXCEPTION_ALLOW_JIT = NO;
RUNTIME_EXCEPTION_ALLOW_UNSIGNED_EXECUTABLE_MEMORY = NO;
RUNTIME_EXCEPTION_DEBUGGING_TOOL = NO;
RUNTIME_EXCEPTION_DISABLE_EXECUTABLE_PAGE_PROTECTION = NO;
RUNTIME_EXCEPTION_DISABLE_LIBRARY_VALIDATION = NO;
SDKROOT = auto;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
@ -316,15 +326,29 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
AUTOMATION_APPLE_EVENTS = NO;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = CS727NF72U;
ENABLE_APP_SANDBOX = YES;
ENABLE_FILE_ACCESS_DOWNLOADS_FOLDER = readwrite;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_INCOMING_NETWORK_CONNECTIONS = NO;
ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES;
ENABLE_PREVIEWS = YES;
ENABLE_USER_SELECTED_FILES = readonly;
ENABLE_RESOURCE_ACCESS_AUDIO_INPUT = NO;
ENABLE_RESOURCE_ACCESS_BLUETOOTH = NO;
ENABLE_RESOURCE_ACCESS_CALENDARS = NO;
ENABLE_RESOURCE_ACCESS_CAMERA = NO;
ENABLE_RESOURCE_ACCESS_CONTACTS = NO;
ENABLE_RESOURCE_ACCESS_LOCATION = NO;
ENABLE_RESOURCE_ACCESS_PHOTO_LIBRARY = NO;
ENABLE_RESOURCE_ACCESS_PRINTING = NO;
ENABLE_RESOURCE_ACCESS_USB = NO;
ENABLE_USER_SELECTED_FILES = readwrite;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_CFBundleDisplayName = "Neon Vision Editor";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
@ -348,6 +372,12 @@
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
REGISTER_APP_GROUPS = YES;
RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES = NO;
RUNTIME_EXCEPTION_ALLOW_JIT = NO;
RUNTIME_EXCEPTION_ALLOW_UNSIGNED_EXECUTABLE_MEMORY = NO;
RUNTIME_EXCEPTION_DEBUGGING_TOOL = NO;
RUNTIME_EXCEPTION_DISABLE_EXECUTABLE_PAGE_PROTECTION = NO;
RUNTIME_EXCEPTION_DISABLE_LIBRARY_VALIDATION = NO;
SDKROOT = auto;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";

View file

@ -0,0 +1,28 @@
import Foundation
struct GrokAPIClient {
let apiKey: String
private let baseURL = URL(string: "https://api.x.ai/v1")!
func generateText(prompt: String, maxTokens: Int = 100) async throws -> String {
var request = URLRequest(url: baseURL.appendingPathComponent("generate"))
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body: [String: Any] = [
"model": "grok-4",
"prompt": prompt,
"max_tokens": maxTokens
]
request.httpBody = try JSONSerialization.data(withJSONObject: body)
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw URLError(.badServerResponse)
}
let json = try JSONDecoder().decode([String: String].self, from: data)
return json["text"] ?? ""
}
}

View file

@ -1,20 +0,0 @@
{
"colors" : [
{
"idiom" : "universal",
"color" : {
"color-space" : "srgb",
"components" : {
"red" : "0.694",
"green" : "0.302",
"blue" : "0.831",
"alpha" : "1.0"
}
}
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -1,68 +0,0 @@
{
"images" : [
{
"filename" : "NeonVisionEditor-16.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "NeonVisionEditor-32 1.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "NeonVisionEditor-32.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "NeonVisionEditor-64.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"filename" : "NeonVisionEditor-128.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"filename" : "NeonVisionEditor-256.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"filename" : "NeonVisionEditor-256 1.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "NeonVisionEditor-512 1.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "NeonVisionEditor-512.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "NeonVision Editor.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 756 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because it is too large Load diff

View file

@ -1,48 +1,84 @@
import SwiftUI
import SwiftData
import Combine
import UniformTypeIdentifiers
struct TabData: Identifiable {
let id = UUID()
var name: String
var content: String
var language: String
var fileURL: URL?
}
@MainActor
class EditorViewModel: ObservableObject {
@Published var tabs: [Tab] = []
@Published var selectedTab: Tab?
@Published var tabs: [TabData] = []
@Published var selectedTabID: UUID?
@Published var showSidebar: Bool = true
func addNewTab(context: ModelContext) {
let newTab = Tab(name: "New Tab \(tabs.count + 1)", content: "", language: "swift")
tabs.append(newTab)
context.insert(newTab)
selectedTab = newTab
try? context.save()
@Published var isBrainDumpMode: Bool = false
@Published var showingRename: Bool = false
@Published var renameText: String = ""
var selectedTab: TabData? {
get { tabs.first(where: { $0.id == selectedTabID }) }
set { selectedTabID = newValue?.id }
}
func openFile() {
let openPanel = NSOpenPanel()
openPanel.allowedContentTypes = [.text, .sourceCode, .swiftSource, .pythonScript, .javaScript, .html, .css, .cSource, .cppSource, .json, .markdown]
openPanel.allowsMultipleSelection = false
openPanel.canChooseDirectories = false
openPanel.canChooseFiles = true
guard openPanel.runModal() == .OK, let url = openPanel.url else { return }
do {
let content = try String(contentsOf: url, encoding: .utf8)
let language = languageMap[url.pathExtension.lowercased()] ?? "plaintext"
let newTab = Tab(name: url.lastPathComponent, content: content, language: language, fileURL: url)
tabs.append(newTab)
selectedTab = newTab
if let context = try? ModelContext(ModelContainer(for: Tab.self)) {
context.insert(newTab)
try? context.save()
}
} catch {
print("Error opening file: \(error)")
private let languageMap: [String: String] = [
"swift": "swift",
"py": "python",
"js": "javascript",
"html": "html",
"css": "css",
"c": "c",
"cpp": "cpp",
"h": "c",
"json": "json",
"md": "markdown"
]
init() {
addNewTab()
}
func addNewTab() {
let newTab = TabData(name: "Untitled \(tabs.count + 1)", content: "", language: "swift", fileURL: nil)
tabs.append(newTab)
selectedTabID = newTab.id
}
func renameTab(tab: TabData, newName: String) {
if let index = tabs.firstIndex(where: { $0.id == tab.id }) {
tabs[index].name = newName
}
}
func saveFile(tab: Tab) {
if let url = tab.fileURL {
func updateTabContent(tab: TabData, content: String) {
if let index = tabs.firstIndex(where: { $0.id == tab.id }) {
tabs[index].content = content
}
}
func updateTabLanguage(tab: TabData, language: String) {
if let index = tabs.firstIndex(where: { $0.id == tab.id }) {
tabs[index].language = language
}
}
func closeTab(tab: TabData) {
tabs.removeAll { $0.id == tab.id }
if tabs.isEmpty {
addNewTab()
} else if selectedTabID == tab.id {
selectedTabID = tabs.first?.id
}
}
func saveFile(tab: TabData) {
guard let index = tabs.firstIndex(where: { $0.id == tab.id }) else { return }
if let url = tabs[index].fileURL {
do {
try tab.content.write(to: url, atomically: true, encoding: .utf8)
print("Saved to \(url.path)")
try tabs[index].content.write(to: url, atomically: true, encoding: .utf8)
} catch {
print("Error saving file: \(error)")
}
@ -50,28 +86,51 @@ class EditorViewModel: ObservableObject {
saveFileAs(tab: tab)
}
}
func saveFileAs(tab: Tab) {
let savePanel = NSSavePanel()
savePanel.allowedContentTypes = [.text, .sourceCode, .swiftSource, .pythonScript, .javaScript, .html, .css, .cSource, .cppSource, .json, .markdown]
savePanel.nameFieldStringValue = tab.name
guard savePanel.runModal() == .OK, let url = savePanel.url else { return }
do {
try tab.content.write(to: url, atomically: true, encoding: .utf8)
tab.fileURL = url
tab.name = url.lastPathComponent
if let context = try? ModelContext(ModelContainer(for: Tab.self)) {
try? context.save()
func saveFileAs(tab: TabData) {
guard let index = tabs.firstIndex(where: { $0.id == tab.id }) else { return }
let panel = NSSavePanel()
panel.nameFieldStringValue = tabs[index].name
panel.allowedContentTypes = [.text, .swiftSource, .pythonScript, .javaScript, .html, .css, .cSource, .json, UTType(importedAs: "public.markdown")]
Task {
if panel.runModal() == .OK, let url = panel.url {
do {
try tabs[index].content.write(to: url, atomically: true, encoding: .utf8)
tabs[index].fileURL = url
tabs[index].name = url.lastPathComponent
} catch {
print("Error saving file: \(error)")
}
}
print("Saved as \(url.path)")
} catch {
print("Error saving file: \(error)")
}
}
let languageMap: [String: String] = [
"swift": "swift", "py": "python", "js": "javascript", "html": "html", "css": "css",
"c": "c", "cpp": "cpp", "json": "json", "md": "markdown"
]
}
func openFile() {
let panel = NSOpenPanel()
panel.allowedContentTypes = [.text, .sourceCode, .swiftSource, .pythonScript, .javaScript, .html, .css, .cSource, .json, UTType(importedAs: "public.markdown")]
panel.allowsMultipleSelection = false
panel.canChooseDirectories = false
Task {
if panel.runModal() == .OK, let url = panel.url {
do {
let content = try String(contentsOf: url, encoding: .utf8)
let newTab = TabData(name: url.lastPathComponent,
content: content,
language: languageMap[url.pathExtension.lowercased()] ?? "swift",
fileURL: url)
tabs.append(newTab)
selectedTabID = newTab.id
} catch {
print("Error opening file: \(error)")
}
}
}
}
func wordCount(for text: String) -> Int {
text.components(separatedBy: .whitespacesAndNewlines)
.filter { !$0.isEmpty }.count
}
}

View file

@ -1,45 +0,0 @@
import Foundation
class GrokAPIClient {
private let apiKey: String
private let baseURL = "https://api.x.ai/v1"
init(apiKey: String) {
self.apiKey = apiKey
}
func generateText(prompt: String, model: String = "grok-3-beta", maxTokens: Int = 500) async throws -> String {
let url = URL(string: "\(baseURL)/chat/completions")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body: [String: Any] = [
"model": model,
"messages": [
["role": "user", "content": prompt]
],
"max_tokens": maxTokens
]
request.httpBody = try JSONSerialization.data(withJSONObject: body)
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw NSError(domain: "GrokAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "API request failed"])
}
let json = try JSONDecoder().decode(GrokResponse.self, from: data)
return json.choices.first?.message.content ?? ""
}
}
struct GrokResponse: Codable {
struct Choice: Codable {
struct Message: Codable {
let content: String
}
let message: Message
}
let choices: [Choice]
}

View file

@ -1,112 +1,159 @@
import SwiftUI
import SwiftData
import FoundationModels
class AppDelegate: NSObject, NSApplicationDelegate {
var viewModel: EditorViewModel?
var modelContext: ModelContext?
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
guard let viewModel = viewModel, let modelContext = modelContext else {
return .terminateNow
}
for tab in viewModel.tabs {
if !tab.content.isEmpty && tab.fileURL == nil {
let alert = NSAlert()
alert.messageText = "Save changes to \"\(tab.name)\" before quitting?"
alert.informativeText = "Your changes will be lost if you don't save them."
alert.addButton(withTitle: "Save")
alert.addButton(withTitle: "Cancel")
alert.addButton(withTitle: "Don't Save")
alert.alertStyle = .warning
switch alert.runModal() {
case .alertFirstButtonReturn: // Save
viewModel.saveFileAs(tab: tab)
case .alertSecondButtonReturn: // Cancel
return .terminateCancel
case .alertThirdButtonReturn: // Don't Save
break
default:
break
}
}
}
// Clear all tabs on quit
for tab in viewModel.tabs {
modelContext.delete(tab)
}
try? modelContext.save()
return .terminateNow
}
enum AIModel: String, Identifiable {
case appleIntelligence = "Apple Intelligence"
case grok = "Grok"
var id: String { rawValue }
}
@main
struct NeonVisionEditorApp: App {
@StateObject private var viewModel = EditorViewModel()
@State private var appDelegate = AppDelegate()
@State private var modelContainer: ModelContainer?
@State private var showGrokError: Bool = false
@State private var grokErrorMessage: String = ""
@State private var selectedAIModel: AIModel = .appleIntelligence
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(viewModel)
.environment(\.modelContext, modelContainer?.mainContext ?? ModelContext(ModelContainer(for: Tab.self)))
.frame(minWidth: 1000, minHeight: 600)
.onAppear {
if modelContainer == nil {
do {
let container = try ModelContainer(for: Tab.self)
modelContainer = container
appDelegate.viewModel = viewModel
appDelegate.modelContext = container.mainContext
NSApplication.shared.delegate = appDelegate
} catch {
print("Failed to create ModelContainer: \(error)")
}
}
.environment(\.showGrokError, $showGrokError)
.environment(\.grokErrorMessage, $grokErrorMessage)
.environment(\.selectedAIModel, $selectedAIModel)
.frame(minWidth: 600, minHeight: 400)
.background(.ultraThinMaterial)
.overlay(.ultraThinMaterial.opacity(0.2)) // Fallback for liquidGlassEffect
.task {
// Pre-warm Apple Intelligence model
let session = LanguageModelSession(model: SystemLanguageModel())
session.prewarm()
}
}
.defaultSize(width: 1000, height: 600)
.commands {
CommandGroup(replacing: .newItem) {
CommandMenu("File") {
Button("New Tab") {
if let context = modelContainer?.mainContext {
viewModel.addNewTab(context: context)
}
viewModel.addNewTab()
}
.keyboardShortcut("t", modifiers: .command)
}
CommandMenu("File") {
Button("Open File...") {
viewModel.openFile()
}
.keyboardShortcut("o", modifiers: .command)
Button("Save") {
if let selectedTab = viewModel.selectedTab {
viewModel.saveFile(tab: selectedTab)
if let tab = viewModel.selectedTab {
viewModel.saveFile(tab: tab)
}
}
.keyboardShortcut("s", modifiers: .command)
.disabled(viewModel.selectedTab == nil)
Button("Save As...") {
if let selectedTab = viewModel.selectedTab {
viewModel.saveFileAs(tab: selectedTab)
if let tab = viewModel.selectedTab {
viewModel.saveFileAs(tab: tab)
}
}
.disabled(viewModel.selectedTab == nil)
}
CommandMenu("View") {
Button(viewModel.showSidebar ? "Hide Sidebar" : "Show Sidebar") {
viewModel.showSidebar.toggle()
Button("Rename") {
viewModel.showingRename = true
viewModel.renameText = viewModel.selectedTab?.name ?? "Untitled"
}
.keyboardShortcut("b", modifiers: [.command, .shift])
.disabled(viewModel.selectedTab == nil)
Button("Close Tab") {
if let tab = viewModel.selectedTab {
viewModel.closeTab(tab: tab)
}
}
.keyboardShortcut("w", modifiers: .command)
.disabled(viewModel.selectedTab == nil)
}
CommandMenu("Language") {
ForEach(["swift", "python", "javascript", "html", "css", "c", "cpp", "json", "markdown"], id: \.self) { lang in
Button(lang.capitalized) {
if let tab = viewModel.selectedTab {
viewModel.updateTabLanguage(tab: tab, language: lang)
}
}
.disabled(viewModel.selectedTab == nil)
}
}
CommandMenu("View") {
Toggle("Toggle Sidebar", isOn: $viewModel.showSidebar)
.keyboardShortcut("s", modifiers: [.command, .option])
Toggle("Brain Dump Mode", isOn: $viewModel.isBrainDumpMode)
.keyboardShortcut("d", modifiers: [.command, .shift])
}
CommandMenu("Tools") {
Button("Suggest Code") {
Task {
if let tab = viewModel.selectedTab {
switch selectedAIModel {
case .appleIntelligence:
let session = LanguageModelSession(model: SystemLanguageModel())
let prompt = "System: Output a code suggestion for this \(tab.language) code.\nUser: \(tab.content.prefix(1000))"
do {
let suggestion = try await session.respond(to: prompt)
viewModel.updateTabContent(tab: tab, content: tab.content + "\n\n// Apple Intelligence Suggestion:\n" + suggestion.content)
} catch {
grokErrorMessage = error.localizedDescription
showGrokError = true
}
case .grok:
let client = GrokAPIClient(apiKey: "your-xai-api-key") // Replace with your xAI API key from https://x.ai/api
let prompt = "Suggest improvements for this \(tab.language) code: \(tab.content.prefix(1000))"
do {
let suggestion = try await client.generateText(prompt: prompt, maxTokens: 200)
viewModel.updateTabContent(tab: tab, content: tab.content + "\n\n// Grok Suggestion:\n" + suggestion)
} catch {
grokErrorMessage = error.localizedDescription
showGrokError = true
}
}
}
}
}
.keyboardShortcut("g", modifiers: [.command, .shift])
.disabled(viewModel.selectedTab == nil)
}
}
}
}
struct ShowGrokErrorKey: EnvironmentKey {
static let defaultValue: Binding<Bool> = .constant(false)
}
struct GrokErrorMessageKey: EnvironmentKey {
static let defaultValue: Binding<String> = .constant("")
}
struct SelectedAIModelKey: EnvironmentKey {
static let defaultValue: Binding<AIModel> = .constant(.appleIntelligence)
}
extension EnvironmentValues {
var showGrokError: Binding<Bool> {
get { self[ShowGrokErrorKey.self] }
set { self[ShowGrokErrorKey.self] = newValue }
}
var grokErrorMessage: Binding<String> {
get { self[GrokErrorMessageKey.self] }
set { self[GrokErrorMessageKey.self] = newValue }
}
var selectedAIModel: Binding<AIModel> {
get { self[SelectedAIModelKey.self] }
set { self[SelectedAIModelKey.self] = newValue }
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 KiB

View file

@ -0,0 +1,29 @@
{
"fill" : {
"automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
},
"groups" : [
{
"layers" : [
{
"image-name" : "5.png",
"name" : "5"
}
],
"shadow" : {
"kind" : "neutral",
"opacity" : 0.5
},
"translucency" : {
"enabled" : true,
"value" : 0.5
}
}
],
"supported-platforms" : {
"circles" : [
"watchOS"
],
"squares" : "shared"
}
}

View file

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.772",
"green" : "0.532",
"red" : "0.898"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.816",
"green" : "0.261",
"red" : "0.569"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1,22 @@
{
"images" : [
{
"filename" : "NeonVision Editor.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "NeonVision Editor 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB