下面列出了怎么用javax.swing.text.Segment的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public void write(Writer out, Document doc, int pos, int len) throws IOException, BadLocationException {
if ((pos < 0) || ((pos + len) > doc.getLength())) {
throw new BadLocationException("DefaultEditorKit.write", pos);
}
Segment data = new Segment();
int nleft = len;
int offs = pos;
while (nleft > 0) {
int n = Math.min(nleft, 4096);
doc.getText(offs, n, data);
out.write(data.array, data.offset, data.count);
offs += n;
nleft -= n;
}
}
synchronized void returnPressed() {
Document doc = getDocument();
int len = doc.getLength();
Segment segment = new Segment();
try {
doc.getText(outputMark, len - outputMark, segment);
} catch(javax.swing.text.BadLocationException ignored) {
ignored.printStackTrace();
}
if(segment.count > 0) {
history.add(segment.toString());
}
historyIndex = history.size();
inPipe.write(segment.array, segment.offset, segment.count);
append("\n");
outputMark = doc.getLength();
inPipe.write("\n");
inPipe.flush();
console1.flush();
}
/**
* Returns the first token in the linked list of tokens generated
* from <code>text</code>. This method must be implemented by
* subclasses so they can correctly implement syntax highlighting.
*
* @param text The text from which to get tokens.
* @param initialTokenType The token type we should start with.
* @param startOffset The offset into the document at which
* <code>text</code> starts.
* @return The first <code>Token</code> in a linked list representing
* the syntax highlighted text.
*/
public Token getTokenList(Segment text, int initialTokenType, int startOffset) {
resetTokenList();
this.offsetShift = -text.offset + startOffset;
// Start off in the proper state.
int state = Token.NULL;
switch (initialTokenType) {
/* No multi-line comments */
/* No documentation comments */
default:
state = Token.NULL;
}
s = text;
try {
yyreset(zzReader);
yybegin(state);
return yylex();
} catch (IOException ioe) {
ioe.printStackTrace();
return new TokenImpl();
}
}
@Override
public void getText(int offset, int length, Segment txt) throws BadLocationException {
if (lastOffset == offset && lastLength == length) {
txt.array = segArray;
txt.offset = segOffset;
txt.count = segCount;
txt.setPartialReturn(segPartialReturn);
return;
}
super.getText(offset, length, txt);
if (length > CACHE_BOUNDARY || lastLength <= CACHE_BOUNDARY) {
segArray = txt.array;
segOffset = txt.offset;
segCount = txt.count;
segPartialReturn = txt.isPartialReturn();
lastOffset = offset;
lastLength = length;
}
}
/**
* Copy portion of the document into target character array.
*
* @param srcDoc document from which to copy.
* @param srcStartOffset offset of the first character to copy.
* @param srcEndOffset offset that follows the last character to copy.
* @param dst destination character array into which the data will be copied.
* @param dstOffset offset in the destination array at which the putting
* of the characters starts.
*
* @throws javax.swing.text.BadLocationException
*/
public static void copyText(Document srcDoc, int srcStartOffset,
int srcEndOffset, char[] dst, int dstOffset) throws BadLocationException {
Segment text = new Segment();
int gapStart = getGapStart(srcDoc);
if (gapStart != -1 && srcStartOffset < gapStart && gapStart < srcEndOffset) {
// Get part below gap
srcDoc.getText(srcStartOffset, gapStart - srcStartOffset, text);
System.arraycopy(text.array, text.offset, dst, dstOffset, text.count);
dstOffset += text.count;
srcStartOffset = gapStart;
}
srcDoc.getText(srcStartOffset, srcEndOffset - srcStartOffset, text);
System.arraycopy(text.array, text.offset, dst, dstOffset, srcEndOffset - srcStartOffset);
}
/**
* Parse the entire document and return list of tokens that do not already
* exist in the tokens list. There may be overlaps, and replacements, which
* we will cleanup later.
*
* @return list of tokens that do not exist in the tokens field
*/
private void parse() {
// if we have no lexer, then we must have no tokens...
if (lexer == null) {
tokens = null;
return;
}
int len = getLength();
List<Token> toks = new ArrayList<Token>(len / 10);
long ts = System.nanoTime();
try {
Segment seg = new Segment();
getText(0, len, seg);
lexer.parse(seg, 0, toks);
} catch (BadLocationException ex) {
log.log(Level.SEVERE, null, ex);
} finally {
if (log.isLoggable(Level.FINEST)) {
log.finest(String.format("Parsed %d in %d ms, giving %d tokens\n",
len, (System.nanoTime() - ts) / 1000000, toks.size()));
}
tokens = toks;
}
}
public static int getTabbedTextOffset(Segment segment, FontMetrics metrics, int tabBase,int x,TabExpander e, int startOffset){
List<Segment> segments=new ArrayList<Segment>();
List<Boolean> unis=new ArrayList<Boolean>();
Font origFont=metrics.getFont();
getSegments(origFont, segment, segments, unis);
Graphics g=new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB).getGraphics();
Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
int ofs=0;
int totalto = 0;
for(int i=0;i<segments.size();i++){
Segment seg=segments.get(i);
FontMetrics fm=unis.get(i)?g.getFontMetrics(uniFont):metrics;
int to = Utilities.getTabbedTextOffset(seg, fm, tabBase+ofs,x, e, startOffset);
totalto += to;
ofs+=fm.stringWidth(seg.toString());
if(to<seg.length()){
break;
}
}
return totalto;
}
public static int drawTabbedText(Segment segment, int x, int y, Graphics g, TabExpander e, int startOffset){
List<Segment> segments=new ArrayList<Segment>();
List<Boolean> unis=new ArrayList<Boolean>();
getSegments(g.getFont(), segment, segments, unis);
Font origFont=g.getFont();
Font uniFont = defaultUniFont.deriveFont(origFont.getStyle(),origFont.getSize2D());
int ret=x;
int pos=0;
for(int i=0;i<segments.size();i++){
Segment seg=segments.get(i);
if(unis.get(i)){
g.setFont(uniFont);
}else{
g.setFont(origFont);
}
ret = Utilities.drawTabbedText(seg, ret, y, g, e, startOffset+pos);
pos += seg.length();
}
g.setFont(origFont);
return ret;
}
/**
* Returns the first token in the linked list of tokens generated
* from <code>text</code>. This method must be implemented by
* subclasses so they can correctly implement syntax highlighting.
*
* @param text The text from which to get tokens.
* @param initialTokenType The token type we should start with.
* @param startOffset The offset into the document at which
* <code>text</code> starts.
* @return The first <code>Token</code> in a linked list representing
* the syntax highlighted text.
*/
public Token getTokenList(Segment text, int initialTokenType, int startOffset) {
resetTokenList();
this.offsetShift = -text.offset + startOffset;
// Start off in the proper state.
s = text;
try {
yyreset(zzReader);
yybegin(YYINITIAL);
return yylex();
} catch (IOException ioe) {
ioe.printStackTrace();
return new TokenImpl();
}
}
/**
* Looks up a key.
*
* @param text The text segment
* @param offset The offset of the substring within the text segment
* @param length The length of the substring
*/
public byte lookup(final Segment text, final int offset, final int length) {
if (length == 0) {
return Token.NULL;
}
Keyword k = map[getSegmentMapKey(text, offset, length)];
while (k != null) {
if (length != k.keyword.length) {
k = k.next;
continue;
}
if (SyntaxUtilities.regionMatches(text, offset, k.keyword)) {
return k.id;
}
k = k.next;
}
return Token.NULL;
}
public void getText(int offset, int length, Segment txt) throws BadLocationException {
if (lastOffset == offset && lastLength == length) {
txt.array = segArray;
txt.offset = segOffset;
txt.count = segCount;
txt.setPartialReturn(segPartialReturn);
return;
}
super.getText(offset, length, txt);
if (length > CACHE_BOUNDARY || lastLength <= CACHE_BOUNDARY) {
segArray = txt.array;
segOffset = txt.offset;
segCount = txt.count;
segPartialReturn = txt.isPartialReturn();
lastOffset = offset;
lastLength = length;
}
}
@Override
public void getText(int offset, int length, Segment txt) throws BadLocationException {
if (lastOffset == offset && lastLength == length) {
txt.array = segArray;
txt.offset = segOffset;
txt.count = segCount;
txt.setPartialReturn(segPartialReturn);
return;
}
super.getText(offset, length, txt);
if (length > CACHE_BOUNDARY || lastLength <= CACHE_BOUNDARY) {
segArray = txt.array;
segOffset = txt.offset;
segCount = txt.count;
segPartialReturn = txt.isPartialReturn();
lastOffset = offset;
lastLength = length;
}
}
@Override
public void getText(int offset, int length, Segment txt) throws BadLocationException {
if (lastOffset == offset && lastLength == length) {
txt.array = segArray;
txt.offset = segOffset;
txt.count = segCount;
txt.setPartialReturn(segPartialReturn);
return;
}
super.getText(offset, length, txt);
if (length > CACHE_BOUNDARY || lastLength <= CACHE_BOUNDARY) {
segArray = txt.array;
segOffset = txt.offset;
segCount = txt.count;
segPartialReturn = txt.isPartialReturn();
lastOffset = offset;
lastLength = length;
}
}
@Override
public void getText(int offset, int length, Segment txt) throws BadLocationException {
if (lastOffset == offset && lastLength == length) {
txt.array = segArray;
txt.offset = segOffset;
txt.count = segCount;
txt.setPartialReturn(segPartialReturn);
return;
}
super.getText(offset, length, txt);
if (length > CACHE_BOUNDARY || lastLength <= CACHE_BOUNDARY) {
segArray = txt.array;
segOffset = txt.offset;
segCount = txt.count;
segPartialReturn = txt.isPartialReturn();
lastOffset = offset;
lastLength = length;
}
}
/**
* Find the next position that matches <code>pattern</code> in the document.
* returns -1 if the pattern is not found.
* @param pattern the regex pattern to find
* @param start The beginning index of search
* @return
* @deprecated use {@link getMatcher} instead
*/
@Deprecated
public int getIndexOf(Pattern pattern, int start) {
int ndx = -1;
if (pattern == null || getLength() == 0) {
return -1;
}
try {
Segment segment = new Segment();
getText(start, getLength() - start, segment);
Matcher m = pattern.matcher(segment);
if (m.find()) {
// remember that the index is relative to the document, so
// always add the start position to it
ndx = m.start() + start;
}
} catch (BadLocationException ex) {
log.log(Level.SEVERE, null, ex);
}
return ndx;
}
/**
* Draw text. This can directly call the Utilities.drawTabbedText.
* Sub-classes can override this method to provide any other decorations.
* @param segment - the source of the text
* @param x - the X origin >= 0
* @param y - the Y origin >= 0
* @param graphics - the graphics context
* @param e - how to expand the tabs. If this value is null, tabs will be
* expanded as a space character.
* @param startOffset - starting offset of the text in the document >= 0
* @return
*/
public int drawText(Segment segment, int x, int y,
Graphics graphics, TabExpander e, int startOffset) {
graphics.setFont(graphics.getFont().deriveFont(getFontStyle()));
FontMetrics fontMetrics = graphics.getFontMetrics();
int a = fontMetrics.getAscent();
int h = a + fontMetrics.getDescent();
int w = Utilities.getTabbedTextWidth(segment, fontMetrics, 0, e, startOffset);
int rX = x - 1;
int rY = y - a;
int rW = w + 2;
int rH = h;
if ((getFontStyle() & 0x10) != 0) {
graphics.setColor(Color.decode("#EEEEEE"));
graphics.fillRect(rX, rY, rW, rH);
}
graphics.setColor(getColor());
x = Utilities.drawTabbedText(segment, x, y, graphics, e, startOffset);
if ((getFontStyle() & 0x8) != 0) {
graphics.setColor(Color.RED);
graphics.drawRect(rX, rY, rW, rH);
}
return x;
}
/**
* Return a matcher that matches the given pattern in the part of the
* document starting at offset start and ending at start + length. Note that
* the matcher will have offset starting from <code>start</code>
*
* @param pattern
* @param start
* @param length
* @return matcher that <b>MUST</b> be offset by start to get the proper
* location within the document
*/
public Matcher getMatcher(Pattern pattern, int start, int length) {
Matcher matcher = null;
if (getLength() == 0) {
return null;
}
if (start >= getLength()) {
return null;
}
try {
if (start < 0) {
start = 0;
}
if (start + length > getLength()) {
length = getLength() - start;
}
Segment seg = new Segment();
getText(start, length, seg);
matcher = pattern.matcher(seg);
} catch (BadLocationException ex) {
log.log(Level.SEVERE, "Requested offset: " + ex.offsetRequested(), ex);
}
return matcher;
}
/**
* Checks the token to give it the exact ID it deserves before
* being passed up to the super method.
*
* @param segment <code>Segment</code> to get text from.
* @param start Start offset in <code>segment</code> of token.
* @param end End offset in <code>segment</code> of token.
* @param tokenType The token's type.
* @param startOffset The offset in the document at which the token occurs.
*/
@Override
public void addToken(Segment segment, int start, int end, int tokenType, int startOffset) {
switch (tokenType) {
// Since reserved words, functions, and data types are all passed
// into here as "identifiers," we have to see what the token
// really is...
case Token.IDENTIFIER:
int value = wordsToHighlight.get(segment, start,end);
if (value!=-1)
tokenType = value;
break;
case Token.ANNOTATION:
value = wordsToHighlight.get(segment, start,end);
if (value!=-1)
tokenType = value;
break;
}
super.addToken(segment, start, end, tokenType, startOffset);
}
/**
* Checks if a subregion of a <code>Segment</code> is equal to a string.
*
* @param ignoreCase
* True if case should be ignored, false otherwise
* @param text
* The segment
* @param offset
* The offset into the segment
* @param match
* The string to match
*/
public static boolean regionMatches(boolean ignoreCase, Segment text, int offset, String match) {
int length = offset + match.length();
char[] textArray = text.array;
if (length > text.offset + text.count) {
return false;
}
for (int i = offset, j = 0; i < length; i++, j++) {
char c1 = textArray[i];
char c2 = match.charAt(j);
if (ignoreCase) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
}
if (c1 != c2) {
return false;
}
}
return true;
}
/**
* Looks up a key.
*
* @param text
* The text segment
* @param offset
* The offset of the substring within the text segment
* @param length
* The length of the substring
*/
public byte lookup(Segment text, int offset, int length) {
if (length == 0) {
return Token.NULL;
}
Keyword k = map[getSegmentMapKey(text, offset, length)];
while (k != null) {
if (length != k.keyword.length) {
k = k.next;
continue;
}
if (SyntaxUtilities.regionMatches(ignoreCase, text, offset, k.keyword)) {
return k.id;
}
k = k.next;
}
return Token.NULL;
}
/**
* Checks the token to give it the exact ID it deserves before
* being passed up to the super method.
*
* @param segment <code>Segment</code> to get text from.
* @param start Start offset in <code>segment</code> of token.
* @param end End offset in <code>segment</code> of token.
* @param tokenType The token's type.
* @param startOffset The offset in the document at which the token occurs.
*/
public void addToken(Segment segment, int start, int end, int tokenType, int startOffset) {
switch (tokenType) {
// Since reserved words, functions, and data types are all passed
// into here as "identifiers," we have to see what the token
// really is...
case Token.IDENTIFIER:
int value = wordsToHighlight.get(segment, start,end);
if (value!=-1)
tokenType = value;
break;
case Token.WHITESPACE:
case Token.SEPARATOR:
case Token.OPERATOR:
case Token.ERROR_IDENTIFIER:
case Token.ERROR_NUMBER_FORMAT:
case Token.ERROR_STRING_DOUBLE:
case Token.ERROR_CHAR:
case Token.COMMENT_EOL:
case Token.COMMENT_MULTILINE:
case Token.LITERAL_BOOLEAN:
case Token.LITERAL_NUMBER_DECIMAL_INT:
case Token.LITERAL_NUMBER_FLOAT:
case Token.LITERAL_NUMBER_HEXADECIMAL:
break;
case Token.LITERAL_STRING_DOUBLE_QUOTE:
case Token.LITERAL_CHAR:
break;
default:
logger.error("Unknown tokenType: '" + tokenType + "'");
tokenType = Token.IDENTIFIER;
break;
}
super.addToken(segment, start, end, tokenType, startOffset);
}
@Override
public Object fromString(Type type, String value, Map<String, String> attributes) {
requireNonNull(type, "type cannot be null");
if (value == null) {
return null;
}
ObjectBuilder builder = new ObjectBuilder();
char[] array = value.toCharArray();
CharSequence charSequence = new Segment(array, 0, array.length);
if (consumeItem(type, charSequence, 0, builder, isCompactMode(attributes)) != value.length()) {
throw new IllegalArgumentException(MSG_UNEXPECTED_EXTRA_DATA);
}
return builder.build();
}
static int getSmartHomeOffset(JTextComponent target, SyntaxDocument sDoc,
int dot) throws BadLocationException {
Element el = sDoc.getParagraphElement(dot);
Segment seg = new Segment();
sDoc.getText(el.getStartOffset(),
el.getEndOffset() - el.getStartOffset() - 1, seg);
int homeOffset = 0;
int dotLineOffset = dot - el.getStartOffset();
boolean inText = false;
// see the location of first non-space offset
for (int i = 0; i < dotLineOffset; i++) {
if (!Character.isWhitespace(seg.charAt(i))) {
inText = true;
break;
}
}
// if we are at first char in line, or we are past the non space
// chars in the line, then we move to non-space char
// otherwise, we move to first char of line
if (dotLineOffset == 0 || inText) {
for (char ch = seg.first();
ch != CharacterIterator.DONE && Character.isWhitespace(ch);
ch = seg.next()) {
homeOffset++;
}
}
return el.getStartOffset() + homeOffset;
}
/**
* Convert all the '\r\n' or '\r' to '\n' (linefeed).
* This method
* @param text the text to be converted. Text is converted
* in the original array of the given segment.
* The <CODE>count</CODE> field
* of the text parameter will possibly be changed by the conversion
* if '\r\n' sequences are present.
* @return whether the last character in the text was the '\r' character.
* That character was already converted to '\n' and is present
* in the segment. However this notification is important
* because if there would be '\n' at the begining
* of the next buffer then that character should be skipped.
*/
private static boolean convertSegmentToLineFeed(Segment text) {
char[] chars = text.array;
int storeOffset = text.offset; // offset at which chars are stored
int endOffset = storeOffset + text.count;
boolean storeChar = false; // to prevent copying same chars to same offsets
boolean lastCharCR = false; // whether last char was '\r'
for (int offset = storeOffset; offset < endOffset; offset++) {
char ch = chars[offset];
if (lastCharCR && ch == '\n') { // found CRLF sequence
lastCharCR = false;
storeChar = true; // storeOffset now differs from offset
} else { // not CRLF sequence
if (ch == '\r') {
lastCharCR = true;
chars[storeOffset++] = '\n'; // convert it to '\n'
} else if (ch == LS || ch == PS) { // Unicode LS, PS
lastCharCR = false;
chars[storeOffset++] = '\n';
} else { // current char not '\r'
lastCharCR = false;
if (storeChar) {
chars[storeOffset] = ch;
}
storeOffset++;
}
}
}
text.count = storeOffset - text.offset;
return lastCharCR;
}
public Token getWordAt(int offs, Pattern p) {
Token word = null;
try {
Element line = getParagraphElement(offs);
if (line == null) {
return word;
}
int lineStart = line.getStartOffset();
int lineEnd = Math.min(line.getEndOffset(), getLength());
Segment seg = new Segment();
getText(lineStart, lineEnd - lineStart, seg);
if (seg.count > 0) {
// we need to get the word using the words pattern p
Matcher m = p.matcher(seg);
int o = offs - lineStart;
while (m.find()) {
if (m.start() <= o && o <= m.end()) {
word = new Token(TokenType.DEFAULT, m.start() + lineStart, m.end() - m.start());
break;
}
}
}
} catch (BadLocationException ex) {
Logger.getLogger(SyntaxDocument.class.getName()).log(Level.SEVERE, null, ex);
} finally {
return word;
}
}
/**
* Gets the line at given position. The line returned will NOT include the
* line terminator '\n'
*
* @param pos Position (usually from text.getCaretPosition()
* @return the STring of text at given position
* @throws BadLocationException
*/
public String getLineAt(int pos) throws BadLocationException {
Element e = getParagraphElement(pos);
Segment seg = new Segment();
getText(e.getStartOffset(), e.getEndOffset() - e.getStartOffset(), seg);
char last = seg.last();
if (last == '\n' || last == '\r') {
seg.count--;
}
return seg.toString();
}
/** Read from some reader and insert into document */
static void read(BaseDocument doc, Reader reader, int pos)
throws BadLocationException, IOException {
int readBufferSize = ((Integer)doc.getProperty(EditorPreferencesKeys.READ_BUFFER_SIZE)).intValue();
LineSeparatorConversion.ToLineFeed toLF
= new LineSeparatorConversion.ToLineFeed(reader, readBufferSize);
Segment text = toLF.nextConverted();
while (text != null) {
doc.insertString(pos, new String(text.array, text.offset, text.count), null);
pos += text.count;
text = toLF.nextConverted();
}
}
@Override
public Token getTokenList(Segment text, int initialTokenType, int startOffset) {
Token tokens = super.getTokenList(text, initialTokenType, startOffset);
if (startOffset > 0 && tokens.getType() != TokenTypes.NULL) {
try {
processTokens(tokens);
} catch (Exception e) {
LOG.error("Process tokens failed for text: {}", text, e);
}
}
return tokens;
}
private int drawText(Graphics g,
int x, int y,
int startOffset, int endOffset,
boolean error,
boolean selected,
DocElement docElem) throws BadLocationException {
Segment s = EventQueue.isDispatchThread() ? SEGMENT : new Segment();
s.array = docElem.getChars();
s.offset = startOffset - docElem.offset;
s.count = endOffset - startOffset;
g.setColor(getColor(error, selected));
return Utilities.drawTabbedText(s, x, y, g, this, startOffset);
}
/**
* Releases a Segment. You should not use a Segment after you release it,
* and you should NEVER release the same Segment more than once, eg:
* <pre>
* segmentCache.releaseSegment(segment);
* segmentCache.releaseSegment(segment);
* </pre>
* Will likely result in very bad things happening!
*/
public void releaseSegment(Segment segment) {
if (segment instanceof CachedSegment) {
synchronized (this) {
segment.array = null;
segment.count = 0;
segments.add(segment);
}
}
}