diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index adb1dff775..95526a7588 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -7,16 +7,12 @@ objects = { /* Begin PBXBuildFile section */ - 0439FEF527DD104500528317 /* WorkspaceEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0439FEF427DD104500528317 /* WorkspaceEditorView.swift */; }; 043C321427E31FF6006AE443 /* CodeEditDocumentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043C321327E31FF6006AE443 /* CodeEditDocumentController.swift */; }; 043C321627E3201F006AE443 /* WorkspaceDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043C321527E3201F006AE443 /* WorkspaceDocument.swift */; }; - 043C321827E32246006AE443 /* CodeFileEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043C321727E32246006AE443 /* CodeFileEditor.swift */; }; 043C321A27E32295006AE443 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 043C321927E32295006AE443 /* MainMenu.xib */; }; 04540D5B27DD08C300E91B77 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04F2BF0E27DBB28E0024EAB1 /* SettingsView.swift */; }; 04540D5C27DD08C300E91B77 /* GeneralSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04F2BF1127DBB3C10024EAB1 /* GeneralSettingsView.swift */; }; 04540D5E27DD08C300E91B77 /* WorkspaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B658FB3127DA9E0F00EA4DBD /* WorkspaceView.swift */; }; - 04540D5F27DD08C300E91B77 /* EditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043DF9C127DD045800CA0FC3 /* EditorView.swift */; }; - 04540D6127DD08C300E91B77 /* CodeFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 348313FB27DC8C070016D42C /* CodeFile.swift */; }; 04540D6327DD08C300E91B77 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0468438427DC76E200F8E88E /* AppDelegate.swift */; }; 04660F6127E3A68A00477777 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 04660F6027E3A68A00477777 /* Info.plist */; }; 04660F6427E3ACAF00477777 /* Appearances.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6327E3ACAF00477777 /* Appearances.swift */; }; @@ -25,11 +21,12 @@ 287776E927E34BC700D46668 /* TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776E827E34BC700D46668 /* TabBar.swift */; }; 287776ED27E350D800D46668 /* SideBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776EC27E350D800D46668 /* SideBarItem.swift */; }; 287776EF27E3515300D46668 /* TabBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776EE27E3515300D46668 /* TabBarItem.swift */; }; - 28B0A19827E385C300B73177 /* SideBarToolbarTop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B0A19727E385C300B73177 /* SideBarToolbarTop.swift */; }; - 28FFE1BF27E3A441001939DB /* SideBarToolbarBottom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FFE1BE27E3A441001939DB /* SideBarToolbarBottom.swift */; }; + 28B0A19827E385C300B73177 /* SideBarToolbarTop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B0A19727E385C300B73177 /* SideBarToolbarTop.swift */; }; + 28FFE1BF27E3A441001939DB /* SideBarToolbarBottom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28FFE1BE27E3A441001939DB /* SideBarToolbarBottom.swift */; }; 345F667527DF6C180069BD69 /* FileTabRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 345F667427DF6C180069BD69 /* FileTabRow.swift */; }; 34EE19BE27E0469C00F152CE /* BlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34EE19BD27E0469C00F152CE /* BlurView.swift */; }; 5C403B8F27E20F8000788241 /* WorkspaceClient in Frameworks */ = {isa = PBXBuildFile; productRef = 5C403B8E27E20F8000788241 /* WorkspaceClient */; }; + 5CF38A5E27E48E6C0096A0F7 /* CodeFile in Frameworks */ = {isa = PBXBuildFile; productRef = 5CF38A5D27E48E6C0096A0F7 /* CodeFile */; }; B658FB3427DA9E1000EA4DBD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B658FB3327DA9E1000EA4DBD /* Assets.xcassets */; }; B658FB3727DA9E1000EA4DBD /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B658FB3627DA9E1000EA4DBD /* Preview Assets.xcassets */; }; D7211D4327E066CE008F2ED7 /* Localized+Ex.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7211D4227E066CE008F2ED7 /* Localized+Ex.swift */; }; @@ -54,12 +51,9 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 0439FEF427DD104500528317 /* WorkspaceEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceEditorView.swift; sourceTree = ""; }; 043C321327E31FF6006AE443 /* CodeEditDocumentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeEditDocumentController.swift; sourceTree = ""; }; 043C321527E3201F006AE443 /* WorkspaceDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceDocument.swift; sourceTree = ""; }; - 043C321727E32246006AE443 /* CodeFileEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeFileEditor.swift; sourceTree = ""; }; 043C321927E32295006AE443 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; }; - 043DF9C127DD045800CA0FC3 /* EditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditorView.swift; sourceTree = ""; }; 04660F6027E3A68A00477777 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 04660F6327E3ACAF00477777 /* Appearances.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Appearances.swift; sourceTree = ""; }; 04660F6527E3ACEF00477777 /* ReopenBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReopenBehavior.swift; sourceTree = ""; }; @@ -73,7 +67,6 @@ 28B0A19727E385C300B73177 /* SideBarToolbarTop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideBarToolbarTop.swift; sourceTree = ""; }; 28FFE1BE27E3A441001939DB /* SideBarToolbarBottom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SideBarToolbarBottom.swift; sourceTree = ""; }; 345F667427DF6C180069BD69 /* FileTabRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileTabRow.swift; sourceTree = ""; }; - 348313FB27DC8C070016D42C /* CodeFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeFile.swift; sourceTree = ""; }; 34EE19BD27E0469C00F152CE /* BlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurView.swift; sourceTree = ""; }; B658FB2C27DA9E0F00EA4DBD /* CodeEdit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CodeEdit.app; sourceTree = BUILT_PRODUCTS_DIR; }; B658FB3127DA9E0F00EA4DBD /* WorkspaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceView.swift; sourceTree = ""; }; @@ -93,6 +86,7 @@ buildActionMask = 2147483647; files = ( 5C403B8F27E20F8000788241 /* WorkspaceClient in Frameworks */, + 5CF38A5E27E48E6C0096A0F7 /* CodeFile in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -113,20 +107,9 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 0439FEF327DD100800528317 /* Editor */ = { - isa = PBXGroup; - children = ( - 043DF9C127DD045800CA0FC3 /* EditorView.swift */, - 0439FEF427DD104500528317 /* WorkspaceEditorView.swift */, - 043C321727E32246006AE443 /* CodeFileEditor.swift */, - ); - path = Editor; - sourceTree = ""; - }; 043C321227E31FE8006AE443 /* Documents */ = { isa = PBXGroup; children = ( - 348313FB27DC8C070016D42C /* CodeFile.swift */, 043C321327E31FF6006AE443 /* CodeEditDocumentController.swift */, 043C321527E3201F006AE443 /* WorkspaceDocument.swift */, ); @@ -224,7 +207,6 @@ 287776EA27E350A100D46668 /* SideBar */, 287776EB27E350BA00D46668 /* TabBar */, 345F667327DF6BCC0069BD69 /* Rows */, - 0439FEF327DD100800528317 /* Editor */, 04F2BF1027DBB3AF0024EAB1 /* Settings */, 34EE19BC27E0467F00F152CE /* CustomViews */, D7211D4427E066D4008F2ED7 /* Localization */, @@ -271,6 +253,7 @@ name = CodeEdit; packageProductDependencies = ( 5C403B8E27E20F8000788241 /* WorkspaceClient */, + 5CF38A5D27E48E6C0096A0F7 /* CodeFile */, ); productName = CodeEdit; productReference = B658FB2C27DA9E0F00EA4DBD /* CodeEdit.app */; @@ -395,7 +378,6 @@ 043C321427E31FF6006AE443 /* CodeEditDocumentController.swift in Sources */, 04660F6427E3ACAF00477777 /* Appearances.swift in Sources */, 04540D5E27DD08C300E91B77 /* WorkspaceView.swift in Sources */, - 04540D5F27DD08C300E91B77 /* EditorView.swift in Sources */, 34EE19BE27E0469C00F152CE /* BlurView.swift in Sources */, D7211D4327E066CE008F2ED7 /* Localized+Ex.swift in Sources */, 287776E927E34BC700D46668 /* TabBar.swift in Sources */, @@ -403,14 +385,11 @@ 287776EF27E3515300D46668 /* TabBarItem.swift in Sources */, 287776E727E3413200D46668 /* SideBar.swift in Sources */, 287776ED27E350D800D46668 /* SideBarItem.swift in Sources */, - 04540D6127DD08C300E91B77 /* CodeFile.swift in Sources */, 04660F6627E3ACEF00477777 /* ReopenBehavior.swift in Sources */, 043C321627E3201F006AE443 /* WorkspaceDocument.swift in Sources */, - 28B0A19827E385C300B73177 /* SideBarToolbarTop.swift in Sources */, + 28B0A19827E385C300B73177 /* SideBarToolbarTop.swift in Sources */, 345F667527DF6C180069BD69 /* FileTabRow.swift in Sources */, - 043C321827E32246006AE443 /* CodeFileEditor.swift in Sources */, 04540D6327DD08C300E91B77 /* AppDelegate.swift in Sources */, - 0439FEF527DD104500528317 /* WorkspaceEditorView.swift in Sources */, 28FFE1BF27E3A441001939DB /* SideBarToolbarBottom.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -778,6 +757,10 @@ isa = XCSwiftPackageProductDependency; productName = WorkspaceClient; }; + 5CF38A5D27E48E6C0096A0F7 /* CodeFile */ = { + isa = XCSwiftPackageProductDependency; + productName = CodeFile; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = B658FB2427DA9E0F00EA4DBD /* Project object */; diff --git a/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000000..8450bfb4c9 --- /dev/null +++ b/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,34 @@ +{ + "object": { + "pins": [ + { + "package": "CodeEditor", + "repositoryURL": "https://github.com/ZeeZide/CodeEditor.git", + "state": { + "branch": null, + "revision": "5856fac22b0a2174dbdea212784567c8c9cd1129", + "version": "1.2.0" + } + }, + { + "package": "Highlightr", + "repositoryURL": "https://github.com/raspu/Highlightr", + "state": { + "branch": null, + "revision": "93199b9e434f04bda956a613af8f571933f9f037", + "version": "2.1.2" + } + }, + { + "package": "SnapshotTesting", + "repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing.git", + "state": { + "branch": null, + "revision": "f8a9c997c3c1dab4e216a8ec9014e23144cbab37", + "version": "1.9.0" + } + } + ] + }, + "version": 1 +} diff --git a/CodeEdit/ContentView.swift b/CodeEdit/ContentView.swift index c8a92524e8..78822650a1 100644 --- a/CodeEdit/ContentView.swift +++ b/CodeEdit/ContentView.swift @@ -7,6 +7,7 @@ import SwiftUI import WorkspaceClient +import CodeEditorView struct WorkspaceView: View { @State private var directoryURL: URL? @@ -57,7 +58,8 @@ struct WorkspaceView: View { ZStack { if let selectedId = selectedId { if let selectedItem = try? workspaceClient.getFileItem(selectedId) { - WorkspaceEditorView(item: selectedItem) + CodeEditorView(fileURL: selectedItem.url) + .padding(.top, 31.0) } } diff --git a/CodeEdit/Documents/CodeEditDocumentController.swift b/CodeEdit/Documents/CodeEditDocumentController.swift index 7f19cf3d8e..5fc822f5ff 100644 --- a/CodeEdit/Documents/CodeEditDocumentController.swift +++ b/CodeEdit/Documents/CodeEditDocumentController.swift @@ -8,9 +8,7 @@ import Cocoa class CodeEditDocumentController: NSDocumentController { - override func openDocument(_ sender: Any?) { - print("Opening") - + override func openDocument(_ sender: Any?) { let dialog = NSOpenPanel() dialog.title = "Open Workspace or File" diff --git a/CodeEdit/Documents/CodeFile.swift b/CodeEdit/Documents/CodeFile.swift deleted file mode 100644 index c5b90a6a2d..0000000000 --- a/CodeEdit/Documents/CodeFile.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// CodeFile.swift -// CodeEdit -// -// Created by Rehatbir Singh on 12/03/2022. -// - -import Foundation -import AppKit -import SwiftUI - -enum CodeFileError: Error { - case failedToDecode - case failedToEncode -} - -@objc(CodeFile) -class CodeFile: NSDocument, ObservableObject { - - @Published var text = "" - - // MARK: - NSDocument - - override class var autosavesInPlace: Bool { - return true - } - - override func makeWindowControllers() { - // Returns the Storyboard that contains your Document window. - let contentView = CodeFileEditor(file: self) - let window = NSWindow( - contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), - styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], - backing: .buffered, defer: false) - window.center() - window.contentView = NSHostingView(rootView: contentView) - let windowController = NSWindowController(window: window) - self.addWindowController(windowController) - } - - override func data(ofType typeName: String) throws -> Data { - guard let data = self.text.data(using: .utf8) else { throw CodeFileError.failedToEncode } - return data - } - - override func read(from data: Data, ofType typeName: String) throws { - guard let text = String(data: data, encoding: .utf8) else { throw CodeFileError.failedToDecode } - self.text = text - } -} diff --git a/CodeEdit/Documents/WorkspaceDocument.swift b/CodeEdit/Documents/WorkspaceDocument.swift index ad1f7d86f7..91321136d6 100644 --- a/CodeEdit/Documents/WorkspaceDocument.swift +++ b/CodeEdit/Documents/WorkspaceDocument.swift @@ -10,6 +10,7 @@ import AppKit import SwiftUI import WorkspaceClient import Combine +import CodeFile @objc(WorkspaceDocument) class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { @@ -19,12 +20,23 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { @Published var openFileItems: [WorkspaceClient.FileItem] = [] @Published var sortFoldersOnTop: Bool = true @Published var fileItems: [WorkspaceClient.FileItem] = [] - var openedCodeFiles: [WorkspaceClient.FileItem : CodeFile] = [:] - private var cancellable: AnyCancellable? + var openedCodeFiles: [WorkspaceClient.FileItem : CodeFileDocument] = [:] + private var cancellables = Set() deinit { - cancellable?.cancel() - cancellable = nil + cancellables.forEach { $0.cancel() } + } + + override init() { + super.init() +// $selectedId +// .sink { [weak self] id in +// guard let self = self else { return } +// if let item = self.fileItems.filter { $0.id == id }.first { +// self.openFile(item: item) +// } +// } +// .store(in: &cancellables) } func closeFileTab(item: WorkspaceClient.FileItem) { @@ -47,7 +59,7 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { func openFile(item: WorkspaceClient.FileItem) { do { - let codeFile = try CodeFile(for: item.url, withContentsOf: item.url, ofType: "public.source-code") + let codeFile = try CodeFileDocument(for: item.url, withContentsOf: item.url, ofType: "public.source-code") if !openFileItems.contains(item) { openFileItems.append(item) @@ -95,15 +107,10 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { folderURL: url, ignoredFilesAndFolders: ignoredFilesAndDirectory ) - cancellable = workspaceClient? + workspaceClient? .getFiles .sink { [weak self] files in guard let self = self else { return } - -// defer { -// // this sorts the array alphabetically -// self.fileItems = self.fileItems.sorted() -// } guard !self.fileItems.isEmpty else { self.fileItems = files @@ -124,6 +131,7 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { } } } + .store(in: &cancellables) } override func write(to url: URL, ofType typeName: String) throws {} diff --git a/CodeEdit/Editor/CodeFileEditor.swift b/CodeEdit/Editor/CodeFileEditor.swift deleted file mode 100644 index 6def3894b9..0000000000 --- a/CodeEdit/Editor/CodeFileEditor.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// CodeFileEditor.swift -// CodeEdit -// -// Created by Pavel Kasila on 17.03.22. -// - -import SwiftUI - -struct CodeFileEditor: View { - @ObservedObject var file: CodeFile - - var body: some View { - EditorView(text: $file.text) - } -} - -struct CodeFileEditor_Previews: PreviewProvider { - static var previews: some View { - CodeFileEditor(file: .init()) - } -} diff --git a/CodeEdit/Editor/EditorView.swift b/CodeEdit/Editor/EditorView.swift deleted file mode 100644 index 77f47be3e3..0000000000 --- a/CodeEdit/Editor/EditorView.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// EditorView.swift -// CodeEdit -// -// Created by Pavel Kasila on 12.03.22. -// - -import SwiftUI - -struct EditorView: View { - @Binding var text: String - - var body: some View { - TextEditor(text: $text) - .disableAutocorrection(true) - .font(.callout.monospaced()) - } -} - -struct EditorView_Previews: PreviewProvider { - static var previews: some View { - EditorView(text: .constant("Hello, world!")) - } -} diff --git a/CodeEdit/Editor/WorkspaceEditorView.swift b/CodeEdit/Editor/WorkspaceEditorView.swift deleted file mode 100644 index 9a179bbf41..0000000000 --- a/CodeEdit/Editor/WorkspaceEditorView.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// WorkspaceEditorView.swift -// CodeEdit -// -// Created by Pavel Kasila on 12.03.22. -// - -import SwiftUI -import WorkspaceClient - -struct WorkspaceEditorView: View { - @ObservedObject var workspace: WorkspaceDocument - var item: WorkspaceClient.FileItem - var windowController: NSWindowController - - var body: some View { - ScrollView(.vertical, showsIndicators: true) { - if let file = workspace.openedCodeFiles[item] { - CodeFileEditor(file: file) - } else { - Text("File cannot be opened") - } - } - .background(Color(nsColor: NSColor.textBackgroundColor)) - .onAppear { workspace.openFile(item: item) } - } -} diff --git a/CodeEdit/Info.plist b/CodeEdit/Info.plist index 9b44fcf5b3..8bd6939483 100644 --- a/CodeEdit/Info.plist +++ b/CodeEdit/Info.plist @@ -30,7 +30,7 @@ public.source-code NSDocumentClass - CodeFile + CodeFileDocument CFBundleURLTypes diff --git a/CodeEdit/SideBar/SideBar.swift b/CodeEdit/SideBar/SideBar.swift index ae4bad12ff..5ab819811f 100644 --- a/CodeEdit/SideBar/SideBar.swift +++ b/CodeEdit/SideBar/SideBar.swift @@ -13,8 +13,8 @@ struct SideBar: View { var windowController: NSWindowController @State private var selection: Int = 0 - var body: some View { - List { + var body: some View { + List { switch selection { case 0: Section(header: Text(workspace.fileURL?.lastPathComponent ?? "Unknown")) { @@ -28,13 +28,13 @@ struct SideBar: View { } default: EmptyView() } - } - .safeAreaInset(edge: .top) { - SideBarToolbarTop(selection: $selection) - .padding(.bottom, -8) - } - .safeAreaInset(edge: .bottom) { - SideBarToolbarBottom(workspace: workspace) - } - } + } + .safeAreaInset(edge: .top) { + SideBarToolbarTop(selection: $selection) + .padding(.bottom, -8) + } + .safeAreaInset(edge: .bottom) { + SideBarToolbarBottom(workspace: workspace) + } + } } diff --git a/CodeEdit/SideBar/SideBarItem.swift b/CodeEdit/SideBar/SideBarItem.swift index e552268d96..5787c18710 100644 --- a/CodeEdit/SideBar/SideBarItem.swift +++ b/CodeEdit/SideBar/SideBarItem.swift @@ -7,6 +7,7 @@ import SwiftUI import WorkspaceClient +import CodeFile struct SideBarItem: View { @@ -25,19 +26,26 @@ struct SideBarItem: View { } } - func sidebarFileItem(_ item: WorkspaceClient.FileItem) -> some View { + func sidebarFileItem(_ item: WorkspaceClient.FileItem) -> some View { NavigationLink(tag: item.id, selection: $workspace.selectedId) { - WorkspaceEditorView(workspace: workspace, item: item, windowController: windowController) - .safeAreaInset(edge: .top) { - TabBar(windowController: windowController, workspace: workspace) - } - } label: { + ZStack { + if let codeFile = workspace.openedCodeFiles[item] { + CodeFileView(codeFile: codeFile) + .safeAreaInset(edge: .top, spacing: 0) { + TabBar(windowController: windowController, workspace: workspace) + } + } else { + Text("File cannot be opened") + } + } + .onAppear { workspace.openFile(item: item) } + } label: { Label(item.url.lastPathComponent, systemImage: item.systemImage) .accentColor(.secondary) .font(.callout) } .buttonStyle(.plain) - } + } func sidebarFolderItem(_ item: WorkspaceClient.FileItem) -> some View { DisclosureGroup(isExpanded: $isExpanded) { diff --git a/CodeEditModules/Modules/CodeFile/Tests/UnitTests.swift b/CodeEditModules/Modules/CodeFile/Tests/UnitTests.swift new file mode 100644 index 0000000000..6d7cb94c4f --- /dev/null +++ b/CodeEditModules/Modules/CodeFile/Tests/UnitTests.swift @@ -0,0 +1,33 @@ +// +// UnitTests.swift +// CodeEdit +// +// Created by Marco Carnevali on 18/03/22. +// +@testable import CodeFile +import Foundation +import SnapshotTesting +import SwiftUI +import XCTest + +final class CodeFileUnitTests: XCTestCase { + func testViewSnapshot() throws { + let directory = try FileManager.default.url(for: .developerApplicationDirectory, in: .userDomainMask, appropriateFor: nil, create: true) + .appendingPathComponent("CodeEdit", isDirectory: true) + .appendingPathComponent("WorkspaceClientTests", isDirectory: true) + try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) + + let fileURL = directory.appendingPathComponent("fakeFile.md") + + try "Fake String".data(using: .utf8)?.write(to: fileURL) + let codeFile = try CodeFileDocument( + for: fileURL, + withContentsOf: fileURL, + ofType: "public.source-code" + ) + let view = CodeFileView(codeFile: codeFile) + let hosting = NSHostingView(rootView: view) + hosting.frame = CGRect(x: 0, y: 0, width: 100, height: 100) + assertSnapshot(matching: hosting, as: .image) + } +} diff --git a/CodeEditModules/Modules/CodeFile/Tests/__Snapshots__/UnitTests/testViewSnapshot.1.png b/CodeEditModules/Modules/CodeFile/Tests/__Snapshots__/UnitTests/testViewSnapshot.1.png new file mode 100644 index 0000000000..5ff74e142c Binary files /dev/null and b/CodeEditModules/Modules/CodeFile/Tests/__Snapshots__/UnitTests/testViewSnapshot.1.png differ diff --git a/CodeEditModules/Modules/CodeFile/src/CodeFile.swift b/CodeEditModules/Modules/CodeFile/src/CodeFile.swift new file mode 100644 index 0000000000..82a0fff029 --- /dev/null +++ b/CodeEditModules/Modules/CodeFile/src/CodeFile.swift @@ -0,0 +1,71 @@ +// +// CodeFile.swift +// CodeEdit +// +// Created by Rehatbir Singh on 12/03/2022. +// + +import AppKit +import CodeEditor +import Foundation +import SwiftUI + +public enum CodeFileError: Error { + case failedToDecode + case failedToEncode +} + +@objc(CodeFileDocument) +public final class CodeFileDocument: NSDocument, ObservableObject { + @Published var content = "" + + // MARK: - NSDocument + + override public class var autosavesInPlace: Bool { + return true + } + + public func fileLanguage() -> CodeEditor.Language { + if let fileURL = fileURL { + return .init(url: fileURL) + } else { + return .markdown + } + } + + override public func makeWindowControllers() { + // Returns the Storyboard that contains your Document window. + let contentView = CodeFileView(codeFile: self) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), + styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], + backing: .buffered, defer: false + ) + window.center() + window.contentView = NSHostingView(rootView: contentView) + let windowController = NSWindowController(window: window) + addWindowController(windowController) + } + + override public func data(ofType _: String) throws -> Data { + guard let data = content.data(using: .utf8) else { throw CodeFileError.failedToEncode } + return data + } + + override public func read(from data: Data, ofType _: String) throws { + guard let content = String(data: data, encoding: .utf8) else { throw CodeFileError.failedToDecode } + self.content = content + } +} + +private extension CodeEditor.Language { + init(url: URL) { + var value = url.pathExtension + switch value { + case "js": value = "javascript" + case "sh": value = "shell" + default: break + } + self.init(rawValue: value) + } +} diff --git a/CodeEditModules/Modules/CodeFile/src/CodeFileView.swift b/CodeEditModules/Modules/CodeFile/src/CodeFileView.swift new file mode 100644 index 0000000000..19ff86180e --- /dev/null +++ b/CodeEditModules/Modules/CodeFile/src/CodeFileView.swift @@ -0,0 +1,28 @@ +// +// CodeFileView.swift +// CodeEdit +// +// Created by Marco Carnevali on 17/03/22. +// + +import CodeEditor +import Foundation +import SwiftUI + +/// CodeFileView is just a wrapper of the `CodeEditor` dependency +public struct CodeFileView: View { + @ObservedObject public var codeFile: CodeFileDocument + + public init(codeFile: CodeFileDocument) { + self.codeFile = codeFile + } + + public var body: some View { + CodeEditor( + source: $codeFile.content, + language: codeFile.fileLanguage(), + theme: .atelierSavannaLight, + indentStyle: .system + ) + } +} diff --git a/CodeEditModules/Modules/WorkspaceClient/src/Model/FileItem+Array.swift b/CodeEditModules/Modules/WorkspaceClient/src/Model/FileItem+Array.swift index 8ac175eb9a..10e2e0be6c 100644 --- a/CodeEditModules/Modules/WorkspaceClient/src/Model/FileItem+Array.swift +++ b/CodeEditModules/Modules/WorkspaceClient/src/Model/FileItem+Array.swift @@ -1,25 +1,25 @@ // // File.swift -// +// // // Created by Lukas Pistrol on 17.03.22. // import Foundation -extension Array where Element == WorkspaceClient.FileItem { - public func sortItems(foldersOnTop: Bool) -> Self { - var alphabetically = self.sorted { $0.fileName < $1.fileName } +public extension Array where Element == WorkspaceClient.FileItem { + func sortItems(foldersOnTop: Bool) -> Self { + var alphabetically = sorted { $0.fileName < $1.fileName } - if foldersOnTop { - var foldersOnTop = alphabetically.filter { $0.children != nil } - alphabetically.removeAll { $0.children != nil } + if foldersOnTop { + var foldersOnTop = alphabetically.filter { $0.children != nil } + alphabetically.removeAll { $0.children != nil } - foldersOnTop.append(contentsOf: alphabetically) + foldersOnTop.append(contentsOf: alphabetically) - return foldersOnTop - } else { - return alphabetically - } - } + return foldersOnTop + } else { + return alphabetically + } + } } diff --git a/CodeEditModules/Modules/WorkspaceClient/src/Model/FileItem.swift b/CodeEditModules/Modules/WorkspaceClient/src/Model/FileItem.swift index 3c63ca6ebf..0f34b96c07 100644 --- a/CodeEditModules/Modules/WorkspaceClient/src/Model/FileItem.swift +++ b/CodeEditModules/Modules/WorkspaceClient/src/Model/FileItem.swift @@ -21,10 +21,11 @@ public extension WorkspaceClient { return children.isEmpty ? "folder" : "folder.fill" } } - public var fileName: String { - url.lastPathComponent - } - + + public var fileName: String { + url.lastPathComponent + } + public var fileIcon: String { switch fileType { case "json", "js": @@ -68,13 +69,14 @@ public extension WorkspaceClient { ) { self.url = url self.children = children - self.id = url.relativePath + id = url.relativePath } - - public static func ==(lhs: FileItem, rhs: FileItem) -> Bool { + + public static func == (lhs: FileItem, rhs: FileItem) -> Bool { return lhs.id == rhs.id } - public static func <(lhs: FileItem, rhs: FileItem) -> Bool { + + public static func < (lhs: FileItem, rhs: FileItem) -> Bool { return lhs.url.lastPathComponent < rhs.url.lastPathComponent } } diff --git a/CodeEditModules/Package.swift b/CodeEditModules/Package.swift index 8ae0a07f3a..1d03d550e1 100644 --- a/CodeEditModules/Package.swift +++ b/CodeEditModules/Package.swift @@ -6,15 +6,30 @@ let package = Package( name: "CodeEditModules", defaultLocalization: "en", platforms: [ - .macOS(.v10_15), + .macOS(.v11), ], products: [ .library( name: "WorkspaceClient", targets: ["WorkspaceClient"] ), + .library( + name: "CodeFile", + targets: ["CodeFile"] + ), + ], + dependencies: [ + .package( + name: "CodeEditor", + url: "https://github.com/ZeeZide/CodeEditor.git", + from: "1.2.0" + ), + .package( + name: "SnapshotTesting", + url: "https://github.com/pointfreeco/swift-snapshot-testing.git", + from: "1.9.0" + ), ], - dependencies: [], targets: [ .target( name: "WorkspaceClient", @@ -27,5 +42,20 @@ let package = Package( ], path: "Modules/WorkspaceClient/Tests" ), + .target( + name: "CodeFile", + dependencies: [ + "CodeEditor", + ], + path: "Modules/CodeFile/src" + ), + .testTarget( + name: "CodeFileTests", + dependencies: [ + "CodeFile", + "SnapshotTesting", + ], + path: "Modules/CodeFile/Tests" + ), ] )