From e87de3a9e5c8dee20d0d5d3a225db332ab9bf9f5 Mon Sep 17 00:00:00 2001 From: Vitalii Parovishnyk <870237+ikorich@users.noreply.github.com> Date: Tue, 13 Jan 2026 14:04:30 +0200 Subject: [PATCH 1/2] updated SPMs --- .../xcshareddata/swiftpm/Package.resolved | 123 ++++++++++++++++++ BifcodePackage/Package.resolved | 105 +++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 Bifcode.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 BifcodePackage/Package.resolved diff --git a/Bifcode.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Bifcode.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..0ead720 --- /dev/null +++ b/Bifcode.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,123 @@ +{ + "originHash" : "12c35fbdbe657f2d43e66c49702894fe4acff2e94879d546a9bedf76b8a0b966", + "pins" : [ + { + "identity" : "codeeditlanguages", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CodeEditApp/CodeEditLanguages.git", + "state" : { + "revision" : "331d5dbc5fc8513be5848fce8a2a312908f36a11", + "version" : "0.1.20" + } + }, + { + "identity" : "codeeditsourceeditor", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CodeEditApp/CodeEditSourceEditor", + "state" : { + "revision" : "424453d2232c9912933a3b5a1f3d3df669404ed0", + "version" : "0.15.2" + } + }, + { + "identity" : "codeeditsymbols", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CodeEditApp/CodeEditSymbols.git", + "state" : { + "revision" : "ae69712b08571c4469c2ed5cd38ad9f19439793e", + "version" : "0.2.3" + } + }, + { + "identity" : "codeedittextview", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CodeEditApp/CodeEditTextView.git", + "state" : { + "revision" : "d7ac3f11f22ec2e820187acce8f3a3fb7aa8ddec", + "version" : "0.12.1" + } + }, + { + "identity" : "developersupportstore", + "kind" : "remoteSourceControl", + "location" : "https://github.com/IGRSoft/DeveloperSupportStore", + "state" : { + "revision" : "c9d8f3282a649273fdbf4d3841e45e10a4951ee4", + "version" : "1.0.3" + } + }, + { + "identity" : "rearrange", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ChimeHQ/Rearrange", + "state" : { + "revision" : "f1d74e1642956f0300756ad8d1d64e9034857bc3", + "version" : "2.0.0" + } + }, + { + "identity" : "storehelper", + "kind" : "remoteSourceControl", + "location" : "https://github.com/russell-archer/StoreHelper.git", + "state" : { + "revision" : "1c55f49473d847fd5a2f495aabe45f6e5ea3e2ef", + "version" : "2.7.1" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", + "version" : "1.3.0" + } + }, + { + "identity" : "swiftlintplugin", + "kind" : "remoteSourceControl", + "location" : "https://github.com/lukepistrol/SwiftLintPlugin", + "state" : { + "revision" : "17c132fe0ce3b4324dc23b575636b223483207b3", + "version" : "0.63.0" + } + }, + { + "identity" : "swifttreesitter", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ChimeHQ/SwiftTreeSitter.git", + "state" : { + "revision" : "08ef81eb8620617b55b08868126707ad72bf754f", + "version" : "0.25.0" + } + }, + { + "identity" : "textformation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ChimeHQ/TextFormation", + "state" : { + "revision" : "b1ce9a14bd86042bba4de62236028dc4ce9db6a1", + "version" : "0.9.0" + } + }, + { + "identity" : "textstory", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ChimeHQ/TextStory", + "state" : { + "revision" : "91df6fc9bd817f9712331a4a3e826f7bdc823e1d", + "version" : "0.9.1" + } + }, + { + "identity" : "tree-sitter", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tree-sitter/tree-sitter", + "state" : { + "revision" : "da6fe9beb4f7f67beb75914ca8e0d48ae48d6406", + "version" : "0.25.10" + } + } + ], + "version" : 3 +} diff --git a/BifcodePackage/Package.resolved b/BifcodePackage/Package.resolved new file mode 100644 index 0000000..f1d1567 --- /dev/null +++ b/BifcodePackage/Package.resolved @@ -0,0 +1,105 @@ +{ + "originHash" : "804d0b5514c0fb966aa534f4db8957d2ecd87c6e2c79a0c5e33d6986765da294", + "pins" : [ + { + "identity" : "codeeditlanguages", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CodeEditApp/CodeEditLanguages.git", + "state" : { + "revision" : "331d5dbc5fc8513be5848fce8a2a312908f36a11", + "version" : "0.1.20" + } + }, + { + "identity" : "codeeditsourceeditor", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CodeEditApp/CodeEditSourceEditor", + "state" : { + "revision" : "424453d2232c9912933a3b5a1f3d3df669404ed0", + "version" : "0.15.2" + } + }, + { + "identity" : "codeeditsymbols", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CodeEditApp/CodeEditSymbols.git", + "state" : { + "revision" : "ae69712b08571c4469c2ed5cd38ad9f19439793e", + "version" : "0.2.3" + } + }, + { + "identity" : "codeedittextview", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CodeEditApp/CodeEditTextView.git", + "state" : { + "revision" : "d7ac3f11f22ec2e820187acce8f3a3fb7aa8ddec", + "version" : "0.12.1" + } + }, + { + "identity" : "rearrange", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ChimeHQ/Rearrange", + "state" : { + "revision" : "f1d74e1642956f0300756ad8d1d64e9034857bc3", + "version" : "2.0.0" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "7b847a3b7008b2dc2f47ca3110d8c782fb2e5c7e", + "version" : "1.3.0" + } + }, + { + "identity" : "swiftlintplugin", + "kind" : "remoteSourceControl", + "location" : "https://github.com/lukepistrol/SwiftLintPlugin", + "state" : { + "revision" : "9bbc46a4cf8275ceb39334f6276b6b215d67d5d5", + "version" : "0.62.2" + } + }, + { + "identity" : "swifttreesitter", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ChimeHQ/SwiftTreeSitter.git", + "state" : { + "revision" : "08ef81eb8620617b55b08868126707ad72bf754f", + "version" : "0.25.0" + } + }, + { + "identity" : "textformation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ChimeHQ/TextFormation", + "state" : { + "revision" : "b1ce9a14bd86042bba4de62236028dc4ce9db6a1", + "version" : "0.9.0" + } + }, + { + "identity" : "textstory", + "kind" : "remoteSourceControl", + "location" : "https://github.com/ChimeHQ/TextStory", + "state" : { + "revision" : "91df6fc9bd817f9712331a4a3e826f7bdc823e1d", + "version" : "0.9.1" + } + }, + { + "identity" : "tree-sitter", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tree-sitter/tree-sitter", + "state" : { + "revision" : "da6fe9beb4f7f67beb75914ca8e0d48ae48d6406", + "version" : "0.25.10" + } + } + ], + "version" : 3 +} From 81675d64c5f4a25fc99508033bd57e0cc1d79bcd Mon Sep 17 00:00:00 2001 From: Vitalii Parovishnyk <870237+ikorich@users.noreply.github.com> Date: Tue, 27 Jan 2026 15:42:33 +0200 Subject: [PATCH 2/2] #26 feat: add multiple font family selection Add support for SF Mono, Menlo, Monaco, and Courier New fonts: - Add FontFamily enum in SettingsTypes.swift with font creation - Add font picker UI to ToolBarView in Code Style section - Update CodeEditorView to use selected font family - Update ContentView export to use selected font metrics --- .../Sources/BifcodeFeature/ContentView.swift | 9 ++- .../BifcodeFeature/Models/SettingsTypes.swift | 81 ++++++++++++++++++- .../BifcodeFeature/Views/CodeEditorView.swift | 13 ++- .../BifcodeFeature/Views/ToolBarView.swift | 38 +++++++-- 4 files changed, 127 insertions(+), 14 deletions(-) diff --git a/BifcodePackage/Sources/BifcodeFeature/ContentView.swift b/BifcodePackage/Sources/BifcodeFeature/ContentView.swift index bb51890..466585d 100644 --- a/BifcodePackage/Sources/BifcodeFeature/ContentView.swift +++ b/BifcodePackage/Sources/BifcodeFeature/ContentView.swift @@ -2,7 +2,7 @@ // ContentView.swift // // Created on 17.12.2025. -// Copyright © 2025 IGR Soft. All rights reserved. +// Copyright © 2026 IGR Soft. All rights reserved. // import AppKit @@ -89,6 +89,7 @@ public struct ContentView: View { @AppStorage("indicatorSize") private var indicatorSize: Double = 48 @AppStorage("showTitle") private var showTitle: Bool = true @AppStorage("fontSize") private var fontSize: Double = 14 + @AppStorage("fontFamily") private var fontFamilyRaw: String = FontFamily.system.rawValue @AppStorage("selectedTheme") private var selectedThemeRaw: String = EditorThemeOption.atomOneDark.rawValue @AppStorage("themeMode") private var themeModeRaw: String = ThemeMode.dark.rawValue @@ -104,6 +105,10 @@ public struct ContentView: View { IndicatorStyle(rawValue: indicatorStyleRaw) ?? .iconAndText } + private var fontFamily: FontFamily { + FontFamily(rawValue: fontFamilyRaw) ?? .system + } + private var selectedTheme: EditorThemeOption { EditorThemeOption(rawValue: selectedThemeRaw) ?? .atomOneDark } @@ -292,7 +297,7 @@ public struct ContentView: View { @MainActor private func renderExportViewToImage() async -> NSImage? { // Calculate size based on layout and content - let font = NSFont.monospacedSystemFont(ofSize: fontSize, weight: .regular) + let font = fontFamily.font(size: fontSize) // Find the longest line in both panels let doLines = viewModel.doPanel.code.components(separatedBy: "\n") diff --git a/BifcodePackage/Sources/BifcodeFeature/Models/SettingsTypes.swift b/BifcodePackage/Sources/BifcodeFeature/Models/SettingsTypes.swift index 3d03a58..0de77e3 100644 --- a/BifcodePackage/Sources/BifcodeFeature/Models/SettingsTypes.swift +++ b/BifcodePackage/Sources/BifcodeFeature/Models/SettingsTypes.swift @@ -2,13 +2,92 @@ // SettingsTypes.swift // // Created on 17.12.2025. -// Copyright © 2025 IGR Soft. All rights reserved. +// Copyright © 2026 IGR Soft. All rights reserved. // import AppKit import CodeEditSourceEditor import Foundation +// MARK: - Font Family + +/// The font family for code display in the editor. +/// +/// Provides a selection of popular monospace fonts suitable for code editing. +/// The default is the system monospace font (SF Mono on macOS). +/// +/// ## Usage +/// +/// ```swift +/// @AppStorage("fontFamily") private var fontFamily = FontFamily.system.rawValue +/// ``` +/// +/// ## Available Fonts +/// +/// - **System** - SF Mono (default system monospace) +/// - **Menlo** - Classic macOS monospace font +/// - **Monaco** - Legacy macOS programming font +/// - **Courier** - Traditional monospace font +/// +/// ## Topics +/// +/// ### Fonts +/// +/// - ``system`` +/// - ``menlo`` +/// - ``monaco`` +/// - ``courier`` +public enum FontFamily: String, CaseIterable, Sendable { + /// System monospace font (SF Mono on macOS). + /// + /// The default font, matching Apple's design guidelines + /// for code display. Available in all weights. + case system + + /// Menlo font family. + /// + /// A classic macOS monospace font derived from Bitstream Vera Sans Mono. + /// Has been the default Terminal font for many years. + case menlo = "Menlo" + + /// Monaco font family. + /// + /// The original macOS programming font, used in classic Mac OS + /// and early versions of Xcode. Has a distinctive, compact style. + case monaco = "Monaco" + + /// Courier New font family. + /// + /// A traditional typewriter-style monospace font. Has a more + /// classic, formal appearance than other options. + case courier = "Courier New" + + /// A human-readable label for display in pickers. + public var label: String { + switch self { + case .system: "SF Mono" + case .menlo: "Menlo" + case .monaco: "Monaco" + case .courier: "Courier New" + } + } + + /// Creates an NSFont with this font family at the specified size. + /// + /// - Parameter size: The font size in points. + /// - Returns: An NSFont configured with this font family, or the + /// system monospace font if the specified font is unavailable. + public func font(size: CGFloat) -> NSFont { + switch self { + case .system: + NSFont.monospacedSystemFont(ofSize: size, weight: .regular) + case .menlo, .monaco, .courier: + NSFont(name: rawValue, size: size) + ?? NSFont.monospacedSystemFont(ofSize: size, weight: .regular) + } + } +} + // MARK: - Indicator Position /// The position of the indicator badge within a code panel. diff --git a/BifcodePackage/Sources/BifcodeFeature/Views/CodeEditorView.swift b/BifcodePackage/Sources/BifcodeFeature/Views/CodeEditorView.swift index 8aa58f2..6cbe84c 100644 --- a/BifcodePackage/Sources/BifcodeFeature/Views/CodeEditorView.swift +++ b/BifcodePackage/Sources/BifcodeFeature/Views/CodeEditorView.swift @@ -2,7 +2,7 @@ // CodeEditorView.swift // // Created on 17.12.2025. -// Copyright © 2025 IGR Soft. All rights reserved. +// Copyright © 2026 IGR Soft. All rights reserved. // import AppKit @@ -75,6 +75,7 @@ public struct CodeEditorView: View { @AppStorage("dontIndicatorLabel") private var dontIndicatorLabel: String = "Don'ts" @AppStorage("showTitle") private var showTitle: Bool = true @AppStorage("fontSize") private var fontSize: Double = 14 + @AppStorage("fontFamily") private var fontFamilyRaw: String = FontFamily.system.rawValue @AppStorage("selectedTheme") private var selectedThemeRaw: String = EditorThemeOption.atomOneDark.rawValue @AppStorage("themeMode") private var themeModeRaw: String = ThemeMode.dark.rawValue @@ -86,6 +87,10 @@ public struct CodeEditorView: View { IndicatorStyle(rawValue: indicatorStyleRaw) ?? .iconAndText } + private var fontFamily: FontFamily { + FontFamily(rawValue: fontFamilyRaw) ?? .system + } + private var selectedTheme: EditorThemeOption { EditorThemeOption(rawValue: selectedThemeRaw) ?? .atomOneDark } @@ -135,7 +140,7 @@ public struct CodeEditorView: View { /// Line height matching the editor's font private var lineHeight: CGFloat { - let font = NSFont.monospacedSystemFont(ofSize: fontSize, weight: .regular) + let font = fontFamily.font(size: fontSize) return font.ascender - font.descender + font.leading } @@ -230,7 +235,7 @@ public struct CodeEditorView: View { /// Unique identifier for forcing editor recreation when language, theme, or font changes private var editorIdentifier: String { - "\(panel.id)-\(panel.language.id)-\(selectedThemeRaw)-\(Int(fontSize))" + "\(panel.id)-\(panel.language.id)-\(selectedThemeRaw)-\(fontFamilyRaw)-\(Int(fontSize))" } /// Tracks if initial appearance has occurred to force editor recreation @@ -262,7 +267,7 @@ public struct CodeEditorView: View { SourceEditorConfiguration( appearance: .init( theme: selectedTheme.editorTheme, - font: NSFont.monospacedSystemFont(ofSize: fontSize, weight: .regular), + font: fontFamily.font(size: fontSize), wrapLines: false ), peripherals: .init(showMinimap: false, showFoldingRibbon: false) diff --git a/BifcodePackage/Sources/BifcodeFeature/Views/ToolBarView.swift b/BifcodePackage/Sources/BifcodeFeature/Views/ToolBarView.swift index a19742e..14465ec 100644 --- a/BifcodePackage/Sources/BifcodeFeature/Views/ToolBarView.swift +++ b/BifcodePackage/Sources/BifcodeFeature/Views/ToolBarView.swift @@ -2,7 +2,7 @@ // ToolBarView.swift // // Created on 17.12.2025. -// Copyright © 2025 IGR Soft. All rights reserved. +// Copyright © 2026 IGR Soft. All rights reserved. // import CodeEditLanguages @@ -58,6 +58,7 @@ public struct ToolBarView: View { @AppStorage("doIndicatorLabel") private var doIndicatorLabel: String = "Do's" @AppStorage("dontIndicatorLabel") private var dontIndicatorLabel: String = "Don'ts" @AppStorage("fontSize") private var fontSize: Double = 14 + @AppStorage("fontFamily") private var fontFamilyRaw: String = FontFamily.system.rawValue @AppStorage("selectedTheme") private var selectedThemeRaw: String = EditorThemeOption.atomOneDark.rawValue @AppStorage("themeMode") private var themeModeRaw: String = ThemeMode.dark.rawValue @@ -173,12 +174,21 @@ public struct ToolBarView: View { themePicker } - // Font Size with Label - VStack(alignment: .leading, spacing: 4) { - Text("Font Size") - .font(.caption) - .foregroundStyle(Color.tertiaryText) - fontSizeControl + // Font Family & Size + HStack(spacing: 12) { + VStack(alignment: .leading, spacing: 4) { + Text("Font") + .font(.caption) + .foregroundStyle(Color.tertiaryText) + fontFamilyPicker + } + + VStack(alignment: .leading, spacing: 4) { + Text("Size") + .font(.caption) + .foregroundStyle(Color.tertiaryText) + fontSizeControl + } } // Mode & Layout Controls @@ -296,6 +306,20 @@ public struct ToolBarView: View { } } + // MARK: - Font Family Picker + + private var fontFamilyPicker: some View { + Picker("", selection: $fontFamilyRaw) { + ForEach(FontFamily.allCases, id: \.rawValue) { family in + Text(family.label).tag(family.rawValue) + } + } + .pickerStyle(.menu) + .fixedSize() + .accessibilityLabel("Font Family") + .accessibilityHint("Select monospace font for code editor") + } + private var commonLanguages: [CodeLanguage] { [ .swift, .python, .javascript, .typescript,