Skip to content

Commit e871ad0

Browse files
committed
Upgraded: Snapshot/anchor to Snapshot/selection
1 parent e1b09e2 commit e871ad0

File tree

7 files changed

+44
-61
lines changed

7 files changed

+44
-61
lines changed

Sources/DiffableTextKit/DiffableTextStyle.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,7 @@ public extension DiffableTextStyle {
8989
// MARK: Utilities
9090
//=------------------------------------------------------------------------=
9191

92-
@inlinable func update(_ cache: inout Cache) {
93-
cache = self.cache()
94-
}
92+
@inlinable func update(_ cache: inout Cache) { cache = self.cache() }
9593
}
9694

9795
//=----------------------------------------------------------------------------=

Sources/DiffableTextKit/Models/Layout.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
/// A model describing a snapshot and a selection in it.
1515
///
16-
/// - Autocorrects selection when the snapshot changes.
16+
/// - Autocorrects selection when the snapshot changes.
1717
/// - Autocorrects selection when the selection changes.
1818
///
1919
@usableFromInline struct Layout {
@@ -29,8 +29,10 @@
2929
// MARK: Initializers
3030
//=------------------------------------------------------------------------=
3131

32-
@inlinable init( _ snapshot: Snapshot) {
33-
self.snapshot = snapshot; self.selection = .initial(snapshot) // O(n)
32+
@inlinable init(_ snapshot: Snapshot) {
33+
self.snapshot = snapshot /*----------------------------*/
34+
let selection = Selection(Caret.upper(snapshot.endIndex))
35+
self.selection = snapshot.resolve(selection) /*---------*/
3436
}
3537

3638
//=------------------------------------------------------------------------=
@@ -69,6 +71,7 @@
6971
carets.upper.momentum = Direction(from: self.selection.upper, to: selection.upper)
7072
}
7173

72-
self.selection = Selection(unchecked: carets).map(snapshot.resolve(_:))
74+
let unchecked = Selection(unchecked:carets)
75+
self.selection = snapshot.resolve(unchecked)
7376
}
7477
}

