Revision 4890

View differences:

trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/JavaScriptTokenMarker.java
1
package com.iver.utiles.console.jedit;
2
/*
3
 * JavaScriptTokenMarker.java - JavaScript token marker
4
 * Copyright (C) 1999 Slava Pestov
5
 *
6
 * You may use and modify this package for any purpose. Redistribution is
7
 * permitted, in both source and binary form, provided that this notice
8
 * remains intact in all source distributions of this package.
9
 */
10

  
11
import javax.swing.text.Segment;
12

  
13
/**
14
 * JavaScript token marker.
15
 *
16
 * @author Slava Pestov
17
 * @version $Id$
18
 */
19
public class JavaScriptTokenMarker extends CTokenMarker
20
{
21
	public JavaScriptTokenMarker()
22
	{
23
		super(false,getKeywords());
24
	}
25

  
26
	public static KeywordMap getKeywords()
27
	{
28
		if(javaScriptKeywords == null)
29
		{
30
			javaScriptKeywords = new KeywordMap(false);
31
			javaScriptKeywords.add("function",Token.KEYWORD3);
32
			javaScriptKeywords.add("var",Token.KEYWORD3);
33
			javaScriptKeywords.add("else",Token.KEYWORD1);
34
			javaScriptKeywords.add("for",Token.KEYWORD1);
35
			javaScriptKeywords.add("if",Token.KEYWORD1);
36
			javaScriptKeywords.add("in",Token.KEYWORD1);
37
			javaScriptKeywords.add("new",Token.KEYWORD1);
38
			javaScriptKeywords.add("return",Token.KEYWORD1);
39
			javaScriptKeywords.add("while",Token.KEYWORD1);
40
			javaScriptKeywords.add("with",Token.KEYWORD1);
41
			javaScriptKeywords.add("break",Token.KEYWORD1);
42
			javaScriptKeywords.add("case",Token.KEYWORD1);
43
			javaScriptKeywords.add("continue",Token.KEYWORD1);
44
			javaScriptKeywords.add("default",Token.KEYWORD1);
45
			javaScriptKeywords.add("false",Token.LABEL);
46
			javaScriptKeywords.add("this",Token.LABEL);
47
			javaScriptKeywords.add("true",Token.LABEL);
48
		}
49
		return javaScriptKeywords;
50
	}
51

  
52
	// private members
53
	private static KeywordMap javaScriptKeywords;
54
}
0 55

  
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/IDLTokenMarker.java
1
package com.iver.utiles.console.jedit;
2
/*
3
 * IDLTokenMarker.java - IDL token marker
4
 * Copyright (C) 1999 Slava Pestov
5
 * Copyright (C) 1999 Juha Lindfors
6
 *
7
 * You may use and modify this package for any purpose. Redistribution is
8
 * permitted, in both source and binary form, provided that this notice
9
 * remains intact in all source distributions of this package.
10
 */
11

  
12
import javax.swing.text.Segment;
13

  
14
/**
15
 * IDL token marker.
16
 *
17
 * @author Slava Pestov
18
 * @author Juha Lindfors
19
 * @version $Id$
20
 */
21
public class IDLTokenMarker extends CTokenMarker
22
{
23
	public IDLTokenMarker()
24
	{
25
		super(true,getKeywords());
26
	}
27

  
28
	public static KeywordMap getKeywords()
29
	{
30
		if(idlKeywords == null)
31
		{
32
			idlKeywords = new KeywordMap(false);
33

  
34
			idlKeywords.add("any",      Token.KEYWORD3);
35
			idlKeywords.add("attribute",Token.KEYWORD1);
36
			idlKeywords.add("boolean",  Token.KEYWORD3);
37
			idlKeywords.add("case",     Token.KEYWORD1);
38
			idlKeywords.add("char",     Token.KEYWORD3);
39
			idlKeywords.add("const",    Token.KEYWORD1);
40
			idlKeywords.add("context",  Token.KEYWORD1);
41
			idlKeywords.add("default",  Token.KEYWORD1);
42
			idlKeywords.add("double",   Token.KEYWORD3);
43
			idlKeywords.add("enum",     Token.KEYWORD3);
44
			idlKeywords.add("exception",Token.KEYWORD1);
45
			idlKeywords.add("FALSE",    Token.LITERAL2);
46
			idlKeywords.add("fixed",    Token.KEYWORD1);
47
			idlKeywords.add("float",    Token.KEYWORD3);
48
			idlKeywords.add("in",       Token.KEYWORD1);
49
			idlKeywords.add("inout",    Token.KEYWORD1);
50
			idlKeywords.add("interface",Token.KEYWORD1);
51
			idlKeywords.add("long",     Token.KEYWORD3);
52
			idlKeywords.add("module",   Token.KEYWORD1);
53
			idlKeywords.add("Object",   Token.KEYWORD3);
54
			idlKeywords.add("octet",    Token.KEYWORD3);
55
			idlKeywords.add("oneway",   Token.KEYWORD1);
56
			idlKeywords.add("out",      Token.KEYWORD1);
57
			idlKeywords.add("raises",   Token.KEYWORD1);
58
			idlKeywords.add("readonly", Token.KEYWORD1);
59
			idlKeywords.add("sequence", Token.KEYWORD3);
60
			idlKeywords.add("short",    Token.KEYWORD3);
61
			idlKeywords.add("string",   Token.KEYWORD3);
62
			idlKeywords.add("struct",   Token.KEYWORD3);
63
			idlKeywords.add("switch",   Token.KEYWORD1);
64
			idlKeywords.add("TRUE",     Token.LITERAL2);
65
			idlKeywords.add("typedef",  Token.KEYWORD3);
66
			idlKeywords.add("unsigned", Token.KEYWORD3);
67
			idlKeywords.add("union",    Token.KEYWORD3);
68
			idlKeywords.add("void",     Token.KEYWORD3);
69
			idlKeywords.add("wchar",    Token.KEYWORD3);
70
			idlKeywords.add("wstring",  Token.KEYWORD3);
71
		}
72
		return idlKeywords;
73
	}
74

  
75
	// private members
76
	private static KeywordMap idlKeywords;
77
}
0 78

  
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/MakefileTokenMarker.java
1
package com.iver.utiles.console.jedit;
2
/*
3
 * MakefileTokenMarker.java - Makefile token marker
4
 * Copyright (C) 1998, 1999 Slava Pestov
5
 *
6
 * You may use and modify this package for any purpose. Redistribution is
7
 * permitted, in both source and binary form, provided that this notice
8
 * remains intact in all source distributions of this package.
9
 */
