Skip to content

Source Control Filter #2024

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ final class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate {
@Published var sortFoldersOnTop: Bool = true
/// A string used to filter the displayed files and folders in the project navigator area based on user input.
@Published var navigatorFilter: String = ""
/// Whether the workspace only shows files with changes.
@Published var sourceControlFilter = false

private var workspaceState: [String: Any] {
get {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ struct ProjectNavigatorOutlineView: NSViewControllerRepresentable {
.throttle(for: 0.1, scheduler: RunLoop.main, latest: true)
.sink { [weak self] _ in self?.controller?.handleFilterChange() }
.store(in: &cancellables)
workspace.$sourceControlFilter
.throttle(for: 0.1, scheduler: RunLoop.main, latest: true)
.sink { [weak self] _ in self?.controller?.handleFilterChange() }
.store(in: &cancellables)
}

var cancellables: Set<AnyCancellable> = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ extension ProjectNavigatorViewController: NSOutlineViewDataSource {
}

if let children = workspace?.workspaceFileManager?.childrenOfFile(item) {
if let filter = workspace?.navigatorFilter, !filter.isEmpty {
let filteredChildren = children.filter { fileSearchMatches(filter, for: $0) }
if let filter = workspace?.navigatorFilter, let sourceControlFilter = workspace?.sourceControlFilter,
!filter.isEmpty || sourceControlFilter {
let filteredChildren = children.filter {
fileSearchMatches(filter, for: $0, sourceControlFilter: sourceControlFilter)
}
filteredContentChildren[item] = filteredChildren
return filteredChildren
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ final class ProjectNavigatorViewController: NSViewController {
/// to open the file a second time.
var shouldSendSelectionUpdate: Bool = true

var filterIsEmpty: Bool {
workspace?.navigatorFilter.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true
}

/// Setup the ``scrollView`` and ``outlineView``
override func loadView() {
self.scrollView = NSScrollView()
Expand Down Expand Up @@ -193,13 +197,13 @@ final class ProjectNavigatorViewController: NSViewController {
guard let workspace else { return }

/// If the filter is empty, show all items and restore the expanded state.
if workspace.navigatorFilter.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
restoreExpandedState()
outlineView.autosaveExpandedItems = true
} else {
if workspace.sourceControlFilter || !filterIsEmpty {
outlineView.autosaveExpandedItems = false
/// Expand all items for search.
outlineView.expandItem(outlineView.item(atRow: 0), expandChildren: true)
} else {
restoreExpandedState()
outlineView.autosaveExpandedItems = true
}

if let root = content.first(where: { $0.isRoot }), let children = filteredContentChildren[root] {
Expand All @@ -213,16 +217,24 @@ final class ProjectNavigatorViewController: NSViewController {
}

/// Checks if the given filter matches the name of the item or any of its children.
func fileSearchMatches(_ filter: String, for item: CEWorkspaceFile) -> Bool {
guard !filter.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return true }
func fileSearchMatches(_ filter: String, for item: CEWorkspaceFile, sourceControlFilter: Bool) -> Bool {
guard !filterIsEmpty || sourceControlFilter else {
return true
}

if item.name.localizedLowercase.contains(filter.localizedLowercase) {
if sourceControlFilter {
if item.gitStatus != nil && item.gitStatus != GitStatus.none &&
(filterIsEmpty || item.name.localizedCaseInsensitiveContains(filter)) {
saveAllContentChildren(for: item)
return true
}
} else if item.name.localizedCaseInsensitiveContains(filter) {
saveAllContentChildren(for: item)
return true
}

if let children = workspace?.workspaceFileManager?.childrenOfFile(item) {
return children.contains { fileSearchMatches(filter, for: $0) }
return children.contains { fileSearchMatches(filter, for: $0, sourceControlFilter: sourceControlFilter) }
}

return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ struct ProjectNavigatorToolbarBottom: View {
@EnvironmentObject var editorManager: EditorManager

@State var recentsFilter: Bool = false
@State var sourceControlFilter: Bool = false

var body: some View {
HStack(spacing: 5) {
Expand Down Expand Up @@ -48,7 +47,7 @@ struct ProjectNavigatorToolbarBottom: View {
Image(systemName: "clock")
}
.help("Show only recent files")
Toggle(isOn: $sourceControlFilter) {
Toggle(isOn: $workspace.sourceControlFilter) {
Image(systemName: "plusminus.circle")
}
.help("Show only files with source-control status")
Expand All @@ -57,7 +56,7 @@ struct ProjectNavigatorToolbarBottom: View {
.padding(.trailing, 2.5)
},
clearable: true,
hasValue: !workspace.navigatorFilter.isEmpty || recentsFilter || sourceControlFilter
hasValue: !workspace.navigatorFilter.isEmpty || recentsFilter || workspace.sourceControlFilter
)
}
.padding(.horizontal, 5)
Expand Down