Skip to content
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 @@ -8,27 +8,34 @@

/* Begin PBXBuildFile section */
6C2265DF2D306AB7008710D7 /* CodeEditTextView in Frameworks */ = {isa = PBXBuildFile; productRef = 6C2265DE2D306AB7008710D7 /* CodeEditTextView */; };
6C2265E42D306B90008710D7 /* SwiftUITextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2265E32D306B90008710D7 /* SwiftUITextView.swift */; };
6C2265E62D306D37008710D7 /* TextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2265E52D306D37008710D7 /* TextViewController.swift */; };
6CCDA29B2D306A25007CD84A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6CCDA2942D306A25007CD84A /* Assets.xcassets */; };
6CCDA29D2D306A25007CD84A /* CodeEditTextViewExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CCDA2952D306A25007CD84A /* CodeEditTextViewExampleApp.swift */; };
6CCDA29E2D306A25007CD84A /* CodeEditTextViewExampleDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CCDA2962D306A25007CD84A /* CodeEditTextViewExampleDocument.swift */; };
6CCDA29F2D306A25007CD84A /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CCDA2972D306A25007CD84A /* ContentView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
6C2265E12D306B58008710D7 /* CodeEditTextViewExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CodeEditTextViewExample.entitlements; sourceTree = "<group>"; };
6C2265E32D306B90008710D7 /* SwiftUITextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUITextView.swift; sourceTree = "<group>"; };
6C2265E52D306D37008710D7 /* TextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewController.swift; sourceTree = "<group>"; };
6CCDA27D2D306A1B007CD84A /* CodeEditTextViewExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CodeEditTextViewExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
6CCDA2942D306A25007CD84A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6CCDA2952D306A25007CD84A /* CodeEditTextViewExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeEditTextViewExampleApp.swift; sourceTree = "<group>"; };
6CCDA2962D306A25007CD84A /* CodeEditTextViewExampleDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeEditTextViewExampleDocument.swift; sourceTree = "<group>"; };
6CCDA2972D306A25007CD84A /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
6CCDA2982D306A25007CD84A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
6CCDA2A12D306A5B007CD84A /* CodeEditTextView */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = CodeEditTextView; path = ../..; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
B6654F662DF001EB003B32B8 /* Exceptions for "CodeEditTextViewExample" folder in "CodeEditTextViewExample" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = 6CCDA27C2D306A1B007CD84A /* CodeEditTextViewExample */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
B6654F5D2DF001EB003B32B8 /* CodeEditTextViewExample */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
B6654F662DF001EB003B32B8 /* Exceptions for "CodeEditTextViewExample" folder in "CodeEditTextViewExample" target */,
);
path = CodeEditTextViewExample;
sourceTree = "<group>";
};
/* End PBXFileSystemSynchronizedRootGroup section */