10

  
11
import javax.swing.text.Segment;
12

  
13
/**
14
 * Makefile token marker.
15
 *
16
 * @author Slava Pestov
17
 * @version $Id$
18
 */
19
public class MakefileTokenMarker extends TokenMarker
20
{
21
	// public members
22
	public byte markTokensImpl(byte token, Segment line, int lineIndex)
23
	{
24
		char[] array = line.array;
25
		int offset = line.offset;
26
		int lastOffset = offset;
27
		int length = line.count + offset;
28
		boolean backslash = false;
29
loop:		for(int i = offset; i < length; i++)
30
		{
31
			int i1 = (i+1);
32

  
33
			char c = array[i];
34
			if(c == '\\')
35
			{
36
				backslash = !backslash;
37
				continue;
38
			}
39

  
40
			switch(token)
41
			{
42
			case Token.NULL:
43
				switch(c)
44
				{
45
				case ':': case '=': case ' ': case '\t':
46
					backslash = false;
47
					if(lastOffset == offset)
48
					{
49
						addToken(i1 - lastOffset,Token.KEYWORD1);
50
						lastOffset = i1;
51
					}
52
					break;
53
				case '#':
54
					if(backslash)
55
						backslash = false;
56
					else
57
					{
58
						addToken(i - lastOffset,token);
59
						addToken(length - i,Token.COMMENT1);
60
						lastOffset = length;
61
						break loop;
62
					}
63
					break;
64
				case '$':
65
					if(backslash)
66
						backslash = false;
67
					else if(lastOffset != offset)
68
					{
69
						addToken(i - lastOffset,token);
70
						lastOffset = i;
71
						if(length - i > 1)
72
						{
73
							char c1 = array[i1];
74
							if(c1 == '(' || c1 == '{')
75
								token = Token.KEYWORD2;
76
							else
77
							{
78
								addToken(2,Token.KEYWORD2);
79
								lastOffset += 2;
80
								i++;
81
							}
82
						}
83
					}
84
					break;
85
				case '"':
86
					if(backslash)
87
						backslash = false;
88
					else
89
					{
90
						addToken(i - lastOffset,token);
91
						token = Token.LITERAL1;
92
						lastOffset = i;
93
					}
94
					break;
95
				case '\'':
96
					if(backslash)
97
						backslash = false;
98
					else
99
					{
100
						addToken(i - lastOffset,token);
101
						token = Token.LITERAL2;
102
						lastOffset = i;
103
					}
104
					break;
105
				default:
106
					backslash = false;
107
					break;
108
				}
109
			case Token.KEYWORD2:
110
				backslash = false;
111
				if(c == ')' || c == '}')
112
				{
113
					addToken(i1 - lastOffset,token);
114
					token = Token.NULL;
115
					lastOffset = i1;
116
				}
117
				break;
118
			case Token.LITERAL1:
119
				if(backslash)
120
					backslash = false;
121
				else if(c == '"')
122
				{
123
					addToken(i1 - lastOffset,token);
124
					token = Token.NULL;
125
					lastOffset = i1;
126
				}
127
				else
128
					backslash = false;
129
				break;
130
			case Token.LITERAL2:
131
				if(backslash)
132
					backslash = false;
133
				else if(c == '\'')
134
				{
135
					addToken(i1 - lastOffset,Token.LITERAL1);
136
					token = Token.NULL;
137
					lastOffset = i1;
138
				}
139
				else
140
					backslash = false;
141
				break;
142
			}
143
		}
144
		switch(token)
145
		{
146
		case Token.KEYWORD2:
147
			addToken(length - lastOffset,Token.INVALID);
148
			token = Token.NULL;
149
			break;
150
		case Token.LITERAL2:
151
			addToken(length - lastOffset,Token.LITERAL1);
152
			break;
153
		default:
154
			addToken(length - lastOffset,token);
155
			break;
156
		}
157
		return token;
158
	}
159
}
0 160

  
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/TextUtilities.java
1
package com.iver.utiles.console.jedit;
2
/*
3
 * TextUtilities.java - Utility functions used by the text area classes
4
 * Copyright (C) 1999 Slava Pestov
5
 *
6
 * You may use and modify this package for any purpose. Redistribution is
7
 * permitted, in both source and binary form, provided that this notice
8
 * remains intact in all source distributions of this package.
9
 */
10

  
11
import javax.swing.text.*;
12

  
13
/**
14
 * Class with several utility functions used by the text area component.
15
 * @author Slava Pestov
16
 * @version $Id$
17
 */
