From 0834fc889138e394fc8d2e8f6b9386ecb38a58a0 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 10:40:14 +0300 Subject: [PATCH 01/16] Simple "Open Quickly" panel --- CodeEdit.xcodeproj/project.pbxproj | 12 ++++ CodeEdit/AppDelegate.swift | 70 ++++++++++--------- .../Documents/CodeEditWindowController.swift | 21 ++++++ CodeEdit/MainMenu.xib | 5 ++ CodeEdit/Quick Open/QuickOpenView.swift | 31 ++++++++ 5 files changed, 105 insertions(+), 34 deletions(-) create mode 100644 CodeEdit/Quick Open/QuickOpenView.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index 723038b1c..4ef444029 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 04660F6427E3ACAF00477777 /* Appearances.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6327E3ACAF00477777 /* Appearances.swift */; }; 04660F6627E3ACEF00477777 /* ReopenBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6527E3ACEF00477777 /* ReopenBehavior.swift */; }; 04660F6A27E51E5C00477777 /* CodeEditWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6927E51E5C00477777 /* CodeEditWindowController.swift */; }; + 0485EB1927E70F4900138301 /* QuickOpenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1827E70F4900138301 /* QuickOpenView.swift */; }; 286620A527E4AB6900E18C2B /* BreadcrumbsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */; }; 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */; }; 287776E727E3413200D46668 /* SideBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776E627E3413200D46668 /* SideBar.swift */; }; @@ -67,6 +68,7 @@ 04660F6527E3ACEF00477777 /* ReopenBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReopenBehavior.swift; sourceTree = ""; }; 04660F6927E51E5C00477777 /* CodeEditWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeEditWindowController.swift; sourceTree = ""; }; 0468438427DC76E200F8E88E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 0485EB1827E70F4900138301 /* QuickOpenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenView.swift; sourceTree = ""; }; 04ADA0C827E5D29000BF00B2 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 04ADA0CA27E5D41F00BF00B2 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/Localizable.strings; sourceTree = ""; }; 04F2BF0E27DBB28E0024EAB1 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; @@ -148,6 +150,14 @@ path = Models; sourceTree = ""; }; + 0485EB1727E7016400138301 /* Quick Open */ = { + isa = PBXGroup; + children = ( + 0485EB1827E70F4900138301 /* QuickOpenView.swift */, + ); + path = "Quick Open"; + sourceTree = ""; + }; 04F2BF1027DBB3AF0024EAB1 /* Settings */ = { isa = PBXGroup; children = ( @@ -232,6 +242,7 @@ B658FB2E27DA9E0F00EA4DBD /* CodeEdit */ = { isa = PBXGroup; children = ( + 0485EB1727E7016400138301 /* Quick Open */, 04660F6027E3A68A00477777 /* Info.plist */, D72E1A8127E3B0A300EB11B9 /* Welcome */, 043C321227E31FE8006AE443 /* Documents */, @@ -477,6 +488,7 @@ 34EE19BE27E0469C00F152CE /* BlurView.swift in Sources */, D7211D4327E066CE008F2ED7 /* Localized+Ex.swift in Sources */, 287776E927E34BC700D46668 /* TabBar.swift in Sources */, + 0485EB1927E70F4900138301 /* QuickOpenView.swift in Sources */, 286620A527E4AB6900E18C2B /* BreadcrumbsComponent.swift in Sources */, 287776EF27E3515300D46668 /* TabBarItem.swift in Sources */, D72E1A8727E4242900EB11B9 /* RecentProjectsView.swift in Sources */, diff --git a/CodeEdit/AppDelegate.swift b/CodeEdit/AppDelegate.swift index a731d9d39..c21739334 100644 --- a/CodeEdit/AppDelegate.swift +++ b/CodeEdit/AppDelegate.swift @@ -46,40 +46,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { return true } - @IBAction func openPreferences(_ sender: Any) { - if let window = NSApp.windows.filter({ window in - return (window.contentView as? NSHostingView) != nil - }).first { - window.makeKeyAndOrderFront(self) - return - } - - let window = NSWindow( - contentRect: NSRect(x: 0, y: 0, width: 500, height: 400), - styleMask: [.titled, .closable], - backing: .buffered, defer: false) - window.center() - window.toolbar = NSToolbar() - window.title = "Settings" - window.toolbarStyle = .unifiedCompact - _ = NSWindowController(window: window) - let contentView = SettingsView() - window.contentView = NSHostingView(rootView: contentView) - window.makeKeyAndOrderFront(sender) - } - - @IBAction func openWelcome(_ sender: Any) { - let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 800, height: 460), - styleMask: [.titled, .fullSizeContentView], backing: .buffered, defer: false) - let windowController = NSWindowController(window: window) - window.center() - let contentView = WelcomeWindowView(windowController: windowController).edgesIgnoringSafeArea(.top) - window.titlebarAppearsTransparent = true - window.isMovableByWindowBackground = true - window.contentView = NSHostingView(rootView: contentView) - window.makeKeyAndOrderFront(self) - } - func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool { if flag { return false @@ -118,4 +84,40 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { } return .terminateNow } + + // MARK: - Open windows + + @IBAction func openPreferences(_ sender: Any) { + if let window = NSApp.windows.filter({ window in + return (window.contentView as? NSHostingView) != nil + }).first { + window.makeKeyAndOrderFront(self) + return + } + + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 500, height: 400), + styleMask: [.titled, .closable], + backing: .buffered, defer: false) + window.center() + window.toolbar = NSToolbar() + window.title = "Settings" + window.toolbarStyle = .unifiedCompact + _ = NSWindowController(window: window) + let contentView = SettingsView() + window.contentView = NSHostingView(rootView: contentView) + window.makeKeyAndOrderFront(sender) + } + + @IBAction func openWelcome(_ sender: Any) { + let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 800, height: 460), + styleMask: [.titled, .fullSizeContentView], backing: .buffered, defer: false) + let windowController = NSWindowController(window: window) + window.center() + let contentView = WelcomeWindowView(windowController: windowController).edgesIgnoringSafeArea(.top) + window.titlebarAppearsTransparent = true + window.isMovableByWindowBackground = true + window.contentView = NSHostingView(rootView: contentView) + window.makeKeyAndOrderFront(self) + } } diff --git a/CodeEdit/Documents/CodeEditWindowController.swift b/CodeEdit/Documents/CodeEditWindowController.swift index 03658e539..5f4ce30f9 100644 --- a/CodeEdit/Documents/CodeEditWindowController.swift +++ b/CodeEdit/Documents/CodeEditWindowController.swift @@ -6,6 +6,7 @@ // import Cocoa +import SwiftUI import CodeFile class CodeEditWindowController: NSWindowController { @@ -31,4 +32,24 @@ class CodeEditWindowController: NSWindowController { @IBAction func saveDocument(_ sender: Any) { getSelectedCodeFile()?.save(sender) } + + @IBAction func openQuickly(_ sender: Any) { + if let window = NSApp.windows.filter({ window in + return (window.contentView as? NSHostingView) != nil + }).first { + window.close() + return + } + + let panel = NSPanel( + contentRect: NSRect(x: 0, y: 0, width: 500, height: 48), + styleMask: [.fullSizeContentView, .titled], + backing: .buffered, defer: false) + let contentView = QuickOpenView() + panel.center() + panel.titlebarAppearsTransparent = true + panel.isMovableByWindowBackground = true + panel.contentView = NSHostingView(rootView: contentView) + panel.makeKeyAndOrderFront(sender) + } } diff --git a/CodeEdit/MainMenu.xib b/CodeEdit/MainMenu.xib index 7460f6d53..605193b44 100644 --- a/CodeEdit/MainMenu.xib +++ b/CodeEdit/MainMenu.xib @@ -85,6 +85,11 @@ + + + + + diff --git a/CodeEdit/Quick Open/QuickOpenView.swift b/CodeEdit/Quick Open/QuickOpenView.swift new file mode 100644 index 000000000..3aad847d1 --- /dev/null +++ b/CodeEdit/Quick Open/QuickOpenView.swift @@ -0,0 +1,31 @@ +// +// QuickOpenView.swift +// CodeEdit +// +// Created by Pavel Kasila on 20.03.22. +// + +import SwiftUI + +struct QuickOpenView: View { + var body: some View { + HStack(alignment: .center, spacing: 0) { + Image(systemName: "doc.text.magnifyingglass") + .imageScale(.large) + .padding(.horizontal) + TextField("Open Quickly", text: .constant("")) + .font(.system(size: 22, weight: .light, design: .default)) + .textFieldStyle(.plain) + } + .foregroundColor(.primary.opacity(0.8)) + .frame(maxHeight: .infinity) + .background(BlurView(material: .hudWindow, blendingMode: .behindWindow)) + .edgesIgnoringSafeArea(.vertical) + } +} + +struct QuickOpenView_Previews: PreviewProvider { + static var previews: some View { + QuickOpenView() + } +} From fa7e2e57028dfc10191edc15f44a6b0120bfe7c3 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 10:51:23 +0300 Subject: [PATCH 02/16] Make "Open Quickly" panel child window of Workspace window --- CodeEdit/Documents/CodeEditWindowController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeEdit/Documents/CodeEditWindowController.swift b/CodeEdit/Documents/CodeEditWindowController.swift index 5f4ce30f9..d0de75e7a 100644 --- a/CodeEdit/Documents/CodeEditWindowController.swift +++ b/CodeEdit/Documents/CodeEditWindowController.swift @@ -50,6 +50,6 @@ class CodeEditWindowController: NSWindowController { panel.titlebarAppearsTransparent = true panel.isMovableByWindowBackground = true panel.contentView = NSHostingView(rootView: contentView) - panel.makeKeyAndOrderFront(sender) + window?.addChildWindow(panel, ordered: .above) } } From d759ac7f1c428495094036d04b00cc386e6a2462 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 10:56:35 +0300 Subject: [PATCH 03/16] Provide QuickOpenView access to WorkspaceDocument, store query in the WorkspaceDocument --- CodeEdit/AppDelegate.swift | 4 +-- .../Documents/CodeEditWindowController.swift | 34 ++++++++++--------- CodeEdit/Documents/WorkspaceDocument.swift | 2 ++ CodeEdit/Quick Open/QuickOpenView.swift | 22 +++++++----- 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/CodeEdit/AppDelegate.swift b/CodeEdit/AppDelegate.swift index c21739334..80b3c6f48 100644 --- a/CodeEdit/AppDelegate.swift +++ b/CodeEdit/AppDelegate.swift @@ -84,9 +84,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject { } return .terminateNow } - + // MARK: - Open windows - + @IBAction func openPreferences(_ sender: Any) { if let window = NSApp.windows.filter({ window in return (window.contentView as? NSHostingView) != nil diff --git a/CodeEdit/Documents/CodeEditWindowController.swift b/CodeEdit/Documents/CodeEditWindowController.swift index d0de75e7a..cc94dc7c2 100644 --- a/CodeEdit/Documents/CodeEditWindowController.swift +++ b/CodeEdit/Documents/CodeEditWindowController.swift @@ -34,22 +34,24 @@ class CodeEditWindowController: NSWindowController { } @IBAction func openQuickly(_ sender: Any) { - if let window = NSApp.windows.filter({ window in - return (window.contentView as? NSHostingView) != nil - }).first { - window.close() - return + if let workspace = workspace { + if let window = NSApp.windows.filter({ window in + return (window.contentView as? NSHostingView) != nil + }).first { + window.close() + return + } + + let panel = NSPanel( + contentRect: NSRect(x: 0, y: 0, width: 500, height: 48), + styleMask: [.fullSizeContentView, .titled], + backing: .buffered, defer: false) + let contentView = QuickOpenView(workspace: workspace) + panel.center() + panel.titlebarAppearsTransparent = true + panel.isMovableByWindowBackground = true + panel.contentView = NSHostingView(rootView: contentView) + window?.addChildWindow(panel, ordered: .above) } - - let panel = NSPanel( - contentRect: NSRect(x: 0, y: 0, width: 500, height: 48), - styleMask: [.fullSizeContentView, .titled], - backing: .buffered, defer: false) - let contentView = QuickOpenView() - panel.center() - panel.titlebarAppearsTransparent = true - panel.isMovableByWindowBackground = true - panel.contentView = NSHostingView(rootView: contentView) - window?.addChildWindow(panel, ordered: .above) } } diff --git a/CodeEdit/Documents/WorkspaceDocument.swift b/CodeEdit/Documents/WorkspaceDocument.swift index 755973fc1..9da3ddbf5 100644 --- a/CodeEdit/Documents/WorkspaceDocument.swift +++ b/CodeEdit/Documents/WorkspaceDocument.swift @@ -20,6 +20,8 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { @Published var sortFoldersOnTop: Bool = true @Published var fileItems: [WorkspaceClient.FileItem] = [] + @Published var openQuicklyQuery: String = "" + var openedCodeFiles: [WorkspaceClient.FileItem: CodeFileDocument] = [:] var folderURL: URL? private var cancellables = Set() diff --git a/CodeEdit/Quick Open/QuickOpenView.swift b/CodeEdit/Quick Open/QuickOpenView.swift index 3aad847d1..04c09fece 100644 --- a/CodeEdit/Quick Open/QuickOpenView.swift +++ b/CodeEdit/Quick Open/QuickOpenView.swift @@ -8,16 +8,20 @@ import SwiftUI struct QuickOpenView: View { + @ObservedObject var workspace: WorkspaceDocument + var body: some View { - HStack(alignment: .center, spacing: 0) { - Image(systemName: "doc.text.magnifyingglass") - .imageScale(.large) - .padding(.horizontal) - TextField("Open Quickly", text: .constant("")) - .font(.system(size: 22, weight: .light, design: .default)) - .textFieldStyle(.plain) + VStack { + HStack(alignment: .center, spacing: 0) { + Image(systemName: "doc.text.magnifyingglass") + .imageScale(.large) + .padding(.horizontal) + TextField("Open Quickly", text: $workspace.openQuicklyQuery) + .font(.system(size: 22, weight: .light, design: .default)) + .textFieldStyle(.plain) + } + .foregroundColor(.primary.opacity(0.8)) } - .foregroundColor(.primary.opacity(0.8)) .frame(maxHeight: .infinity) .background(BlurView(material: .hudWindow, blendingMode: .behindWindow)) .edgesIgnoringSafeArea(.vertical) @@ -26,6 +30,6 @@ struct QuickOpenView: View { struct QuickOpenView_Previews: PreviewProvider { static var previews: some View { - QuickOpenView() + QuickOpenView(workspace: .init()) } } From 4648748b8028ddba4af4c7e65bc653d9592d9cf2 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 11:01:57 +0300 Subject: [PATCH 04/16] Focus on "Open Quickly" panel --- CodeEdit/Documents/CodeEditWindowController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/CodeEdit/Documents/CodeEditWindowController.swift b/CodeEdit/Documents/CodeEditWindowController.swift index cc94dc7c2..51ed2a5cf 100644 --- a/CodeEdit/Documents/CodeEditWindowController.swift +++ b/CodeEdit/Documents/CodeEditWindowController.swift @@ -52,6 +52,7 @@ class CodeEditWindowController: NSWindowController { panel.isMovableByWindowBackground = true panel.contentView = NSHostingView(rootView: contentView) window?.addChildWindow(panel, ordered: .above) + panel.makeKeyAndOrderFront(self) } } } From 15085427ae21bc2ae57594bf0d6db673c147288a Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 11:37:02 +0300 Subject: [PATCH 05/16] Sample List below search bar --- CodeEdit.xcodeproj/project.pbxproj | 4 +++ .../Documents/CodeEditWindowController.swift | 4 +-- CodeEdit/Quick Open/QuickOpenPanel.swift | 16 ++++++++++ CodeEdit/Quick Open/QuickOpenView.swift | 30 ++++++++++++------- 4 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 CodeEdit/Quick Open/QuickOpenPanel.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index 4ef444029..2e8a7b090 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 04660F6627E3ACEF00477777 /* ReopenBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6527E3ACEF00477777 /* ReopenBehavior.swift */; }; 04660F6A27E51E5C00477777 /* CodeEditWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6927E51E5C00477777 /* CodeEditWindowController.swift */; }; 0485EB1927E70F4900138301 /* QuickOpenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1827E70F4900138301 /* QuickOpenView.swift */; }; + 0485EB1B27E71BF400138301 /* QuickOpenPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */; }; 286620A527E4AB6900E18C2B /* BreadcrumbsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */; }; 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */; }; 287776E727E3413200D46668 /* SideBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776E627E3413200D46668 /* SideBar.swift */; }; @@ -69,6 +70,7 @@ 04660F6927E51E5C00477777 /* CodeEditWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeEditWindowController.swift; sourceTree = ""; }; 0468438427DC76E200F8E88E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 0485EB1827E70F4900138301 /* QuickOpenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenView.swift; sourceTree = ""; }; + 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenPanel.swift; sourceTree = ""; }; 04ADA0C827E5D29000BF00B2 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 04ADA0CA27E5D41F00BF00B2 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/Localizable.strings; sourceTree = ""; }; 04F2BF0E27DBB28E0024EAB1 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; @@ -154,6 +156,7 @@ isa = PBXGroup; children = ( 0485EB1827E70F4900138301 /* QuickOpenView.swift */, + 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */, ); path = "Quick Open"; sourceTree = ""; @@ -479,6 +482,7 @@ files = ( 2B7A583527E4BA0100D25D4E /* AppDelegate.swift in Sources */, 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */, + 0485EB1B27E71BF400138301 /* QuickOpenPanel.swift in Sources */, 04540D5B27DD08C300E91B77 /* SettingsView.swift in Sources */, D72E1A8927E44D7C00EB11B9 /* WelcomeWindowView.swift in Sources */, 04540D5C27DD08C300E91B77 /* GeneralSettingsView.swift in Sources */, diff --git a/CodeEdit/Documents/CodeEditWindowController.swift b/CodeEdit/Documents/CodeEditWindowController.swift index 51ed2a5cf..67a328e38 100644 --- a/CodeEdit/Documents/CodeEditWindowController.swift +++ b/CodeEdit/Documents/CodeEditWindowController.swift @@ -42,9 +42,9 @@ class CodeEditWindowController: NSWindowController { return } - let panel = NSPanel( + let panel = QuickOpenPanel( contentRect: NSRect(x: 0, y: 0, width: 500, height: 48), - styleMask: [.fullSizeContentView, .titled], + styleMask: [.fullSizeContentView, .titled, .resizable], backing: .buffered, defer: false) let contentView = QuickOpenView(workspace: workspace) panel.center() diff --git a/CodeEdit/Quick Open/QuickOpenPanel.swift b/CodeEdit/Quick Open/QuickOpenPanel.swift new file mode 100644 index 000000000..161c0e73b --- /dev/null +++ b/CodeEdit/Quick Open/QuickOpenPanel.swift @@ -0,0 +1,16 @@ +// +// QuickOpenPanel.swift +// CodeEdit +// +// Created by Pavel Kasila on 20.03.22. +// + +import Cocoa + +class QuickOpenPanel: NSPanel { + override func standardWindowButton(_ button: NSWindow.ButtonType) -> NSButton? { + let btn = super.standardWindowButton(button) + btn?.isHidden = true + return btn + } +} diff --git a/CodeEdit/Quick Open/QuickOpenView.swift b/CodeEdit/Quick Open/QuickOpenView.swift index 04c09fece..654119c9b 100644 --- a/CodeEdit/Quick Open/QuickOpenView.swift +++ b/CodeEdit/Quick Open/QuickOpenView.swift @@ -11,19 +11,27 @@ struct QuickOpenView: View { @ObservedObject var workspace: WorkspaceDocument var body: some View { - VStack { - HStack(alignment: .center, spacing: 0) { - Image(systemName: "doc.text.magnifyingglass") - .imageScale(.large) - .padding(.horizontal) - TextField("Open Quickly", text: $workspace.openQuicklyQuery) - .font(.system(size: 22, weight: .light, design: .default)) - .textFieldStyle(.plain) + VStack(spacing: 0.0) { + VStack { + HStack(alignment: .center, spacing: 0) { + Image(systemName: "doc.text.magnifyingglass") + .imageScale(.large) + .padding(.horizontal) + TextField("Open Quickly", text: $workspace.openQuicklyQuery) + .font(.system(size: 22, weight: .light, design: .default)) + .textFieldStyle(.plain) + } + .padding(.vertical) + .foregroundColor(.primary.opacity(0.85)) } - .foregroundColor(.primary.opacity(0.8)) + Divider() + List(0..<100) { item in + Text("Item \(item)") + } + .removeBackground() } - .frame(maxHeight: .infinity) - .background(BlurView(material: .hudWindow, blendingMode: .behindWindow)) + .frame(minWidth: 500, minHeight: 400, maxHeight: .infinity) + .background(BlurView(material: .popover, blendingMode: .behindWindow)) .edgesIgnoringSafeArea(.vertical) } } From e45825d6e40206fb8ca395b7707fe7fab4d846b1 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 13:29:36 +0300 Subject: [PATCH 06/16] Open file on double click --- CodeEdit.xcodeproj/project.pbxproj | 4 ++ .../Documents/CodeEditWindowController.swift | 7 +++- CodeEdit/Documents/WorkspaceDocument.swift | 30 ++++++++++++++ CodeEdit/Quick Open/QuickOpenItem.swift | 28 +++++++++++++ CodeEdit/Quick Open/QuickOpenView.swift | 39 ++++++++++++++++--- 5 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 CodeEdit/Quick Open/QuickOpenItem.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index 2e8a7b090..7fa5452ea 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 04660F6A27E51E5C00477777 /* CodeEditWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6927E51E5C00477777 /* CodeEditWindowController.swift */; }; 0485EB1927E70F4900138301 /* QuickOpenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1827E70F4900138301 /* QuickOpenView.swift */; }; 0485EB1B27E71BF400138301 /* QuickOpenPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */; }; + 0485EB1D27E7338100138301 /* QuickOpenItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1C27E7338100138301 /* QuickOpenItem.swift */; }; 286620A527E4AB6900E18C2B /* BreadcrumbsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */; }; 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */; }; 287776E727E3413200D46668 /* SideBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776E627E3413200D46668 /* SideBar.swift */; }; @@ -71,6 +72,7 @@ 0468438427DC76E200F8E88E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 0485EB1827E70F4900138301 /* QuickOpenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenView.swift; sourceTree = ""; }; 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenPanel.swift; sourceTree = ""; }; + 0485EB1C27E7338100138301 /* QuickOpenItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenItem.swift; sourceTree = ""; }; 04ADA0C827E5D29000BF00B2 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 04ADA0CA27E5D41F00BF00B2 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/Localizable.strings; sourceTree = ""; }; 04F2BF0E27DBB28E0024EAB1 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; @@ -157,6 +159,7 @@ children = ( 0485EB1827E70F4900138301 /* QuickOpenView.swift */, 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */, + 0485EB1C27E7338100138301 /* QuickOpenItem.swift */, ); path = "Quick Open"; sourceTree = ""; @@ -482,6 +485,7 @@ files = ( 2B7A583527E4BA0100D25D4E /* AppDelegate.swift in Sources */, 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */, + 0485EB1D27E7338100138301 /* QuickOpenItem.swift in Sources */, 0485EB1B27E71BF400138301 /* QuickOpenPanel.swift in Sources */, 04540D5B27DD08C300E91B77 /* SettingsView.swift in Sources */, D72E1A8927E44D7C00EB11B9 /* WelcomeWindowView.swift in Sources */, diff --git a/CodeEdit/Documents/CodeEditWindowController.swift b/CodeEdit/Documents/CodeEditWindowController.swift index 67a328e38..b0fdd9a6f 100644 --- a/CodeEdit/Documents/CodeEditWindowController.swift +++ b/CodeEdit/Documents/CodeEditWindowController.swift @@ -35,7 +35,7 @@ class CodeEditWindowController: NSWindowController { @IBAction func openQuickly(_ sender: Any) { if let workspace = workspace { - if let window = NSApp.windows.filter({ window in + if let window = window?.childWindows?.filter({ window in return (window.contentView as? NSHostingView) != nil }).first { window.close() @@ -46,7 +46,10 @@ class CodeEditWindowController: NSWindowController { contentRect: NSRect(x: 0, y: 0, width: 500, height: 48), styleMask: [.fullSizeContentView, .titled, .resizable], backing: .buffered, defer: false) - let contentView = QuickOpenView(workspace: workspace) + let contentView = QuickOpenView(workspace: workspace) { + self.window?.removeChildWindow(panel) + panel.close() + } panel.center() panel.titlebarAppearsTransparent = true panel.isMovableByWindowBackground = true diff --git a/CodeEdit/Documents/WorkspaceDocument.swift b/CodeEdit/Documents/WorkspaceDocument.swift index 9da3ddbf5..0f195d887 100644 --- a/CodeEdit/Documents/WorkspaceDocument.swift +++ b/CodeEdit/Documents/WorkspaceDocument.swift @@ -21,6 +21,8 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { @Published var fileItems: [WorkspaceClient.FileItem] = [] @Published var openQuicklyQuery: String = "" + @Published var openQuicklyFiles: [WorkspaceClient.FileItem] = [] + @Published var isShowingOpenQuicklyFiles: Bool = false var openedCodeFiles: [WorkspaceClient.FileItem: CodeFileDocument] = [:] var folderURL: URL? @@ -147,4 +149,32 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { } super.close() } + + func fetchOpenQuickly() { + if openQuicklyQuery == "" { + openQuicklyFiles = [] + self.isShowingOpenQuicklyFiles = !openQuicklyFiles.isEmpty + return + } + + if let url = fileURL { + let enumerator = FileManager.default.enumerator(at: url, + includingPropertiesForKeys: [ + .isRegularFileKey + ], + options: [ + .skipsHiddenFiles, + .skipsPackageDescendants + ]) + if let filePaths = enumerator?.allObjects as? [URL] { + openQuicklyFiles = filePaths.filter { + $0.lastPathComponent.lowercased().contains(openQuicklyQuery.lowercased()) + }.map { url in + WorkspaceClient.FileItem(url: url, children: nil) + } + } + } + + self.isShowingOpenQuicklyFiles = !openQuicklyFiles.isEmpty + } } diff --git a/CodeEdit/Quick Open/QuickOpenItem.swift b/CodeEdit/Quick Open/QuickOpenItem.swift new file mode 100644 index 000000000..88c1cb687 --- /dev/null +++ b/CodeEdit/Quick Open/QuickOpenItem.swift @@ -0,0 +1,28 @@ +// +// QuickOpenItem.swift +// CodeEdit +// +// Created by Pavel Kasila on 20.03.22. +// + +import SwiftUI +import WorkspaceClient + +public struct QuickOpenItem: View { + let fileItem: WorkspaceClient.FileItem + + public var body: some View { + HStack(spacing: 8) { + Image(nsImage: NSWorkspace.shared.icon(forFile: fileItem.url.path)) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 32, height: 32) + VStack(alignment: .leading) { + Text(fileItem.url.lastPathComponent).font(.system(size: 13)) + .lineLimit(1) + }.padding(.trailing, 15) + Spacer() + } + .contentShape(Rectangle()) + } +} diff --git a/CodeEdit/Quick Open/QuickOpenView.swift b/CodeEdit/Quick Open/QuickOpenView.swift index 654119c9b..6fed017d1 100644 --- a/CodeEdit/Quick Open/QuickOpenView.swift +++ b/CodeEdit/Quick Open/QuickOpenView.swift @@ -9,6 +9,7 @@ import SwiftUI struct QuickOpenView: View { @ObservedObject var workspace: WorkspaceDocument + var onClose: () -> Void var body: some View { VStack(spacing: 0.0) { @@ -20,24 +21,50 @@ struct QuickOpenView: View { TextField("Open Quickly", text: $workspace.openQuicklyQuery) .font(.system(size: 22, weight: .light, design: .default)) .textFieldStyle(.plain) + .onReceive( + workspace.$openQuicklyQuery + .debounce(for: .seconds(0.4), scheduler: DispatchQueue.main) + ) { _ in + workspace.fetchOpenQuickly() + } } + .frame(height: 28) .padding(.vertical) .foregroundColor(.primary.opacity(0.85)) + .background(BlurView(material: .sidebar, blendingMode: .behindWindow)) } Divider() - List(0..<100) { item in - Text("Item \(item)") + NavigationView { + List(workspace.openQuicklyFiles, id: \.id) { file in + NavigationLink { + Text(file.url.lastPathComponent) + } label: { + QuickOpenItem(fileItem: file) + } + .onTapGesture(count: 2) { + workspace.openFile(item: file) + self.onClose() + } + } + .removeBackground() + .frame(minWidth: 250, maxWidth: 250) + if workspace.openQuicklyFiles.isEmpty { + EmptyView() + } else { + Text("Select a file to preview") + } } - .removeBackground() } - .frame(minWidth: 500, minHeight: 400, maxHeight: .infinity) - .background(BlurView(material: .popover, blendingMode: .behindWindow)) + .background(BlurView(material: .sidebar, blendingMode: .behindWindow)) .edgesIgnoringSafeArea(.vertical) + .frame(minWidth: 600, + minHeight: 400, + maxHeight: .infinity) } } struct QuickOpenView_Previews: PreviewProvider { static var previews: some View { - QuickOpenView(workspace: .init()) + QuickOpenView(workspace: .init(), onClose: {}) } } From 4aa864102b2248e667645cd3a235a42dcf37a9b5 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 14:28:09 +0300 Subject: [PATCH 07/16] Fix unexpected behavior when closing file opened through "Open Quickly" --- CodeEdit.xcodeproj/project.pbxproj | 4 +++ .../Documents/WorkspaceCodeFileView.swift | 28 +++++++++++++++++++ CodeEdit/Documents/WorkspaceDocument.swift | 4 +-- CodeEdit/SideBar/SideBarItem.swift | 12 +++----- CodeEdit/WorkspaceView.swift | 11 +++++++- 5 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 CodeEdit/Documents/WorkspaceCodeFileView.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index 7fa5452ea..c1074f3a4 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ 0485EB1927E70F4900138301 /* QuickOpenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1827E70F4900138301 /* QuickOpenView.swift */; }; 0485EB1B27E71BF400138301 /* QuickOpenPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */; }; 0485EB1D27E7338100138301 /* QuickOpenItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1C27E7338100138301 /* QuickOpenItem.swift */; }; + 0485EB1F27E7458B00138301 /* WorkspaceCodeFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1E27E7458B00138301 /* WorkspaceCodeFileView.swift */; }; 286620A527E4AB6900E18C2B /* BreadcrumbsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */; }; 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */; }; 287776E727E3413200D46668 /* SideBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776E627E3413200D46668 /* SideBar.swift */; }; @@ -73,6 +74,7 @@ 0485EB1827E70F4900138301 /* QuickOpenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenView.swift; sourceTree = ""; }; 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenPanel.swift; sourceTree = ""; }; 0485EB1C27E7338100138301 /* QuickOpenItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenItem.swift; sourceTree = ""; }; + 0485EB1E27E7458B00138301 /* WorkspaceCodeFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceCodeFileView.swift; sourceTree = ""; }; 04ADA0C827E5D29000BF00B2 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 04ADA0CA27E5D41F00BF00B2 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/Localizable.strings; sourceTree = ""; }; 04F2BF0E27DBB28E0024EAB1 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; @@ -140,6 +142,7 @@ 043C321327E31FF6006AE443 /* CodeEditDocumentController.swift */, 043C321527E3201F006AE443 /* WorkspaceDocument.swift */, 04660F6927E51E5C00477777 /* CodeEditWindowController.swift */, + 0485EB1E27E7458B00138301 /* WorkspaceCodeFileView.swift */, ); path = Documents; sourceTree = ""; @@ -496,6 +499,7 @@ 34EE19BE27E0469C00F152CE /* BlurView.swift in Sources */, D7211D4327E066CE008F2ED7 /* Localized+Ex.swift in Sources */, 287776E927E34BC700D46668 /* TabBar.swift in Sources */, + 0485EB1F27E7458B00138301 /* WorkspaceCodeFileView.swift in Sources */, 0485EB1927E70F4900138301 /* QuickOpenView.swift in Sources */, 286620A527E4AB6900E18C2B /* BreadcrumbsComponent.swift in Sources */, 287776EF27E3515300D46668 /* TabBarItem.swift in Sources */, diff --git a/CodeEdit/Documents/WorkspaceCodeFileView.swift b/CodeEdit/Documents/WorkspaceCodeFileView.swift new file mode 100644 index 000000000..a3696496b --- /dev/null +++ b/CodeEdit/Documents/WorkspaceCodeFileView.swift @@ -0,0 +1,28 @@ +// +// WorkspaceCodeFileEditor.swift +// CodeEdit +// +// Created by Pavel Kasila on 20.03.22. +// + +import SwiftUI +import CodeFile +import WorkspaceClient + +struct WorkspaceCodeFileView: View { + var codeFile: CodeFileDocument + var windowController: NSWindowController + var workspace: WorkspaceDocument + var item: WorkspaceClient.FileItem + + var body: some View { + CodeFileView(codeFile: codeFile) + .safeAreaInset(edge: .top, spacing: 0) { + VStack(spacing: 0) { + TabBar(windowController: windowController, workspace: workspace) + CustomDivider() + BreadcrumbsView(item, workspace: workspace) + } + } + } +} diff --git a/CodeEdit/Documents/WorkspaceDocument.swift b/CodeEdit/Documents/WorkspaceDocument.swift index 0f195d887..b496318e3 100644 --- a/CodeEdit/Documents/WorkspaceDocument.swift +++ b/CodeEdit/Documents/WorkspaceDocument.swift @@ -33,6 +33,7 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { } func closeFileTab(item: WorkspaceClient.FileItem) { + Swift.print(item) defer { let file = openedCodeFiles.removeValue(forKey: item) file?.save(self) @@ -40,11 +41,10 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { guard let idx = openFileItems.firstIndex(of: item) else { return } let closedFileItem = openFileItems.remove(at: idx) - guard closedFileItem.id == selectedId else { return } + guard closedFileItem.id == item.id else { return } if openFileItems.isEmpty { selectedId = nil - self.windowControllers.first?.document = self } else if idx == 0 { selectedId = openFileItems.first?.id } else { diff --git a/CodeEdit/SideBar/SideBarItem.swift b/CodeEdit/SideBar/SideBarItem.swift index 670852921..0bf60406e 100644 --- a/CodeEdit/SideBar/SideBarItem.swift +++ b/CodeEdit/SideBar/SideBarItem.swift @@ -32,14 +32,10 @@ struct SideBarItem: View { NavigationLink(tag: item.id, selection: $workspace.selectedId) { ZStack { if let codeFile = workspace.openedCodeFiles[item] { - CodeFileView(codeFile: codeFile) - .safeAreaInset(edge: .top, spacing: 0) { - VStack(spacing: 0) { - TabBar(windowController: windowController, workspace: workspace) - CustomDivider() - BreadcrumbsView(item, workspace: workspace) - } - } + WorkspaceCodeFileView(codeFile: codeFile, + windowController: windowController, + workspace: workspace, + item: item) } else { Text("CodeEdit cannot open this file because its file type is not supported.") } diff --git a/CodeEdit/WorkspaceView.swift b/CodeEdit/WorkspaceView.swift index 796e64877..5d4586e09 100644 --- a/CodeEdit/WorkspaceView.swift +++ b/CodeEdit/WorkspaceView.swift @@ -30,7 +30,16 @@ struct WorkspaceView: View { SideBar(workspace: workspace, windowController: windowController) .frame(minWidth: 250) - Text("Open file from sidebar") + if let item = workspace.openFileItems.first(where: { file in + return file.id == workspace.selectedId + }), let codeFile = workspace.openedCodeFiles[item] { + WorkspaceCodeFileView(codeFile: codeFile, + windowController: windowController, + workspace: workspace, + item: item) + } else { + Text("Open file from sidebar") + } } else { EmptyView() } From 1b3f9e82cb18541cc35af14e9a26f3aeff58d6fe Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 14:48:58 +0300 Subject: [PATCH 08/16] Run search in a new thread instead of running everything in the main thread --- CodeEdit/Documents/WorkspaceDocument.swift | 42 +++++++++++++--------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/CodeEdit/Documents/WorkspaceDocument.swift b/CodeEdit/Documents/WorkspaceDocument.swift index b496318e3..c96347ea9 100644 --- a/CodeEdit/Documents/WorkspaceDocument.swift +++ b/CodeEdit/Documents/WorkspaceDocument.swift @@ -157,24 +157,34 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { return } - if let url = fileURL { - let enumerator = FileManager.default.enumerator(at: url, - includingPropertiesForKeys: [ - .isRegularFileKey - ], - options: [ - .skipsHiddenFiles, - .skipsPackageDescendants - ]) - if let filePaths = enumerator?.allObjects as? [URL] { - openQuicklyFiles = filePaths.filter { - $0.lastPathComponent.lowercased().contains(openQuicklyQuery.lowercased()) - }.map { url in - WorkspaceClient.FileItem(url: url, children: nil) + DispatchQueue(label: "austincondiff.CodeEdit.quickOpen.searchFiles").async { + if let url = self.fileURL { + let enumerator = FileManager.default.enumerator(at: url, + includingPropertiesForKeys: [ + .isRegularFileKey + ], + options: [ + .skipsHiddenFiles, + .skipsPackageDescendants, + ]) + if let filePaths = enumerator?.allObjects as? [URL] { + let files = filePaths.filter { url in + let state1 = url.lastPathComponent.lowercased().contains(self.openQuicklyQuery.lowercased()) + do { + let values = try url.resourceValues(forKeys: [.isRegularFileKey]) + return state1 && (values.isRegularFile ?? false) + } catch { + return false + } + }.map { url in + WorkspaceClient.FileItem(url: url, children: nil) + } + DispatchQueue.main.async { + self.openQuicklyFiles = files + self.isShowingOpenQuicklyFiles = !self.openQuicklyFiles.isEmpty + } } } } - - self.isShowingOpenQuicklyFiles = !openQuicklyFiles.isEmpty } } From 8315053d3a6fbf09ec53804bdef25384daf9be28 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 14:56:44 +0300 Subject: [PATCH 09/16] add truncated file path relative to base directory of the workspace --- CodeEdit/Documents/WorkspaceDocument.swift | 3 +-- CodeEdit/Quick Open/QuickOpenItem.swift | 5 +++++ CodeEdit/Quick Open/QuickOpenView.swift | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CodeEdit/Documents/WorkspaceDocument.swift b/CodeEdit/Documents/WorkspaceDocument.swift index c96347ea9..bb0ca2c88 100644 --- a/CodeEdit/Documents/WorkspaceDocument.swift +++ b/CodeEdit/Documents/WorkspaceDocument.swift @@ -33,7 +33,6 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { } func closeFileTab(item: WorkspaceClient.FileItem) { - Swift.print(item) defer { let file = openedCodeFiles.removeValue(forKey: item) file?.save(self) @@ -165,7 +164,7 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { ], options: [ .skipsHiddenFiles, - .skipsPackageDescendants, + .skipsPackageDescendants ]) if let filePaths = enumerator?.allObjects as? [URL] { let files = filePaths.filter { url in diff --git a/CodeEdit/Quick Open/QuickOpenItem.swift b/CodeEdit/Quick Open/QuickOpenItem.swift index 88c1cb687..f802afa8e 100644 --- a/CodeEdit/Quick Open/QuickOpenItem.swift +++ b/CodeEdit/Quick Open/QuickOpenItem.swift @@ -9,6 +9,7 @@ import SwiftUI import WorkspaceClient public struct QuickOpenItem: View { + let baseDirectory: URL let fileItem: WorkspaceClient.FileItem public var body: some View { @@ -20,6 +21,10 @@ public struct QuickOpenItem: View { VStack(alignment: .leading) { Text(fileItem.url.lastPathComponent).font(.system(size: 13)) .lineLimit(1) + Text(fileItem.url.path.replacingOccurrences(of: baseDirectory.path, with: "")) + .font(.system(size: 11)) + .lineLimit(1) + .truncationMode(.tail) }.padding(.trailing, 15) Spacer() } diff --git a/CodeEdit/Quick Open/QuickOpenView.swift b/CodeEdit/Quick Open/QuickOpenView.swift index 6fed017d1..f22a9ae57 100644 --- a/CodeEdit/Quick Open/QuickOpenView.swift +++ b/CodeEdit/Quick Open/QuickOpenView.swift @@ -39,7 +39,7 @@ struct QuickOpenView: View { NavigationLink { Text(file.url.lastPathComponent) } label: { - QuickOpenItem(fileItem: file) + QuickOpenItem(baseDirectory: workspace.fileURL!, fileItem: file) } .onTapGesture(count: 2) { workspace.openFile(item: file) From 7b7020548557a10a2427ee8695384ed0fb393142 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 17:53:29 +0300 Subject: [PATCH 10/16] Some optimizations, still high memory usage after opening many files --- CodeEdit/Breadcrumbs/BreadcrumbsView.swift | 2 +- .../Documents/CodeEditWindowController.swift | 4 +- CodeEdit/Documents/WorkspaceDocument.swift | 85 +++++++++++-------- CodeEdit/Quick Open/QuickOpenView.swift | 18 ++-- CodeEdit/SideBar/SideBarItem.swift | 20 +++-- CodeEdit/WorkspaceView.swift | 14 +-- 6 files changed, 84 insertions(+), 59 deletions(-) diff --git a/CodeEdit/Breadcrumbs/BreadcrumbsView.swift b/CodeEdit/Breadcrumbs/BreadcrumbsView.swift index 10fb5ec07..833818d05 100644 --- a/CodeEdit/Breadcrumbs/BreadcrumbsView.swift +++ b/CodeEdit/Breadcrumbs/BreadcrumbsView.swift @@ -60,7 +60,7 @@ struct BreadcrumbsView: View { } private func fileInfo() { - guard let projName = workspace.folderURL?.lastPathComponent, + guard let projName = workspace.fileURL?.lastPathComponent, var components = file.url.pathComponents.split(separator: projName).last else { return } components.removeLast() diff --git a/CodeEdit/Documents/CodeEditWindowController.swift b/CodeEdit/Documents/CodeEditWindowController.swift index b0fdd9a6f..d42b0355f 100644 --- a/CodeEdit/Documents/CodeEditWindowController.swift +++ b/CodeEdit/Documents/CodeEditWindowController.swift @@ -34,7 +34,7 @@ class CodeEditWindowController: NSWindowController { } @IBAction func openQuickly(_ sender: Any) { - if let workspace = workspace { + if let workspace = workspace, let state = workspace.quickOpenState { if let window = window?.childWindows?.filter({ window in return (window.contentView as? NSHostingView) != nil }).first { @@ -46,7 +46,7 @@ class CodeEditWindowController: NSWindowController { contentRect: NSRect(x: 0, y: 0, width: 500, height: 48), styleMask: [.fullSizeContentView, .titled, .resizable], backing: .buffered, defer: false) - let contentView = QuickOpenView(workspace: workspace) { + let contentView = QuickOpenView(state: state) { self.window?.removeChildWindow(panel) panel.close() } diff --git a/CodeEdit/Documents/WorkspaceDocument.swift b/CodeEdit/Documents/WorkspaceDocument.swift index bb0ca2c88..ed7418b19 100644 --- a/CodeEdit/Documents/WorkspaceDocument.swift +++ b/CodeEdit/Documents/WorkspaceDocument.swift @@ -14,18 +14,16 @@ import CodeFile @objc(WorkspaceDocument) class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { - @Published var workspaceClient: WorkspaceClient? + var workspaceClient: WorkspaceClient? + @Published var selectedId: String? @Published var openFileItems: [WorkspaceClient.FileItem] = [] @Published var sortFoldersOnTop: Bool = true @Published var fileItems: [WorkspaceClient.FileItem] = [] - @Published var openQuicklyQuery: String = "" - @Published var openQuicklyFiles: [WorkspaceClient.FileItem] = [] - @Published var isShowingOpenQuicklyFiles: Bool = false + var quickOpenState: QuickOpenState? var openedCodeFiles: [WorkspaceClient.FileItem: CodeFileDocument] = [:] - var folderURL: URL? private var cancellables = Set() deinit { @@ -104,12 +102,12 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { } override func read(from url: URL, ofType typeName: String) throws { - self.folderURL = url self.workspaceClient = try .default( fileManager: .default, folderURL: url, ignoredFilesAndFolders: ignoredFilesAndDirectory ) + self.quickOpenState = .init(self) workspaceClient? .getFiles .sink { [weak self] files in @@ -148,39 +146,56 @@ class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate { } super.close() } +} + +// MARK: - Quick Open - func fetchOpenQuickly() { - if openQuicklyQuery == "" { - openQuicklyFiles = [] - self.isShowingOpenQuicklyFiles = !openQuicklyFiles.isEmpty - return +extension WorkspaceDocument { + + class QuickOpenState: ObservableObject { + init(_ workspace: WorkspaceDocument) { + self.workspace = workspace } - DispatchQueue(label: "austincondiff.CodeEdit.quickOpen.searchFiles").async { - if let url = self.fileURL { - let enumerator = FileManager.default.enumerator(at: url, - includingPropertiesForKeys: [ - .isRegularFileKey - ], - options: [ - .skipsHiddenFiles, - .skipsPackageDescendants - ]) - if let filePaths = enumerator?.allObjects as? [URL] { - let files = filePaths.filter { url in - let state1 = url.lastPathComponent.lowercased().contains(self.openQuicklyQuery.lowercased()) - do { - let values = try url.resourceValues(forKeys: [.isRegularFileKey]) - return state1 && (values.isRegularFile ?? false) - } catch { - return false + var workspace: WorkspaceDocument + + @Published var openQuicklyQuery: String = "" + @Published var openQuicklyFiles: [WorkspaceClient.FileItem] = [] + @Published var isShowingOpenQuicklyFiles: Bool = false + + func fetchOpenQuickly() { + if openQuicklyQuery == "" { + openQuicklyFiles = [] + self.isShowingOpenQuicklyFiles = !openQuicklyFiles.isEmpty + return + } + + DispatchQueue(label: "austincondiff.CodeEdit.quickOpen.searchFiles").async { + if let url = self.workspace.fileURL { + let enumerator = FileManager.default.enumerator(at: url, + includingPropertiesForKeys: [ + .isRegularFileKey + ], + options: [ + .skipsHiddenFiles, + .skipsPackageDescendants + ]) + if let filePaths = enumerator?.allObjects as? [URL] { + let files = filePaths.filter { url in + let state1 = url.lastPathComponent.lowercased().contains(self.openQuicklyQuery.lowercased()) + do { + let values = try url.resourceValues(forKeys: [.isRegularFileKey]) + return state1 && (values.isRegularFile ?? false) + } catch { + return false + } + }.map { url in + WorkspaceClient.FileItem(url: url, children: nil) + } + DispatchQueue.main.async { + self.openQuicklyFiles = files + self.isShowingOpenQuicklyFiles = !self.openQuicklyFiles.isEmpty } - }.map { url in - WorkspaceClient.FileItem(url: url, children: nil) - } - DispatchQueue.main.async { - self.openQuicklyFiles = files - self.isShowingOpenQuicklyFiles = !self.openQuicklyFiles.isEmpty } } } diff --git a/CodeEdit/Quick Open/QuickOpenView.swift b/CodeEdit/Quick Open/QuickOpenView.swift index f22a9ae57..3b37fa92b 100644 --- a/CodeEdit/Quick Open/QuickOpenView.swift +++ b/CodeEdit/Quick Open/QuickOpenView.swift @@ -8,7 +8,7 @@ import SwiftUI struct QuickOpenView: View { - @ObservedObject var workspace: WorkspaceDocument + @ObservedObject var state: WorkspaceDocument.QuickOpenState var onClose: () -> Void var body: some View { @@ -18,14 +18,14 @@ struct QuickOpenView: View { Image(systemName: "doc.text.magnifyingglass") .imageScale(.large) .padding(.horizontal) - TextField("Open Quickly", text: $workspace.openQuicklyQuery) + TextField("Open Quickly", text: $state.openQuicklyQuery) .font(.system(size: 22, weight: .light, design: .default)) .textFieldStyle(.plain) .onReceive( - workspace.$openQuicklyQuery + state.$openQuicklyQuery .debounce(for: .seconds(0.4), scheduler: DispatchQueue.main) ) { _ in - workspace.fetchOpenQuickly() + state.fetchOpenQuickly() } } .frame(height: 28) @@ -35,20 +35,20 @@ struct QuickOpenView: View { } Divider() NavigationView { - List(workspace.openQuicklyFiles, id: \.id) { file in + List(state.openQuicklyFiles, id: \.id) { file in NavigationLink { Text(file.url.lastPathComponent) } label: { - QuickOpenItem(baseDirectory: workspace.fileURL!, fileItem: file) + QuickOpenItem(baseDirectory: state.workspace.fileURL!, fileItem: file) } .onTapGesture(count: 2) { - workspace.openFile(item: file) + state.workspace.openFile(item: file) self.onClose() } } .removeBackground() .frame(minWidth: 250, maxWidth: 250) - if workspace.openQuicklyFiles.isEmpty { + if state.openQuicklyFiles.isEmpty { EmptyView() } else { Text("Select a file to preview") @@ -65,6 +65,6 @@ struct QuickOpenView: View { struct QuickOpenView_Previews: PreviewProvider { static var previews: some View { - QuickOpenView(workspace: .init(), onClose: {}) + QuickOpenView(state: .init(.init()), onClose: {}) } } diff --git a/CodeEdit/SideBar/SideBarItem.swift b/CodeEdit/SideBar/SideBarItem.swift index 0bf60406e..6158b7bc8 100644 --- a/CodeEdit/SideBar/SideBarItem.swift +++ b/CodeEdit/SideBar/SideBarItem.swift @@ -29,15 +29,21 @@ struct SideBarItem: View { } func sidebarFileItem(_ item: WorkspaceClient.FileItem) -> some View { - NavigationLink(tag: item.id, selection: $workspace.selectedId) { + NavigationLink { ZStack { - if let codeFile = workspace.openedCodeFiles[item] { - WorkspaceCodeFileView(codeFile: codeFile, - windowController: windowController, - workspace: workspace, - item: item) + if let item = workspace.openFileItems.first(where: { file in + return file.id == workspace.selectedId + }) { + if let codeFile = workspace.openedCodeFiles[item] { + WorkspaceCodeFileView(codeFile: codeFile, + windowController: windowController, + workspace: workspace, + item: item) + } else { + Text("CodeEdit cannot open this file because its file type is not supported.") + } } else { - Text("CodeEdit cannot open this file because its file type is not supported.") + Text("Open file from sidebar") } } .onAppear { workspace.openFile(item: item) } diff --git a/CodeEdit/WorkspaceView.swift b/CodeEdit/WorkspaceView.swift index 5d4586e09..de6a401ee 100644 --- a/CodeEdit/WorkspaceView.swift +++ b/CodeEdit/WorkspaceView.swift @@ -32,11 +32,15 @@ struct WorkspaceView: View { if let item = workspace.openFileItems.first(where: { file in return file.id == workspace.selectedId - }), let codeFile = workspace.openedCodeFiles[item] { - WorkspaceCodeFileView(codeFile: codeFile, - windowController: windowController, - workspace: workspace, - item: item) + }) { + if let codeFile = workspace.openedCodeFiles[item] { + WorkspaceCodeFileView(codeFile: codeFile, + windowController: windowController, + workspace: workspace, + item: item) + } else { + Text("CodeEdit cannot open this file because its file type is not supported.") + } } else { Text("Open file from sidebar") } From 9377b34391e93496fecec507dbb8ae08be743f26 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 18:16:27 +0300 Subject: [PATCH 11/16] Add Preview to Open Quickly --- CodeEdit.xcodeproj/project.pbxproj | 4 ++ .../Quick Open/QuickOpenPreviewView.swift | 45 ++++++++++++++++++ CodeEdit/Quick Open/QuickOpenView.swift | 9 +++- .../Modules/CodeFile/src/CodeFile.swift | 2 +- .../Modules/CodeFile/src/CodeFileView.swift | 14 +----- .../Modules/CodeFile/src/ThemedCodeView.swift | 46 +++++++++++++++++++ 6 files changed, 104 insertions(+), 16 deletions(-) create mode 100644 CodeEdit/Quick Open/QuickOpenPreviewView.swift create mode 100644 CodeEditModules/Modules/CodeFile/src/ThemedCodeView.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index c1074f3a4..7ea2790c3 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ 0485EB1B27E71BF400138301 /* QuickOpenPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */; }; 0485EB1D27E7338100138301 /* QuickOpenItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1C27E7338100138301 /* QuickOpenItem.swift */; }; 0485EB1F27E7458B00138301 /* WorkspaceCodeFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1E27E7458B00138301 /* WorkspaceCodeFileView.swift */; }; + 0485EB2327E7791400138301 /* QuickOpenPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB2227E7791400138301 /* QuickOpenPreviewView.swift */; }; 286620A527E4AB6900E18C2B /* BreadcrumbsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */; }; 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */; }; 287776E727E3413200D46668 /* SideBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776E627E3413200D46668 /* SideBar.swift */; }; @@ -75,6 +76,7 @@ 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenPanel.swift; sourceTree = ""; }; 0485EB1C27E7338100138301 /* QuickOpenItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenItem.swift; sourceTree = ""; }; 0485EB1E27E7458B00138301 /* WorkspaceCodeFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceCodeFileView.swift; sourceTree = ""; }; + 0485EB2227E7791400138301 /* QuickOpenPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenPreviewView.swift; sourceTree = ""; }; 04ADA0C827E5D29000BF00B2 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 04ADA0CA27E5D41F00BF00B2 /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/Localizable.strings; sourceTree = ""; }; 04F2BF0E27DBB28E0024EAB1 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; @@ -163,6 +165,7 @@ 0485EB1827E70F4900138301 /* QuickOpenView.swift */, 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */, 0485EB1C27E7338100138301 /* QuickOpenItem.swift */, + 0485EB2227E7791400138301 /* QuickOpenPreviewView.swift */, ); path = "Quick Open"; sourceTree = ""; @@ -514,6 +517,7 @@ 28B0A19827E385C300B73177 /* SideBarToolbarTop.swift in Sources */, 345F667527DF6C180069BD69 /* FileTabRow.swift in Sources */, 28FFE1BF27E3A441001939DB /* SideBarToolbarBottom.swift in Sources */, + 0485EB2327E7791400138301 /* QuickOpenPreviewView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/CodeEdit/Quick Open/QuickOpenPreviewView.swift b/CodeEdit/Quick Open/QuickOpenPreviewView.swift new file mode 100644 index 000000000..8fab267dc --- /dev/null +++ b/CodeEdit/Quick Open/QuickOpenPreviewView.swift @@ -0,0 +1,45 @@ +// +// QuickOpenPreviewView.swift +// CodeEdit +// +// Created by Pavel Kasila on 20.03.22. +// + +import SwiftUI +import WorkspaceClient +import CodeFile +import CodeEditor + +struct QuickOpenPreviewView: View { + var item: WorkspaceClient.FileItem + @State var content: String = "" + @State var loaded = false + @State var error: String? + + var body: some View { + VStack { + if loaded { + ThemedCodeView($content, language: .init(url: item.url)) + } else if let error = error { + Text(error) + } else { + ProgressView() + } + } + .onAppear { + loaded = false + error = nil + DispatchQueue(label: "austincondiff.CodeEdit.quickOpen.preview").async { + do { + let data = try String(contentsOf: item.url) + DispatchQueue.main.async { + self.content = data + self.loaded = true + } + } catch let error { + self.error = error.localizedDescription + } + } + } + } +} diff --git a/CodeEdit/Quick Open/QuickOpenView.swift b/CodeEdit/Quick Open/QuickOpenView.swift index 3b37fa92b..e16515f31 100644 --- a/CodeEdit/Quick Open/QuickOpenView.swift +++ b/CodeEdit/Quick Open/QuickOpenView.swift @@ -6,9 +6,11 @@ // import SwiftUI +import WorkspaceClient struct QuickOpenView: View { @ObservedObject var state: WorkspaceDocument.QuickOpenState + @State var selectedItem: WorkspaceClient.FileItem? var onClose: () -> Void var body: some View { @@ -36,8 +38,8 @@ struct QuickOpenView: View { Divider() NavigationView { List(state.openQuicklyFiles, id: \.id) { file in - NavigationLink { - Text(file.url.lastPathComponent) + NavigationLink(tag: file, selection: $selectedItem) { + QuickOpenPreviewView(item: file) } label: { QuickOpenItem(baseDirectory: state.workspace.fileURL!, fileItem: file) } @@ -45,6 +47,9 @@ struct QuickOpenView: View { state.workspace.openFile(item: file) self.onClose() } + .onTapGesture(count: 1) { + self.selectedItem = file + } } .removeBackground() .frame(minWidth: 250, maxWidth: 250) diff --git a/CodeEditModules/Modules/CodeFile/src/CodeFile.swift b/CodeEditModules/Modules/CodeFile/src/CodeFile.swift index 82a0fff02..9fb606b3c 100644 --- a/CodeEditModules/Modules/CodeFile/src/CodeFile.swift +++ b/CodeEditModules/Modules/CodeFile/src/CodeFile.swift @@ -58,7 +58,7 @@ public final class CodeFileDocument: NSDocument, ObservableObject { } } -private extension CodeEditor.Language { +public extension CodeEditor.Language { init(url: URL) { var value = url.pathExtension switch value { diff --git a/CodeEditModules/Modules/CodeFile/src/CodeFileView.swift b/CodeEditModules/Modules/CodeFile/src/CodeFileView.swift index 2f708b87c..0f03bc4c9 100644 --- a/CodeEditModules/Modules/CodeFile/src/CodeFileView.swift +++ b/CodeEditModules/Modules/CodeFile/src/CodeFileView.swift @@ -20,18 +20,6 @@ public struct CodeFileView: View { } public var body: some View { - CodeEditor( - source: $codeFile.content, - language: codeFile.fileLanguage(), - theme: getTheme(), - indentStyle: .system - ) + ThemedCodeView($codeFile.content, language: codeFile.fileLanguage()) } - - private func getTheme() -> CodeEditor.ThemeName { - if theme == .atelierSavannaAuto { - return colorScheme == .light ? .atelierSavannaLight : .atelierSavannaDark - } - return theme - } } diff --git a/CodeEditModules/Modules/CodeFile/src/ThemedCodeView.swift b/CodeEditModules/Modules/CodeFile/src/ThemedCodeView.swift new file mode 100644 index 000000000..956ad330d --- /dev/null +++ b/CodeEditModules/Modules/CodeFile/src/ThemedCodeView.swift @@ -0,0 +1,46 @@ +// +// ThemedCodeView.swift +// +// +// Created by Pavel Kasila on 20.03.22. +// + +import SwiftUI +import CodeEditor + +public struct ThemedCodeView: View { + @Binding public var content: String + public var language: CodeEditor.Language + public var editable: Bool + @Environment(\.colorScheme) private var colorScheme + @AppStorage(CodeEditorTheme.storageKey) var theme: CodeEditor.ThemeName = .atelierSavannaAuto + + public init(_ content: Binding, language: CodeEditor.Language, editable: Bool = true) { + self._content = content + self.language = language + self.editable = editable + } + + public var body: some View { + CodeEditor( + source: $content, + language: language, + theme: getTheme(), + flags: editable ? .defaultEditorFlags : .defaultViewerFlags, + indentStyle: .system + ) + } + + private func getTheme() -> CodeEditor.ThemeName { + if theme == .atelierSavannaAuto { + return colorScheme == .light ? .atelierSavannaLight : .atelierSavannaDark + } + return theme + } +} + +struct SwiftUIView_Previews: PreviewProvider { + static var previews: some View { + ThemedCodeView(.constant("## Example"), language: .markdown) + } +} From 3b6a537912748a61d4ee8e9656324d0097c8044f Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 18:25:07 +0300 Subject: [PATCH 12/16] Disable editing in preview --- CodeEdit/Quick Open/QuickOpenPreviewView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CodeEdit/Quick Open/QuickOpenPreviewView.swift b/CodeEdit/Quick Open/QuickOpenPreviewView.swift index 8fab267dc..79cba2f5a 100644 --- a/CodeEdit/Quick Open/QuickOpenPreviewView.swift +++ b/CodeEdit/Quick Open/QuickOpenPreviewView.swift @@ -19,7 +19,7 @@ struct QuickOpenPreviewView: View { var body: some View { VStack { if loaded { - ThemedCodeView($content, language: .init(url: item.url)) + ThemedCodeView($content, language: .init(url: item.url), editable: false) } else if let error = error { Text(error) } else { From dc1550830811e8d150b35dc33635b15dde85d989 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 18:31:11 +0300 Subject: [PATCH 13/16] Move `StatusBar` to `WorkspaceCodeFileEditor` --- CodeEdit/Documents/WorkspaceCodeFileView.swift | 4 ++++ CodeEdit/SideBar/SideBarItem.swift | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CodeEdit/Documents/WorkspaceCodeFileView.swift b/CodeEdit/Documents/WorkspaceCodeFileView.swift index a3696496b..0eca263eb 100644 --- a/CodeEdit/Documents/WorkspaceCodeFileView.swift +++ b/CodeEdit/Documents/WorkspaceCodeFileView.swift @@ -8,6 +8,7 @@ import SwiftUI import CodeFile import WorkspaceClient +import StatusBar struct WorkspaceCodeFileView: View { var codeFile: CodeFileDocument @@ -24,5 +25,8 @@ struct WorkspaceCodeFileView: View { BreadcrumbsView(item, workspace: workspace) } } + .safeAreaInset(edge: .bottom) { + StatusBarView() + } } } diff --git a/CodeEdit/SideBar/SideBarItem.swift b/CodeEdit/SideBar/SideBarItem.swift index e0f35ed6c..6158b7bc8 100644 --- a/CodeEdit/SideBar/SideBarItem.swift +++ b/CodeEdit/SideBar/SideBarItem.swift @@ -8,7 +8,6 @@ import SwiftUI import WorkspaceClient import CodeFile -import StatusBar struct SideBarItem: View { From 071084b6182a8e775f4d17ff42ff77cc98e9fab7 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 18:33:57 +0300 Subject: [PATCH 14/16] Move all check to `WorkspaceCodeFileView` --- .../Documents/WorkspaceCodeFileView.swift | 36 +++++++++++-------- CodeEdit/SideBar/SideBarItem.swift | 20 ++--------- CodeEdit/WorkspaceView.swift | 16 ++------- 3 files changed, 27 insertions(+), 45 deletions(-) diff --git a/CodeEdit/Documents/WorkspaceCodeFileView.swift b/CodeEdit/Documents/WorkspaceCodeFileView.swift index 0eca263eb..2a6db0fdc 100644 --- a/CodeEdit/Documents/WorkspaceCodeFileView.swift +++ b/CodeEdit/Documents/WorkspaceCodeFileView.swift @@ -11,22 +11,30 @@ import WorkspaceClient import StatusBar struct WorkspaceCodeFileView: View { - var codeFile: CodeFileDocument var windowController: NSWindowController - var workspace: WorkspaceDocument - var item: WorkspaceClient.FileItem + @ObservedObject var workspace: WorkspaceDocument - var body: some View { - CodeFileView(codeFile: codeFile) - .safeAreaInset(edge: .top, spacing: 0) { - VStack(spacing: 0) { - TabBar(windowController: windowController, workspace: workspace) - CustomDivider() - BreadcrumbsView(item, workspace: workspace) - } - } - .safeAreaInset(edge: .bottom) { - StatusBarView() + @ViewBuilder var body: some View { + if let item = workspace.openFileItems.first(where: { file in + return file.id == workspace.selectedId + }) { + if let codeFile = workspace.openedCodeFiles[item] { + CodeFileView(codeFile: codeFile) + .safeAreaInset(edge: .top, spacing: 0) { + VStack(spacing: 0) { + TabBar(windowController: windowController, workspace: workspace) + CustomDivider() + BreadcrumbsView(item, workspace: workspace) + } + } + .safeAreaInset(edge: .bottom) { + StatusBarView() + } + } else { + Text("CodeEdit cannot open this file because its file type is not supported.") } + } else { + Text("Open file from sidebar") + } } } diff --git a/CodeEdit/SideBar/SideBarItem.swift b/CodeEdit/SideBar/SideBarItem.swift index 6158b7bc8..f6efdd040 100644 --- a/CodeEdit/SideBar/SideBarItem.swift +++ b/CodeEdit/SideBar/SideBarItem.swift @@ -30,23 +30,9 @@ struct SideBarItem: View { func sidebarFileItem(_ item: WorkspaceClient.FileItem) -> some View { NavigationLink { - ZStack { - if let item = workspace.openFileItems.first(where: { file in - return file.id == workspace.selectedId - }) { - if let codeFile = workspace.openedCodeFiles[item] { - WorkspaceCodeFileView(codeFile: codeFile, - windowController: windowController, - workspace: workspace, - item: item) - } else { - Text("CodeEdit cannot open this file because its file type is not supported.") - } - } else { - Text("Open file from sidebar") - } - } - .onAppear { workspace.openFile(item: item) } + WorkspaceCodeFileView(windowController: windowController, + workspace: workspace) + .onAppear { workspace.openFile(item: item) } } label: { Label(item.url.lastPathComponent, systemImage: item.systemImage) .accentColor(iconStyle == .color ? item.iconColor : .secondary) diff --git a/CodeEdit/WorkspaceView.swift b/CodeEdit/WorkspaceView.swift index de6a401ee..7c82b36e2 100644 --- a/CodeEdit/WorkspaceView.swift +++ b/CodeEdit/WorkspaceView.swift @@ -30,20 +30,8 @@ struct WorkspaceView: View { SideBar(workspace: workspace, windowController: windowController) .frame(minWidth: 250) - if let item = workspace.openFileItems.first(where: { file in - return file.id == workspace.selectedId - }) { - if let codeFile = workspace.openedCodeFiles[item] { - WorkspaceCodeFileView(codeFile: codeFile, - windowController: windowController, - workspace: workspace, - item: item) - } else { - Text("CodeEdit cannot open this file because its file type is not supported.") - } - } else { - Text("Open file from sidebar") - } + WorkspaceCodeFileView(windowController: windowController, + workspace: workspace) } else { EmptyView() } From ff37a05fc2e007cbdab03a2c8dd3edcc133b5911 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 20:24:30 +0300 Subject: [PATCH 15/16] Small changes to icon in `QuickOpenView` --- CodeEdit/Quick Open/QuickOpenView.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CodeEdit/Quick Open/QuickOpenView.swift b/CodeEdit/Quick Open/QuickOpenView.swift index e16515f31..af1008dc1 100644 --- a/CodeEdit/Quick Open/QuickOpenView.swift +++ b/CodeEdit/Quick Open/QuickOpenView.swift @@ -19,7 +19,8 @@ struct QuickOpenView: View { HStack(alignment: .center, spacing: 0) { Image(systemName: "doc.text.magnifyingglass") .imageScale(.large) - .padding(.horizontal) + .padding(.horizontal, 20) + .offset(x: 2, y: 0) TextField("Open Quickly", text: $state.openQuicklyQuery) .font(.system(size: 22, weight: .light, design: .default)) .textFieldStyle(.plain) From bbf597a6d82459353ddfd552f9abe2bc85c52b62 Mon Sep 17 00:00:00 2001 From: Pavel Kasila Date: Sun, 20 Mar 2022 22:47:21 +0300 Subject: [PATCH 16/16] Move `QuickOpenPanel` to `Overlays` module and rename it to `OverlayPanel` (it can be used by any other overlay). Make `OverlayPanel` close on `windowDidResignKey` as Xcode does --- CodeEdit.xcodeproj/project.pbxproj | 11 ++++--- .../Documents/CodeEditWindowController.swift | 10 ++---- CodeEdit/Quick Open/QuickOpenPanel.swift | 16 --------- .../Modules/Overlays/src/OverlayPanel.swift | 33 +++++++++++++++++++ CodeEditModules/Package.swift | 12 +++++-- 5 files changed, 52 insertions(+), 30 deletions(-) delete mode 100644 CodeEdit/Quick Open/QuickOpenPanel.swift create mode 100644 CodeEditModules/Modules/Overlays/src/OverlayPanel.swift diff --git a/CodeEdit.xcodeproj/project.pbxproj b/CodeEdit.xcodeproj/project.pbxproj index 9162aebfa..48f4613e2 100644 --- a/CodeEdit.xcodeproj/project.pbxproj +++ b/CodeEdit.xcodeproj/project.pbxproj @@ -17,10 +17,10 @@ 04660F6627E3ACEF00477777 /* ReopenBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6527E3ACEF00477777 /* ReopenBehavior.swift */; }; 04660F6A27E51E5C00477777 /* CodeEditWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04660F6927E51E5C00477777 /* CodeEditWindowController.swift */; }; 0485EB1927E70F4900138301 /* QuickOpenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1827E70F4900138301 /* QuickOpenView.swift */; }; - 0485EB1B27E71BF400138301 /* QuickOpenPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */; }; 0485EB1D27E7338100138301 /* QuickOpenItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1C27E7338100138301 /* QuickOpenItem.swift */; }; 0485EB1F27E7458B00138301 /* WorkspaceCodeFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB1E27E7458B00138301 /* WorkspaceCodeFileView.swift */; }; 0485EB2327E7791400138301 /* QuickOpenPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485EB2227E7791400138301 /* QuickOpenPreviewView.swift */; }; + 0485EB2527E7B9C800138301 /* Overlays in Frameworks */ = {isa = PBXBuildFile; productRef = 0485EB2427E7B9C800138301 /* Overlays */; }; 286620A527E4AB6900E18C2B /* BreadcrumbsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286620A427E4AB6900E18C2B /* BreadcrumbsComponent.swift */; }; 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2875A46C27E3BE5B007805F8 /* BreadcrumbsView.swift */; }; 287776E727E3413200D46668 /* SideBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 287776E627E3413200D46668 /* SideBar.swift */; }; @@ -74,7 +74,6 @@ 04660F6927E51E5C00477777 /* CodeEditWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeEditWindowController.swift; sourceTree = ""; }; 0468438427DC76E200F8E88E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 0485EB1827E70F4900138301 /* QuickOpenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenView.swift; sourceTree = ""; }; - 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenPanel.swift; sourceTree = ""; }; 0485EB1C27E7338100138301 /* QuickOpenItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenItem.swift; sourceTree = ""; }; 0485EB1E27E7458B00138301 /* WorkspaceCodeFileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkspaceCodeFileView.swift; sourceTree = ""; }; 0485EB2227E7791400138301 /* QuickOpenPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickOpenPreviewView.swift; sourceTree = ""; }; @@ -116,6 +115,7 @@ buildActionMask = 2147483647; files = ( 5C403B8F27E20F8000788241 /* WorkspaceClient in Frameworks */, + 0485EB2527E7B9C800138301 /* Overlays in Frameworks */, B65E614627E6765D00255275 /* Introspect in Frameworks */, D70F5E2C27E4E8CF004EE4B9 /* WelcomeModule in Frameworks */, 28CE5EA027E6493D0065D29C /* StatusBar in Frameworks */, @@ -165,7 +165,6 @@ isa = PBXGroup; children = ( 0485EB1827E70F4900138301 /* QuickOpenView.swift */, - 0485EB1A27E71BF400138301 /* QuickOpenPanel.swift */, 0485EB1C27E7338100138301 /* QuickOpenItem.swift */, 0485EB2227E7791400138301 /* QuickOpenPreviewView.swift */, ); @@ -328,6 +327,7 @@ D70F5E2B27E4E8CF004EE4B9 /* WelcomeModule */, B65E614527E6765D00255275 /* Introspect */, 28CE5E9F27E6493D0065D29C /* StatusBar */, + 0485EB2427E7B9C800138301 /* Overlays */, ); productName = CodeEdit; productReference = B658FB2C27DA9E0F00EA4DBD /* CodeEdit.app */; @@ -495,7 +495,6 @@ 2B7A583527E4BA0100D25D4E /* AppDelegate.swift in Sources */, 2875A46D27E3BE5B007805F8 /* BreadcrumbsView.swift in Sources */, 0485EB1D27E7338100138301 /* QuickOpenItem.swift in Sources */, - 0485EB1B27E71BF400138301 /* QuickOpenPanel.swift in Sources */, 04540D5B27DD08C300E91B77 /* SettingsView.swift in Sources */, D72E1A8927E44D7C00EB11B9 /* WelcomeWindowView.swift in Sources */, 04540D5C27DD08C300E91B77 /* GeneralSettingsView.swift in Sources */, @@ -898,6 +897,10 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 0485EB2427E7B9C800138301 /* Overlays */ = { + isa = XCSwiftPackageProductDependency; + productName = Overlays; + }; 28CE5E9F27E6493D0065D29C /* StatusBar */ = { isa = XCSwiftPackageProductDependency; productName = StatusBar; diff --git a/CodeEdit/Documents/CodeEditWindowController.swift b/CodeEdit/Documents/CodeEditWindowController.swift index d42b0355f..8f1649baf 100644 --- a/CodeEdit/Documents/CodeEditWindowController.swift +++ b/CodeEdit/Documents/CodeEditWindowController.swift @@ -8,6 +8,7 @@ import Cocoa import SwiftUI import CodeFile +import Overlays class CodeEditWindowController: NSWindowController { @@ -42,17 +43,10 @@ class CodeEditWindowController: NSWindowController { return } - let panel = QuickOpenPanel( - contentRect: NSRect(x: 0, y: 0, width: 500, height: 48), - styleMask: [.fullSizeContentView, .titled, .resizable], - backing: .buffered, defer: false) + let panel = OverlayPanel() let contentView = QuickOpenView(state: state) { - self.window?.removeChildWindow(panel) panel.close() } - panel.center() - panel.titlebarAppearsTransparent = true - panel.isMovableByWindowBackground = true panel.contentView = NSHostingView(rootView: contentView) window?.addChildWindow(panel, ordered: .above) panel.makeKeyAndOrderFront(self) diff --git a/CodeEdit/Quick Open/QuickOpenPanel.swift b/CodeEdit/Quick Open/QuickOpenPanel.swift deleted file mode 100644 index 161c0e73b..000000000 --- a/CodeEdit/Quick Open/QuickOpenPanel.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// QuickOpenPanel.swift -// CodeEdit -// -// Created by Pavel Kasila on 20.03.22. -// - -import Cocoa - -class QuickOpenPanel: NSPanel { - override func standardWindowButton(_ button: NSWindow.ButtonType) -> NSButton? { - let btn = super.standardWindowButton(button) - btn?.isHidden = true - return btn - } -} diff --git a/CodeEditModules/Modules/Overlays/src/OverlayPanel.swift b/CodeEditModules/Modules/Overlays/src/OverlayPanel.swift new file mode 100644 index 000000000..a6ab7c789 --- /dev/null +++ b/CodeEditModules/Modules/Overlays/src/OverlayPanel.swift @@ -0,0 +1,33 @@ +// +// OverlayPanel.swift +// CodeEdit +// +// Created by Pavel Kasila on 20.03.22. +// + +import Cocoa + +public class OverlayPanel: NSPanel, NSWindowDelegate { + public init() { + super.init( + contentRect: NSRect(x: 0, y: 0, width: 500, height: 48), + styleMask: [.fullSizeContentView, .titled, .resizable], + backing: .buffered, defer: false) + self.delegate = self + self.center() + self.titlebarAppearsTransparent = true + self.isMovableByWindowBackground = true + } + + public override func standardWindowButton(_ button: NSWindow.ButtonType) -> NSButton? { + let btn = super.standardWindowButton(button) + btn?.isHidden = true + return btn + } + + public func windowDidResignKey(_ notification: Notification) { + if let panel = notification.object as? OverlayPanel { + panel.close() + } + } +} diff --git a/CodeEditModules/Package.swift b/CodeEditModules/Package.swift index fc39fed2f..3a638ab78 100644 --- a/CodeEditModules/Package.swift +++ b/CodeEditModules/Package.swift @@ -24,7 +24,11 @@ let package = Package( .library( name: "StatusBar", targets: ["StatusBar"] - ) + ), + .library( + name: "Overlays", + targets: ["Overlays"] + ) ], dependencies: [ .package( @@ -82,6 +86,10 @@ let package = Package( .target( name: "StatusBar", path: "Modules/StatusBar/src" - ) + ), + .target( + name: "Overlays", + path: "Modules/Overlays/src" + ) ] )