-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added LSP binaries settings page * Fix icon colors * Renamed 'LSP Binaries' to 'Developer Settings' * Update KeyValueTable instructions, small refactors * Bug fix * Form styling for the modal * Toggle developer menu on F12 * Properly deinit event monitor * Refactor * Added header to modal and changed text field style * Fixed spacing on modal buttons
- Loading branch information
1 parent
aa7454e
commit f2caddf
Showing
8 changed files
with
341 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
// | ||
// KeyValueTable.swift | ||
// CodeEdit | ||
// | ||
// Created by Abe Malla on 5/16/24. | ||
// | ||
|
||
import SwiftUI | ||
|
||
struct KeyValueItem: Identifiable, Equatable { | ||
let id = UUID() | ||
let key: String | ||
let value: String | ||
} | ||
|
||
private struct NewListTableItemView: View { | ||
@Environment(\.dismiss) | ||
var dismiss | ||
|
||
@State private var key = "" | ||
@State private var value = "" | ||
|
||
let keyColumnName: String | ||
let valueColumnName: String | ||
let newItemInstruction: String | ||
let headerView: AnyView? | ||
var completion: (String, String) -> Void | ||
|
||
init( | ||
_ keyColumnName: String, | ||
_ valueColumnName: String, | ||
_ newItemInstruction: String, | ||
headerView: AnyView? = nil, | ||
completion: @escaping (String, String) -> Void | ||
) { | ||
self.keyColumnName = keyColumnName | ||
self.valueColumnName = valueColumnName | ||
self.newItemInstruction = newItemInstruction | ||
self.headerView = headerView | ||
self.completion = completion | ||
} | ||
|
||
var body: some View { | ||
VStack(spacing: 0) { | ||
Form { | ||
Section { | ||
TextField(keyColumnName, text: $key) | ||
.textFieldStyle(.plain) | ||
TextField(valueColumnName, text: $value) | ||
.textFieldStyle(.plain) | ||
} header: { | ||
headerView | ||
} | ||
} | ||
.formStyle(.grouped) | ||
.scrollDisabled(true) | ||
.scrollContentBackground(.hidden) | ||
.onSubmit { | ||
if !key.isEmpty && !value.isEmpty { | ||
completion(key, value) | ||
} | ||
} | ||
|
||
HStack { | ||
Spacer() | ||
Button("Cancel") { | ||
dismiss() | ||
} | ||
Button("Add") { | ||
if !key.isEmpty && !value.isEmpty { | ||
completion(key, value) | ||
} | ||
} | ||
.buttonStyle(.borderedProminent) | ||
.disabled(key.isEmpty || value.isEmpty) | ||
} | ||
.padding(.horizontal, 20) | ||
// .padding(.top, 2) | ||
.padding(.bottom, 20) | ||
} | ||
.frame(maxWidth: 480) | ||
} | ||
} | ||
|
||
struct KeyValueTable<Header: View>: View { | ||
@Binding var items: [String: String] | ||
|
||
let keyColumnName: String | ||
let valueColumnName: String | ||
let newItemInstruction: String | ||
let header: () -> Header | ||
|
||
@State private var showingModal = false | ||
@State private var selection: UUID? | ||
@State private var tableItems: [KeyValueItem] = [] | ||
|
||
init( | ||
items: Binding<[String: String]>, | ||
keyColumnName: String, | ||
valueColumnName: String, | ||
newItemInstruction: String, | ||
@ViewBuilder header: @escaping () -> Header = { EmptyView() } | ||
) { | ||
self._items = items | ||
self.keyColumnName = keyColumnName | ||
self.valueColumnName = valueColumnName | ||
self.newItemInstruction = newItemInstruction | ||
self.header = header | ||
} | ||
|
||
var body: some View { | ||
VStack { | ||
Table(tableItems, selection: $selection) { | ||
TableColumn(keyColumnName) { item in | ||
Text(item.key) | ||
} | ||
TableColumn(valueColumnName) { item in | ||
Text(item.value) | ||
} | ||
} | ||
.frame(height: 200) | ||
.actionBar { | ||
HStack(spacing: 2) { | ||
Button { | ||
showingModal = true | ||
} label: { | ||
Image(systemName: "plus") | ||
} | ||
|
||
Divider() | ||
.frame(minHeight: 15) | ||
|
||
Button { | ||
removeItem() | ||
} label: { | ||
Image(systemName: "minus") | ||
} | ||
.disabled(selection == nil) | ||
.opacity(selection == nil ? 0.5 : 1) | ||
} | ||
Spacer() | ||
} | ||
.sheet(isPresented: $showingModal) { | ||
NewListTableItemView( | ||
keyColumnName, | ||
valueColumnName, | ||
newItemInstruction, | ||
headerView: AnyView(header()) | ||
) { key, value in | ||
items[key] = value | ||
updateTableItems() | ||
showingModal = false | ||
} | ||
} | ||
.cornerRadius(6) | ||
.onAppear(perform: updateTableItems) | ||
} | ||
} | ||
|
||
private func updateTableItems() { | ||
tableItems = items.map { KeyValueItem(key: $0.key, value: $0.value) } | ||
} | ||
|
||
private func removeItem() { | ||
guard let selectedId = selection else { return } | ||
if let selectedItem = tableItems.first(where: { $0.id == selectedId }) { | ||
items.removeValue(forKey: selectedItem.key) | ||
updateTableItems() | ||
} | ||
selection = nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
CodeEdit/Features/Settings/Pages/DeveloperSettings/DeveloperSettingsView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// | ||
// DeveloperSettingsView.swift | ||
// CodeEdit | ||
// | ||
// Created by Abe Malla on 5/16/24. | ||
// | ||
|
||
import SwiftUI | ||
|
||
/// A view that implements the Developer settings section | ||
struct DeveloperSettingsView: View { | ||
@AppSettings(\.developerSettings.lspBinaries) | ||
var lspBinaries | ||
|
||
var body: some View { | ||
SettingsForm { | ||
Section { | ||
KeyValueTable( | ||
items: $lspBinaries, | ||
keyColumnName: "Language", | ||
valueColumnName: "Language Server Path", | ||
newItemInstruction: "Add a language server" | ||
) { | ||
Text("Add a language server") | ||
Text( | ||
"Specify the absolute path to your LSP binary and its associated language." | ||
) | ||
} | ||
} header: { | ||
Text("LSP Binaries") | ||
Text("Specify the language and the absolute path to the language server binary.") | ||
} | ||
} | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
CodeEdit/Features/Settings/Pages/DeveloperSettings/Models/DeveloperSettings.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// | ||
// DeveloperSettings.swift | ||
// CodeEdit | ||
// | ||
// Created by Abe Malla on 5/15/24. | ||
// | ||
|
||
import Foundation | ||
|
||
extension SettingsData { | ||
struct DeveloperSettings: Codable, Hashable, SearchableSettingsPage { | ||
|
||
/// The search keys | ||
var searchKeys: [String] { | ||
[ | ||
"Developer", | ||
"Language Server Protocol", | ||
"LSP Binaries" | ||
] | ||
.map { NSLocalizedString($0, comment: "") } | ||
} | ||
|
||
/// A dictionary that stores a file type and a path to an LSP binary | ||
var lspBinaries: [String: String] = [:] | ||
|
||
/// 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.lspBinaries = try container.decodeIfPresent( | ||
[String: String].self, | ||
forKey: .lspBinaries | ||
) ?? [:] | ||
} | ||
} | ||
} |
Oops, something went wrong.