18
public class TextUtilities
19
{
20
	/**
21
	 * Returns the offset of the bracket matching the one at the
22
	 * specified offset of the document, or -1 if the bracket is
23
	 * unmatched (or if the character is not a bracket).
24
	 * @param doc The document
25
	 * @param offset The offset
26
	 * @exception BadLocationException If an out-of-bounds access
27
	 * was attempted on the document text
28
	 */
29
	public static int findMatchingBracket(Document doc, int offset)
30
		throws BadLocationException
31
	{
32
		if(doc.getLength() == 0)
33
			return -1;
34
		char c = doc.getText(offset,1).charAt(0);
35
		char cprime; // c` - corresponding character
36
		boolean direction; // true = back, false = forward
37

  
38
		switch(c)
39
		{
40
		case '(': cprime = ')'; direction = false; break;
41
		case ')': cprime = '('; direction = true; break;
42
		case '[': cprime = ']'; direction = false; break;
43
		case ']': cprime = '['; direction = true; break;
44
		case '{': cprime = '}'; direction = false; break;
45
		case '}': cprime = '{'; direction = true; break;
46
		default: return -1;
47
		}
48

  
49
		int count;
50

  
51
		// How to merge these two cases is left as an exercise
52
		// for the reader.
53

  
54
		// Go back or forward
55
		if(direction)
56
		{
57
			// Count is 1 initially because we have already
58
			// `found' one closing bracket
59
			count = 1;
60

  
61
			// Get text[0,offset-1];
62
			String text = doc.getText(0,offset);
63

  
64
			// Scan backwards
65
			for(int i = offset - 1; i >= 0; i--)
66
			{
67
				// If text[i] == c, we have found another
68
				// closing bracket, therefore we will need
69
				// two opening brackets to complete the
70
				// match.
71
				char x = text.charAt(i);
72
				if(x == c)
73
					count++;
74

  
75
				// If text[i] == cprime, we have found a
76
				// opening bracket, so we return i if
77
				// --count == 0
78
				else if(x == cprime)
79
				{
80
					if(--count == 0)
81
						return i;
82
				}
83
			}
84
		}
85
		else
86
		{
87
			// Count is 1 initially because we have already
88
			// `found' one opening bracket
89
			count = 1;
90

  
91
			// So we don't have to + 1 in every loop
92
			offset++;
93

  
94
			// Number of characters to check
95
			int len = doc.getLength() - offset;
96

  
97
			// Get text[offset+1,len];
98
			String text = doc.getText(offset,len);
99

  
100
			// Scan forwards
101
			for(int i = 0; i < len; i++)
102
			{
103
				// If text[i] == c, we have found another
104
				// opening bracket, therefore we will need
105
				// two closing brackets to complete the
106
				// match.
107
				char x = text.charAt(i);
108

  
109
				if(x == c)
110
					count++;
111

  
112
				// If text[i] == cprime, we have found an
113
				// closing bracket, so we return i if
114
				// --count == 0
115
				else if(x == cprime)
116
				{
117
					if(--count == 0)
118
						return i + offset;
119
				}
120
			}
121
		}
122

  
123
		// Nothing found
124
		return -1;
125
	}
126

  
127
	/**
128
	 * Locates the start of the word at the specified position.
129
	 * @param line The text
130
	 * @param pos The position
131
	 */
132
	public static int findWordStart(String line, int pos, String noWordSep)
133
	{
134
		char ch = line.charAt(pos - 1);
135

  
136
		if(noWordSep == null)
137
			noWordSep = "";
138
		boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
139
			&& noWordSep.indexOf(ch) == -1);
140

  
141
		int wordStart = 0;
142
		for(int i = pos - 1; i >= 0; i--)
143
		{
144
			ch = line.charAt(i);
145
			if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
146
				noWordSep.indexOf(ch) == -1))
147
			{
148
				wordStart = i + 1;
149
				break;
150
			}
151
		}
152

  
153
		return wordStart;
154
	}
155

  
156
	/**
157
	 * Locates the end of the word at the specified position.
158
	 * @param line The text
159
	 * @param pos The position
160
	 */
161
	public static int findWordEnd(String line, int pos, String noWordSep)
162
	{
163
		char ch = line.charAt(pos);
164

  
165
		if(noWordSep == null)
166
			noWordSep = "";
167
		boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
168
			&& noWordSep.indexOf(ch) == -1);
169

  
170
		int wordEnd = line.length();
171
		for(int i = pos; i < line.length(); i++)
172
		{
173
			ch = line.charAt(i);
174
			if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
175
				noWordSep.indexOf(ch) == -1))
176
			{
177
				wordEnd = i;
178
				break;
179
			}
180
		}
181
		return wordEnd;
182
	}
183
}
0 184

  
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/Token.java
1
package com.iver.utiles.console.jedit;
2
/*
3
 * Token.java - Generic token
4
 * Copyright (C) 1998, 1999 Slava Pestov
5
 *
6
 * You may use and modify this package for any purpose. Redistribution is
7
 * permitted, in both source and binary form, provided that this notice
8
 * remains intact in all source distributions of this package.
9
 */
10

  
11
/**
12
 * A linked list of tokens. Each token has three fields - a token
13
 * identifier, which is a byte value that can be looked up in the
14
 * array returned by <code>SyntaxDocument.getColors()</code>
15
 * to get a color value, a length value which is the length of the
16
 * token in the text, and a pointer to the next token in the list.
17
 *
18
 * @author Slava Pestov
19
 * @version $Id$
20
 */
