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

feat(settings): section with glob pattern crud #1507

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
36 changes: 36 additions & 0 deletions CodeEdit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,11 @@
58F2EB1E292FB954004A9BDE /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 58F2EB1D292FB954004A9BDE /* Sparkle */; };
58FD7608291EA1CB0051D6E4 /* CommandPaletteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FD7605291EA1CB0051D6E4 /* CommandPaletteViewModel.swift */; };
58FD7609291EA1CB0051D6E4 /* CommandPaletteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58FD7607291EA1CB0051D6E4 /* CommandPaletteView.swift */; };
5B241BF32B6DDBFF0016E616 /* IgnorePatternListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B241BF22B6DDBFF0016E616 /* IgnorePatternListItemView.swift */; };
5B698A0A2B262FA000DE9392 /* SearchSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B698A092B262FA000DE9392 /* SearchSettingsView.swift */; };
5B698A0D2B26327800DE9392 /* SearchSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B698A0C2B26327800DE9392 /* SearchSettings.swift */; };
5B698A0F2B2636A700DE9392 /* SearchSettingsIgnoreGlobPatternItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B698A0E2B2636A700DE9392 /* SearchSettingsIgnoreGlobPatternItemView.swift */; };
5B698A162B263BCE00DE9392 /* SearchSettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B698A152B263BCE00DE9392 /* SearchSettingsModel.swift */; };
5C4BB1E128212B1E00A92FB2 /* World.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4BB1E028212B1E00A92FB2 /* World.swift */; };
610C0FDA2B44438F00A01CA7 /* WorkspaceDocument+FindAndReplace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 610C0FD92B44438F00A01CA7 /* WorkspaceDocument+FindAndReplace.swift */; };
611191FA2B08CC9000D4459B /* SearchIndexer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 611191F92B08CC9000D4459B /* SearchIndexer.swift */; };
Expand Down Expand Up @@ -797,6 +802,11 @@
58F2EAE1292FB2B0004A9BDE /* SoftwareUpdater.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoftwareUpdater.swift; sourceTree = "<group>"; };
58FD7605291EA1CB0051D6E4 /* CommandPaletteViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandPaletteViewModel.swift; sourceTree = "<group>"; };
58FD7607291EA1CB0051D6E4 /* CommandPaletteView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandPaletteView.swift; sourceTree = "<group>"; };
5B241BF22B6DDBFF0016E616 /* IgnorePatternListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IgnorePatternListItemView.swift; sourceTree = "<group>"; };
5B698A092B262FA000DE9392 /* SearchSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsView.swift; sourceTree = "<group>"; };
5B698A0C2B26327800DE9392 /* SearchSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettings.swift; sourceTree = "<group>"; };
5B698A0E2B2636A700DE9392 /* SearchSettingsIgnoreGlobPatternItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsIgnoreGlobPatternItemView.swift; sourceTree = "<group>"; };
5B698A152B263BCE00DE9392 /* SearchSettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsModel.swift; sourceTree = "<group>"; };
5C4BB1E028212B1E00A92FB2 /* World.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = World.swift; sourceTree = "<group>"; };
610C0FD92B44438F00A01CA7 /* WorkspaceDocument+FindAndReplace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WorkspaceDocument+FindAndReplace.swift"; sourceTree = "<group>"; };
611191F92B08CC9000D4459B /* SearchIndexer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchIndexer.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2256,6 +2266,26 @@
path = Views;
sourceTree = "<group>";
};
5B698A082B262F8400DE9392 /* SearchSettings */ = {
isa = PBXGroup;
children = (
5B698A0B2B26326000DE9392 /* Models */,
5B698A092B262FA000DE9392 /* SearchSettingsView.swift */,
5B241BF22B6DDBFF0016E616 /* IgnorePatternListItemView.swift */,
5B698A0E2B2636A700DE9392 /* SearchSettingsIgnoreGlobPatternItemView.swift */,
);
path = SearchSettings;
sourceTree = "<group>";
};
5B698A0B2B26326000DE9392 /* Models */ = {
isa = PBXGroup;
children = (
5B698A0C2B26327800DE9392 /* SearchSettings.swift */,
5B698A152B263BCE00DE9392 /* SearchSettingsModel.swift */,
);
path = Models;
sourceTree = "<group>";
};
5C403B8D27E20F8000788241 /* Frameworks */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2482,6 +2512,7 @@
B61DA9DD29D929BF00BF4A43 /* Pages */ = {
isa = PBXGroup;
children = (
5B698A082B262F8400DE9392 /* SearchSettings */,
6C5BE51A2A3D5419002DA0FC /* FeatureFlags */,
B6CF632629E5417C0085880A /* Keybindings */,
B6E41C6E29DD15540088F9F4 /* AccountsSettings */,
Expand Down Expand Up @@ -3204,6 +3235,7 @@
587B9E8429301D8F00AC7927 /* GitHubUser.swift in Sources */,
04BA7C1C2AE2D84100584E1C /* GitClient+Commit.swift in Sources */,
B65B10EC2B073913002852CF /* CEContentUnavailableView.swift in Sources */,
5B698A0A2B262FA000DE9392 /* SearchSettingsView.swift in Sources */,
B65B10FB2B08B054002852CF /* Divided.swift in Sources */,
B65B11012B09D5D4002852CF /* GitClient+Pull.swift in Sources */,
2072FA13280D74ED00C7F8D4 /* HistoryInspectorModel.swift in Sources */,
Expand All @@ -3217,6 +3249,7 @@
587B9E9229301D8F00AC7927 /* BitBucketAccount.swift in Sources */,
DE513F52281B672D002260B9 /* EditorTabBarAccessory.swift in Sources */,
2813F93927ECC4C300E305E4 /* NavigatorAreaView.swift in Sources */,
5B698A0F2B2636A700DE9392 /* SearchSettingsIgnoreGlobPatternItemView.swift in Sources */,
587B9E8A29301D8F00AC7927 /* GitHubIssue.swift in Sources */,
EC0870F72A455F6400EB8692 /* ProjectNavigatorViewController+NSMenuDelegate.swift in Sources */,
B60718202B0C6CE7009CDAB4 /* GitStashEntry.swift in Sources */,
Expand Down Expand Up @@ -3460,6 +3493,7 @@
B607184C2B17E037009CDAB4 /* SourceControlStashChangesView.swift in Sources */,
6C14CEB32877A68F001468FE /* FindNavigatorMatchListCell.swift in Sources */,
20EBB501280C325D00F3A5DA /* FileInspectorView.swift in Sources */,
5B698A162B263BCE00DE9392 /* SearchSettingsModel.swift in Sources */,
58822531292C280D00E83CDE /* View+isHovering.swift in Sources */,
587B9E9929301D8F00AC7927 /* GitChangedFile.swift in Sources */,
6C147C4B29A32A7B0089B630 /* Environment+SplitEditor.swift in Sources */,
Expand All @@ -3478,6 +3512,7 @@
6CFF967629BEBCD900182D6F /* FileCommands.swift in Sources */,
B60718462B17DC15009CDAB4 /* RepoOutlineGroupItem.swift in Sources */,
B697937A29FF5668002027EC /* AccountsSettingsAccountLink.swift in Sources */,
5B698A0D2B26327800DE9392 /* SearchSettings.swift in Sources */,
B685DE7929CC9CCD002860C8 /* StatusBarIcon.swift in Sources */,
587B9DA629300ABD00AC7927 /* ToolbarBranchPicker.swift in Sources */,
6C6BD6F629CD145F00235D17 /* ExtensionInfo.swift in Sources */,
Expand Down Expand Up @@ -3591,6 +3626,7 @@
611192002B08CCD700D4459B /* SearchIndexer+Memory.swift in Sources */,
587B9E8129301D8F00AC7927 /* PublicKey.swift in Sources */,
611191FE2B08CCD200D4459B /* SearchIndexer+File.swift in Sources */,
5B241BF32B6DDBFF0016E616 /* IgnorePatternListItemView.swift in Sources */,
6CB52DC92AC8DC3E002E75B3 /* CEWorkspaceFileManager+FileManagement.swift in Sources */,
58F2EB0B292FB2B0004A9BDE /* AccountsSettings.swift in Sources */,
5882252A292C280D00E83CDE /* StatusBarToggleUtilityAreaButton.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "43c802fb7f96e090dde015344a94b5e85779eff1",
"version" : "509.1.0"
"revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036",
"version" : "509.0.2"
}
},
{
Expand Down
6 changes: 6 additions & 0 deletions CodeEdit/Features/Settings/Models/SettingsData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ struct SettingsData: Codable, Hashable {
/// Feature Flags settings
var featureFlags: FeatureFlagsSettings = .init()

/// Searh Settings
var search: SearchSettings = .init()

/// Default initializer
init() {}

Expand All @@ -58,6 +61,7 @@ struct SettingsData: Codable, Hashable {
self.theme = try container.decodeIfPresent(ThemeSettings.self, forKey: .theme) ?? .init()
self.terminal = try container.decodeIfPresent(TerminalSettings.self, forKey: .terminal) ?? .init()
self.textEditing = try container.decodeIfPresent(TextEditingSettings.self, forKey: .textEditing) ?? .init()
self.search = try container.decodeIfPresent(SearchSettings.self, forKey: .search) ?? .init()
self.sourceControl = try container.decodeIfPresent(
SourceControlSettings.self,
forKey: .sourceControl
Expand All @@ -84,6 +88,8 @@ struct SettingsData: Codable, Hashable {
textEditing.searchKeys.forEach { settings.append(.init(name, isSetting: true, settingName: $0)) }
case .terminal:
terminal.searchKeys.forEach { settings.append(.init(name, isSetting: true, settingName: $0)) }
case .search:
search.searchKeys.forEach { settings.append(.init(name, isSetting: true, settingName: $0)) }
case .sourceControl:
sourceControl.searchKeys.forEach { settings.append(.init(name, isSetting: true, settingName: $0)) }
case .location:
Expand Down
1 change: 1 addition & 0 deletions CodeEdit/Features/Settings/Models/SettingsPage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct SettingsPage: Hashable, Equatable, Identifiable {
case theme = "Themes"
case textEditing = "Text Editing"
case terminal = "Terminal"
case search = "Search"
case keybindings = "Key Bindings"
case sourceControl = "Source Control"
case components = "Components"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// IgnorePatternListItemView.swift
// CodeEdit
//
// Created by Esteban on 2/2/24.
//

import SwiftUI

struct IgnorePatternListItem: View {
@Binding var pattern: GlobPattern
@Binding var selectedPattern: GlobPattern?
var addPattern: () -> Void
var removePattern: (GlobPattern) -> Void
var focusedField: FocusState<String?>.Binding
var isLast: Bool

@State var value: String

@FocusState private var isFocused: Bool

init(
pattern: Binding<GlobPattern>,
selectedPattern: Binding<GlobPattern?>,
addPattern: @escaping () -> Void,
removePattern: @escaping (GlobPattern) -> Void,
focusedField: FocusState<String?>.Binding,
isLast: Bool
) {
self._pattern = pattern
self._selectedPattern = selectedPattern
self.addPattern = addPattern
self.removePattern = removePattern
self.focusedField = focusedField
self.isLast = isLast
self._value = State(initialValue: pattern.wrappedValue.value)
}

var body: some View {
TextField("", text: $value)
.focused(focusedField, equals: pattern.id.uuidString)
.focused($isFocused)
.disableAutocorrection(true)
.autocorrectionDisabled()
.labelsHidden()
.onSubmit {
if !value.isEmpty && isLast {
addPattern()
}
}
.onChange(of: isFocused) { newIsFocused in
if newIsFocused {
if selectedPattern != pattern {
selectedPattern = pattern
}
} else {
if value.isEmpty {
removePattern(pattern)
} else {
pattern.value = value
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// SearchSettings.swift
// CodeEdit
//
// Created by Esteban on 12/10/23.
//

import Foundation

extension SettingsData {
struct SearchSettings: Codable, Hashable, SearchableSettingsPage {

/// The search keys
var searchKeys: [String] {
[
"Ignore Glob Patterns",
"Ignore Patterns"
]
.map { NSLocalizedString($0, comment: "") }
}

/// List of Glob Patterns that determine which files or directories to ignore
var ignoreGlobPatterns: [GlobPattern] = .init()

/// Default initializer
init() {}

/// Explicit decoder init for setting default values when key is not present in `JSON`
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.ignoreGlobPatterns = try container.decodeIfPresent(
[GlobPattern].self,
forKey: .ignoreGlobPatterns
) ?? []
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// SearchSettingsModel.swift
// CodeEdit
//
// Created by Esteban on 12/10/23.
//

import SwiftUI

struct GlobPattern: Identifiable, Hashable, Decodable, Encodable {
/// Ephimeral UUID used to track its representation in the UI
var id = UUID()

/// The Glob Pattern to render
var value: String
}

/// The Search Settings View Model. Accessible via the singleton "``SearchSettings/shared``".
///
/// **Usage:**
/// ```swift
/// @StateObject
/// private var searchSettigs: SearchSettingsModel = .shared
/// ```
final class SearchSettingsModel: ObservableObject {
/// Reads settings file for Search Settings and updates the values in this model
/// correspondingly
private init() {
let value = Settings[\.search].ignoreGlobPatterns
self.ignoreGlobPatterns = value
}

static let shared: SearchSettingsModel = .init()

/// Default instance of the `FileManager`
private let filemanager = FileManager.default

/// The base folder url `~/Library/Application Support/CodeEdit/`
private var baseURL: URL {
filemanager.homeDirectoryForCurrentUser.appendingPathComponent("Library/Application Support/CodeEdit")
}

/// The URL of the `search` folder
internal var searchURL: URL {
baseURL.appendingPathComponent("search", isDirectory: true)
}

/// The URL of the `Extensions` folder
internal var extensionsURL: URL {
baseURL.appendingPathComponent("Extensions", isDirectory: true)
}

/// The URL of the `settings.json` file
internal var settingsURL: URL {
baseURL.appendingPathComponent("settings.json", isDirectory: true)
}

/// Stores the new values from the Search Settings Model into the settings.json whenever
/// `ignoreGlobPatterns` is updated
@Published var ignoreGlobPatterns: [GlobPattern] {
didSet {
DispatchQueue.main.async {
Settings[\.search].ignoreGlobPatterns = self.ignoreGlobPatterns
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// SearchSettingsIgnoreGlobPatternItemView.swift
// CodeEdit
//
// Created by Esteban on 12/10/23.
//

import SwiftUI

struct SearchSettingsIgnoreGlobPatternItemView: View {
@Binding var globPattern: String

var body: some View {
Text(globPattern)
}
}
Loading
Loading