/* Begin PBXFrameworksBuildPhase section */
6CCDA27A2D306A1B007CD84A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
Expand All @@ -41,29 +48,11 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
6C2265E02D306AEB008710D7 /* Documents */ = {
isa = PBXGroup;
children = (
6CCDA2962D306A25007CD84A /* CodeEditTextViewExampleDocument.swift */,
);
path = Documents;
sourceTree = "<group>";
};
6C2265E22D306B69008710D7 /* Views */ = {
isa = PBXGroup;
children = (
6CCDA2972D306A25007CD84A /* ContentView.swift */,
6C2265E32D306B90008710D7 /* SwiftUITextView.swift */,
6C2265E52D306D37008710D7 /* TextViewController.swift */,
);
path = Views;
sourceTree = "<group>";
};
6CCDA2742D306A1B007CD84A = {
isa = PBXGroup;
children = (
6CCDA2A12D306A5B007CD84A /* CodeEditTextView */,
6CCDA2992D306A25007CD84A /* CodeEditTextViewExample */,
B6654F5D2DF001EB003B32B8 /* CodeEditTextViewExample */,
6CCDA2A02D306A5B007CD84A /* Frameworks */,
6CCDA27E2D306A1B007CD84A /* Products */,
);
Expand All @@ -77,19 +66,6 @@
name = Products;
sourceTree = "<group>";
};
6CCDA2992D306A25007CD84A /* CodeEditTextViewExample */ = {
isa = PBXGroup;
children = (
6CCDA2952D306A25007CD84A /* CodeEditTextViewExampleApp.swift */,
6C2265E02D306AEB008710D7 /* Documents */,
6C2265E22D306B69008710D7 /* Views */,
6CCDA2942D306A25007CD84A /* Assets.xcassets */,
6CCDA2982D306A25007CD84A /* Info.plist */,
6C2265E12D306B58008710D7 /* CodeEditTextViewExample.entitlements */,
);
path = CodeEditTextViewExample;
sourceTree = "<group>";
};
6CCDA2A02D306A5B007CD84A /* Frameworks */ = {
isa = PBXGroup;
children = (
Expand All @@ -112,6 +88,9 @@
);
dependencies = (
);
fileSystemSynchronizedGroups = (
B6654F5D2DF001EB003B32B8 /* CodeEditTextViewExample */,
);
name = CodeEditTextViewExample;
packageProductDependencies = (
6C2265DE2D306AB7008710D7 /* CodeEditTextView */,
Expand Down Expand Up @@ -159,7 +138,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6CCDA29B2D306A25007CD84A /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -170,11 +148,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6C2265E62D306D37008710D7 /* TextViewController.swift in Sources */,
6CCDA29D2D306A25007CD84A /* CodeEditTextViewExampleApp.swift in Sources */,
6CCDA29E2D306A25007CD84A /* CodeEditTextViewExampleDocument.swift in Sources */,
6CCDA29F2D306A25007CD84A /* ContentView.swift in Sources */,
6C2265E42D306B90008710D7 /* SwiftUITextView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,35 +1,68 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
"size" : "16x16",
"idiom" : "mac",
"filename" : "CodeEditTextView-Icon-16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "CodeEditTextView-Icon-32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "CodeEditTextView-Icon-32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "CodeEditTextView-Icon-64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "CodeEditTextView-Icon-128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "CodeEditTextView-Icon-256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "CodeEditTextView-Icon-256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "CodeEditTextView-Icon-512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "CodeEditTextView-Icon-512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "CodeEditTextView-Icon-1024.png",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
"version" : 1,
"author" : "xcode"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,28 @@ struct ContentView: View {
@Binding var document: CodeEditTextViewExampleDocument
@AppStorage("wraplines") private var wrapLines: Bool = true
@AppStorage("edgeinsets") private var enableEdgeInsets: Bool = false
@AppStorage("usesystemcursor") private var useSystemCursor: Bool = false
@AppStorage("isselectable") private var isSelectable: Bool = true
@AppStorage("iseditable") private var isEditable: Bool = true

var body: some View {
VStack(spacing: 0) {
HStack {
Toggle("Wrap Lines", isOn: $wrapLines)
Toggle("Inset Edges", isOn: $enableEdgeInsets)
}
Divider()
SwiftUITextView(
SwiftUITextView(
text: document.text,
wrapLines: $wrapLines,
enableEdgeInsets: $enableEdgeInsets,
useSystemCursor: $useSystemCursor,
isSelectable: $isSelectable,
isEditable: $isEditable
)
.padding(.bottom, 28)
.overlay(alignment: .bottom) {
StatusBar(
text: document.text,
wrapLines: $wrapLines,
enableEdgeInsets: $enableEdgeInsets
enableEdgeInsets: $enableEdgeInsets,
useSystemCursor: $useSystemCursor,
isSelectable: $isSelectable,
isEditable: $isEditable
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// StatusBar.swift
// CodeEditTextViewExample
//
// Created by Austin Condiff on 6/3/25.
//

import SwiftUI

struct StatusBar: View {
@Environment(\.colorScheme)
var colorScheme

var text: NSTextStorage

@Binding var wrapLines: Bool
@Binding var enableEdgeInsets: Bool
@Binding var useSystemCursor: Bool
@Binding var isSelectable: Bool
@Binding var isEditable: Bool

var body: some View {
HStack {
Menu {
Toggle("Wrap Lines", isOn: $wrapLines)
Toggle("Inset Edges", isOn: $enableEdgeInsets)
Toggle("Use System Cursor", isOn: $useSystemCursor)
Toggle("Selectable", isOn: $isSelectable)
Toggle("Editable", isOn: $isEditable)
} label: {}
.background {
Image(systemName: "switch.2")
.foregroundStyle(.secondary)
.font(.system(size: 13.5, weight: .regular))
}
.menuStyle(.borderlessButton)
.menuIndicator(.hidden)
.frame(maxWidth: 18, alignment: .center)
Spacer()
Group {
Text("\(text.length) characters")
}
.foregroundStyle(.secondary)
}
.font(.subheadline)
.fontWeight(.medium)
.controlSize(.small)
.padding(.horizontal, 8)
.frame(height: 28)
.background(.bar)
.overlay(alignment: .top) {
VStack {
Divider()
.overlay {
if colorScheme == .dark {
Color.black
}
}
}
}
.zIndex(2)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,26 @@ struct SwiftUITextView: NSViewControllerRepresentable {
var text: NSTextStorage
@Binding var wrapLines: Bool
@Binding var enableEdgeInsets: Bool
@Binding var useSystemCursor: Bool
@Binding var isSelectable: Bool
@Binding var isEditable: Bool

func makeNSViewController(context: Context) -> TextViewController {
let controller = TextViewController(string: "")
controller.textView.setTextStorage(text)
controller.wrapLines = wrapLines
controller.enableEdgeInsets = enableEdgeInsets
controller.useSystemCursor = useSystemCursor
controller.isSelectable = isSelectable
controller.isEditable = isEditable
return controller
}

func updateNSViewController(_ nsViewController: TextViewController, context: Context) {
nsViewController.wrapLines = wrapLines
nsViewController.enableEdgeInsets = enableEdgeInsets
nsViewController.useSystemCursor = useSystemCursor
nsViewController.isSelectable = isSelectable
nsViewController.isEditable = isEditable
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ class TextViewController: NSViewController {
textView.wrapLines = wrapLines
}
}
var useSystemCursor: Bool = false {
didSet {
textView.useSystemCursor = useSystemCursor
// Force cursor update by temporarily removing and re-adding the selection
if let range = textView.selectionManager.textSelections.first?.range {
textView.selectionManager.setSelectedRange(NSRange(location: range.location, length: 0))
}
}
}
var isSelectable: Bool = true {
didSet {
textView.isSelectable = isSelectable
}
}
var isEditable: Bool = true {
didSet {
textView.isEditable = isEditable
}
}

init(string: String) {
textView = TextView(string: string)
Expand Down