21
public class Token
22
{
23
	/**
24
	 * Normal text token id. This should be used to mark
25
	 * normal text.
26
	 */
27
	public static final byte NULL = 0;
28

  
29
	/**
30
	 * Comment 1 token id. This can be used to mark a comment.
31
	 */
32
	public static final byte COMMENT1 = 1;
33

  
34
	/**
35
	 * Comment 2 token id. This can be used to mark a comment.
36
	 */
37
	public static final byte COMMENT2 = 2;
38

  
39
	
40
	/**
41
	 * Literal 1 token id. This can be used to mark a string
42
	 * literal (eg, C mode uses this to mark "..." literals)
43
	 */
44
	public static final byte LITERAL1 = 3;
45

  
46
	/**
47
	 * Literal 2 token id. This can be used to mark an object
48
	 * literal (eg, Java mode uses this to mark true, false, etc)
49
	 */
50
	public static final byte LITERAL2 = 4;
51

  
52
	/**
53
	 * Label token id. This can be used to mark labels
54
	 * (eg, C mode uses this to mark ...: sequences)
55
	 */
56
	public static final byte LABEL = 5;
57

  
58
	/**
59
	 * Keyword 1 token id. This can be used to mark a
60
	 * keyword. This should be used for general language
61
	 * constructs.
62
	 */
63
	public static final byte KEYWORD1 = 6;
64

  
65
	/**
66
	 * Keyword 2 token id. This can be used to mark a
67
	 * keyword. This should be used for preprocessor
68
	 * commands, or variables.
69
	 */
70
	public static final byte KEYWORD2 = 7;
71

  
72
	/**
73
	 * Keyword 3 token id. This can be used to mark a
74
	 * keyword. This should be used for data types.
75
	 */
76
	public static final byte KEYWORD3 = 8;
77

  
78
	/**
79
	 * Operator token id. This can be used to mark an
80
	 * operator. (eg, SQL mode marks +, -, etc with this
81
	 * token type)
82
	 */
83
	public static final byte OPERATOR = 9;
84

  
85
	/**
86
	 * Invalid token id. This can be used to mark invalid
87
	 * or incomplete tokens, so the user can easily spot
88
	 * syntax errors.
89
	 */
90
	public static final byte INVALID = 10;
91

  
92
	/**
93
	 * The total number of defined token ids.
94
	 */
95
	public static final byte ID_COUNT = 11;
96

  
97
	/**
98
	 * The first id that can be used for internal state
99
	 * in a token marker.
100
	 */
101
	public static final byte INTERNAL_FIRST = 100;
102

  
103
	/**
104
	 * The last id that can be used for internal state
105
	 * in a token marker.
106
	 */
107
	public static final byte INTERNAL_LAST = 126;
108

  
109
	/**
110
	 * The token type, that along with a length of 0
111
	 * marks the end of the token list.
112
	 */
113
	public static final byte END = 127;
114

  
115
	/**
116
	 * The length of this token.
117
	 */
118
	public int length;
119

  
120
	/**
121
	 * The id of this token.
122
	 */
123
	public byte id;
124

  
125
	/**
126
	 * The next token in the linked list.
127
	 */
128
	public Token next;
129

  
130
	/**
131
	 * Creates a new token.
132
	 * @param length The length of the token
133
	 * @param id The id of the token
134
	 */
135
	public Token(int length, byte id)
136
	{
137
		this.length = length;
138
		this.id = id;
139
	}
140

  
141
	/**
142
	 * Returns a string representation of this token.
143
	 */
144
	public String toString()
145
	{
146
		return "[id=" + id + ",length=" + length + "]";
147
	}
148
}
0 149

  
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/TokenMarker.java
1
package com.iver.utiles.console.jedit;
2
/*
3
 * TokenMarker.java - Generic token marker
4
 * Copyright (C) 1998, 1999 Slava Pestov
5
 *
6
 * You may use and modify this package for any purpose. Redistribution is
7
 * permitted, in both source and binary form, provided that this notice
8
 * remains intact in all source distributions of this package.
9
 */
10

  
11
import javax.swing.text.Segment;
12
import java.util.*;
13

  
14
/**
15
 * A token marker that splits lines of text into tokens. Each token carries
16
 * a length field and an indentification tag that can be mapped to a color
17
 * for painting that token.<p>
18
 *
19
 * For performance reasons, the linked list of tokens is reused after each
20
 * line is tokenized. Therefore, the return value of <code>markTokens</code>
21
 * should only be used for immediate painting. Notably, it cannot be
22
 * cached.
23
 *
24
 * @author Slava Pestov
25
 * @version $Id$
26
 *
27
 * @see org.gjt.sp.jedit.syntax.Token
28
 */
