Skip to content

Commit 8ea4862

Browse files
authored
Merge pull request #163 from oscbyspro/dev
Added: dismiss mechanism. Improved: debug messages. Cleanup.
2 parents 1fd63b1 + ac76804 commit 8ea4862

File tree

10 files changed

+142
-57
lines changed

10 files changed

+142
-57
lines changed

Sources/DiffableTextKit/Models/Context.swift

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ extension Context {
164164
//=------------------------------------------------------------------------=
165165

166166
/// Use this method on view update.
167-
@inlinable public mutating func merge(_ status: Status, with cache: inout Cache) -> Update {
167+
@inlinable public mutating func merge(
168+
_ status: Status, with cache: inout Cache,
169+
and options: Synchronize) throws -> Update {
168170
var update = Update()
169171
//=--------------------------------------=
170172
// Values
@@ -173,14 +175,20 @@ extension Context {
173175
if !values.merge(status) { return update }
174176
let next = Self(deferring: values, with: &cache, then: &update)
175177
//=--------------------------------------=
178+
// Validation
179+
//=--------------------------------------=
180+
if options.contains(.invariant), update.contains(.value) {
181+
let input = Info.mark(status.value)
182+
let output = Info.mark(next .value)
183+
throw Info(["input \(input) != \(output) output"])
184+
}
185+
//=--------------------------------------=
176186
// Update x Active == 2
177187
//=--------------------------------------=
178188
if layout != nil, next.layout != nil {
179189
self.unique()
180190
self.storage.status = next.status
181-
self.storage.layout!.merge(
182-
snapshot:/**/next.layout!.snapshot,
183-
preference: next.layout!.preference)
191+
self.storage.layout!.merge(next.layout!.snapshot, and: next.layout!.preference)
184192
//=--------------------------------------=
185193
// Update x Active <= 1
186194
//=--------------------------------------=
@@ -199,8 +207,9 @@ extension Context {
199207
//=------------------------------------------------------------------------=
200208

201209
/// Use this method on changes to text.
202-
@inlinable public mutating func merge<T>(_ characters: String,
203-
in range: Range<Offset<T>>, with cache: inout Cache) throws -> Update {
210+
@inlinable public mutating func merge<T>(
211+
_ text: String, in range: Range<Offset<T>>,
212+
with cache: inout Cache) throws -> Update {
204213
var update = Update()
205214
//=--------------------------------------=
206215
// Layout
@@ -209,8 +218,7 @@ extension Context {
209218
//=--------------------------------------=
210219
// Values
211220
//=--------------------------------------=
212-
let proposal = Proposal(layout!.snapshot,
213-
with: Snapshot(characters), in:/**/range)
221+
let proposal = Proposal(layout!.snapshot, with: text, in: range)
214222
let commit = try status.resolve(proposal, with: &cache)
215223
//=--------------------------------------=
216224
// Update
@@ -222,9 +230,7 @@ extension Context {
222230
self.unique()
223231
self.storage.status.value = commit.value
224232
self.storage.layout!.selection.collapse()
225-
self.storage.layout!.merge(
226-
snapshot:/**/commit.snapshot,
227-
preference: commit.selection)
233+
self.storage.layout!.merge(commit.snapshot, and: commit.selection)
228234
//=--------------------------------------=
229235
// Return
230236
//=--------------------------------------=
@@ -236,7 +242,8 @@ extension Context {
236242
//=------------------------------------------------------------------------=
237243

238244
/// Use this method on changes to selection.
239-
@inlinable public mutating func merge<T>(selection: Range<Offset<T>>, momentums: Bool) -> Update {
245+
@inlinable public mutating func merge<T>(
246+
_ selection: Range<Offset<T>>, with options: Resolve) -> Update {
240247
var update = Update()
241248
//=--------------------------------------=
242249
// Layout
@@ -245,16 +252,12 @@ extension Context {
245252
//=--------------------------------------=
246253
// Values
247254
//=--------------------------------------=
248-
let selection = Selection(
249-
layout!.snapshot.range(at: selection))
255+
let selection = Selection(layout!.snapshot.range(at: selection))
250256
//=--------------------------------------=
251257
// Update
252258
//=--------------------------------------=
253259
self.unique()
254-
self.storage.layout!.merge(
255-
selection: selection,
256-
resolve: [.max, .momentums(momentums)])
257-
260+
self.storage.layout!.merge(selection, with: options)
258261
update += .selection(layout!.selection != selection)
259262
//=--------------------------------------=
260263
// Return

Sources/DiffableTextKit/Models/Layout.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
// MARK: Initializers
3131
//=------------------------------------------------------------------------=
3232

33-
@inlinable init(_ snapshot: Snapshot, preference: Selection<Index>?) {
34-
self.init(deferring: (snapshot, preference)); self.autocorrect()
33+
@inlinable init(_ snapshot: Snapshot, and preference: Selection<Index>?) {
34+
self.init(deferring:(snapshot, preference)); /**/ self.autocorrect()
3535
}
3636

3737
/// Use this method to defer autocorrection.
@@ -47,15 +47,15 @@
4747

4848
/// Use this method to resolve a deferred selection.
4949
@inlinable mutating func autocorrect() {
50-
self.merge(selection: self.selection)
50+
self.merge(selection)
5151
}
5252

5353
//=------------------------------------------------------------------------=
5454
// MARK: Transformations
5555
//=------------------------------------------------------------------------=
5656

5757
/// Use this method on changes to text.
58-
@inlinable mutating func merge(snapshot: Snapshot, preference: Selection<Index>?) {
58+
@inlinable mutating func merge(_ snapshot: Snapshot, and preference: Selection<Index>?) {
5959
//=--------------------------------------=
6060
// Values
6161
//=--------------------------------------=
@@ -67,15 +67,15 @@
6767
//=--------------------------------------=
6868
self.snapshot = snapshot
6969
self.preference = preference
70-
self.merge(selection: selection)
70+
self.merge(selection)
7171
}
7272

7373
/// Use this method on changes to selection.
74-
@inlinable mutating func merge(selection: Selection<Index>, resolve: Resolve = []) {
74+
@inlinable mutating func merge(_ selection: Selection<Index>, with options: Resolve = []) {
7575
//=--------------------------------------=
7676
// Accept Max Selection
7777
//=--------------------------------------=
78-
if resolve.contains(.max), selection == .max(snapshot) {
78+
if options.contains(.max), selection == .max(snapshot) {
7979
self.selection = selection; return
8080
}
8181
//=--------------------------------------=
@@ -89,7 +89,7 @@
8989
//=--------------------------------------=
9090
var carets = selection.carets().detached()
9191

92-
if resolve.contains(.momentums) {
92+
if options.contains(.momentums) {
9393
carets.lower.momentum = Direction(from: self.selection.lower, to: selection.lower)
9494
carets.upper.momentum = Direction(from: self.selection.upper, to: selection.upper)
9595
}

Sources/DiffableTextKit/Models/Proposal.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ public struct Proposal {
5050
self.base = base; self.replacement = replacement; self.range = range
5151
}
5252

53-
@inlinable public init<T>(_ base: Snapshot, with replacement: Snapshot, in range: Range<Offset<T>>) {
54-
self.base = base; self.replacement = replacement; self.range = base.range(at: range)
53+
@inlinable public init<T>(_ base: Snapshot, with replacement: String, in range: Range<Offset<T>>) {
54+
self.init(base, with: Snapshot(replacement), in: base.range(at: range))
5555
}
5656

5757
//=------------------------------------------------------------------------=

Sources/DiffableTextKit/Models/Resolve.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
//*========================================================================*
1313

1414
/// A message describing selection behavior.
15-
@usableFromInline struct Resolve: OptionSet {
15+
@frozen public struct Resolve: OptionSet {
1616

1717
/// Resolve max selection.
1818
public static let max = Self(rawValue: 1 << 0)
@@ -22,9 +22,9 @@
2222

2323
//=--------------------------------------------------------------------=
2424

25-
@usableFromInline var rawValue: UInt8
25+
public var rawValue: UInt8
2626

2727
//=--------------------------------------------------------------------=
2828

29-
@inlinable init(rawValue: UInt8) { self.rawValue = rawValue }
29+
@inlinable public init(rawValue: UInt8) { self.rawValue = rawValue }
3030
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//=----------------------------------------------------------------------------=
2+
// This source file is part of the DiffableTextViews open source project.
3+
//
4+
// Copyright (c) 2022 Oscar Byström Ericsson
5+
// Licensed under Apache License, Version 2.0
6+
//
7+
// See http://www.apache.org/licenses/LICENSE-2.0 for license information.
8+
//=----------------------------------------------------------------------------=
9+
10+
//*============================================================================*
11+
// MARK: * Synchronize [...]
12+
//*============================================================================*
13+
14+
/// A message describing synchronization behavior.
15+
@frozen public struct Synchronize: OptionSet {
16+
17+
/// Requires that input and output values are equal.
18+
public static let invariant = Self(rawValue: 1 << 0)
19+
20+
//=------------------------------------------------------------------------=
21+
22+
public let rawValue: UInt8
23+
24+
//=------------------------------------------------------------------------=
25+
26+
@inlinable public init(rawValue: UInt8) { self.rawValue = rawValue }
27+
}

Sources/DiffableTextKit/Utilities/Brrr.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
/// It uses conditional compilation such that it has no size or cost in RELEASE mode.
1717
///
1818
public struct Brrr: Equatable {
19-
20-
public static let cancellation = Self("User input cancelled:")
21-
public static let autocorrection = Self("User input autocorrected:")
22-
19+
20+
public static let dismiss = Self("dismiss")
21+
public static let cancellation = Self("cancellation")
22+
public static let autocorrection = Self("autocorrection")
23+
public static let unsynchronizable = Self("unsynchronizable")
24+
2325
//=------------------------------------------------------------------------=
2426

2527
#if DEBUG
@@ -36,7 +38,7 @@ public struct Brrr: Equatable {
3638

3739
@inlinable @inline(__always) public static func << (brrr: Self, message: @autoclosure () -> Any) {
3840
#if DEBUG
39-
Swift.print(brrr.context, message())
41+
Swift.print("[DiffableTextViews] \(brrr.context): \(message())")
4042
#endif
4143
}
4244
}

Sources/DiffableTextKitXPattern/Style.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ extension PatternTextStyle {
166166
// Content <= Capacity
167167
//=------------------------------=
168168
if !virtuals.isEmpty {
169-
throw Info([.mark(mismatches.first!), "is invalid."])
169+
throw Info([.mark(mismatches.first!), "is invalid"])
170170
//=------------------------------=
171171
// Content > Capacity
172172
//=------------------------------=

Sources/DiffableTextKitXUIKit/DiffableTextField.swift

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,17 @@ public struct DiffableTextField<Style: DiffableTextStyle>: UIViewRepresentable {
152152
//=----------------------------------=
153153
// Synchronize
154154
//=----------------------------------=
155-
self.synchronize()
155+
self.synchronize(.invariant)
156156
}
157157

158158
//=--------------------------------------------------------------------=
159159
// MARK: Events
160160
//=--------------------------------------------------------------------=
161161

162162
@inlinable @inline(never)
163-
public func textField(_ textField: UITextField,
163+
public func textField(_ view: UITextField,
164164
shouldChangeCharactersIn nsrange: NSRange,
165-
replacementString characters: String) -> Bool {
165+
replacementString text: String) -> Bool {
166166
//=----------------------------------=
167167
// Lock
168168
//=----------------------------------=
@@ -176,7 +176,7 @@ public struct DiffableTextField<Style: DiffableTextStyle>: UIViewRepresentable {
176176
Offset<UTF16>(nsrange.upperBound)
177177

178178
let update = try self.context.merge(
179-
characters, in: range, with: &cache)
179+
text, in: range, with: &self.cache)
180180
//=------------------------------=
181181
// Push
182182
//=------------------------------=
@@ -193,11 +193,11 @@ public struct DiffableTextField<Style: DiffableTextStyle>: UIViewRepresentable {
193193
return false
194194
}
195195

196-
@inlinable @inline(never) public func textFieldDidChangeSelection(_ textField: UITextField) {
196+
@inlinable @inline(never) public func textFieldDidChangeSelection(_ view: UITextField) {
197197
//=----------------------------------=
198198
// Marked
199199
//=----------------------------------=
200-
if let _ = textField.markedTextRange {
200+
if let _ = view.markedTextRange {
201201
//=------------------------------=
202202
// Push
203203
//=------------------------------=
@@ -214,8 +214,8 @@ public struct DiffableTextField<Style: DiffableTextStyle>: UIViewRepresentable {
214214
// Pull
215215
//=------------------------------=
216216
let update = self.context.merge(
217-
selection: downstream.selection,
218-
momentums: downstream.momentums)
217+
downstream.selection,with:[.max,
218+
.momentums(downstream.momentums)])
219219
//=------------------------------=
220220
// Push
221221
//=------------------------------=
@@ -227,33 +227,45 @@ public struct DiffableTextField<Style: DiffableTextStyle>: UIViewRepresentable {
227227
// MARK: Events
228228
//=--------------------------------------------------------------------=
229229

230-
@inlinable public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
231-
let _ = textField.resignFirstResponder()
232-
self.sidestream.onSubmit?(); return true
230+
@inlinable public func textFieldShouldReturn(_ view: UITextField) -> Bool {
231+
self.downstream.dismiss(); self.sidestream.onSubmit?(); return true
233232
}
234233

235-
@inlinable public func textFieldDidBeginEditing(_ textField: UITextField) {
236-
self.synchronize()
234+
@inlinable public func textFieldDidBeginEditing(_ view: UITextField) {
235+
self.synchronize([])
237236
}
238237

239-
@inlinable public func textFieldDidEndEditing(_ textField: UITextField) {
240-
self.synchronize()
238+
@inlinable public func textFieldDidEndEditing(_ view: UITextField) {
239+
self.synchronize([])
241240
}
242241

243242
//=--------------------------------------------------------------------=
244243
// MARK: Synchronization
245244
//=--------------------------------------------------------------------=
246245

247-
@inlinable func synchronize() {
246+
@inlinable func synchronize(_ options: Synchronize) {
248247
//=----------------------------------=
249248
// Pull
250249
//=----------------------------------=
251-
let status = self.pull()
252-
let update = self.context.merge(status, with: &self.cache)
250+
attempt: do {
251+
let status = self.pull()
252+
let update = try self.context.merge(
253+
status, with: &cache, and: options)
254+
//=------------------------------=
255+
// Push
256+
//=------------------------------=
257+
self.push(update)
253258
//=----------------------------------=
254-
// Push
259+
// Dismiss
255260
//=----------------------------------=
256-
self.push(update)
261+
} catch let reason {
262+
Brrr.unsynchronizable << Info(reason)
263+
Brrr.dismiss << Info(["reentrant view updates are prohibited"])
264+
//=------------------------------=
265+
// Task
266+
//=------------------------------=
267+
Task { self.downstream.dismiss() }
268+
}
257269
}
258270

259271
@inlinable func pull() -> Status<Style> {

Sources/DiffableTextKitXUIKit/Streams/Downstream.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ import UIKit
5454
set { view.delegate = newValue }
5555
}
5656

57+
@inlinable func dismiss() {
58+
self.view.resignFirstResponder()
59+
}
60+
5761
//=------------------------------------------------------------------------=
5862
// MARK: Transformations
5963
//=------------------------------------------------------------------------=

0 commit comments

Comments
 (0)