Skip to content

Commit

Permalink
Add support for XML.
Browse files Browse the repository at this point in the history
Add bindings to XMLFragment, XMLElement, XMLText, and XMLEvent. Allows
reading and writing of XML fragments from the document, which rich text
editors use heavily.

Closes jupyter-server#151
  • Loading branch information
ColonelThirtyTwo committed Sep 27, 2024
1 parent f37f4f0 commit 85dee3e
Show file tree
Hide file tree
Showing 8 changed files with 939 additions and 17 deletions.
4 changes: 4 additions & 0 deletions python/pycrdt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
from ._sync import write_var_uint as write_var_uint
from ._text import Text as Text
from ._text import TextEvent as TextEvent
from ._xml import XmlElement as XmlElement
from ._xml import XmlFragment as XmlFragment
from ._xml import XmlText as XmlText
from ._xml import XmlEvent as XmlEvent
from ._transaction import ReadTransaction as ReadTransaction
from ._transaction import Transaction as Transaction
from ._undo import UndoManager as UndoManager
Expand Down
126 changes: 125 additions & 1 deletion python/pycrdt/_pycrdt.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Callable
from typing import Any, Callable, Iterator

class Doc:
"""Shared document."""
Expand Down Expand Up @@ -28,6 +28,9 @@ class Doc:
def get_or_insert_map(self, name: str) -> Map:
"""Create a map root type on this document, or get an existing one."""

def get_or_insert_xml_fragment(self, name: str) -> XmlFragment:
"""Create an XML fragment root type on this document, or get an existing one."""

def get_state(self) -> bytes:
"""Get the current document state."""

Expand Down Expand Up @@ -91,6 +94,10 @@ class MapEvent:
"""Event generated by `Map.observe` method. Emitted during transaction commit
phase."""

class XmlEvent:
"""Event generated by `Xml*.observe` methods. Emitted during transaction commit
phase."""

class Text:
"""Shared text."""

Expand Down Expand Up @@ -180,6 +187,123 @@ class Map:
"""Unsubscribes previously subscribed event callback identified by given
`subscription`."""

class XmlFragment:
def parent(self) -> XmlFragment | XmlElement | XmlText | None:
...

def get_string(self, txn: Transaction) -> str:
"""Returns a text representation of the current shared xml."""

def len(self, txn: Transaction) -> int:
"""Returns the numer of children of the current shared xml."""

def get(self, txn: Transaction, index: int) -> XmlFragment | XmlElement | XmlText | None:
"""Gets a child item by index, or None if the index is out of bounds"""

def remove_range(self, txn: Transaction, index: int, len: int) -> None:
"""Removes a range of children"""

def insert_str(self, txn: Transaction, index: int, text: str) -> XmlText:
"""Inserts a text node"""

def insert_element_prelim(self, txn: Transaction, index: int, tag: str) -> XmlElement:
"""Inserts an empty element node"""

def observe(self, callback: Callable[[XmlEvent], None]) -> Subscription:
"""Subscribes a callback to be called with the xml change event.
Returns a subscription that can be used to unsubscribe."""

def observe_deep(self, callback: Callable[[XmlEvent], None]) -> Subscription:
"""Subscribes a callback to be called with the xml change event
and its nested elements.
Returns a subscription that can be used to unsubscribe."""

class XmlElement:
def parent(self) -> XmlFragment | XmlElement | XmlText | None:
...

def get_string(self, txn: Transaction) -> str:
"""Returns a text representation of the current shared xml."""

def len(self, txn: Transaction) -> int:
"""Returns the numer of children of the current shared xml."""

def get(self, txn: Transaction, index: int) -> XmlFragment | XmlElement | XmlText | None:
"""Gets a child item by index, or None if the index is out of bounds"""

def remove_range(self, txn: Transaction, index: int, len: int) -> None:
"""Removes a range of children"""

def insert_str(self, txn: Transaction, index: int, text: str) -> XmlText:
"""Inserts a text node"""

def insert_element_prelim(self, txn: Transaction, index: int, tag: str) -> XmlElement:
"""Inserts an empty element node"""

def attributes(self, txn: Transaction) -> list[tuple[str, str]]:
"""Gets all attributes, as a list of `(key, value)` tuples"""

def attribute(self, txn: Transaction, name: str) -> str | None:
"""Gets an attribute, or None if the attribute does not exist"""

def insert_attribute(self, txn: Transaction, name: str, value: str) -> None:
"""Inserts or overwrites an attribute."""

def remove_attribute(self, txn: Transaction, name: str) -> None:
"""Removes an attribute"""

def siblings(self, txn) -> list[XmlFragment | XmlElement | XmlText]:
"""Gets the siblings of this node"""

def observe(self, callback: Callable[[XmlEvent], None]) -> Subscription:
"""Subscribes a callback to be called with the xml change event.
Returns a subscription that can be used to unsubscribe."""

def observe_deep(self, callback: Callable[[XmlEvent], None]) -> Subscription:
"""Subscribes a callback to be called with the xml change event
and its nested elements.
Returns a subscription that can be used to unsubscribe."""

class XmlText:
def parent(self) -> XmlFragment | XmlElement | XmlText | None:
...

def get_string(self, txn: Transaction) -> str:
"""Returns a text representation of the current shared xml."""

def attributes(self, txn: Transaction) -> list[tuple[str, str]]:
"""Gets all attributes, as a list of `(key, value)` tuples"""

def attribute(self, txn: Transaction, name: str) -> str | None:
"""Gets an attribute, or None if the attribute does not exist"""

def insert_attribute(self, txn: Transaction, name: str, value: str) -> None:
"""Inserts or overwrites an attribute."""

def remove_attribute(self, txn: Transaction, name: str) -> None:
"""Removes an attribute"""

def siblings(self, txn: Transaction) -> list[XmlFragment | XmlElement | XmlText]:
"""Gets the siblings of this node"""

def insert(self, txn: Transaction, index: int, text: str, attrs: Iterator[tuple[str, Any]] | None = None):
"""Inserts text, optionally with attributes"""

def remove_range(self, txn: Transaction, index: int, len: int):
"""Removes text"""

def format(self, txn: Transaction, index: int, len: int, attrs: Iterator[tuple[str, Any]]):
"""Adds attributes to a section of text"""

def observe(self, callback: Callable[[XmlEvent], None]) -> Subscription:
"""Subscribes a callback to be called with the xml change event.
Returns a subscription that can be used to unsubscribe."""

def observe_deep(self, callback: Callable[[XmlEvent], None]) -> Subscription:
"""Subscribes a callback to be called with the xml change event
and its nested elements.
Returns a subscription that can be used to unsubscribe."""

class UndoManager:
"""Undo manager."""

Expand Down
Loading

0 comments on commit 85dee3e

Please sign in to comment.