created mirror
This commit is contained in:
166
Modules/nile/draft/Nile3Ops.java
Normal file
166
Modules/nile/draft/Nile3Ops.java
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
Nile3Ops.java
|
||||
*
|
||||
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
|
||||
*
|
||||
* You may use and distribute under the terms of either the GNU Lesser
|
||||
* General Public License, either version 2 of the license or,
|
||||
* at your choice, any later version. Alternatively, you may use and
|
||||
* distribute under the terms of the XPL.
|
||||
*
|
||||
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
|
||||
* the licenses.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
|
||||
* file for more details.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Written by Tuomas Lukka
|
||||
*/
|
||||
package org.gzigzag.module;
|
||||
import org.gzigzag.*;
|
||||
import java.util.*;
|
||||
|
||||
/** A library of routines for operating on Nile streams.
|
||||
* @see Nile1
|
||||
*/
|
||||
|
||||
public abstract class Nile3Ops {
|
||||
public static final String rcsid = "$Id: Nile3Ops.java,v 1.1 2001/01/07 18:59:06 bfallenstein Exp $";
|
||||
public static boolean dbg = false;
|
||||
static void p(String s) { if(dbg) System.out.println(s); }
|
||||
static void pa(String s) { System.out.println(s); }
|
||||
|
||||
static public void saveCursor(ZZCell win) {
|
||||
ZZCell s = win.getOrNewCell("d.nile-save", 1);
|
||||
if(ZZCursorReal.get(s) == null)
|
||||
ZZCursorReal.set(s, new ZZCursorReal(win));
|
||||
}
|
||||
static public void clearSavedCursor(ZZCell win) {
|
||||
ZZCell s = win.getOrNewCell("d.nile-save", 1);
|
||||
if(ZZCursorReal.get(s) != null)
|
||||
ZZCursorReal.set(s, (ZZCell)null);
|
||||
}
|
||||
static public ZZCursor getSavedCursor(ZZCell win) {
|
||||
ZZCell s = win.getOrNewCell("d.nile-save", 1);
|
||||
return new ZZCursorReal(s);
|
||||
}
|
||||
|
||||
static public void setCursor(Nile3Unit unit, ZZCell win, ZZCursor to) {
|
||||
Nile3Pos pos = new Nile3Pos(to);
|
||||
setPart(win, unit.extend(pos));
|
||||
}
|
||||
|
||||
static public void moveCursor(Nile3Unit unit, ZZCell win, int dir) {
|
||||
Nile3Part part = getPart(win);
|
||||
if(!unit.step(part, dir)) return;
|
||||
setPart(win, part);
|
||||
}
|
||||
|
||||
static public void adjust(Nile3Unit unit, ZZCell win, int end, int dir) {
|
||||
Nile3Part part = getPart(win);
|
||||
if(!unit.adjust(part, end, dir)) return;
|
||||
setPart(win, part);
|
||||
}
|
||||
|
||||
static public void hop(Nile3Unit unit, ZZCell win, int dir) {
|
||||
Nile3Part part = getPart(win);
|
||||
Nile3Pos pos = part.side(dir);
|
||||
if(!unit.insertPos(pos, dir, part, false)) return;
|
||||
unit.move(part, pos, false);
|
||||
setPart(win, part);
|
||||
}
|
||||
|
||||
/** Tunnel text from one nile window to another.
|
||||
* The text can be copied or cut.
|
||||
*/
|
||||
static public void tunnel(Nile3Unit unit, ZZCell from, ZZCell to,
|
||||
boolean copy) {
|
||||
Nile3Part part = getPart(from);
|
||||
Nile3Pos pos = getPart(to).start;
|
||||
if(!unit.insertPos(pos, -1, part, true)) return;
|
||||
unit.move(part, pos, copy);
|
||||
setPart(to, part);
|
||||
}
|
||||
|
||||
static public boolean insert(ZZCell win, String key) {
|
||||
if(key == null)
|
||||
return false;
|
||||
if(key.length() != 1)
|
||||
return false;
|
||||
Nile3Pos pos = getPart(win).start;
|
||||
pos.insert(key, 1);
|
||||
setPos(win, pos);
|
||||
return true;
|
||||
}
|
||||
|
||||
static public void backspace(Nile3Unit unit, ZZCell win) {
|
||||
Nile3Part orig = getPart(win);
|
||||
Nile3Part part = new Nile3Part(orig.start, orig.start);
|
||||
unit.edge(part.start, -1, -1, false);
|
||||
unit.edge(part.end, 1, -1, true);
|
||||
unit.cut(part);
|
||||
}
|
||||
|
||||
static public void del(Nile3Unit unit, ZZCell win) {
|
||||
Nile3Pos pos = unit.cut(getPart(win));
|
||||
setPos(win, pos);
|
||||
}
|
||||
|
||||
static public void breakParagraph(Nile3Unit unit, ZZCell win) {
|
||||
Nile3Part part = getPart(win);
|
||||
part.start.breakParagraph();
|
||||
}
|
||||
|
||||
|
||||
/** Get a whole Nile stream as a string, properly capitalized.
|
||||
* Converts paragraph breaks (==struct cells) to double newlines.<br>
|
||||
* XXX a) It's no good this calls Nile1View.<br>
|
||||
* XXX b) Do this for a Nile3Part (a selection), not only
|
||||
* for a whole stream.<br>
|
||||
* XXX c) Does this belong in this class? (It seemed to fit?)
|
||||
*
|
||||
* @param inStream Some cell inside the stream to be read.
|
||||
*/
|
||||
static public String stringify(ZZCell inStream) {
|
||||
ZZCell hd = inStream.h("d.nile");
|
||||
Nile1View n1v = new Nile1View();
|
||||
n1v.init__zob();
|
||||
String s = "";
|
||||
ZZCell tail = Nile2Iter.findStruct(hd, 1, false);
|
||||
while(hd != null) {
|
||||
FText ft = n1v.paragraph(hd, tail, null, null, null);
|
||||
ft.capitalize();
|
||||
s = s + FText.Part.join(ft.parts);
|
||||
hd = tail;
|
||||
if(hd != null) tail = Nile2Iter.findStruct(hd, 1, false);
|
||||
s = s + "\n\n";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// Shorthand...
|
||||
static public Nile3Part getPart(ZZCell win) {
|
||||
ZZCursorReal start = new ZZCursorReal(win);
|
||||
if(start.getOffs() == start.NO_OFFSET)
|
||||
start = new ZZCursorReal(win.getOrNewCell("d.nile-save"));
|
||||
ZZCursorReal end = new ZZCursorReal(win.getOrNewCell("d.nile-sel"));
|
||||
return new Nile3Part(start, end);
|
||||
}
|
||||
|
||||
static public void setPart(ZZCell win, Nile3Part part) {
|
||||
ZZCursor start = part.start.get(), end = part.end.get();
|
||||
ZZCursorReal.set(win, start.get());
|
||||
// if(ZZCursorReal.getOffs(win) != ZZCursorReal.NO_OFFSET)
|
||||
ZZCursorReal.setOffs(win, start.getOffs());
|
||||
ZZCursorReal.set(win.getOrNewCell("d.nile-save"), start);
|
||||
ZZCursorReal.set(win.getOrNewCell("d.nile-sel"), end);
|
||||
}
|
||||
|
||||
static public void setPos(ZZCell win, Nile3Pos pos) {
|
||||
setPart(win, new Nile3Part(pos, pos));
|
||||
}
|
||||
}
|
||||
132
Modules/nile/draft/Nile3Part.java
Normal file
132
Modules/nile/draft/Nile3Part.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Nile3Part.java
|
||||
*
|
||||
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
|
||||
*
|
||||
* You may use and distribute under the terms of either the GNU Lesser
|
||||
* General Public License, either version 2 of the license or,
|
||||
* at your choice, any later version. Alternatively, you may use and
|
||||
* distribute under the terms of the XPL.
|
||||
*
|
||||
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
|
||||
* the licenses.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
|
||||
* file for more details.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Written by Benjamin Fallenstein
|
||||
*/
|
||||
|
||||
package org.gzigzag.module;
|
||||
import org.gzigzag.*;
|
||||
|
||||
/** A Nile span, with a start and an end.
|
||||
* This object explicitly assumes no modifications to the
|
||||
* stream while it is working.
|
||||
*/
|
||||
|
||||
public final class Nile3Part implements Cloneable {
|
||||
public static final String rcsid = "$Id: Nile3Part.java,v 1.1 2001/01/07 18:59:06 bfallenstein Exp $";
|
||||
public static boolean dbg = true;
|
||||
static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
static final void pa(String s) { System.out.println(s); }
|
||||
|
||||
public final Nile3Pos start = new Nile3Pos();
|
||||
public final Nile3Pos end = new Nile3Pos();
|
||||
|
||||
public Nile3Part(Nile3Pos start, Nile3Pos end) {
|
||||
this.start.set(start); this.end.set(end);
|
||||
check();
|
||||
}
|
||||
public Nile3Part(ZZCursor start, ZZCursor end) {
|
||||
p(start + " " + end);
|
||||
this.start.set(start); this.end.set(end);
|
||||
check();
|
||||
}
|
||||
|
||||
public Nile3Pos side(int dir) {
|
||||
if(dir < 0) return start;
|
||||
else return end;
|
||||
}
|
||||
|
||||
public Nile3Pos cut() {
|
||||
if(isStream())
|
||||
return null; // XXX should this throw an error?
|
||||
check();
|
||||
start.split(false, 1);
|
||||
end.split(false, -1);
|
||||
Nile3Pos before = (Nile3Pos)start.clone();
|
||||
Nile3Pos after = (Nile3Pos)end.clone();
|
||||
if(!before.bias(-1) || !after.bias(1))
|
||||
throw new ZZError("HELP! End of stream after split! XXX");
|
||||
start.c.disconnect("d.nile", -1);
|
||||
end.c.disconnect("d.nile", 1);
|
||||
before.c.connect("d.nile", 1, after.c);
|
||||
return before;
|
||||
}
|
||||
|
||||
/** Make a cell's content into a span. */
|
||||
static public Span spanify(ZZCell c0) {
|
||||
Span sp = c0.getSpan();
|
||||
if(sp != null) return sp;
|
||||
|
||||
StringScroll sc = c0.getSpace().getStringScroll();
|
||||
String s = c0.getText();
|
||||
long soffs = sc.append(s);
|
||||
sp = Span.create(
|
||||
Address.scrollOffs(sc, soffs),
|
||||
Address.scrollOffs(sc, soffs + s.length() - 1)
|
||||
);
|
||||
c0.setSpan(sp);
|
||||
return sp;
|
||||
}
|
||||
|
||||
public Nile3Part copy() {
|
||||
check();
|
||||
start.split(false, 1);
|
||||
end.split(false, -1);
|
||||
ZZCell c = start.c;
|
||||
ZZCell first = c.N(), last = first;
|
||||
while(true) {
|
||||
last.setSpan(spanify(c));
|
||||
if(c.equals(end.c)) break;
|
||||
c = c.s("d.nile");
|
||||
last = last.N("d.nile");
|
||||
}
|
||||
return new Nile3Part(
|
||||
new ZZCursorVirtual(first, 0),
|
||||
new ZZCursorVirtual(last, last.getText().length()));
|
||||
}
|
||||
|
||||
/** Return true if there's nothing before or after this. */
|
||||
public boolean isStream() {
|
||||
return start.end(-1) && end.end(1);
|
||||
}
|
||||
|
||||
/** Check the integrity of this Nile3Part: start <= end? */
|
||||
public void check() {
|
||||
boolean good = true;
|
||||
if(start.c.equals(end.c)) {
|
||||
good = start.offs <= end.offs;
|
||||
p(start.offs + " " + end.offs);
|
||||
} else {
|
||||
good = start.c.findCell("d.nile", 1, end.c);
|
||||
p(start.c + " " + end.c);
|
||||
}
|
||||
if(!good)
|
||||
throw new ZZError("Malformed Nile3Part stream! XXX");
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch(CloneNotSupportedException e) {
|
||||
ZZLogger.exc(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
338
Modules/nile/draft/Nile3Pos.java
Normal file
338
Modules/nile/draft/Nile3Pos.java
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
Nile3Pos.java
|
||||
*
|
||||
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
|
||||
*
|
||||
* You may use and distribute under the terms of either the GNU Lesser
|
||||
* General Public License, either version 2 of the license or,
|
||||
* at your choice, any later version. Alternatively, you may use and
|
||||
* distribute under the terms of the XPL.
|
||||
*
|
||||
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
|
||||
* the licenses.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
|
||||
* file for more details.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Written by Benjamin Fallenstein
|
||||
*/
|
||||
|
||||
package org.gzigzag.module;
|
||||
import org.gzigzag.*;
|
||||
import java.util.*;
|
||||
|
||||
/** A character-level iterator object that knows about
|
||||
* paragraphs for a Nile stream.
|
||||
* This object explicitly assumes no modifications to the
|
||||
* stream while it is working.
|
||||
* The position is between the characters, not on a character.
|
||||
* Actually, it is <em>between (a char | a para boundary) and
|
||||
* (a char | a para boundary)</em>, i.e., it can be at the beginning or end
|
||||
* of a para or between two paras.
|
||||
*/
|
||||
|
||||
public final class Nile3Pos implements Cloneable {
|
||||
public static final String rcsid = "$Id: Nile3Pos.java,v 1.1 2001/01/07 18:59:06 bfallenstein Exp $";
|
||||
public static boolean dbg = false;
|
||||
static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
static final void pa(String s) { System.out.println(s); }
|
||||
|
||||
/** Returned by type() or read(), this denotes end/beginning of stream. */
|
||||
public static final int END = -1;
|
||||
/** Returned by type() or read(), this denotes a paragraph break. */
|
||||
public static final int PARA = -2;
|
||||
/** Returned by type(), this means punctuation. */
|
||||
public static final int PUNCT = -3;
|
||||
/** Returned by type(), this means alphanumeric character. */
|
||||
public static final int ALPHA = -4;
|
||||
/** Returned by type(), this means whitespace. */
|
||||
public static final int WS = -5;
|
||||
/** Returned by read(), this means special thing (to type, it's PUNCT). */
|
||||
public static final int SPECIAL = -6;
|
||||
|
||||
ZZCell c;
|
||||
int offs;
|
||||
|
||||
// Cache these for speed.
|
||||
// Note: ctxt and cspan are only valid if NOT (isStruct || isSpecial)!
|
||||
int clen;
|
||||
String ctxt;
|
||||
Span cspan;
|
||||
|
||||
// Is this cell a struct cell, a text object?
|
||||
private boolean isStruct, isSpecial;
|
||||
|
||||
public Nile3Pos(Nile3Pos pos) { set(pos); }
|
||||
public Nile3Pos(ZZCursor pos) { set(pos); }
|
||||
Nile3Pos() {}
|
||||
|
||||
public ZZCursor get() { return new ZZCursorVirtual(c, offs); };
|
||||
|
||||
|
||||
private void load(ZZCell c) {
|
||||
this.c = c;
|
||||
isStruct = (c.s("d.nile-struct", 1) != null);
|
||||
isSpecial = (c.s("d.nile-special", 1) != null);
|
||||
|
||||
if(isStruct || isSpecial)
|
||||
clen = 1;
|
||||
else {
|
||||
ctxt = c.getText();
|
||||
cspan = c.getSpan();
|
||||
clen = ctxt.length();
|
||||
}
|
||||
}
|
||||
|
||||
public void set(Nile3Pos pos) {
|
||||
load(pos.c);
|
||||
offs = pos.offs;
|
||||
}
|
||||
public void set(ZZCursor pos) {
|
||||
load(pos.get());
|
||||
offs = pos.getOffs();
|
||||
if(offs == pos.NO_OFFSET) offs = 0;
|
||||
}
|
||||
|
||||
/** Internal convenience: try to insert with bias, if can't, return */
|
||||
private boolean insert(String s, int side, int bias) {
|
||||
if(!bias(bias)) return false;
|
||||
if(cspan != null) return false;
|
||||
|
||||
c.setText(ctxt.substring(0, offs) + s + ctxt.substring(offs));
|
||||
ZZCursorReal.adjustCursors(c, offs, s.length());
|
||||
if(side > 0) offs += s.length();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void insert(String s, int side) {
|
||||
if(insert(s, side, 1)) return;
|
||||
if(offs == 0)
|
||||
if(insert(s, side, -1)) return;
|
||||
split(false, 1);
|
||||
load(c.N("d.nile", -1));
|
||||
c.setText(s);
|
||||
offs = (side < 0) ? (0) : (clen);
|
||||
}
|
||||
|
||||
public void insert(Nile3Part what, int side) {
|
||||
if(!what.isStream())
|
||||
throw new ZZError("Can't insert non-stream Nile3Part!");
|
||||
split(false, side);
|
||||
ZZCell other = c.s("d.nile", -side);
|
||||
c.disconnect("d.nile", -side);
|
||||
c.connect("d.nile", -side, what.side(side).c);
|
||||
other.connect("d.nile", side, what.side(-side).c);
|
||||
}
|
||||
|
||||
public boolean delete(int bias) {
|
||||
// First, ensure we are in the same cell as the character to delete.
|
||||
if(!bias(bias)) return false;
|
||||
|
||||
// Then, a special case check (also for isStruct and isSpecial cells)
|
||||
if(clen == 1) {
|
||||
ZZCell from = c;
|
||||
if(c.s("d.nile") != null) {
|
||||
load(c.s("d.nile"));
|
||||
offs = 0;
|
||||
} else if(c.s("d.nile", -1) != null) {
|
||||
load(c.s("d.nile", -1));
|
||||
offs = clen;
|
||||
} else {
|
||||
load(c.N("d.nile"));
|
||||
offs = 0;
|
||||
}
|
||||
Enumeration e = ZZCursorReal.getPointers(from);
|
||||
while(e.hasMoreElements()) {
|
||||
ZZCell curs = (ZZCell)e.nextElement();
|
||||
ZZCursorReal.setcursor(curs, c);
|
||||
if(ZZCursorReal.getOffs(curs) != ZZCursorReal.NO_OFFSET)
|
||||
ZZCursorReal.setOffs(curs, offs);
|
||||
}
|
||||
from.delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
if(cspan == null) {
|
||||
if(bias < 0) offs--;
|
||||
c.setText(ctxt.substring(0, offs) + ctxt.substring(offs));
|
||||
ZZCursorReal.adjustCursors(c, offs, -1);
|
||||
} else {
|
||||
split(false, bias);
|
||||
if(bias > 0) c.setSpan(cspan.subSpan(1));
|
||||
else c.setSpan(cspan.subSpan(0, clen-1));
|
||||
}
|
||||
load(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Split at the current position.
|
||||
* The original cell will remain the first.
|
||||
* If side is greater than zero, this pos will be set to the second cell;
|
||||
* if side is less than zero, this pos will be set to the first cell.
|
||||
* If offs is zero or equal to the number of characters in c, nothing is
|
||||
* done and either the current cell or the next cell is returned.
|
||||
* <p>
|
||||
* The most special case involves doing this at the very end of the stream,
|
||||
* in which case an empty new cell is created and returned.
|
||||
* @param side The side of the split to make this Nile3Pos point to.
|
||||
* @param always Whether to split even if the offset is at the beginning
|
||||
* or end of a cell. Used e.g. for inserting a paragraph.
|
||||
*/
|
||||
public void split(boolean always, int side) {
|
||||
if(always) {
|
||||
ZZCell c1 = c.N("d.nile");
|
||||
if(cspan == null) {
|
||||
c.setText(ctxt.substring(0, offs));
|
||||
c1.setText(ctxt.substring(offs));
|
||||
} else {
|
||||
c.setSpan(cspan.subSpan(0, offs));
|
||||
c1.setSpan(cspan.subSpan(offs));
|
||||
}
|
||||
Enumeration e = ZZCursorReal.getPointers(c);
|
||||
while(e.hasMoreElements()) {
|
||||
ZZCell p = (ZZCell)e.nextElement();
|
||||
int poffs = ZZCursorReal.getOffs(p);
|
||||
if(poffs != ZZCursorReal.NO_OFFSET && poffs > offs) {
|
||||
ZZCursorReal.setcursor(p, c1);
|
||||
ZZCursorReal.setOffs(p, poffs-offs);
|
||||
}
|
||||
}
|
||||
if(side > 0) { load(c1); offs = 0; }
|
||||
} else {
|
||||
if(offs == 0) {
|
||||
if(side < 0) {
|
||||
load(c.getOrNewCell("d.nile", -1));
|
||||
offs = clen;
|
||||
}
|
||||
} else if(offs >= clen) {
|
||||
if(side > 0) {
|
||||
load(c.getOrNewCell("d.nile"));
|
||||
offs = 0;
|
||||
}
|
||||
} else
|
||||
split(true, side);
|
||||
}
|
||||
}
|
||||
|
||||
public int type(int dir) {
|
||||
int ch = read(dir);
|
||||
if(ch < 0) return ch;
|
||||
if(Character.isLetterOrDigit((char)ch)) return ALPHA;
|
||||
if(Character.isWhitespace((char)ch)) return WS;
|
||||
return PUNCT;
|
||||
}
|
||||
/** Return true if type() would return <code>Nile3Pos.END</code>. */
|
||||
public boolean end(int dir) {
|
||||
return type(dir) == END;
|
||||
}
|
||||
/** Return true if type() would return <code>Nile3Pos.PARA</code>. */
|
||||
public boolean para(int dir) {
|
||||
return type(dir) == PARA;
|
||||
}
|
||||
/** Return true if type() would return <code>Nile3Pos.PUNCT</code>. */
|
||||
public boolean punct(int dir) {
|
||||
return type(dir) == PUNCT;
|
||||
}
|
||||
/** Return true if type() would return <code>Nile3Pos.ALPHA</code>. */
|
||||
public boolean alpha(int dir) {
|
||||
return type(dir) == ALPHA;
|
||||
}
|
||||
/** Return true if type() would return <code>Nile3Pos.WS</code>. */
|
||||
public boolean ws(int dir) {
|
||||
return type(dir) == WS;
|
||||
}
|
||||
/** Return true if boundary, i.e. if end() or para() would return true. */
|
||||
public boolean boundary(int dir) {
|
||||
int t = type(dir);
|
||||
return (t == END) || (t == PARA);
|
||||
}
|
||||
/** Return true if boundary() or ws() would test true. */
|
||||
public boolean bws(int dir) {
|
||||
int t = type(dir);
|
||||
return (t == WS) || (t == END) || (t == PARA);
|
||||
}
|
||||
|
||||
/** Read character in given direction. */
|
||||
public int read(int dir) {
|
||||
if(!bias(dir)) return END;
|
||||
if(isStruct) return PARA;
|
||||
if(isSpecial) return SPECIAL;
|
||||
return ctxt.charAt((dir < 0) ? (offs - 1) : (offs));
|
||||
}
|
||||
|
||||
/** Move n characters forwards or backwards.
|
||||
* If the offset given is out of bounds, moves as far as possible
|
||||
* and returns false, otherwise returns true. In general, this moves as
|
||||
* little as possible, i.e. if n was positive, bias is negative, and if
|
||||
* n was negative, bias is positive after call.
|
||||
*/
|
||||
public boolean move(int n) {
|
||||
n += offs;
|
||||
offs = 0;
|
||||
|
||||
while(n > clen) {
|
||||
n -= clen;
|
||||
ZZCell nc = c.s("d.nile");
|
||||
if(nc == null) {
|
||||
// End of stream!
|
||||
offs = clen;
|
||||
if(n > 0) return false;
|
||||
return true;
|
||||
}
|
||||
load(nc);
|
||||
}
|
||||
while(n < 0) {
|
||||
ZZCell nc = c.s("d.nile", -1);
|
||||
if(nc == null) {
|
||||
offs = 0;
|
||||
return false;
|
||||
}
|
||||
load(nc);
|
||||
n += clen;
|
||||
}
|
||||
|
||||
offs = n;
|
||||
return true;
|
||||
}
|
||||
/** (Convenience:) Move if doMove is true.
|
||||
* This is used by Nile3Unit to make includeThis code simpler.
|
||||
*/
|
||||
public boolean move(boolean doMove, int n) {
|
||||
if(doMove) return move(n);
|
||||
else return true;
|
||||
}
|
||||
|
||||
/** Ensure bias in a given direction.
|
||||
* This means that after bias(1), we are in the cell that contains the
|
||||
* character in positive direction, and after bias(-1), same in negative
|
||||
* direction.<br>
|
||||
* If we bump on the end of the stream, return false, else return true.
|
||||
*/
|
||||
boolean bias(int dir) {
|
||||
if(offs + dir >= 0 && offs + dir <= clen) return true;
|
||||
do {
|
||||
ZZCell nc = c.s("d.nile", dir);
|
||||
if(nc == null) return false;
|
||||
load(nc);
|
||||
} while(clen == 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void breakParagraph() {
|
||||
split(false, 1);
|
||||
c.N("d.nile", -1).N("d.nile-struct").setText("P");
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch(CloneNotSupportedException e) {
|
||||
ZZLogger.exc(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
305
Modules/nile/draft/Nile3Unit.java
Normal file
305
Modules/nile/draft/Nile3Unit.java
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
Nile3Unit.java
|
||||
*
|
||||
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
|
||||
*
|
||||
* You may use and distribute under the terms of either the GNU Lesser
|
||||
* General Public License, either version 2 of the license or,
|
||||
* at your choice, any later version. Alternatively, you may use and
|
||||
* distribute under the terms of the XPL.
|
||||
*
|
||||
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
|
||||
* the licenses.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
|
||||
* file for more details.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Written by Benjamin Fallenstein, based on Nile2Unit by Tuomas Lukka
|
||||
*/
|
||||
|
||||
package org.gzigzag.module;
|
||||
import org.gzigzag.*;
|
||||
|
||||
/** A nile unit of division.
|
||||
* Spaces between units may be non-zero-width. Units may be zero-width, if
|
||||
* neighbouring units are separated by non-zero spaces.
|
||||
*/
|
||||
|
||||
public abstract class Nile3Unit {
|
||||
public static final String rcsid = "$Id: Nile3Unit.java,v 1.1 2001/01/07 18:59:06 bfallenstein Exp $";
|
||||
public static boolean dbg = false;
|
||||
static final void p(String s) { if(dbg) System.out.println(s); }
|
||||
static final void pa(String s) { System.out.println(s); }
|
||||
|
||||
|
||||
public static class Char extends Nile3Unit {
|
||||
public boolean isEdge(Nile3Pos pos, int dir) {
|
||||
return !pos.boundary(dir);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Word extends Nile3Unit {
|
||||
/** An alphanumeric word. */
|
||||
static final int AWORD = 1;
|
||||
/** A punctuation word, e.g. a smilie. */
|
||||
static final int PWORD = 2;
|
||||
/** An A- or PWORD. */
|
||||
static final int WORD = AWORD | PWORD;
|
||||
/** A piece of left-bound punctuation, like commas. */
|
||||
static final int LPUNCT = 4;
|
||||
/** A piece of right-bound punctuation, like opening brackets. */
|
||||
static final int RPUNCT = 8;
|
||||
/** A piece of left- or right-bound punctuation. */
|
||||
static final int BPUNCT = LPUNCT | RPUNCT;
|
||||
/** A paragraph boundary or the end of the stream. */
|
||||
static final int BOUNDARY = 16;
|
||||
|
||||
/** Not a correct combination of words. */
|
||||
static final int BAD = 0;
|
||||
/** Correct combination iff no space in between. */
|
||||
static final int NSP = 1;
|
||||
/** Correct combination iff space in between. */
|
||||
static final int SP = 2;
|
||||
|
||||
/** The type of a joining position. */
|
||||
public static final int jointype(int lefttype, int righttype) {
|
||||
if(lefttype & WORD > 0 && righttype & WORD > 0)
|
||||
return SP;
|
||||
else if(lefttype == AWORD && righttype == LPUNCT)
|
||||
return NSP;
|
||||
else if(lefttype == AWORD && righttype == RPUNCT)
|
||||
return SP;
|
||||
else if(lefttype == RPUNCT && righttype == AWORD)
|
||||
return NSP;
|
||||
else if(lefttype == LPUNCT && righttype == AWORD)
|
||||
return SP;
|
||||
else if(lefttype & BPUNCT > 0 && righttype == lefttype)
|
||||
return NSP;
|
||||
else if(lefttype == LPUNCT && righttype == RPUNCT)
|
||||
return SP;
|
||||
else if(lefttype == BOUNDARY && righttype == BOUNDARY)
|
||||
return NSP;
|
||||
else if(lefttype == BOUNDARY && righttype & WORD > 0)
|
||||
return NSP;
|
||||
else if(lefttype & WORD > 0 && righttype == BOUNDARY)
|
||||
return NSP;
|
||||
else if(lefttype == LPUNCT && righttype == BOUNDARY)
|
||||
return NSP;
|
||||
else if(lefttype == BOUNDARY && righttype == RPUNCT)
|
||||
return NSP;
|
||||
else
|
||||
return BAD;
|
||||
}
|
||||
|
||||
/** Find out the types of the words next to a word boundary.
|
||||
* This may only be called on what is known to be a word boundary.
|
||||
* Else, its behavior is undefined.
|
||||
*/
|
||||
public static final int[] wordtype(Nile3Pos pos, int dir) {
|
||||
int[] res = new int[2];
|
||||
|
||||
int lch = pos.type(-1), rch = pos.type(1);
|
||||
boolean lp = pos.punct(-1), rp = pos.punct(1);
|
||||
Nile3Pos lpos, rpos;
|
||||
if(lp) {
|
||||
lpos = (Nile3Pos)pos.clone();
|
||||
while(lpos.punct(-1)) lpos.move(-1);
|
||||
}
|
||||
if(rp) {
|
||||
rpos = (Nile3Pos)pos.clone();
|
||||
while(rpos.punct(1)) rpos.move(1);
|
||||
}
|
||||
|
||||
if(!lp && !rp) {
|
||||
if(pos.
|
||||
}
|
||||
|
||||
public void cleanJoin(Nile3Pos pos, int lefttype, int righttype) {
|
||||
int type = jointype(lefttype, righttype);
|
||||
if(jointype == NSP) {
|
||||
while(pos.ws(-1)) pos.delete(-1);
|
||||
while(pos.ws(1)) pos.delete(1);
|
||||
} else if(jointype == SP) {
|
||||
if(!pos.ws(-1) && !pos.ws(1)) pos.insert(" ", 1);
|
||||
} else {
|
||||
p("Nile3Unit.Word: Detected bad joining in cleanJoin");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEdge(Nile3Pos pos, int dir) {
|
||||
if(pos.punct(-dir)) return true;
|
||||
if(pos.bws(dir) && pos.alpha(-dir)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Can what be inserted at pos? */
|
||||
public boolean isInsertPos(Nile3Pos pos, Nile3Part what) {
|
||||
if(!pos.boundary(1) && !isEdge(pos, -1)) return false;
|
||||
if(what.start.punct(1) && !what.start.bws(-1)) {
|
||||
}
|
||||
if(what.end.punct(-1) && !what.end.bws(1)) {
|
||||
if(
|
||||
}
|
||||
if(jointype(pos.-1, what.start.1) == BAD) return false;
|
||||
if(jointype(pos.1, what.end.-1) == BAD) return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Sentence extends Nile3Unit {
|
||||
public boolean isEdge(Nile3Pos pos, int dir) {
|
||||
if(pos.ws(dir)) return false;
|
||||
if(pos.boundary(-dir)) return true;
|
||||
if(!pos.move(-dir)) return false;
|
||||
if((pos.bws(-dir)) && pos.ws(dir)) return true;
|
||||
pos.move(dir);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ugh! Paragraph is *inefficient*!
|
||||
// XXX is this a problem? in very long paragraphs maybe?
|
||||
public static class Paragraph extends Nile3Unit {
|
||||
public boolean isEdge(Nile3Pos pos, int dir) {
|
||||
return pos.boundary(-dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean step(Nile3Part part, int n) {
|
||||
int abs = (n < 0) ? (-n) : (n);
|
||||
int dir = (n < 0) ? (-1) : (1);
|
||||
Nile3Pos pos = part.side(dir), other = part.side(-dir);
|
||||
for(int i=0; i<abs; i++) {
|
||||
other.set(pos);
|
||||
if(!edge(other, -dir, dir, true)) return false;
|
||||
pos.set(other);
|
||||
if(!edge(pos, dir, dir, false)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean adjust(Nile3Part part, int side, int n) {
|
||||
int abs = (n < 0) ? (-n) : (n);
|
||||
int dir = (n < 0) ? (-1) : (1);
|
||||
for(int i=0; i<abs; i++) {
|
||||
if(!edge(part.side(side), side, dir, false)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Nile3Part extend(Nile3Pos pos) {
|
||||
Nile3Part res = new Nile3Part(pos, pos);
|
||||
if(!extend(res)) return null;
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean extend(Nile3Part part) {
|
||||
if(!edge(part.start, -1, -1, true)) return false;
|
||||
if(!edge(part.end, 1, 1, true)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean delete(Nile3Part part) {
|
||||
cleanUp(part.delete());
|
||||
}
|
||||
|
||||
protected void cleanUp(Nile3Pos pos) {}
|
||||
|
||||
/** Move a Nile3Part to a position. */
|
||||
public void move(Nile3Part what, Nile3Pos where, int moveDir,
|
||||
boolean includeThis, boolean copy) {
|
||||
// First, prepare the part.
|
||||
if(!extend(what)) return null;
|
||||
if(copy) what = what.copy();
|
||||
else rmSpace(what.cut());
|
||||
|
||||
// Then, prepare the pos.
|
||||
if(!insertPos(pos, moveDir, what, includeThis)) return null;
|
||||
|
||||
// Finally, move.
|
||||
Nile3Pos res = paste(what, where);
|
||||
rmSpace(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/** The previous or next position where this type of unit may be inserted.
|
||||
* By standard, return edge(pos, -1, dir, includeThis).
|
||||
*/
|
||||
protected boolean insertPos(Nile3Pos pos, int dir, Nile3Part what,
|
||||
boolean includeThis) {
|
||||
if(!pos.move(!includeThis, moveDir)) return false;
|
||||
do {
|
||||
if(pos.boundary(1) || isEdge(pos, -1)) return true;
|
||||
} while(pos.move(moveDir));
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Is this an edge of this type of unit in the given direction?
|
||||
* Positive direction means there follows such a unit after this point;
|
||||
* negative direction menas this point is preceded by such a unit.
|
||||
*/
|
||||
protected abstract boolean isEdge(Nile3Pos pos, int dir);
|
||||
|
||||
public boolean edge(Nile3Pos pos, int edgeDir, int moveDir,
|
||||
boolean includeThis) {
|
||||
if(!pos.move(!includeThis, moveDir)) return false;
|
||||
do {
|
||||
if(isEdge(pos, edgeDir)) return true;
|
||||
} while(pos.move(moveDir));
|
||||
return false;
|
||||
}
|
||||
|
||||
/** The previous or next beginning position of this type of unit.
|
||||
* @returns false if we bump into end of string.
|
||||
*/
|
||||
public boolean start(Nile3Pos pos, int dir, boolean includeThis) {
|
||||
return edge(pos, -1, dir, includeThis);
|
||||
}
|
||||
|
||||
/** The previous or next ending position of this type of unit.
|
||||
* @returns false if we bump into end of string.
|
||||
*/
|
||||
public boolean end(Nile3Pos pos, int dir, boolean includeThis) {
|
||||
return edge(pos, 1, dir, includeThis);
|
||||
}
|
||||
|
||||
/** Modify the selection so that it makes sense to the user. */
|
||||
public boolean select(Nile3Part part, boolean extend) {
|
||||
boolean res = start(part.start, extend ? -1 : 1, true);
|
||||
res = res && end(part.end, extend ? 1 : -1, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Modify the selection for moving it around (cut, copy) */
|
||||
public boolean prepare(Nile3Part part) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Cut the stream.
|
||||
* This routine modifies the Nile3Part to point
|
||||
* to the cut stream, and returns the cut position.
|
||||
* @return The pasted-together cutaway point, from which
|
||||
* the insert position can be searched with !includeThis.
|
||||
*/
|
||||
public Nile3Pos cut(Nile3Part part) { return part.cut(); }
|
||||
|
||||
/** Copy a part of the stream.
|
||||
* First every cell is spanified, then a new stream with the same spans
|
||||
* is created.
|
||||
* This routine modifies the start and to iterators to point
|
||||
* to the beginning and end of the copied stream.
|
||||
* XXX any special copying rules to obey, like in cut?
|
||||
*/
|
||||
public Nile3Part copy(Nile3Part what) {
|
||||
this.start(what.start, -1, true);
|
||||
this.end(what.end, 1, true);
|
||||
return what.copy();
|
||||
}
|
||||
|
||||
protected void paste(Nile3Pos at, Nile3Part what) { at.insert(what, 1); }
|
||||
}
|
||||
Reference in New Issue
Block a user