Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigation style setting and file history navigation improvements #1603

Merged
merged 12 commits into from
Mar 12, 2024
Merged
36 changes: 30 additions & 6 deletions CodeEdit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,8 @@
B65B10FE2B08B07D002852CF /* SourceControlNavigatorChangesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65B10FD2B08B07D002852CF /* SourceControlNavigatorChangesList.swift */; };
B65B11012B09D5D4002852CF /* GitClient+Pull.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65B11002B09D5D4002852CF /* GitClient+Pull.swift */; };
B65B11042B09DB1C002852CF /* GitClient+Fetch.swift in Sources */ = {isa = PBXBuildFile; fileRef = B65B11032B09DB1C002852CF /* GitClient+Fetch.swift */; };
B664C3B02B965F6C00816B4E /* NavigationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B664C3AF2B965F6C00816B4E /* NavigationSettings.swift */; };
B664C3B32B96634F00816B4E /* NavigationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B664C3B22B96634F00816B4E /* NavigationSettingsView.swift */; };
B66A4E4529C8E86D004573B4 /* CommandsFixes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66A4E4429C8E86D004573B4 /* CommandsFixes.swift */; };
B66A4E4C29C9179B004573B4 /* CodeEditApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66A4E4B29C9179B004573B4 /* CodeEditApp.swift */; };
B66A4E4F29C917B8004573B4 /* WelcomeWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66A4E4E29C917B8004573B4 /* WelcomeWindow.swift */; };
Expand Down Expand Up @@ -970,6 +972,8 @@
B65B10FD2B08B07D002852CF /* SourceControlNavigatorChangesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceControlNavigatorChangesList.swift; sourceTree = "<group>"; };
B65B11002B09D5D4002852CF /* GitClient+Pull.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GitClient+Pull.swift"; sourceTree = "<group>"; };
B65B11032B09DB1C002852CF /* GitClient+Fetch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GitClient+Fetch.swift"; sourceTree = "<group>"; };
B664C3AF2B965F6C00816B4E /* NavigationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationSettings.swift; sourceTree = "<group>"; };
B664C3B22B96634F00816B4E /* NavigationSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationSettingsView.swift; sourceTree = "<group>"; };
B66A4E4429C8E86D004573B4 /* CommandsFixes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandsFixes.swift; sourceTree = "<group>"; };
B66A4E4B29C9179B004573B4 /* CodeEditApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodeEditApp.swift; sourceTree = "<group>"; };
B66A4E4E29C917B8004573B4 /* WelcomeWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeWindow.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1277,13 +1281,13 @@
287776EA27E350A100D46668 /* NavigatorArea */ = {
isa = PBXGroup;
children = (
307AC4CB2ABABD9800163376 /* ViewModels */,
D7012EE627E757660001E1EF /* FindNavigator */,
581550CB29FBD30400684881 /* OutlineView */,
286471AC27ED52950039369D /* ProjectNavigator */,
201169D52837B29600F92B46 /* SourceControlNavigator */,
B67660682AA972D400CD56B0 /* Models */,
B67660692AA972DC00CD56B0 /* Views */,
307AC4CB2ABABD9800163376 /* ViewModels */,
);
path = NavigatorArea;
sourceTree = "<group>";
Expand Down Expand Up @@ -2553,16 +2557,17 @@
B61DA9DD29D929BF00BF4A43 /* Pages */ = {
isa = PBXGroup;
children = (
B664C3AD2B965F4500816B4E /* NavigationSettings */,
B61DA9E129D929F900BF4A43 /* GeneralSettings */,
B6E41C6E29DD15540088F9F4 /* AccountsSettings */,
58F2EAAE292FB2B0004A9BDE /* ThemeSettings */,
B6EA1FF329DA37D3001BF195 /* TextEditingSettings */,
5B698A082B262F8400DE9392 /* SearchSettings */,
6C5BE51A2A3D5419002DA0FC /* FeatureFlags */,
B6CF632629E5417C0085880A /* Keybindings */,
B6E41C6E29DD15540088F9F4 /* AccountsSettings */,
B6EA1FF329DA37D3001BF195 /* TextEditingSettings */,
B6F0516E29D9E35300D72287 /* LocationsSettings */,
B6F0516D29D9E34200D72287 /* SourceControlSettings */,
B6F0516C29D9E32700D72287 /* TerminalSettings */,
58F2EAAE292FB2B0004A9BDE /* ThemeSettings */,
B61DA9E129D929F900BF4A43 /* GeneralSettings */,
);
path = Pages;
sourceTree = "<group>";
Expand Down Expand Up @@ -2663,6 +2668,23 @@
path = "Preview Content";
sourceTree = "<group>";
};
B664C3AD2B965F4500816B4E /* NavigationSettings */ = {
isa = PBXGroup;
children = (
B664C3AE2B965F5500816B4E /* Models */,
B664C3B22B96634F00816B4E /* NavigationSettingsView.swift */,
);
path = NavigationSettings;
sourceTree = "<group>";
};
B664C3AE2B965F5500816B4E /* Models */ = {
isa = PBXGroup;
children = (
B664C3AF2B965F6C00816B4E /* NavigationSettings.swift */,
);
path = Models;
sourceTree = "<group>";
};
B66DD19E2B3C0E0C0004FFEC /* History */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -3291,6 +3313,7 @@
587B9E9229301D8F00AC7927 /* BitBucketAccount.swift in Sources */,
DE513F52281B672D002260B9 /* EditorTabBarAccessory.swift in Sources */,
2813F93927ECC4C300E305E4 /* NavigatorAreaView.swift in Sources */,
B664C3B02B965F6C00816B4E /* NavigationSettings.swift in Sources */,
5B698A0F2B2636A700DE9392 /* SearchSettingsIgnoreGlobPatternItemView.swift in Sources */,
587B9E8A29301D8F00AC7927 /* GitHubIssue.swift in Sources */,
EC0870F72A455F6400EB8692 /* ProjectNavigatorViewController+NSMenuDelegate.swift in Sources */,
Expand Down Expand Up @@ -3339,6 +3362,7 @@
611192042B08CCED00D4459B /* SearchIndexer+ProgressiveSearch.swift in Sources */,
611192022B08CCDC00D4459B /* SearchIndexer+Search.swift in Sources */,
04BA7C272AE2E9F100584E1C /* GitClient+Push.swift in Sources */,
B664C3B32B96634F00816B4E /* NavigationSettingsView.swift in Sources */,
2B7A583527E4BA0100D25D4E /* AppDelegate.swift in Sources */,
D7012EE827E757850001E1EF /* FindNavigatorView.swift in Sources */,
58A5DF8029325B5A00D1BD5D /* GitClient.swift in Sources */,
Expand Down Expand Up @@ -4669,7 +4693,7 @@
repositoryURL = "https://github.com/CodeEditApp/CodeEditSourceEditor";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.7.1;
minimumVersion = 0.7.2;
};
};
6CDEFC9429E22C2700B7C684 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = {
Expand Down
2 changes: 1 addition & 1 deletion CodeEdit/Features/CodeEditUI/Views/SegmentedControl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct SegmentedControl: View {
}

var body: some View {
HStack(spacing: 8) {
HStack(spacing: 4) {
ForEach(options.indices, id: \.self) { index in
SegmentedControlItem(
label: options[index],
Expand Down
22 changes: 15 additions & 7 deletions CodeEdit/Features/Editor/Models/Editor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ final class Editor: ObservableObject, Identifiable {
let tab = history[historyOffset]

if !tabs.contains(tab) {
if let selectedTab {
openTab(file: tab.file, at: tabs.firstIndex(of: selectedTab), fromHistory: true)
} else {
openTab(file: tab.file, fromHistory: true)
if let temporaryTab, tabs.contains(temporaryTab) {
closeTab(file: temporaryTab.file, fromHistory: true)
}
temporaryTab = tab
openTab(file: tab.file, fromHistory: true)
}
selectedTab = tab
}
Expand All @@ -64,29 +64,34 @@ final class Editor: ObservableObject, Identifiable {

init() {
self.tabs = []
self.temporaryTab = nil
self.parent = nil
}

init(
files: OrderedSet<CEWorkspaceFile> = [],
selectedTab: Tab? = nil,
temporaryTab: Tab? = nil,
parent: SplitViewData? = nil
) {
self.tabs = []
self.parent = parent
files.forEach { openTab(file: $0) }
self.selectedTab = selectedTab ?? (files.isEmpty ? nil : Tab(file: files.first!))
self.temporaryTab = temporaryTab
}

init(
files: OrderedSet<Tab> = [],
selectedTab: Tab? = nil,
temporaryTab: Tab? = nil,
parent: SplitViewData? = nil
) {
self.tabs = []
self.parent = parent
files.forEach { openTab(file: $0.file) }
self.selectedTab = selectedTab ?? tabs.first
self.temporaryTab = temporaryTab
}

/// Closes the editor.
Expand All @@ -102,14 +107,15 @@ final class Editor: ObservableObject, Identifiable {
/// Closes a tab in the editor.
/// This will also write any changes to the file on disk and will add the tab to the tab history.
/// - Parameter item: the tab to close.
func closeTab(file: CEWorkspaceFile) {
func closeTab(file: CEWorkspaceFile, fromHistory: Bool = false) {
guard canCloseTab(file: file) else { return }

if temporaryTab?.file == file {
temporaryTab = nil
}

historyOffset = 0
if !fromHistory {
historyOffset = 0
}
if file != selectedTab?.file {
history.prepend(EditorInstance(file: file))
}
Expand Down Expand Up @@ -149,7 +155,9 @@ final class Editor: ObservableObject, Identifiable {
switch (temporaryTab, asTemporary) {
case (.some(let tab), true):
if let index = tabs.firstIndex(of: tab) {
history.removeFirst(historyOffset)
history.prepend(item)
historyOffset = 0
tabs.remove(tab)
tabs.insert(item, at: index)
self.selectedTab = item
Expand Down
18 changes: 18 additions & 0 deletions CodeEdit/Features/Editor/Models/EditorLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,24 @@ enum EditorLayout: Equatable {
}
}

/// Gets flattened splitviews.
mutating func getFlattened(parent: SplitViewData) -> [Editor] {
matthijseikelenboom marked this conversation as resolved.
Show resolved Hide resolved
thecoolwinter marked this conversation as resolved.
Show resolved Hide resolved
switch self {
case .one(let editor):
return [editor]
case .horizontal(let data), .vertical(let data):
if data.editorLayouts.count == 1 {
let one = data.editorLayouts[0]
if case .one(let editor) = one {
return [editor]
}
return []
} else {
return data.getFlattened()
}
}
}

var isEmpty: Bool {
switch self {
case .one:
Expand Down
29 changes: 26 additions & 3 deletions CodeEdit/Features/Editor/Models/EditorManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ class EditorManager: ObservableObject {
var tabBarTabIdSubject = PassthroughSubject<String?, Never>()
var cancellable: AnyCancellable?

// This caching mechanism is a temporary solution and is not optimized
@Published var updateCachedFlattenedEditors: Bool = true
var cachedFlettenedEditors: [Editor] = []
var flattenedEditors: [Editor] {
if updateCachedFlattenedEditors {
cachedFlettenedEditors = self.getFlattened()
updateCachedFlattenedEditors = false
}
return cachedFlettenedEditors
}

// MARK: - Init

init() {
Expand All @@ -61,10 +72,21 @@ class EditorManager: ObservableObject {

/// Flattens the splitviews.
func flatten() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling this function "flatten" is a bit weird. editorManager.flatten() kind of reads like this function flattens the manager

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should be flattenEditors. I did not write this. We can go in and change this later.

Copy link
Collaborator Author

@austincondiff austincondiff Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Come to think of it, we might even consider other words like join, combine, or merge. (VS Code uses join)

if case .horizontal(let data) = editorLayout {
data.flatten()
} else if case .vertical(let data) = editorLayout {
switch editorLayout {
case .horizontal(let data), .vertical(let data):
data.flatten()
default:
break
}
}

/// Returns and array of flattened splitviews.
func getFlattened() -> [Editor] {
switch editorLayout {
case .horizontal(let data), .vertical(let data):
return data.getFlattened()
default:
return []
}
}

Expand Down Expand Up @@ -99,6 +121,7 @@ class EditorManager: ObservableObject {

flatten()
objectWillChange.send()
updateCachedFlattenedEditors = true
}

/// Set a new active editor.
Expand Down
17 changes: 15 additions & 2 deletions CodeEdit/Features/Editor/PathBar/Views/EditorPathBarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import SwiftUI

struct EditorPathBarView: View {
private let file: CEWorkspaceFile?
private let shouldShowTabBar: Bool
private let tappedOpenFile: (CEWorkspaceFile) -> Void

@Environment(\.colorScheme)
Expand All @@ -20,13 +21,15 @@ struct EditorPathBarView: View {
@Environment(\.controlActiveState)
private var activeState

static let height = 27.0
static let height = 28.0

init(
file: CEWorkspaceFile?,
shouldShowTabBar: Bool,
tappedOpenFile: @escaping (CEWorkspaceFile) -> Void
) {
self.file = file ?? nil
self.shouldShowTabBar = shouldShowTabBar
self.tappedOpenFile = tappedOpenFile
}

Expand Down Expand Up @@ -63,7 +66,17 @@ struct EditorPathBarView: View {
}
}
}
.padding(.horizontal, 10)
}
.padding(.horizontal, shouldShowTabBar ? (file == nil ? 10 : 4) : 0)
.safeAreaInset(edge: .leading, spacing: 0) {
if !shouldShowTabBar {
EditorTabBarLeadingAccessories()
}
}
.safeAreaInset(edge: .trailing, spacing: 0) {
if !shouldShowTabBar {
EditorTabBarTrailingAccessories()
}
}
.frame(height: Self.height, alignment: .center)
.opacity(activeState == .inactive ? 0.8 : 1.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,9 @@ struct EditorTabBarLeadingAccessories: View {
}
} label: {
Image(systemName: "chevron.left")
.controlSize(.regular)
.opacity(
editor.historyOffset == editor.history.count-1 || editor.history.isEmpty
? 0.5 : 1.0
)
.opacity(editor.historyOffset == editor.history.count-1 || editor.history.isEmpty ? 0.5 : 1)
.frame(height: EditorTabBarView.height - 2)
.padding(.horizontal, 4)
} primaryAction: {
editorManager.activeEditor = editor
editor.goBackInHistory()
Expand All @@ -103,20 +101,19 @@ struct EditorTabBarLeadingAccessories: View {
}
} label: {
Image(systemName: "chevron.right")
.controlSize(.regular)
.opacity(editor.historyOffset == 0 ? 0.5 : 1.0)
.opacity(editor.historyOffset == 0 ? 0.5 : 1)
.frame(height: EditorTabBarView.height - 2)
.padding(.horizontal, 4)
} primaryAction: {
editorManager.activeEditor = editor
editor.goForwardInHistory()
}
.disabled(editor.historyOffset == 0)
.help("Navigate forward")
}
.buttonStyle(.icon)
.controlSize(.small)
.font(EditorTabBarAccessoryIcon.iconFont)
.frame(height: EditorTabBarView.height - 2)
.padding(.horizontal, 4)
.contentShape(Rectangle())
}
.foregroundColor(.secondary)
.buttonStyle(.plain)
Expand All @@ -136,9 +133,3 @@ struct EditorTabBarLeadingAccessories: View {
}
}
}

struct TabBarLeadingAccessories_Previews: PreviewProvider {
static var previews: some View {
EditorTabBarLeadingAccessories()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,12 @@ struct EditorTabBarTrailingAccessories: View {
func split(edge: Edge) {
let newEditor: Editor
if let tab = editor.selectedTab {
newEditor = .init(files: [tab])
newEditor = .init(files: [tab], temporaryTab: tab)
thecoolwinter marked this conversation as resolved.
Show resolved Hide resolved
} else {
newEditor = .init()
}
splitEditor(edge, newEditor)
editorManager.updateCachedFlattenedEditors = true
editorManager.activeEditor = newEditor
}
}
Expand Down
Loading
Loading