29
public abstract class TokenMarker
30
{
31
	/**
32
	 * A wrapper for the lower-level <code>markTokensImpl</code> method
33
	 * that is called to split a line up into tokens.
34
	 * @param line The line
35
	 * @param lineIndex The line number
36
	 */
37
	public Token markTokens(Segment line, int lineIndex)
38
	{
39
		if(lineIndex >= length)
40
		{
41
			throw new IllegalArgumentException("Tokenizing invalid line: "
42
				+ lineIndex);
43
		}
44

  
45
		lastToken = null;
46

  
47
		LineInfo info = lineInfo[lineIndex];
48
		LineInfo prev;
49
		if(lineIndex == 0)
50
			prev = null;
51
		else
52
			prev = lineInfo[lineIndex - 1];
53

  
54
		byte oldToken = info.token;
55
		byte token = markTokensImpl(prev == null ?
56
			Token.NULL : prev.token,line,lineIndex);
57

  
58
		info.token = token;
59

  
60
		/*
61
		 * This is a foul hack. It stops nextLineRequested
62
		 * from being cleared if the same line is marked twice.
63
		 *
64
		 * Why is this necessary? It's all JEditTextArea's fault.
65
		 * When something is inserted into the text, firing a
66
		 * document event, the insertUpdate() method shifts the
67
		 * caret (if necessary) by the amount inserted.
68
		 *
69
		 * All caret movement is handled by the select() method,
70
		 * which eventually pipes the new position to scrollTo()
71
		 * and calls repaint().
72
		 *
73
		 * Note that at this point in time, the new line hasn't
74
		 * yet been painted; the caret is moved first.
75
		 *
76
		 * scrollTo() calls offsetToX(), which tokenizes the line
77
		 * unless it is being called on the last line painted
78
		 * (in which case it uses the text area's painter cached
79
		 * token list). What scrollTo() does next is irrelevant.
80
		 *
81
		 * After scrollTo() has done it's job, repaint() is
82
		 * called, and eventually we end up in paintLine(), whose
83
		 * job is to paint the changed line. It, too, calls
84
		 * markTokens().
85
		 *
86
		 * The problem was that if the line started a multiline
87
		 * token, the first markTokens() (done in offsetToX())
88
		 * would set nextLineRequested (because the line end
89
		 * token had changed) but the second would clear it
90
		 * (because the line was the same that time) and therefore
91
		 * paintLine() would never know that it needed to repaint
92
		 * subsequent lines.
93
		 *
94
		 * This bug took me ages to track down, that's why I wrote
95
		 * all the relevant info down so that others wouldn't
96
		 * duplicate it.
97
		 */
98
		 if(!(lastLine == lineIndex && nextLineRequested))
99
			nextLineRequested = (oldToken != token);
100

  
101
		lastLine = lineIndex;
102

  
103
		addToken(0,Token.END);
104

  
105
		return firstToken;
106
	}
107

  
108
	/**
109
	 * An abstract method that splits a line up into tokens. It
110
	 * should parse the line, and call <code>addToken()</code> to
111
	 * add syntax tokens to the token list. Then, it should return
112
	 * the initial token type for the next line.<p>
113
	 *
114
	 * For example if the current line contains the start of a 
115
	 * multiline comment that doesn't end on that line, this method
116
	 * should return the comment token type so that it continues on
117
	 * the next line.
118
	 *
119
	 * @param token The initial token type for this line
120
	 * @param line The line to be tokenized
121
	 * @param lineIndex The index of the line in the document,
122
	 * starting at 0
123
	 * @return The initial token type for the next line
124
	 */
125
	protected abstract byte markTokensImpl(byte token, Segment line,
126
		int lineIndex);
127

  
128
	/**
129
	 * Returns if the token marker supports tokens that span multiple
130
	 * lines. If this is true, the object using this token marker is
131
	 * required to pass all lines in the document to the
132
	 * <code>markTokens()</code> method (in turn).<p>
133
	 *
134
	 * The default implementation returns true; it should be overridden
135
	 * to return false on simpler token markers for increased speed.
136
	 */
137
	public boolean supportsMultilineTokens()
138
	{
139
		return true;
140
	}
141

  
142
	/**
143
	 * Informs the token marker that lines have been inserted into
144
	 * the document. This inserts a gap in the <code>lineInfo</code>
145
	 * array.
146
	 * @param index The first line number
147
	 * @param lines The number of lines 
148
	 */
149
	public void insertLines(int index, int lines)
150
	{
151
		if(lines <= 0)
152
			return;
153
		length += lines;
154
		ensureCapacity(length);
155
		int len = index + lines;
156
		System.arraycopy(lineInfo,index,lineInfo,len,
157
			lineInfo.length - len);
158

  
159
		for(int i = index + lines - 1; i >= index; i--)
160
		{
161
			lineInfo[i] = new LineInfo();
162
		}
163
	}
164
	
165
	/**
166
	 * Informs the token marker that line have been deleted from
167
	 * the document. This removes the lines in question from the
168
	 * <code>lineInfo</code> array.
169
	 * @param index The first line number
170
	 * @param lines The number of lines
171
	 */
172
	public void deleteLines(int index, int lines)
173
	{
174
		if (lines <= 0)
175
			return;
176
		int len = index + lines;
177
		length -= lines;
178
		System.arraycopy(lineInfo,len,lineInfo,
179
			index,lineInfo.length - len);
180
	}
181

  
182
	/**
183
	 * Returns the number of lines in this token marker.
184
	 */
185
	public int getLineCount()
186
	{
187
		return length;
188
	}
189

  
190
	/**
191
	 * Returns true if the next line should be repainted. This
192
	 * will return true after a line has been tokenized that starts
193
	 * a multiline token that continues onto the next line.
194
	 */
195
	public boolean isNextLineRequested()
196
	{
197
		return nextLineRequested;
198
	}
199

  
200
	// protected members
201

  
202
	/**
203
	 * The first token in the list. This should be used as the return
204
	 * value from <code>markTokens()</code>.
205
	 */
206
	protected Token firstToken;
207

  
208
	/**
209
	 * The last token in the list. New tokens are added here.
210
	 * This should be set to null before a new line is to be tokenized.
211
	 */
212
	protected Token lastToken;
213

  
214
	/**
215
	 * An array for storing information about lines. It is enlarged and
216
	 * shrunk automatically by the <code>insertLines()</code> and
217
	 * <code>deleteLines()</code> methods.
218
	 */
219
	protected LineInfo[] lineInfo;
220

  
221
	/**
222
	 * The number of lines in the model being tokenized. This can be
223
	 * less than the length of the <code>lineInfo</code> array.
224
	 */
225
	protected int length;
226

  
227
	/**
228
	 * The last tokenized line.
229
	 */
230
	protected int lastLine;
231

  
232
	/**
233
	 * True if the next line should be painted.
234
	 */
235
	protected boolean nextLineRequested;
236

  
237
	/**
238
	 * Creates a new <code>TokenMarker</code>. This DOES NOT create
239
	 * a lineInfo array; an initial call to <code>insertLines()</code>
240
	 * does that.
241
	 */
242
	protected TokenMarker()
243
	{
244
		lastLine = -1;
245
	}
246

  
247
	/**
248
	 * Ensures that the <code>lineInfo</code> array can contain the
249
	 * specified index. This enlarges it if necessary. No action is
250
	 * taken if the array is large enough already.<p>
251
	 *
252
	 * It should be unnecessary to call this under normal
253
	 * circumstances; <code>insertLine()</code> should take care of
254
	 * enlarging the line info array automatically.
255
	 *
256
	 * @param index The array index
257
	 */
258
	protected void ensureCapacity(int index)
259
	{
260
		if(lineInfo == null)
261
			lineInfo = new LineInfo[index + 1];
262
		else if(lineInfo.length <= index)
263
		{
264
			LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2];
265
			System.arraycopy(lineInfo,0,lineInfoN,0,
266
					 lineInfo.length);
267
			lineInfo = lineInfoN;
268
		}
269
	}
