// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.collide.dto;
// TODO: These should be moved to an Editor2-specific package
/**
* Models one component of a document operation for the Collide code editor.
*
* With exception of RetainLine, all DocOpComponents must only touch one line.
* If there is a multiline insert, that must be split into multiple Inserts, one
* per line.
*
* @see DocOp
*/
public interface DocOpComponent {
/**
* Models a deletion within a document operation. This contains the text to be
* deleted. The deletion must not span multiple lines (can only contain a
* maximum of one newline character, which must be the last character.)
*/
public interface Delete extends DocOpComponent {
String getText();
}
/**
* Models an insertion within a document operation. This contains the text to
* be inserted. The insertion must not span multiple lines (can only contain a
* maximum of one newline character, which must be the last character.)
*/
public interface Insert extends DocOpComponent {
String getText();
}
/*-
* The Retain must indicate whether it is covering the end of the line. This
* is exposed by the hasTrailingNewline() method.
*
* Here's an example of why this is required: Imagine we are composing
* operations A and B in a two line document:
* "Hello\n"
* "World"
*
* A is modifying the first line and second line, and B is modifying the
* second line.
*
* A is
* {(Insert:"This is line 1"), (Retain:6, true), (Insert:"2"),
* (Retain:5)}
*
* B is
* {(RetainLine:1), (Insert:"This is line 2"), Retain(6, false)}.
*
* The composer begins and sees B is retaining one line. It processes
* A's components until A finishes the first line, at which point it can move
* on to B's next component. If A's Retain did not contain the newline
* flag, the composer would continue through to A's (Insert:"2") component
* thinking that insertion is still on the first line. After that, it would
* see RetainLine and think the composition is illegal since RetainLine
* must span the entire line, but the previous component (Insert:"2") did
* not end with a newline.
*/
/**
* Models a retain within a document operation. This contains the number of
* characters to be retained, and a flag indicating that the last character
* being retained is a newline character. This retain must not span multiple
* lines (the characters being retained can only have one newline character.)
*/
public interface Retain extends DocOpComponent {
int getCount();
boolean hasTrailingNewline();
}
/**
* Models a retain through the rest of the line (or the entire line if it is
* the only components on a line) within a document operation. The purpose of
* this is allowing for a component that is agnostic to the actual number of
* characters on some lines. This contains the number of lines to be retained.
* This is the only DocOpComponent that can span multiple lines.
*
* The {@link #getLineCount()} must always be greater than 0.
*/
public interface RetainLine extends DocOpComponent {
int getLineCount();
}
/*
* TODO: saw extreme weirdness when this was an enum. DevMode in
* Chrome would overflow the stack when trying to JSON.stringify this.
* console.logging this showed a seemingly infinite depth of Objects
*/
public static class Type {
public static final int DELETE = 0;
public static final int INSERT = 1;
public static final int RETAIN = 2;
public static final int RETAIN_LINE = 3;
}
public int getType();
}