type Subscription {
  notebookEvents: NotebookEvent!
  cellEvents: CellEvent!
  cellEdits(id: ID): CellSourceEdit!
  presenceEvents: PresenceEvent!
}

interface ICellEvent {
  id: ID!
}

type TextInserted implements ICellEvent {
  id: ID!
  diff: String!
  start: Int!
}

type TextReplaced implements ICellEvent {
  id: ID!
  diff: String!
  start: Int!
  len: Int!
}

type TextDeleted implements ICellEvent {
  id: ID!
  start: Int!
  len: Int!
}

union CellSourceEdit = TextInserted | TextReplaced | TextDeleted

type CellInsertedEvent implements ICellEvent {
  id: ID!
  pos: Int!
  after: ID
  before: ID
}

type CellRemovedEvent implements ICellEvent {
  id: ID!
  pos: Int!
}

type CellMovedEvent implements ICellEvent {
  id: ID!
  from: Int!
  to: Int!
}

type CellReplacedEvent implements ICellEvent {
  id: ID!
  replacedBy: ID!
  pos: Int!
}

type NotebookMetadataEvent {
  entry: MetadataEntry!
}

union NotebookEvent = CellInsertedEvent | CellRemovedEvent | CellMovedEvent | CellReplacedEvent | NotebookMetadataEvent

type CellMetadataEvent implements ICellEvent {
  id: ID!
  entry: MetadataEntry!
}

type OutputAppendedEvent implements ICellEvent {
  id: ID!
  output: CellOutput!
}

type OutputsClearedEvent implements ICellEvent {
  id: ID!
}

union CellEvent = CellMetadataEvent | OutputAppendedEvent | OutputsClearedEvent

type PeerLocation {
  focusedCellId: ID!
  cursorPosition: Position
  textSelection: SelectionRange
}

type Position {
  line: Int!
  column: Int!
}

type SelectionRange {
  lineStart: Int!
  columnStart: Int!
  lineEnd: Int!
  columnEnd: Int!
}

type PeerConnectedEvent {
  id: ID!
  userId: ID
  userName: String
}

type PeerDisconnectedEvent {
  id: ID!
}

type PeerLocationUpdatedEvent {
  id: ID!
  location: PeerLocation
}

union PresenceEvent = PeerConnectedEvent | PeerDisconnectedEvent | PeerLocationUpdatedEvent