270

  
271
	/**
272
	 * Adds a token to the token list.
273
	 * @param length The length of the token
274
	 * @param id The id of the token
275
	 */
276
	protected void addToken(int length, byte id)
277
	{
278
		if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST)
279
			throw new InternalError("Invalid id: " + id);
280

  
281
		if(length == 0 && id != Token.END)
282
			return;
283

  
284
		if(firstToken == null)
285
		{
286
			firstToken = new Token(length,id);
287
			lastToken = firstToken;
288
		}
289
		else if(lastToken == null)
290
		{
291
			lastToken = firstToken;
292
			firstToken.length = length;
293
			firstToken.id = id;
294
		}
295
		else if(lastToken.next == null)
296
		{
297
			lastToken.next = new Token(length,id);
298
			lastToken = lastToken.next;
299
		}
300
		else
301
		{
302
			lastToken = lastToken.next;
303
			lastToken.length = length;
304
			lastToken.id = id;
305
		}
306
	}
307

  
308
	/**
309
	 * Inner class for storing information about tokenized lines.
310
	 */
311
	public class LineInfo
312
	{
313
		/**
314
		 * Creates a new LineInfo object with token = Token.NULL
315
		 * and obj = null.
316
		 */
317
		public LineInfo()
318
		{
319
		}
320

  
321
		/**
322
		 * Creates a new LineInfo object with the specified
323
		 * parameters.
324
		 */
325
		public LineInfo(byte token, Object obj)
326
		{
327
			this.token = token;
328
			this.obj = obj;
329
		}
330

  
331
		/**
332
		 * The id of the last token of the line.
333
		 */
334
		public byte token;
335

  
336
		/**
337
		 * This is for use by the token marker implementations
338
		 * themselves. It can be used to store anything that
339
		 * is an object and that needs to exist on a per-line
340
		 * basis.
341
		 */
342
		public Object obj;
343
	}
344
}
0 345

  
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/SyntaxUtilities.java
1
package com.iver.utiles.console.jedit;
2
/*
3
 * SyntaxUtilities.java - Utility functions used by syntax colorizing
4
 * Copyright (C) 1999 Slava Pestov
5
 *
6
 * You may use and modify this package for any purpose. Redistribution is
7
 * permitted, in both source and binary form, provided that this notice
8
 * remains intact in all source distributions of this package.
9
 */
10

  
11
import javax.swing.text.*;
12
import java.awt.*;
13

  
14
/**
15
 * Class with several utility functions used by jEdit's syntax colorizing
16
 * subsystem.
17
 *
18
 * @author Slava Pestov
19
 * @version $Id$
20
 */
21
public class SyntaxUtilities
22
{
23
	/**
24
	 * Checks if a subregion of a <code>Segment</code> is equal to a
25
	 * string.
26
	 * @param ignoreCase True if case should be ignored, false otherwise
27
	 * @param text The segment
28
	 * @param offset The offset into the segment
29
	 * @param match The string to match
30
	 */
31
	public static boolean regionMatches(boolean ignoreCase, Segment text,
32
					    int offset, String match)
33
	{
34
		int length = offset + match.length();
35
		char[] textArray = text.array;
36
		if(length > text.offset + text.count)
37
			return false;
38
		for(int i = offset, j = 0; i < length; i++, j++)
39
		{
40
			char c1 = textArray[i];
41
			char c2 = match.charAt(j);
42
			if(ignoreCase)
43
			{
44
				c1 = Character.toUpperCase(c1);
45
				c2 = Character.toUpperCase(c2);
46
			}
47
			if(c1 != c2)
48
				return false;
49
		}
50
		return true;
51
	}
52
	
53
	/**
54
	 * Checks if a subregion of a <code>Segment</code> is equal to a
55
	 * character array.
56
	 * @param ignoreCase True if case should be ignored, false otherwise
57
	 * @param text The segment
58
	 * @param offset The offset into the segment
59
	 * @param match The character array to match
60
	 */
61
	public static boolean regionMatches(boolean ignoreCase, Segment text,
62
					    int offset, char[] match)
63
	{
64
		int length = offset + match.length;
65
		char[] textArray = text.array;
66
		if(length > text.offset + text.count)
67
			return false;
68
		for(int i = offset, j = 0; i < length; i++, j++)
69
		{
70
			char c1 = textArray[i];
71
			char c2 = match[j];
72
			if(ignoreCase)
73
			{
74
				c1 = Character.toUpperCase(c1);
75
				c2 = Character.toUpperCase(c2);
76
			}
77
			if(c1 != c2)
78
				return false;
79
		}
80
		return true;
81
	}
82

  
83
	/**
84
	 * Returns the default style table. This can be passed to the
85
	 * <code>setStyles()</code> method of <code>SyntaxDocument</code>
86
	 * to use the default syntax styles.
87
	 */
88
	public static SyntaxStyle[] getDefaultSyntaxStyles()
89
	{
90
		SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
91

  
92
		styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false);
93
		styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false);