Sources/DiffableTextKit/Models/Selection.swift

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,7 @@ public struct Selection<Bound: Comparable>: Equatable {
4444
// MARK: Initializers
4545
//=------------------------------------------------------------------------=
4646

47-
@inlinable static func initial(_ snapshot: Snapshot) -> Self where Bound == Snapshot.Index {
48-
Self(snapshot.resolve(.upper(snapshot.endIndex)))
49-
}
50-
51-
@inlinable static func max<T>(_ collection: T) -> Self where T: Collection, T.Index == Bound {
47+
@inlinable public static func max<T>(_ collection: T) -> Self where T: Collection, T.Index == Bound {
5248
Self(unchecked: (collection.startIndex, collection.endIndex))
5349
}
5450

Sources/DiffableTextKit/Models/Snapshot.swift

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,6 @@
1818
/// |x|o|o|x|x|o|o|o|x|x|o|o|o|x|o|x|x|x|x|~
1919
/// ```
2020
///
21-
/// **Anchor**
22-
///
23-
/// Set the anchor index to select the caret represented by it. This can be
24-
/// desirable on snapshots containing only formatting characters. A pattern
25-
/// style may set the anchor at its first placeholder character, for example.
26-
///
27-
/// ```
28-
/// ↓ == anchor
29-
/// |+|#|#|_|(|#|#|#|)|_|#|#|#|-|#|#|-|#|#|~
30-
/// |x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|~
31-
/// ```
32-
///
3321
/// **Attributes & Characters**
3422
///
3523
/// The number of attributes must equal the number of joint characters in the
@@ -47,6 +35,18 @@
4735
/// |➖| + |➖| + |➖| + |➖| -> |➖|➖|➖|➖|~ (BAD)
4836
/// ```
4937
///
38+
/// **Selection**
39+
///
40+
/// Selection is done by differentiation, but it can also be done manually. It
41+
/// can be appropriate on snapshots containing only formatting characters. A pattern
42+
/// text style may manually select its first placeholder character, for example.
43+
///
44+
/// ```
45+
/// ↓ == selection
46+
/// |+|#|#|_|(|#|#|#|)|_|#|#|#|-|#|#|-|#|#|~
47+
/// |x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|~
48+
/// ```
49+
///
5050
public struct Snapshot: BidirectionalCollection, CustomStringConvertible, Equatable,
5151
ExpressibleByArrayLiteral, ExpressibleByStringLiteral, RangeReplaceableCollection {
5252

@@ -57,9 +57,9 @@ ExpressibleByArrayLiteral, ExpressibleByStringLiteral, RangeReplaceableCollectio
5757
// MARK: State
5858
//=------------------------------------------------------------------------=
5959

60-
@usableFromInline var _characters: String
61-
@usableFromInline var _attributes: [Attribute]
62-
@usableFromInline var _anchor: Self.Index?
60+
@usableFromInline private(set) var _characters: String
61+
@usableFromInline private(set) var _attributes: [Attribute]
62+
public var selection: Selection<Index>?
6363

6464
//=------------------------------------------------------------------------=
6565
// MARK: Initializers
@@ -92,11 +92,6 @@ ExpressibleByArrayLiteral, ExpressibleByStringLiteral, RangeReplaceableCollectio
9292
_attributes
9393
}
9494

95-
@inlinable @inline(__always)
96-
public var anchor: Index? {
97-
_anchor
98-
}
99-
10095
public var description: String {
10196
"\(Self.self)(\"\(_characters)\", \(_attributes))"
10297
}
@@ -106,13 +101,13 @@ ExpressibleByArrayLiteral, ExpressibleByStringLiteral, RangeReplaceableCollectio
106101
//=------------------------------------------------------------------------=
107102

108103
@inlinable @inline(__always)
109-
public mutating func anchorAtEndIndex() {
110-
self._anchor = endIndex
104+
public mutating func select(_ position: Index) {
105+
self.selection = Selection(position)
111106
}
112107

113108
@inlinable @inline(__always)
114-
public mutating func anchor(at index: Index?) {
115-
self._anchor = index
109+
public mutating func select(_ positions: Range<Index>) {
110+
self.selection = Selection(positions)
116111
}
117112

118113
//=------------------------------------------------------------------------=
@@ -387,11 +382,11 @@ extension Snapshot {
387382
// MARK: Resolve
388383
//=------------------------------------------------------------------------=
389384

385+
@inlinable func resolve(_ selection: Selection<Caret<Index>>) -> Selection<Index> {
386+
self.selection ?? selection.map(resolve)
387+
}
388+
390389
@inlinable func resolve(_ caret: Caret<Index>) -> Index {
391-
//=--------------------------------------=
392-
// Anchor
393-
//=--------------------------------------=
394-
if let anchor { return anchor }
395390
//=--------------------------------------=
396391
// Inspect Initial Index
397392
//=--------------------------------------=

Sources/DiffableTextKit/Styles/Prefix.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public struct PrefixTextStyle<Base: DiffableTextStyle>: WrapperTextStyle {
1717
public typealias Cache = Base.Cache
1818
public typealias Value = Base.Value
1919

20+
@usableFromInline typealias Characters = Offset<Character>
21+
2022
//=------------------------------------------------------------------------=
2123
// MARK: State
2224
//=------------------------------------------------------------------------=
@@ -59,13 +61,13 @@ public struct PrefixTextStyle<Base: DiffableTextStyle>: WrapperTextStyle {
5961

6062
@inlinable func label(_ commit: inout Commit<Value>) {
6163
guard !prefix.isEmpty else { return }
62-
let anchor = commit.snapshot.anchor
64+
let selection = commit.snapshot.selection
6365

6466
commit.snapshot = Snapshot(prefix, as: .phantom) + commit.snapshot
6567

66-
guard let anchor else { return }
67-
commit.snapshot.anchor(at: commit.snapshot.index(
68-
commit.snapshot.startIndex, offsetBy: prefix.count + anchor.attribute))
68+
guard let selection else { return }
69+
let offsets = selection.map({ Characters(prefix.count + $0.attribute) })
70+
commit.snapshot.select(commit.snapshot.indices(at: offsets.positions()))
6971
}
7072
}
7173

Sources/DiffableTextKitXPattern/Style.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ extension PatternTextStyle {
117117
} none: {
118118
commit, virtuals in
119119
commit.snapshot.append(contentsOf: virtuals, as: .phantom)
120-
commit.snapshot.anchorAtEndIndex()
120+
commit.snapshot.select(commit.snapshot.endIndex)
121121
} done: {
122122
commit, virtuals, mismatches in
123123
//=----------------------------------=

Tests/DiffableTextKitTests/Models/Snapshot.swift

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ final class SnapshotTests: XCTestCase {
4747
// MARK: Tests x State
4848
//=------------------------------------------------------------------------=
4949

50-
func testAnchorIsNilByDefault() {
51-
XCTAssertEqual(snapshot.anchor, nil)
50+
func testSelectionIsNilByDefault() {
51+
XCTAssertEqual(snapshot.selection, nil)
5252
}
5353

5454
//=------------------------------------------------------------------------=
@@ -90,23 +90,12 @@ final class SnapshotTests: XCTestCase {
9090
// MARK: Tests x Transformations x Anchor
9191
//=------------------------------------------------------------------------=
9292

93-
func testAnchorAtIndex() {
94-
snapshot = Snapshot("ABC")
95-
let index = snapshot.index(at: C(1))
96-
97-
snapshot.anchor(at: index)
98-
XCTAssertEqual(snapshot.anchor, index)
99-
100-
snapshot.anchor(at: nil)
101-
XCTAssertEqual(snapshot.anchor, nil)
102-
}
103-
104-
func testAnchorAtEndIndex() {
93+
func testSelectEndIndex() {
10594
snapshot.append(Symbol(" "))
106-
snapshot.anchorAtEndIndex()
95+
snapshot.select(snapshot.endIndex)
10796
snapshot.append(Symbol(" "))
10897

109-
XCTAssertEqual(snapshot.anchor, snapshot.index(at: C(1)))
98+
XCTAssertEqual(snapshot.selection, Selection(snapshot.index(at: C(1))))
11099
}
111100

112101
//=------------------------------------------------------------------------=

0 commit comments

Comments
 (0)