Skip to content

Commit

Permalink
adding documentation to the new UndoManger methods - partial
Browse files Browse the repository at this point in the history
  • Loading branch information
heckj committed Mar 6, 2024
1 parent 0a42fee commit abfc60b
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 53 deletions.
7 changes: 7 additions & 0 deletions Sources/YSwift/Documentation.docc/Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,10 @@ YSwift is a Swift language overlay of the Rust library [Yrs](https://docs.rs/yrs

- ``YSwift/YProtocol``
- ``YSwift/YSyncMessage``

### Undo Manager

- ``YSwift/YUndoManager``
- ``YSwift/Origin``
- ``YSwift/UndoEvent``
- ``YSwift/YCollection``
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ let remoteText = remoteDocument.getOrCreateText(named: "example")
### Display the Initial State

To read, or update, values from within a ``YDocument``, do so from within a transaction.
The following sample uses ``YText/getString(in:)`` from within the closure passed through ``YDocument/transactSync(_:)`` to directly access the values:
The following sample uses ``YText/getString(in:)`` from within the closure passed through ``YDocument/transactSync(origin:_:)`` to directly access the values:

```swift
localDocument.transactSync { txn in
Expand Down
11 changes: 7 additions & 4 deletions Sources/YSwift/Documentation.docc/YDocument.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ A type that wraps all Y-CRDT shared data types, and provides transactional inter
## Overview

A `YDocument` tracks and coordinates updates to Y-CRDT shared data types, such as ``YSwift/YText``, ``YSwift/YArray``, and ``YSwift/YMap``.
Make any changes to shared data types within a document within a transaction, such as ``YSwift/YDocument/transactSync(_:)``.
Make any changes to shared data types within a document within a transaction, such as ``YSwift/YDocument/transactSync(origin:_:)``.

Interact with other copies of the shared data types by synchronizing documents.

Expand Down Expand Up @@ -48,11 +48,14 @@ For a more detailed example of synchronizing a document, see <doc:SynchronizingD

### Creating Transactions

- ``YSwift/YDocument/transactSync(_:)``
- ``YSwift/YDocument/transact(_:)``
- ``YSwift/YDocument/transactAsync(_:completion:)``
- ``YSwift/YDocument/transactSync(origin:_:)``
- ``YSwift/YDocument/transact(origin:_:)``
- ``YSwift/YDocument/transactAsync(_:_:completion:)``

### Comparing Documents for Synchronization

- ``YSwift/YDocument/diff(txn:from:)``

### Undo and Redo

- ``YSwift/YDocument/undoManager(trackedRefs:)``
33 changes: 17 additions & 16 deletions Sources/YSwift/Origin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,58 @@ import Yniffi

/// A type that contains a reference to Yrs shared collection type.
public protocol YCollection {
func pointer() -> YrsCollectionPtr;
func pointer() -> YrsCollectionPtr
}

/// A struct that identifies the origin of a change.
public struct Origin: Equatable, Codable, Sendable {
public let origin: YrsOrigin

init(_ origin: YrsOrigin) {
self.origin = origin
}

init(_ str: String) {
origin = [UInt8](str.utf8)
}

init(_ u: UInt8) {
origin = [u]
}

init(_ u: UInt16) {
origin = withUnsafeBytes(of: u.bigEndian) { (urbp: UnsafeRawBufferPointer) in
return Array(urbp)
Array(urbp)
}
}

init(_ u: UInt32) {
origin = withUnsafeBytes(of: u.bigEndian) { (urbp: UnsafeRawBufferPointer) in
return Array(urbp)
Array(urbp)
}
}

init(_ u: UInt64) {
origin = withUnsafeBytes(of: u.bigEndian) { (urbp: UnsafeRawBufferPointer) in
return Array(urbp)
Array(urbp)
}
}

init(_ u: Int16) {
origin = withUnsafeBytes(of: u.bigEndian) { (urbp: UnsafeRawBufferPointer) in
return Array(urbp)
Array(urbp)
}
}

init(_ u: Int32) {
origin = withUnsafeBytes(of: u.bigEndian) { (urbp: UnsafeRawBufferPointer) in
return Array(urbp)
Array(urbp)
}
}

init(_ u: Int64) {
origin = withUnsafeBytes(of: u.bigEndian) { (urbp: UnsafeRawBufferPointer) in
return Array(urbp)
Array(urbp)
}
}
}
9 changes: 6 additions & 3 deletions Sources/YSwift/YDocument.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,12 @@ public final class YDocument {
public func getOrCreateMap<T: Codable>(named: String) -> YMap<T> {
YMap(map: document.getMap(name: named), document: self)
}


/// Creates an Undo Manager for a document with the collections that is tracks.
/// - Parameter trackedRefs: The collections to track to undo and redo changes.
/// - Returns: A reference to the undo manager to control those actions.
public func undoManager<T: AnyObject>(trackedRefs: [YCollection]) -> YUndoManager<T> {
let mapped = trackedRefs.map({$0.pointer()})
return YUndoManager(manager: self.document.undoManager(trackedRefs: mapped))
let mapped = trackedRefs.map { $0.pointer() }
return YUndoManager(manager: document.undoManager(trackedRefs: mapped))
}
}
95 changes: 66 additions & 29 deletions Sources/YSwift/YUndoManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,104 @@ import Combine
import Foundation
import Yniffi

/// An undo manager to track and reverse changes on YSwift collections.
public final class YUndoManager<T: AnyObject> {
private let _manager: YrsUndoManager

init(manager: YrsUndoManager) {
_manager = manager
}


/// Sets (adds?) the origin that the Undo manager tracks.
///
/// All other origins will be unaffected by undo redo with this manager.
/// - Parameter origin: The origin to track.
public func addOrigin(_ origin: Origin) {
_manager.addOrigin(origin: origin.origin)
}


/// <#Description#>
/// - Parameter origin: <#origin description#>
public func removeOrigin(_ origin: Origin) {
_manager.removeOrigin(origin: origin.origin)
}


/// <#Description#>
/// - Parameter collection: <#collection description#>
public func track(_ collection: YCollection) {
_manager.addScope(trackedRef: collection.pointer())
}


/// Undo a change on a collection you're tracking back to the last point you set
///
/// Set a point to undo back to with ``wrap()``.
/// Additional calls will undo to points further back on the stack, if set.
/// - Returns: A Boolean value that indicates wether the change was undone.
public func undo() throws -> Bool {
return try _manager.undo()
}


/// Replays a change forward from the Undo managers stack.
/// - Returns: A Boolean value that indicates wether the change was replayed.
public func redo() throws -> Bool {
return try _manager.redo()
}


/// Mark a point in time that you want to be able to reverse back to.
///
/// The Undo Manager tracks the points you set in a stack.
/// Undo the to the most recent point set using ``undo()``.
public func wrap() {
_manager.wrapChanges()
}


/// <#Description#>
public func clear() throws {
try _manager.clear()
}


/// Creates a subscription that is called when the undo manager adds a change.
/// - Parameter body: A closure that provides ``UndoEvent`` about the change.
/// - Returns: A handle to the subscription.
///
/// Cancel the subscription by calling ``unobserveAdded(_:)`` with the subscription Id this method returns.
public func observeAdded(_ body: @escaping (UndoEvent, T?) -> T?) -> UInt32 {
let delegate = YUndoManagerObservationDelegate(callback: body)
return _manager.observeAdded(delegate: delegate)
}

/// Cancels a subscription to the undo manager
/// - Parameter subscriptionId: The subscription Id to cancel.
public func unobserveAdded(_ subscriptionId: UInt32) {
return _manager.unobserveAdded(subscriptionId: subscriptionId)
}


/// Creates a subscription that is called when the undo manager adds a change.
/// - Parameter body: A closure that provides an ``UndoEvent`` about the change.
/// - Returns: A handle to the subscription.
///
/// Call ``unobserveUpdated(_:)`` with the subscription Id this method returns to cancel the subscription.
public func observeUpdated(_ body: @escaping (UndoEvent, T?) -> T?) -> UInt32 {
let delegate = YUndoManagerObservationDelegate(callback: body)
return _manager.observeUpdated(delegate: delegate)
}

/// Cancels a subscription to the XXX
/// - Parameter subscriptionId: The subscription to be cancalled.
public func unobserveUpdated(_ subscriptionId: UInt32) {
return _manager.unobserveUpdated(subscriptionId: subscriptionId)
}


/// Creates a subscription that is called when the undo manager replays a change.
/// - Parameter body: A closure that provides an ``UndoEvent`` about the change.
/// - Returns: A handle to the subscription.
public func observePopped(_ body: @escaping (UndoEvent, T?) -> T?) -> UInt32 {
let delegate = YUndoManagerObservationDelegate(callback: body)
return _manager.observePopped(delegate: delegate)
}

/// Cancels a subscription that is called when the undo manager replays a change.
/// - Parameter subscriptionId: The subscription to be cancelled.
public func unobservePopped(_ subscriptionId: UInt32) {
return _manager.unobservePopped(subscriptionId: subscriptionId)
}
Expand All @@ -76,10 +116,10 @@ class YUndoManagerObservationDelegate<T: AnyObject>: YrsUndoManagerObservationDe
}

func call(e: Yniffi.YrsUndoEvent, ptr: UInt64) -> UInt64 {
return self.callback(e, ptr)
return callback(e, ptr)
}
static func bridge(obj : T?) -> UInt64 {

static func bridge(obj: T?) -> UInt64 {
if let obj {
let ptr = UnsafeRawPointer(Unmanaged.passRetained(obj).toOpaque())
return UInt64(bitPattern: Int64(Int(bitPattern: ptr)))
Expand All @@ -88,7 +128,7 @@ class YUndoManagerObservationDelegate<T: AnyObject>: YrsUndoManagerObservationDe
}
}

static func bridge(ptr : UInt64) -> T? {
static func bridge(ptr: UInt64) -> T? {
let unsafe_ptr = UnsafeRawPointer(bitPattern: Int(ptr))
if let unsafe_ptr {
return Unmanaged.fromOpaque(unsafe_ptr).takeRetainedValue()
Expand All @@ -98,30 +138,27 @@ class YUndoManagerObservationDelegate<T: AnyObject>: YrsUndoManagerObservationDe
}
}

/// Metadata about an undo event
public struct UndoEvent {
let event: YrsUndoEvent
init(_ event: YrsUndoEvent) {
self.event = event
}

var type: YrsUndoEventKind {
get {
return self.event.kind()
}
return event.kind()
}

var origin: Origin? {
get {
let origin = self.event.origin()
if let origin {
return Origin(origin)
} else {
return nil
}
let origin = event.origin()
if let origin {
return Origin(origin)
} else {
return nil
}
}

func hasChanged<T: YCollection>(_ sharedRef: T) -> Bool {
return self.event.hasChanged(sharedRef: sharedRef.pointer())
return event.hasChanged(sharedRef: sharedRef.pointer())
}
}

0 comments on commit abfc60b

Please sign in to comment.