94
		styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true);
95
		styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false);
96
		styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false);
97
		styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false);
98
		styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true);
99
		styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true);
100
		styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true);
101
		styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true);
102

  
103
		return styles;
104
	}
105

  
106
	/**
107
	 * Paints the specified line onto the graphics context. Note that this
108
	 * method munges the offset and count values of the segment.
109
	 * @param line The line segment
110
	 * @param tokens The token list for the line
111
	 * @param styles The syntax style list
112
	 * @param expander The tab expander used to determine tab stops. May
113
	 * be null
114
	 * @param gfx The graphics context
115
	 * @param x The x co-ordinate
116
	 * @param y The y co-ordinate
117
	 * @return The x co-ordinate, plus the width of the painted string
118
	 */
119
	public static int paintSyntaxLine(Segment line, Token tokens,
120
		SyntaxStyle[] styles, TabExpander expander, Graphics gfx,
121
		int x, int y)
122
	{
123
		Font defaultFont = gfx.getFont();
124
		Color defaultColor = gfx.getColor();
125

  
126
		int offset = 0;
127
		for(;;)
128
		{
129
			byte id = tokens.id;
130
			if(id == Token.END)
131
				break;
132

  
133
			int length = tokens.length;
134
			if(id == Token.NULL)
135
			{
136
				if(!defaultColor.equals(gfx.getColor()))
137
					gfx.setColor(defaultColor);
138
				if(!defaultFont.equals(gfx.getFont()))
139
					gfx.setFont(defaultFont);
140
			}
141
			else
142
				styles[id].setGraphicsFlags(gfx,defaultFont);
143

  
144
			line.count = length;
145
			x = Utilities.drawTabbedText(line,x,y,gfx,expander,0);
146
			line.offset += length;
147
			offset += length;
148

  
149
			tokens = tokens.next;
150
		}
151

  
152
		return x;
153
	}
154

  
155
	// private members
156
	private SyntaxUtilities() {}
157
}
0 158

  
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/KeywordMap.java
1
package com.iver.utiles.console.jedit;
2
/*
3
 * KeywordMap.java - Fast keyword->id map
4
 * Copyright (C) 1998, 1999 Slava Pestov
5
 * Copyright (C) 1999 Mike Dillon
6
 *
7
 * You may use and modify this package for any purpose. Redistribution is
8
 * permitted, in both source and binary form, provided that this notice
9
 * remains intact in all source distributions of this package.
10
 */
11

  
12
import javax.swing.text.Segment;
13

  
14
/**
15
 * A <code>KeywordMap</code> is similar to a hashtable in that it maps keys
16
 * to values. However, the `keys' are Swing segments. This allows lookups of
17
 * text substrings without the overhead of creating a new string object.
18
 * <p>
19
 * This class is used by <code>CTokenMarker</code> to map keywords to ids.
20
 *
21
 * @author Slava Pestov, Mike Dillon
22
 * @version $Id$
23
 */
24
public class KeywordMap
25
{
26
	/**
27
	 * Creates a new <code>KeywordMap</code>.
28
	 * @param ignoreCase True if keys are case insensitive
29
	 */
30
	public KeywordMap(boolean ignoreCase)
31
	{
32
		this(ignoreCase, 52);
33
		this.ignoreCase = ignoreCase;
34
	}
35

  
36
	/**
37
	 * Creates a new <code>KeywordMap</code>.
38
	 * @param ignoreCase True if the keys are case insensitive
39
	 * @param mapLength The number of `buckets' to create.
40
	 * A value of 52 will give good performance for most maps.
41
	 */
42
	public KeywordMap(boolean ignoreCase, int mapLength)
43
	{
44
		this.mapLength = mapLength;
45
		this.ignoreCase = ignoreCase;
46
		map = new Keyword[mapLength];
47
	}
48

  
49
	/**
50
	 * Looks up a key.
51
	 * @param text The text segment
52
	 * @param offset The offset of the substring within the text segment
53
	 * @param length The length of the substring
54
	 */
55
	public byte lookup(Segment text, int offset, int length)
56
	{
57
		if(length == 0)
58
			return Token.NULL;
59
		Keyword k = map[getSegmentMapKey(text, offset, length)];
60
		while(k != null)
61
		{
62
			if(length != k.keyword.length)
63
			{
64
				k = k.next;
65
				continue;
66
			}
67
			if(SyntaxUtilities.regionMatches(ignoreCase,text,offset,
68
				k.keyword))
69
				return k.id;
70
			k = k.next;
71
		}
72
		return Token.NULL;
73
	}
74

  
75
	/**
76
	 * Adds a key-value mapping.
77
	 * @param keyword The key
78
	 * @Param id The value
79
	 */
80
	public void add(String keyword, byte id)
81
	{
82
		int key = getStringMapKey(keyword);
83
		map[key] = new Keyword(keyword.toCharArray(),id,map[key]);
84
	}
85

  
86
	/**
87
	 * Returns true if the keyword map is set to be case insensitive,
88
	 * false otherwise.
89
	 */
90
	public boolean getIgnoreCase()
91
	{
92
		return ignoreCase;
93
	}
94

  
95
	/**
96
	 * Sets if the keyword map should be case insensitive.
97
	 * @param ignoreCase True if the keyword map should be case
98
	 * insensitive, false otherwise
99
	 */
100
	public void setIgnoreCase(boolean ignoreCase)
101
	{
102
		this.ignoreCase = ignoreCase;
103
	}
104

  
105
	// protected members
106
	protected int mapLength;
107

  
108
	protected int getStringMapKey(String s)
109
	{
110
		return (Character.toUpperCase(s.charAt(0)) +
111
				Character.toUpperCase(s.charAt(s.length()-1)))
112
				% mapLength;
113
	}
114

  
115
	protected int getSegmentMapKey(Segment s, int off, int len)
116
	{
117
		return (Character.toUpperCase(s.array[off]) +
118
				Character.toUpperCase(s.array[off + len - 1]))
119
				% mapLength;
120
	}
121

  
122
	// private members
123
	class Keyword
124
	{
125
		public Keyword(char[] keyword, byte id, Keyword next)
126
		{
127
			this.keyword = keyword;
128
			this.id = id;
129
			this.next = next;
130
		}
131

  
132
		public char[] keyword;
133
		public byte id;
134
		public Keyword next;
135
	}
136

  
137
	private Keyword[] map;
138
	private boolean ignoreCase;
139
}
0 140

  
trunk/libraries/libIverUtiles/src/com/iver/utiles/console/jedit/PythonTokenMarker.java
1
package com.iver.utiles.console.jedit;
2
/*
3
 * PythonTokenMarker.java - Python token marker
4
 * Copyright (C) 1999 Jonathan Revusky
5
 * Copyright (C) 1998, 1999 Slava Pestov
6
 *
7
 * You may use and modify this package for any purpose. Redistribution is
8
 * permitted, in both source and binary form, provided that this notice
9
 * remains intact in all source distributions of this package.
10
 */
