diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index aa6f9ea1c..50fe3f958 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -7,10 +7,8 @@ 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 */; }; @@ -31,6 +29,7 @@ 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 */; }; @@ -55,12 +54,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 = ""; }; @@ -76,7 +72,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 = ""; }; @@ -96,6 +91,7 @@ buildActionMask = 2147483647; files = ( 5C403B8F27E20F8000788241 /* WorkspaceClient in Frameworks */, + 5CF38A5E27E48E6C0096A0F7 /* CodeFile in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -116,20 +112,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 */, ); @@ -237,7 +222,6 @@ 287776EA27E350A100D46668 /* SideBar */, 287776EB27E350BA00D46668 /* TabBar */, 345F667327DF6BCC0069BD69 /* Rows */, - 0439FEF327DD100800528317 /* Editor */, 04F2BF1027DBB3AF0024EAB1 /* Settings */, 34EE19BC27E0467F00F152CE /* CustomViews */, D7211D4427E066D4008F2ED7 /* Localization */, @@ -284,6 +268,7 @@ name = CodeEdit; packageProductDependencies = ( 5C403B8E27E20F8000788241 /* WorkspaceClient */, + 5CF38A5D27E48E6C0096A0F7 /* CodeFile */, ); productName = CodeEdit; productReference = B658FB2C27DA9E0F00EA4DBD /* CodeEdit.app */; @@ -409,7 +394,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 */, @@ -417,7 +401,6 @@ 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 */, @@ -791,6 +774,10 @@ isa = XCSwiftPackageProductDependency; productName = WorkspaceClient; }; + 5CF38A5D27E48E6C0096A0F7 /* CodeFile */ = { + isa = XCSwiftPackageProductDependency; + productName = CodeFile; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = B658FB2427DA9E0F00EA4DBD /* Project object */; diff --git a/CodeEdit.xcodeproj/xcshareddata/xcschemes/CodeEdit.xcscheme b/CodeEdit.xcodeproj/xcshareddata/xcschemes/CodeEdit.xcscheme new file mode 100644 index 000000000..f506603e1 --- /dev/null +++ b/CodeEdit.xcodeproj/xcshareddata/xcschemes/CodeEdit.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CodeEdit.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 000000000..8450bfb4c --- /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 c8a92524e..78822650a 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 06a4419ed..283bca1fa 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 c5b90a6a2..000000000 --- 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 e266e0ef2..e2263c716 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,13 +20,13 @@ 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] = [:] + + var openedCodeFiles: [WorkspaceClient.FileItem : CodeFileDocument] = [:] var folderURL: URL? - private var cancellable: AnyCancellable? + private var cancellables = Set() deinit { - cancellable?.cancel() - cancellable = nil + cancellables.forEach { $0.cancel() } } func closeFileTab(item: WorkspaceClient.FileItem) { @@ -48,7 +49,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) @@ -97,15 +98,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 @@ -126,6 +122,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 6def3894b..000000000 --- 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 77f47be3e..000000000 --- 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 9a179bbf4..000000000 --- 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 9b44fcf5b..8bd693948 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 ae4bad12f..5ab819811 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 7b11b2ff0..2d31e7c04 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,16 +26,23 @@ 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) { - VStack(spacing: 0) { - TabBar(windowController: windowController, workspace: workspace) - BreadcrumbsView(item, workspace: workspace) - } - } - } label: { + ZStack { + if let codeFile = workspace.openedCodeFiles[item] { + CodeFileView(codeFile: codeFile) + .safeAreaInset(edge: .top, spacing: 0) { + VStack(spacing: 0) { + TabBar(windowController: windowController, workspace: workspace) + BreadcrumbsView(item, workspace: workspace) + } + } + } else { + Text("File cannot be opened") + } + } + .onAppear { workspace.openFile(item: item) } + } label: { Label(item.url.lastPathComponent, systemImage: item.systemImage) .accentColor(item.iconColor) .font(.callout) diff --git a/CodeEditModules/Modules/CodeFile/Tests/UnitTests.swift b/CodeEditModules/Modules/CodeFile/Tests/UnitTests.swift new file mode 100644 index 000000000..6d7cb94c4 --- /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 000000000..5ff74e142 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 000000000..82a0fff02 --- /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 000000000..19ff86180 --- /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 8ac175eb9..10e2e0be6 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 b130ba413..a906a637f 100644 --- a/CodeEditModules/Modules/WorkspaceClient/src/Model/FileItem.swift +++ b/CodeEditModules/Modules/WorkspaceClient/src/Model/FileItem.swift @@ -22,10 +22,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": @@ -88,13 +89,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 8ae0a07f3..1d03d550e 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" + ), ] )