11

  
12
import javax.swing.text.Segment;
13

  
14
/**
15
 * Python token marker.
16
 *
17
 * @author Jonathan Revusky
18
 * @version $Id$
19
 */
20
public class PythonTokenMarker extends TokenMarker
21
{
22
	private static final byte TRIPLEQUOTE1 = Token.INTERNAL_FIRST;
23
	private static final byte TRIPLEQUOTE2 = Token.INTERNAL_LAST;
24

  
25
	public PythonTokenMarker()
26
	{
27
		this.keywords = getKeywords();
28
	}
29

  
30
	public byte markTokensImpl(byte token, Segment line, int lineIndex)
31
	{
32
		char[] array = line.array;
33
		int offset = line.offset;
34
		lastOffset = offset;
35
		lastKeyword = offset;
36
		int length = line.count + offset;
37
		boolean backslash = false;
38

  
39
loop:		for(int i = offset; i < length; i++)
40
		{
41
			int i1 = (i+1);
42

  
43
			char c = array[i];
44
			if(c == '\\')
45
			{
46
				backslash = !backslash;
47
				continue;
48
			}
49

  
50
			switch(token)
51
			{
52
			case Token.NULL:
53
				switch(c)
54
				{
55
				case '#':
56
					if(backslash)
57
						backslash = false;
58
					else
59
					{
60
						doKeyword(line,i,c);
61
						addToken(i - lastOffset,token);
62
						addToken(length - i,Token.COMMENT1);
63
						lastOffset = lastKeyword = length;
64
						break loop;
65
					}
66
					break;
67
				case '"':
68
					doKeyword(line,i,c);
69
					if(backslash)
70
						backslash = false;
71
					else
72
					{
73
						addToken(i - lastOffset,token);
74
						if(SyntaxUtilities.regionMatches(false,
75
							line,i1,"\"\""))
76
						{
77
							token = TRIPLEQUOTE1;
78
						}
79
						else
80
						{
81
							token = Token.LITERAL1;
82
						}
83
						lastOffset = lastKeyword = i;
84
					}
85
					break;
86
				case '\'':
87
					doKeyword(line,i,c);
88
					if(backslash)
89
						backslash = false;
90
					else
91
					{
92
						addToken(i - lastOffset,token);
93
						if(SyntaxUtilities.regionMatches(false,
94
							line,i1,"''"))
95
						{
96
							token = TRIPLEQUOTE2;
97
						}
98
						else
99
						{
100
							token = Token.LITERAL2;
101
						}
102
						lastOffset = lastKeyword = i;
103
					}
104
					break;
105
				default:
106
					backslash = false;
107
					if(!Character.isLetterOrDigit(c)
108
						&& c != '_')
109
						doKeyword(line,i,c);
110
					break;
111
				}
112
				break;
113
			case Token.LITERAL1:
114
				if(backslash)
115
					backslash = false;
116
				else if(c == '"')
117
				{
118
					addToken(i1 - lastOffset,token);
119
					token = Token.NULL;
120
					lastOffset = lastKeyword = i1;
121
				}
122
				break;
123
			case Token.LITERAL2:
124
				if(backslash)
125
					backslash = false;
126
				else if(c == '\'')
127
				{
128
					addToken(i1 - lastOffset,Token.LITERAL1);
129
					token = Token.NULL;
130
					lastOffset = lastKeyword = i1;
131
				}
132
				break;
133
			case TRIPLEQUOTE1:
134
				if(backslash)
135
					backslash = false;
136
				else if(SyntaxUtilities.regionMatches(false,
137
					line,i,"\"\"\""))
138
				{
139
					addToken((i+=4) - lastOffset,
140
						Token.LITERAL1);
141
					token = Token.NULL;
142
					lastOffset = lastKeyword = i;
143
				}
144
				break;
145
			case TRIPLEQUOTE2:
146
				if(backslash)
147
					backslash = false;
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff