This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 19570
Collapse All | Expand All

(-)AbstractInterp.java (-4 / +50 lines)
Lines 24-37 Link Here
24
public abstract class AbstractInterp implements Interp {
24
public abstract class AbstractInterp implements Interp {
25
25
26
    protected interface Actor {
26
    protected interface Actor {
27
	public String action(char c);
27
	public String action(AbstractInterp interp, char c);
28
    }
28
    }
29
29
30
    protected class State {
30
    protected static class State {
31
31
32
	// some generic actors
32
	// some generic actors
33
	Actor act_error = new Actor() {
33
	Actor act_error = new Actor() {
34
	    public String action(char c) {
34
	    public String action(AbstractInterp ai, char c) {
35
		return "generic error";	// NOI18N
35
		return "generic error";	// NOI18N
36
	    } 
36
	    } 
37
	};
37
	};
Lines 80-88 Link Here
80
	} 
80
	} 
81
    };
81
    };
82
82
83
    protected Ops ops;
83
    // Why make these be public and not protected?
84
    // Someone might inherit from us in a package other than org.netbeans
85
    // and while the inherited Interp will see these if they are protected, 
86
    // the corresponding InterpType won't.
87
88
    /*
89
    */
90
    public Ops ops;
91
    public State state;	// current state
84
92
93
    /*
94
    protected Ops ops;
85
    protected State state;	// current state
95
    protected State state;	// current state
96
    */
86
97
87
    protected AbstractInterp(Ops ops) {
98
    protected AbstractInterp(Ops ops) {
88
	this.ops = ops;
99
	this.ops = ops;
Lines 91-95 Link Here
91
    public void reset() {
102
    public void reset() {
92
	;
103
	;
93
    } 
104
    } 
105
106
    /*
107
     * Management of number parsing
108
     */
109
110
    private static final int max_numbers = 5;
111
    private int numberx = 0;
112
    private String number[] = new String[max_numbers];
113
114
    protected void resetNumber() {
115
	for (int x = 0; x < max_numbers; x++) {
116
	    number[x] = new String();
117
	}
118
	numberx = 0;
119
    }
120
    protected void remember_digit(char c) {
121
	number[numberx] += c;
122
    }
123
    protected boolean pushNumber() {
124
	numberx++;
125
	return (numberx < max_numbers);
126
    }
127
    protected boolean noNumber() {
128
	return number[0].equals("");	// NOI18N
129
    }
130
    protected int numberAt(int position) {
131
	if (position > numberx) {
132
	    return 1;
133
	}
134
	return Integer.parseInt(number[position]);
135
    }
136
    protected int nNumbers() {
137
	return numberx;
138
    }
139
94
140
95
} 
141
} 
(-)Buffer.java (-5 / +9 lines)
Lines 49-62 Link Here
49
    private OurVector lines = new OurVector();	// buffer
49
    private OurVector lines = new OurVector();	// buffer
50
50
51
    public int nlines;		// number of lines in buffer
51
    public int nlines;		// number of lines in buffer
52
				// How is tis different from lines.length?
52
				// How is this different from lines.length?
53
53
54
    private int _cols;
54
    private int visible_cols;	// number of columns visible in view
55
56
    public int visible_cols;	// number of columns visible in view
57
    private int extra_cols;	// columns needed to support lines longer
55
    private int extra_cols;	// columns needed to support lines longer
58
				// than visible_cols. Only grows.
56
				// than visible_cols. Only grows.
59
57
58
    public int visibleCols() {
59
	return visible_cols;
60
    } 
61
60
    public int totalCols() {
62
    public int totalCols() {
61
	return visible_cols + extra_cols;
63
	return visible_cols + extra_cols;
62
    } 
64
    } 
Lines 75-81 Link Here
75
77
76
    /*
78
    /*
77
     * Keep track of the largest column # to help set the extent of 
79
     * Keep track of the largest column # to help set the extent of 
78
     * the horizaontal scrollbar.
80
     * the horizontal scrollbar.
79
     */
81
     */
80
    public void noteColumn(int col) {
82
    public void noteColumn(int col) {
81
	int new_extra = col - visible_cols;
83
	int new_extra = col - visible_cols;
Lines 101-108 Link Here
101
	try {
103
	try {
102
	    return (Line) lines.elementAt(brow);
104
	    return (Line) lines.elementAt(brow);
103
	} catch(ArrayIndexOutOfBoundsException x) {
105
	} catch(ArrayIndexOutOfBoundsException x) {
106
	    /* DEBUG
104
	    System.out.println("Buffer.lineAt(" +brow+ ") -> null\n");// NOI18N
107
	    System.out.println("Buffer.lineAt(" +brow+ ") -> null\n");// NOI18N
105
	    Thread.dumpStack();
108
	    Thread.dumpStack();
109
	    */
106
	    return null;
110
	    return null;
107
	} 
111
	} 
108
    } 
112
    } 
(-)InterpANSI.java (-314 / +288 lines)
Lines 23-381 Link Here
23
23
24
package org.netbeans.lib.terminalemulator;
24
package org.netbeans.lib.terminalemulator;
25
25
26
/* OLD
27
import java.lang.Class;
28
import java.lang.reflect.Method;
29
*/
30
31
public class InterpANSI extends InterpDumb {
26
public class InterpANSI extends InterpDumb {
32
27
33
    protected InterpANSI(Ops ops) {
28
    protected static class InterpTypeANSI extends InterpTypeDumb {
34
	super(ops);
29
	protected final State st_esc = new State("esc");	// NOI18N
35
	setup();
30
	protected final State st_esc_lb = new State("esc_lb");	// NOI18N
36
    } 
31
37
32
	protected final Actor act_reset_number = new ACT_RESET_NUMBER();
38
    public String name() {
33
	protected final Actor act_remember_digit = new ACT_REMEMBER_DIGIT();
39
	return "ansi";	// NOI18N
34
40
    } 
35
	protected InterpTypeANSI() {
41
36
	    st_base.setAction((char) 27, st_esc, new ACT_TO_ESC());
42
    public void reset() {
37
43
	super.reset();
38
	    st_esc.setRegular(st_esc, act_regular);
44
    }
39
	    st_esc.setAction('7', st_base, new ACT_SC());
45
40
	    st_esc.setAction('8', st_base, new ACT_RC());
46
    /*
41
	    st_esc.setAction('c', st_base, new ACT_FULL_RESET());
47
     * Management of number parsing
42
	    st_esc.setAction('[', st_esc_lb, act_reset_number);
48
     */
43
49
44
50
    private static final int max_numbers = 5;
45
	    st_esc_lb.setRegular(st_esc_lb, act_regular);
51
    private int numberx = 0;
46
	    for (char c = '0'; c <= '9'; c++)
52
    private String number[] = new String[max_numbers];
47
		st_esc_lb.setAction(c, st_esc_lb, act_remember_digit);
53
48
	    st_esc_lb.setAction(';', st_esc_lb, new ACT_PUSH_NUMBER());
54
    protected void resetNumber() {
49
	    st_esc_lb.setAction('A', st_base, new ACT_UP());
55
	for (int x = 0; x < max_numbers; x++) {
50
	    st_esc_lb.setAction('B', st_base, new ACT_DO());
56
	    number[x] = new String();
51
	    st_esc_lb.setAction('C', st_base, new ACT_ND());
57
	}
52
	    st_esc_lb.setAction('D', st_base, new ACT_BC());
58
	numberx = 0;
53
	    st_esc_lb.setAction('H', st_base, new ACT_HO());
59
    }
54
	    st_esc_lb.setAction('i', st_base, new ACT_PRINT());
60
    protected void remember_digit(char c) {
55
	    st_esc_lb.setAction('J', st_base, new ACT_J());
61
	number[numberx] += c;
56
	    st_esc_lb.setAction('K', st_base, new ACT_K());
62
    }
57
	    st_esc_lb.setAction('L', st_base, new ACT_AL());
63
    protected boolean pushNumber() {
58
	    st_esc_lb.setAction('M', st_base, new ACT_DL());
64
	numberx++;
59
	    st_esc_lb.setAction('m', st_base, new ACT_ATTR());
65
	return (numberx < max_numbers);
60
	    st_esc_lb.setAction('n', st_base, new ACT_DSR());
66
    }
61
	    st_esc_lb.setAction('P', st_base, new ACT_DC());
67
    protected boolean noNumber() {
62
	    st_esc_lb.setAction('h', st_base, new ACT_SM());
68
	return number[0].equals("");	// NOI18N
63
	    st_esc_lb.setAction('l', st_base, new ACT_RM());
69
    }
64
	    st_esc_lb.setAction('r', st_base, new ACT_MARGIN());
70
    protected int numberAt(int position) {
65
	    st_esc_lb.setAction('t', st_base, new ACT_GLYPH());
71
	if (position > numberx) {
66
	    st_esc_lb.setAction('@', st_base, new ACT_IC());
72
	    return 1;
67
	}
73
	}
68
74
	return Integer.parseInt(number[position]);
69
	protected final class ACT_TO_ESC implements Actor {
75
    }
70
	    public String action(AbstractInterp ai, char c) {
76
    protected int nNumbers() {
71
		InterpDumb i = (InterpDumb) ai;
77
	return numberx;
72
		i.ctl_sequence = "";	// NOI18N
78
    }
73
		return null;
79
74
	    }
80
81
    protected State st_esc = new State("esc");	// NOI18N
82
    protected State st_esc_lb = new State("esc_lb");	// NOI18N
83
84
    private void setup() {
85
	st_base.setAction((char) 27, st_esc, new ACT_TO_ESC());
86
87
	st_esc.setRegular(st_esc, act_regular);
88
	st_esc.setAction('7', st_base, new ACT_SC());
89
	st_esc.setAction('8', st_base, new ACT_RC());
90
	st_esc.setAction('c', st_base, new ACT_FULL_RESET());
91
	st_esc.setAction('[', st_esc_lb, act_reset_number);
92
93
94
	st_esc_lb.setRegular(st_esc_lb, act_regular);
95
	for (char c = '0'; c <= '9'; c++)
96
	    st_esc_lb.setAction(c, st_esc_lb, act_remember_digit);
97
	st_esc_lb.setAction(';', st_esc_lb, new ACT_PUSH_NUMBER());
98
	st_esc_lb.setAction('A', st_base, new ACT_UP());
99
	st_esc_lb.setAction('B', st_base, new ACT_DO());
100
	st_esc_lb.setAction('C', st_base, new ACT_ND());
101
	st_esc_lb.setAction('D', st_base, new ACT_BC());
102
	st_esc_lb.setAction('H', st_base, new ACT_HO());
103
	st_esc_lb.setAction('i', st_base, new ACT_PRINT());
104
	st_esc_lb.setAction('J', st_base, new ACT_J());
105
	st_esc_lb.setAction('K', st_base, new ACT_K());
106
	st_esc_lb.setAction('L', st_base, new ACT_AL());
107
	st_esc_lb.setAction('M', st_base, new ACT_DL());
108
	st_esc_lb.setAction('m', st_base, new ACT_ATTR());
109
	st_esc_lb.setAction('n', st_base, new ACT_DSR());
110
	st_esc_lb.setAction('P', st_base, new ACT_DC());
111
	st_esc_lb.setAction('h', st_base, new ACT_SM());
112
	st_esc_lb.setAction('l', st_base, new ACT_RM());
113
	st_esc_lb.setAction('r', st_base, new ACT_MARGIN());
114
	st_esc_lb.setAction('t', st_base, new ACT_GLYPH());
115
	st_esc_lb.setAction('@', st_base, new ACT_IC());
116
117
	state = st_base;
118
    }
119
120
121
    /*
122
     * Actions ..............................................................
123
     */
124
125
    protected final class ACT_TO_ESC implements Actor {
126
	public String action(char c) {
127
	    ctl_sequence = "";	// NOI18N
128
	    return null;
129
	}
75
	}
130
    }
131
76
132
    protected final class ACT_SC implements Actor {
77
	protected final class ACT_SC implements Actor {
133
	public String action(char c) {
78
	    public String action(AbstractInterp ai, char c) {
134
	    ops.op_sc();
79
		ai.ops.op_sc();
135
	    return null;
80
		return null;
81
	    }
136
	}
82
	}
137
    }
83
	protected final class ACT_RC implements Actor {
138
    protected final class ACT_RC implements Actor {
84
	    public String action(AbstractInterp ai, char c) {
139
	public String action(char c) {
85
		ai.ops.op_rc();
140
	    ops.op_rc();
86
		return null;
141
	    return null;
87
	    }
142
	}
88
	}
143
    }
89
	protected final class ACT_FULL_RESET implements Actor {
144
    protected final class ACT_FULL_RESET implements Actor {
90
	    public String action(AbstractInterp ai, char c) {
145
	public String action(char c) {
91
		ai.ops.op_full_reset();
146
	    ops.op_full_reset();
92
		return null;
147
	    return null;
93
	    }
148
	}
94
	}
149
    }
150
95
151
    protected Actor act_reset_number = new Actor() {
96
	protected class ACT_RESET_NUMBER implements Actor {
152
	public String action(char c) {
97
	    public String action(AbstractInterp ai, char c) {
153
	    resetNumber();
98
		ai.resetNumber();
154
	    return null;
99
		return null;
155
	}
100
	    }
156
    };
101
	};
157
102
158
    protected Actor act_remember_digit = new Actor() {
103
	protected class ACT_REMEMBER_DIGIT implements Actor {
159
	public String action(char c) {
104
	    public String action(AbstractInterp ai, char c) {
160
	    remember_digit(c);
105
		ai.remember_digit(c);
161
	    return null;
106
		return null;
162
	}
107
	    }
163
    };
108
	};
164
109
165
    protected final class ACT_PUSH_NUMBER implements Actor {
110
	protected final class ACT_PUSH_NUMBER implements Actor {
166
	public String action(char c) {
111
	    public String action(AbstractInterp ai, char c) {
167
	    if (!pushNumber())
112
		if (!ai.pushNumber())
168
		return "ACT PUSH_NUMBER";	// NOI18N
113
		    return "ACT PUSH_NUMBER";	// NOI18N
169
	    return null;
114
		return null;
115
	    }
170
	}
116
	}
171
    }
117
	protected final class ACT_UP implements Actor {
172
    protected final class ACT_UP implements Actor {
118
	    public String action(AbstractInterp ai, char c) {
173
	public String action(char c) {
119
		if (ai.noNumber())
174
	    if (noNumber())
120
		    ai.ops.op_up(1);
175
		ops.op_up(1);
121
		else
176
	    else
122
		    ai.ops.op_up(ai.numberAt(0));
177
		ops.op_up(numberAt(0));
123
		return null;
178
	    return null;
124
	    }
179
	}
125
	}
180
    }
126
	protected final class ACT_DO implements Actor {
181
    protected final class ACT_DO implements Actor {
127
	    public String action(AbstractInterp ai, char c) {
182
	public String action(char c) {
128
		if (ai.noNumber())
183
	    if (noNumber())
129
		    ai.ops.op_do(1);
184
		ops.op_do(1);
130
		else
185
	    else
131
		    ai.ops.op_do(ai.numberAt(0));
186
		ops.op_do(numberAt(0));
132
		return null;
187
	    return null;
133
	    }
188
	}
134
	}
189
    }
135
	protected final class ACT_ND implements Actor {
190
    protected final class ACT_ND implements Actor {
136
	    public String action(AbstractInterp ai, char c) {
191
	public String action(char c) {
137
		if (ai.noNumber())
192
	    if (noNumber())
138
		    ai.ops.op_nd(1);
193
		ops.op_nd(1);
139
		else
194
	    else
140
		    ai.ops.op_nd(ai.numberAt(0));
195
		ops.op_nd(numberAt(0));
141
		return null;
196
	    return null;
142
	    }
197
	}
143
	}
198
    }
144
	protected final class ACT_BC implements Actor {
199
    protected final class ACT_BC implements Actor {
145
	    public String action(AbstractInterp ai, char c) {
200
	public String action(char c) {
146
		if (ai.noNumber())
201
	    if (noNumber())
147
		    ai.ops.op_bc(1);
202
		ops.op_bc(1);
148
		else
203
	    else
149
		    ai.ops.op_bc(ai.numberAt(0));
204
		ops.op_bc(numberAt(0));
150
		return null;
205
	    return null;
151
	    }
206
	}
152
	}
207
    }
153
	protected final class ACT_MARGIN implements Actor {
208
    protected final class ACT_MARGIN implements Actor {
154
	    public String action(AbstractInterp ai, char c) {
209
	public String action(char c) {
155
		if (ai.noNumber())
210
	    if (noNumber())
156
		    ai.ops.op_margin(0, 0);
211
		ops.op_margin(0, 0);
157
		else
212
	    else
158
		    ai.ops.op_margin(ai.numberAt(0), ai.numberAt(1));
213
		ops.op_margin(numberAt(0), numberAt(1));
159
		return null;
214
	    return null;
160
	    }
215
	}
161
	}
216
    }
162
	protected final class ACT_DC implements Actor {
217
    protected final class ACT_DC implements Actor {
163
	    public String action(AbstractInterp ai, char c) {
218
	public String action(char c) {
164
		if (ai.noNumber())
219
	    if (noNumber())
165
		    ai.ops.op_dc(1);
220
		ops.op_dc(1);
166
		else
221
	    else
167
		    ai.ops.op_dc(ai.numberAt(0));
222
		ops.op_dc(numberAt(0));
168
		return null;
223
	    return null;
169
	    }
224
	}
170
	}
225
    }
226
171
227
    protected final class ACT_SM implements Actor {
172
	protected final class ACT_SM implements Actor {
228
	public String action(char c) {
173
	    public String action(AbstractInterp ai, char c) {
229
	    if (noNumber())
174
		if (ai.noNumber())
230
		ops.op_set_mode(1);
175
		    ai.ops.op_set_mode(1);
231
	    else
176
		else
232
		ops.op_set_mode(numberAt(0));
177
		    ai.ops.op_set_mode(ai.numberAt(0));
233
	    return null;
178
		return null;
179
	    }
234
	}
180
	}
235
    }
236
181
237
    protected final class ACT_RM implements Actor {
182
	protected final class ACT_RM implements Actor {
238
	public String action(char c) {
183
	    public String action(AbstractInterp ai, char c) {
239
	    if (noNumber())
184
		if (ai.noNumber())
240
		ops.op_reset_mode(1);
185
		    ai.ops.op_reset_mode(1);
241
	    else
186
		else
242
		ops.op_reset_mode(numberAt(0));
187
		    ai.ops.op_reset_mode(ai.numberAt(0));
243
	    return null;
188
		return null;
189
	    }
244
	}
190
	}
245
    }
246
191
247
    protected final class ACT_IC implements Actor {
192
	protected final class ACT_IC implements Actor {
248
	public String action(char c) {
193
	    public String action(AbstractInterp ai, char c) {
249
	    if (noNumber())
194
		if (ai.noNumber())
250
		ops.op_ic(1);
195
		    ai.ops.op_ic(1);
251
	    else
196
		else
252
		ops.op_ic(numberAt(0));
197
		    ai.ops.op_ic(ai.numberAt(0));
253
	    return null;
198
		return null;
254
	}
199
	    }
255
    }
256
    protected final class ACT_DL implements Actor {
257
	public String action(char c) {
258
	    if (noNumber()) {
259
		ops.op_dl(1);
260
	    } else {
261
		ops.op_dl(numberAt(0));
262
	    } 
263
	    return null;
264
	}
200
	}
265
    }
201
	protected final class ACT_DL implements Actor {
266
    protected final class ACT_HO implements Actor {
202
	    public String action(AbstractInterp ai, char c) {
267
	public String action(char c) {
203
		if (ai.noNumber()) {
268
	    if (noNumber()) {
204
		    ai.ops.op_dl(1);
269
		ops.op_ho();
205
		} else {
270
	    } else {
206
		    ai.ops.op_dl(ai.numberAt(0));
271
		ops.op_cm(numberAt(0), numberAt(1));	// row, col
207
		} 
272
	    } 
208
		return null;
273
	    return null;
209
	    }
274
	}
210
	}
275
    }
211
	protected final class ACT_HO implements Actor {
276
    protected final class ACT_PRINT implements Actor {
212
	    public String action(AbstractInterp ai, char c) {
277
	public String action(char c) {
213
		if (ai.noNumber()) {
278
	    // Ignored for now, except for 'dump time'
214
		    ai.ops.op_ho();
279
	    if (noNumber()) {
215
		} else {
280
		// Print screen
216
		    ai.ops.op_cm(ai.numberAt(0), ai.numberAt(1));// row, col
281
	    } else {
282
		switch (numberAt(0)) {
283
		    case 1:	// Print Line
284
		    case 4:	// Stop Print Log
285
		    case 5:	// Start Print Log
286
			break;
287
		    case 10:
288
			ops.op_time(true);
289
			break;
290
		    case 11:
291
			ops.op_time(false);
292
			break;
293
		} 
217
		} 
218
		return null;
294
	    }
219
	    }
295
	    return null;
296
	}
220
	}
297
    }
221
	protected final class ACT_PRINT implements Actor {
298
    protected final class ACT_J implements Actor {
222
	    public String action(AbstractInterp ai, char c) {
299
	public String action(char c) {
223
		// Ignored for now, except for 'dump time'
300
	    if (noNumber()) {
224
		if (ai.noNumber()) {
301
		ops.op_cd();
225
		    // Print screen
302
	    } else {
226
		} else {
303
		int count = numberAt(0);
227
		    switch (ai.numberAt(0)) {
304
		if (count == 1) {
228
			case 1:	// Print Line
305
		    return "ACT J: count of 1 not supported";	// NOI18N
229
			case 4:	// Stop Print Log
306
		} else if (count == 2) {
230
			case 5:	// Start Print Log
307
		    ops.op_cl();
231
			    break;
232
			case 10:
233
			    ai.ops.op_time(true);
234
			    break;
235
			case 11:
236
			    ai.ops.op_time(false);
237
			    break;
238
		    } 
239
		}
240
		return null;
241
	    }
242
	}
243
	protected final class ACT_J implements Actor {
244
	    public String action(AbstractInterp ai, char c) {
245
		if (ai.noNumber()) {
246
		    ai.ops.op_cd();
247
		} else {
248
		    int count = ai.numberAt(0);
249
		    if (count == 1) {
250
			return "ACT J: count of 1 not supported";	// NOI18N
251
		    } else if (count == 2) {
252
			ai.ops.op_cl();
253
		    } 
308
		} 
254
		} 
309
	    } 
255
		return null;
310
	    return null;
256
	    }
311
	}
257
	}
312
    }
258
	protected final class ACT_K implements Actor {
313
    protected final class ACT_K implements Actor {
259
	    public String action(AbstractInterp ai, char c) {
314
	public String action(char c) {
260
		if (ai.noNumber()) {
315
	    if (noNumber()) {
261
		    ai.ops.op_ce();
316
		ops.op_ce();
262
		} else {
317
	    } else {
263
		    int count = ai.numberAt(0);
318
		int count = numberAt(0);
264
		    if (count == 1) {
319
		if (count == 1) {
265
			return "ACT K: count of 1 not supported";	// NOI18N
320
		    return "ACT K: count of 1 not supported";	// NOI18N
266
		    } else if (count == 2) {
321
		} else if (count == 2) {
267
			return "ACT K: count of 2 not supported";	// NOI18N
322
		    return "ACT K: count of 2 not supported";	// NOI18N
268
		    } 
323
		} 
269
		} 
324
	    } 
270
		return null;
325
	    return null;
271
	    }
326
	}
272
	}
327
    }
273
	protected final class ACT_AL implements Actor {
328
    protected final class ACT_AL implements Actor {
274
	    public String action(AbstractInterp ai, char c) {
329
	public String action(char c) {
275
		if (ai.noNumber()) {
330
	    if (noNumber()) {
276
		    ai.ops.op_al(1);
331
		ops.op_al(1);
277
		} else {
332
	    } else {
278
		    ai.ops.op_al(ai.numberAt(0));
333
		ops.op_al(numberAt(0));
279
		} 
334
	    } 
280
		return null;
335
	    return null;
281
	    }
336
	}
282
	}
337
    }
338
283
339
    protected final class ACT_ATTR implements Actor {
284
	protected final class ACT_ATTR implements Actor {
340
	public String action(char c) {
285
	    public String action(AbstractInterp ai, char c) {
341
	    // set graphics modes (bold, reverse video etc)
286
		// set graphics modes (bold, reverse video etc)
342
	    if (noNumber()) {
287
		if (ai.noNumber()) {
343
		ops.op_attr(0);	// reset everything
288
		    ai.ops.op_attr(0);	// reset everything
344
	    } else {
289
		} else {
345
		for (int n = 0; n <= nNumbers(); n++)
290
		    for (int n = 0; n <= ai.nNumbers(); n++)
346
		    ops.op_attr(numberAt(n));
291
			ai.ops.op_attr(ai.numberAt(n));
292
		}
293
		return null;
347
	    }
294
	    }
348
	    return null;
349
	}
295
	}
350
    }
351
296
352
    protected final class ACT_DSR implements Actor {
297
	protected final class ACT_DSR implements Actor {
353
	// Device Status Report
298
	    // Device Status Report
354
	public String action(char c) {
299
	    public String action(AbstractInterp ai, char c) {
355
	    if (noNumber()) {
300
		if (ai.noNumber()) {
356
		ops.op_status_report(5);	// reset everything
301
		    ai.ops.op_status_report(5);	// reset everything
357
	    } else {
302
		} else {
358
		ops.op_status_report(numberAt(0));
303
		    ai.ops.op_status_report(ai.numberAt(0));
304
		}
305
		return null;
359
	    }
306
	    }
360
	    return null;
361
	}
307
	}
362
    }
363
308
364
    protected final class ACT_GLYPH implements Actor {
309
	protected final class ACT_GLYPH implements Actor {
365
	public String action(char c) {
310
	    public String action(AbstractInterp ai, char c) {
366
	    if (noNumber()) {
311
		if (ai.noNumber()) {
367
		return "ACT GLYPH: missing number";	// NOI18N
312
		    return "ACT GLYPH: missing number";	// NOI18N
368
	    } else {
369
		int p1 = numberAt(0);
370
		int p2 = numberAt(1);
371
		int p3 = numberAt(2);
372
		if (p1 == 22) {
373
		    ops.op_glyph(p2, p3);
374
		} else {
313
		} else {
375
		    return "ACT GLYPH: op othger than 22 not supported";	// NOI18N
314
		    int p1 = ai.numberAt(0);
315
		    int p2 = ai.numberAt(1);
316
		    int p3 = ai.numberAt(2);
317
		    if (p1 == 22) {
318
			ai.ops.op_glyph(p2, p3);
319
		    } else {
320
			return "ACT GLYPH: op othger than 22 not supported";	// NOI18N
321
		    } 
376
		} 
322
		} 
377
	    } 
323
		return null;
378
	    return null;
324
	    }
379
	}
325
	}
326
    }
327
328
    private InterpTypeANSI type;
329
330
    public static final InterpTypeANSI type_singleton = new InterpTypeANSI();
331
332
    public InterpANSI(Ops ops) {
333
	super(ops, type_singleton);
334
	this.type = type_singleton;
335
	setup();
336
    } 
337
338
    protected InterpANSI(Ops ops, InterpTypeANSI type) {
339
	super(ops, type);
340
	this.type = type;
341
	setup();
342
    } 
343
344
    public String name() {
345
	return "ansi";	// NOI18N
346
    } 
347
348
    public void reset() {
349
	super.reset();
350
    }
351
352
    private void setup() {
353
	state = type.st_base;
380
    }
354
    }
381
}
355
}
(-)InterpDtTerm.java (-110 / +140 lines)
Lines 28-35 Link Here
28
28
29
class InterpDtTerm extends InterpANSI {
29
class InterpDtTerm extends InterpANSI {
30
30
31
    protected InterpDtTerm(Ops ops) {
31
    protected static class InterpTypeDtTerm extends InterpTypeANSI {
32
	super(ops);
32
	protected final State st_esc_rb = new State("esc_rb");	// NOI18N
33
	protected final State st_esc_lb_q = new State("esc_lb_q");// NOI18N
34
	protected final State st_esc_lb_b = new State("esc_lb_b");// NOI18N
35
	protected final State st_wait = new State("wait");	// NOI18N
36
37
	protected final Actor act_DEC_private = new ACT_DEC_PRIVATE();
38
	protected final Actor act_M = new ACT_M();
39
	protected final Actor act_D = new ACT_D();
40
	protected final Actor act_done_collect = new ACT_DONE_COLLECT();
41
	protected final Actor act_collect = new ACT_COLLECT();
42
	protected final Actor act_start_collect = new ACT_START_COLLECT();
43
44
45
	protected InterpTypeDtTerm() {
46
	    st_esc.setAction(']', st_esc_rb, act_start_collect);
47
48
	    // the following two may be generic ANSI escapes
49
	    st_esc.setAction('D', st_base, act_D);
50
	    st_esc.setAction('M', st_base, act_M);
51
52
	    for (char c = 0; c < 128; c++)
53
		st_esc_rb.setAction(c, st_esc_rb, act_collect);
54
	    st_esc_rb.setAction((char) 27, st_wait, act_nop);
55
56
	    st_wait.setAction('\\', st_base, act_done_collect);
57
58
	    st_esc_lb.setAction('?', st_esc_lb_q, act_reset_number);
59
60
	    for (char c = '0'; c <= '9'; c++)
61
		st_esc_lb_q.setAction(c, st_esc_lb_q, act_remember_digit);
62
	    st_esc_lb_q.setAction('h', st_base, act_DEC_private);
63
	    st_esc_lb_q.setAction('l', st_base, act_DEC_private);
64
	    st_esc_lb_q.setAction('r', st_base, act_DEC_private);
65
	    st_esc_lb_q.setAction('s', st_base, act_DEC_private);
66
67
	    st_esc_lb.setAction('!', st_esc_lb_b, act_reset_number);
68
	    st_esc_lb_b.setAction('p', st_base, new ACT_DEC_STR());
69
	}
70
71
	protected final class ACT_START_COLLECT implements Actor {
72
	    public String action(AbstractInterp ai, char c) {
73
		InterpDtTerm i = (InterpDtTerm) ai;
74
		i.text = "";	// NOI18N
75
		return null;
76
	    }
77
	}
78
79
	protected final class ACT_COLLECT implements Actor {
80
	    public String action(AbstractInterp ai, char c) {
81
		// java bug 4318526 text += c;
82
		InterpDtTerm i = (InterpDtTerm) ai;
83
		i.text = i.text + c;
84
		return null;
85
	    }
86
	}
87
88
	protected final class ACT_DONE_COLLECT implements Actor {
89
	    public String action(AbstractInterp ai, char c) {
90
		/* DEBUG
91
		System.out.println("DtTerm emulation: got '" + text + "'");	// NOI18N
92
		*/
93
		return null;
94
	    }
95
	}
96
97
	protected final class ACT_D implements Actor {
98
	    public String action(AbstractInterp ai, char c) {
99
		ai.ops.op_do(1);
100
		return null;
101
	    }
102
	};
103
104
	protected final class ACT_M implements Actor {
105
	    public String action(AbstractInterp ai, char c) {
106
		ai.ops.op_up(1);
107
		return null;
108
	    }
109
	}
110
111
	protected final class ACT_DEC_PRIVATE implements Actor {
112
	    public String action(AbstractInterp ai, char c) {
113
		if (ai.noNumber())
114
		    return "act_DEC_private: no number";	// NOI18N
115
		int n = ai.numberAt(0);
116
		switch(c) {
117
		    case 'h':
118
			if (n == 5)
119
			    ai.ops.op_reverse(true);
120
			else if (n == 25)
121
			    ai.ops.op_cursor_visible(true);
122
			else 
123
			    return "act_DEC_private: unrecognized cmd " + c;	// NOI18N
124
			break;
125
		    case 'l':
126
			if (n == 5)
127
			    ai.ops.op_reverse(false);
128
			else if (n == 25)
129
			    ai.ops.op_cursor_visible(false);
130
			else 
131
			    return "act_DEC_private: unrecognized cmd " + c;	// NOI18N
132
			break;
133
		    case 'r':
134
		    case 's':
135
			/* DEBUG
136
			System.out.println("act_DEC_private " +	// NOI18N
137
			    numberAt(0) + " " + c);	// NOI18N
138
			*/
139
			break;
140
		    default:
141
			return "act_DEC_private: unrecognized cmd " + c;	// NOI18N
142
		} 
143
		return null;
144
	    }
145
	}
146
147
	protected final class ACT_DEC_STR implements Actor {
148
	    public String action(AbstractInterp ai, char c) {
149
		ai.ops.op_soft_reset();
150
		return null;
151
	    }
152
	}
153
    }
154
155
    private String text = null;
156
157
    private InterpTypeDtTerm type;
158
159
    public static final InterpTypeDtTerm type_singleton = new InterpTypeDtTerm();
160
161
    public InterpDtTerm(Ops ops) {
162
	super(ops, type_singleton);
163
	this.type = type_singleton;
164
	setup();
165
    } 
166
167
    protected InterpDtTerm(Ops ops, InterpTypeDtTerm type) {
168
	super(ops, type);
169
	this.type = type;
33
	setup();
170
	setup();
34
    } 
171
    } 
35
172
Lines 42-157 Link Here
42
	text = null;
179
	text = null;
43
    }
180
    }
44
181
45
    protected State st_esc_rb = new State("esc_rb");	// NOI18N
46
    protected State st_esc_lb_q = new State("esc_lb_q");// NOI18N
47
    protected State st_esc_lb_b = new State("esc_lb_b");// NOI18N
48
    protected State st_wait = new State("wait");	// NOI18N
49
50
    private String text = null;
51
182
52
    private void setup() {
183
    private void setup() {
53
	st_esc.setAction(']', st_esc_rb, act_start_collect);
184
	state = type.st_base;
54
55
	// the following two may be generic ANSI escapes
56
	st_esc.setAction('D', st_base, act_D);
57
	st_esc.setAction('M', st_base, act_M);
58
59
	for (char c = 0; c < 128; c++)
60
	    st_esc_rb.setAction(c, st_esc_rb, act_collect);
61
	st_esc_rb.setAction((char) 27, st_wait, act_nop);
62
63
	st_wait.setAction('\\', st_base, act_done_collect);
64
65
	st_esc_lb.setAction('?', st_esc_lb_q, act_reset_number);
66
67
	for (char c = '0'; c <= '9'; c++)
68
	    st_esc_lb_q.setAction(c, st_esc_lb_q, act_remember_digit);
69
	st_esc_lb_q.setAction('h', st_base, act_DEC_private);
70
	st_esc_lb_q.setAction('l', st_base, act_DEC_private);
71
	st_esc_lb_q.setAction('r', st_base, act_DEC_private);
72
	st_esc_lb_q.setAction('s', st_base, act_DEC_private);
73
74
	st_esc_lb.setAction('!', st_esc_lb_b, act_reset_number);
75
	st_esc_lb_b.setAction('p', st_base, new ACT_DEC_STR());
76
77
	state = st_base;
78
    }
185
    }
79
186
80
    protected final Actor act_start_collect = new Actor() {
81
	public String action(char c) {
82
	    text = "";	// NOI18N
83
	    return null;
84
	}
85
    };
86
87
    protected final Actor act_collect = new Actor() {
88
        public String action(char c) {
89
            // java bug 4318526 text += c;
90
            text = text + c;
91
            return null;
92
        }
93
    };
94
95
    protected final Actor act_done_collect = new Actor() {
96
	public String action(char c) {
97
	    // System.out.println("DtTerm emulation: got '" + text + "'");	// NOI18N
98
	    return null;
99
	}
100
    };
101
102
    protected final Actor act_D = new Actor() {
103
	public String action(char c) {
104
	    ops.op_do(1);
105
	    return null;
106
	}
107
    };
108
109
    protected final Actor act_M = new Actor() {
110
	public String action(char c) {
111
	    ops.op_up(1);
112
	    return null;
113
	}
114
    };
115
116
    protected final Actor act_DEC_private = new Actor() {
117
	public String action(char c) {
118
	    if (noNumber())
119
		return "act_DEC_private: no number";	// NOI18N
120
	    int n = numberAt(0);
121
	    switch(c) {
122
		case 'h':
123
		    if (n == 5)
124
			ops.op_reverse(true);
125
		    else if (n == 25)
126
			ops.op_cursor_visible(true);
127
		    else 
128
			return "act_DEC_private: unrecognized cmd " + c;	// NOI18N
129
		    break;
130
		case 'l':
131
		    if (n == 5)
132
			ops.op_reverse(false);
133
		    else if (n == 25)
134
			ops.op_cursor_visible(false);
135
		    else 
136
			return "act_DEC_private: unrecognized cmd " + c;	// NOI18N
137
		    break;
138
		case 'r':
139
		case 's':
140
		    /*
141
		    System.out.println("act_DEC_private " +
142
			numberAt(0) + " " + c);
143
		    */
144
		    break;
145
		default:
146
		    return "act_DEC_private: unrecognized cmd " + c;	// NOI18N
147
	    } 
148
	    return null;
149
	}
150
    };
151
    protected final class ACT_DEC_STR implements Actor {
152
	public String action(char c) {
153
	    ops.op_soft_reset();
154
	    return null;
155
	}
156
    }
157
}
187
}
(-)InterpDumb.java (-88 / +151 lines)
Lines 23-37 Link Here
23
23
24
package org.netbeans.lib.terminalemulator;
24
package org.netbeans.lib.terminalemulator;
25
25
26
/* OLD
26
import java.util.Stack;
27
import java.lang.Class;
28
import java.lang.reflect.Method;
29
*/
30
27
31
public class InterpDumb extends AbstractInterp {
28
public class InterpDumb extends AbstractInterp {
32
29
33
    protected InterpDumb(Ops ops) {
30
    protected static class InterpTypeDumb {
31
	public final State st_base = new State("base");	// NOI18N
32
33
	protected final Actor act_nop = new ACT_NOP();
34
	protected final Actor act_pause = new ACT_PAUSE();
35
	protected final Actor act_err = new ACT_ERR();
36
	protected final Actor act_regular = new ACT_REGULAR();
37
	protected final Actor act_cr = new ACT_CR();
38
	protected final Actor act_lf = new ACT_LF();
39
	protected final Actor act_bs = new ACT_BS();
40
	protected final Actor act_tab = new ACT_TAB();
41
	protected final Actor act_beL = new ACT_BEL();
42
43
	protected InterpTypeDumb() {
44
	    st_base.setRegular(st_base, act_regular);
45
46
	    for (char c = 0; c < 128; c++)
47
		st_base.setAction(c, st_base, act_regular);
48
49
	    st_base.setAction((char) 0, st_base, act_pause);
50
	    st_base.setAction('\r', st_base, act_cr);
51
	    st_base.setAction('\n', st_base, act_lf);
52
	    st_base.setAction('\b', st_base, act_bs);
53
	    st_base.setAction('\t', st_base, act_tab);
54
	    st_base.setAction((char) 7, st_base, act_beL);
55
	}
56
57
	protected final class ACT_NOP implements Actor {
58
	    public String action(AbstractInterp ai, char c) {
59
		return null;
60
	    }
61
	};
62
63
	protected final class ACT_PAUSE implements Actor {
64
	    public String action(AbstractInterp ai, char c) {
65
		ai.ops.op_pause();
66
		return null;
67
	    }
68
	};
69
70
	protected final class ACT_ERR implements Actor {
71
	    public String action(AbstractInterp ai, char c) {
72
		return "ACT ERROR";	// NOI18N
73
	    }
74
	};
75
76
	protected final class ACT_REGULAR implements Actor {
77
	    public String action(AbstractInterp ai, char c) {
78
		ai.ops.op_char(c);
79
		return null;
80
	    }
81
	};
82
83
84
	protected final class ACT_CR implements Actor {
85
	    public String action(AbstractInterp ai, char c) {
86
		ai.ops.op_carriage_return();
87
		return null;
88
	    }
89
	};
90
91
	protected final class ACT_LF implements Actor {
92
	    public String action(AbstractInterp ai, char c) {
93
		ai.ops.op_line_feed();
94
		return null;
95
	    }
96
	};
97
98
99
	protected final class ACT_BS implements Actor {
100
	    public String action(AbstractInterp ai, char c) {
101
		ai.ops.op_back_space();
102
		return null;
103
	    }
104
	};
105
106
	protected final class ACT_TAB implements Actor {
107
	    public String action(AbstractInterp ai, char c) {
108
		ai.ops.op_tab();
109
		return null;
110
	    }
111
	};
112
113
	protected final class ACT_BEL implements Actor {
114
	    public String action(AbstractInterp ai, char c) {
115
		ai.ops.op_bel();
116
		return null;
117
	    }
118
	}
119
    }
120
121
    /*
122
     * A stack for State
123
     */
124
    private Stack stack = new Stack();
125
126
    protected void push_state(State s) {
127
	stack.push(s);
128
    }
129
130
    protected State pop_state() {
131
	return (State) stack.pop();
132
    }
133
134
    protected void pop_all_states() {
135
	while(!stack.empty())
136
	    stack.pop();
137
    }
138
139
140
    protected String ctl_sequence = null;
141
142
    private InterpTypeDumb type;
143
144
    public static final InterpTypeDumb type_singleton = new InterpTypeDumb();
145
146
    public InterpDumb(Ops ops) {
147
	super(ops);
148
	this.type = type_singleton;
149
	setup();
150
	ctl_sequence = null;
151
    } 
152
153
    protected InterpDumb(Ops ops, InterpTypeDumb type) {
34
	super(ops);
154
	super(ops);
155
	this.type = type;
35
	setup();
156
	setup();
36
	ctl_sequence = null;
157
	ctl_sequence = null;
37
    } 
158
    } 
Lines 42-73 Link Here
42
163
43
    public void reset() {
164
    public void reset() {
44
	super.reset();
165
	super.reset();
45
	state = st_base;
166
	pop_all_states();
167
	state = type.st_base;
46
	ctl_sequence = null;
168
	ctl_sequence = null;
47
    }
169
    }
48
170
49
    protected State st_base = new State("base");	// NOI18N
50
    protected String ctl_sequence = null;
51
52
    private void setup() {
171
    private void setup() {
53
	st_base.setRegular(st_base, act_regular);
172
	state = type.st_base;
54
55
	for (char c = 0; c < 128; c++)
56
	    st_base.setAction(c, st_base, act_regular);
57
58
	st_base.setAction((char) 0, st_base, act_pause);
59
	st_base.setAction('\r', st_base, act_cr);
60
	st_base.setAction('\n', st_base, act_lf);
61
	st_base.setAction('\b', st_base, act_bs);
62
	st_base.setAction('\t', st_base, act_tab);
63
	st_base.setAction((char) 7, st_base, act_beL);
64
65
	state = st_base;
66
    }
173
    }
67
174
68
175
69
    private void reset_state_bad() {
176
    private void reset_state_bad() {
70
        /*
177
        /*
178
	DEBUG
71
	System.out.println("Unrecognized sequence in state " + state.name());	// NOI18N
179
	System.out.println("Unrecognized sequence in state " + state.name());	// NOI18N
72
	if (ctl_sequence != null) {
180
	if (ctl_sequence != null) {
73
	    for (int sx = 0; sx < ctl_sequence.length(); sx++)
181
	    for (int sx = 0; sx < ctl_sequence.length(); sx++)
Lines 77-85 Link Here
77
	    for (int sx = 0; sx < ctl_sequence.length(); sx++)
185
	    for (int sx = 0; sx < ctl_sequence.length(); sx++)
78
		System.out.print(ctl_sequence.charAt(sx) + "  ");	// NOI18N
186
		System.out.print(ctl_sequence.charAt(sx) + "  ");	// NOI18N
79
187
80
	    System.out.println();
188
	    System.out.println();	// NOI18N
81
	}
189
	}
82
         */
190
        */
83
	reset();
191
	reset();
84
    } 
192
    } 
85
193
Lines 91-107 Link Here
91
199
92
	try {
200
	try {
93
	    State.Action a = state.getAction(c);
201
	    State.Action a = state.getAction(c);
94
	    String err_str = a.actor.action(c);
202
	    /* DEBUG
203
	    if (a == null) {
204
		System.out.println("null action in state " + state.name() +	// NOI18N
205
		                   " for char " + c + " = " + (int) c);	// NOI18N
206
	    }
207
	    if (a.actor == null) {
208
		System.out.println("null a.actor in state " + state.name() +	// NOI18N
209
				   " for char " + c + " = " + (int) c);	// NOI18N
210
	    }
211
	    */
212
	    String err_str = a.actor.action(this, c);
95
	    if (err_str != null) {
213
	    if (err_str != null) {
96
		// System.out.println("action error: " + err_str);	// NOI18N
214
		/* DEBUG
215
		System.out.println("action error: " + err_str);	// NOI18N
216
		*/
97
		reset_state_bad();
217
		reset_state_bad();
98
		return;
218
		return;
99
	    }
219
	    }
100
220
101
	    state = a.new_state;
221
	    if (a.new_state != null)
222
		state = a.new_state;
223
	    else
224
		;	// must be set by action, usually using pop_state()
102
225
103
	} finally {
226
	} finally {
104
	    if (state == st_base)
227
	    if (state == type.st_base)
105
		ctl_sequence = null;
228
		ctl_sequence = null;
106
	}
229
	}
107
    }
230
    }
Lines 110-173 Link Here
110
     * Actions ..............................................................
233
     * Actions ..............................................................
111
     */
234
     */
112
235
113
    protected final Actor act_nop = new Actor() {
114
	public String action(char c) {
115
	    return null;
116
	}
117
    };
118
119
    protected final Actor act_pause = new Actor() {
120
	public String action(char c) {
121
	    ops.op_pause();
122
	    return null;
123
	}
124
    };
125
126
    protected final Actor act_err = new Actor() {
127
	public String action(char c) {
128
	    return "ACT ERROR";	// NOI18N
129
	}
130
    };
131
132
    protected final Actor act_regular = new Actor() {
133
	public String action(char c) {
134
	    ops.op_char(c);
135
	    return null;
136
	}
137
    };
138
139
    protected final Actor act_cr = new Actor() {
140
	public String action(char c) {
141
	    ops.op_carriage_return();
142
	    return null;
143
	}
144
    };
145
146
    protected final Actor act_lf = new Actor() {
147
	public String action(char c) {
148
	    ops.op_line_feed();
149
	    return null;
150
	}
151
    };
152
153
    protected final Actor act_bs = new Actor() {
154
	public String action(char c) {
155
	    ops.op_back_space();
156
	    return null;
157
	}
158
    };
159
160
    protected final Actor act_tab = new Actor() {
161
	public String action(char c) {
162
	    ops.op_tab();
163
	    return null;
164
	}
165
    };
166
167
    protected final Actor act_beL = new Actor() {
168
	public String action(char c) {
169
	    ops.op_bel();
170
	    return null;
171
	}
172
    };
173
}
236
}
(-)InterpKit.java (-1 / +1 lines)
Lines 36-42 Link Here
36
	else if (name.equals("ansi"))	// NOI18N
36
	else if (name.equals("ansi"))	// NOI18N
37
	    return new InterpANSI(ops);	
37
	    return new InterpANSI(ops);	
38
        else if (name.equals("dtterm"))	// NOI18N
38
        else if (name.equals("dtterm"))	// NOI18N
39
	    return new InterpDtTerm(ops);         
39
	    return new InterpDtTerm(ops);      
40
	else
40
	else
41
	    return null;
41
	    return null;
42
    } 
42
    } 
(-)Line.java (-15 / +73 lines)
Lines 26-33 Link Here
26
    public int glyph_rendition;	// Background color for the whole line
26
    public int glyph_rendition;	// Background color for the whole line
27
    				// This is independent of per-character
27
    				// This is independent of per-character
28
				// rendition.
28
				// rendition.
29
    private char buf[];
29
30
    private int attr[];
30
    private char buf[];		// actual characters
31
    private int attr[];		// attributes (allocated on demand)
31
32
32
    // SHOULD use shorts?
33
    // SHOULD use shorts?
33
    private int capacity;	// == buf.length == attr.length
34
    private int capacity;	// == buf.length == attr.length
Lines 105-115 Link Here
105
    public char [] charArray() {
106
    public char [] charArray() {
106
	return buf;
107
	return buf;
107
    }
108
    }
109
108
    public int [] attrArray() {
110
    public int [] attrArray() {
109
	return attr;
111
	return attr;
110
    }
112
    }
111
113
112
114
115
    public byte width(MyFontMetrics metrics, int at) {
116
	if (at >= capacity)
117
	    return 1;
118
	return (byte) metrics.wcwidth(buf[at]);
119
    }
120
121
    /*
122
     * Convert a cell column to a buffer column.
123
     */
124
    public int cellToBuf(MyFontMetrics metrics, int target_col) {
125
	if (metrics.isMultiCell()) {
126
	    int bc = 0;
127
	    int vc = 0;
128
	    for(;;) {
129
		int w = width(metrics, bc);
130
		if (vc + w - 1 >= target_col)
131
		    break;
132
		vc += w;
133
		bc++;
134
	    }
135
	    return bc;
136
	} else {
137
	    return target_col;
138
	}
139
    }
140
141
    /*
142
     * Convert a buffer column to a cell column.
143
     */
144
    public int bufToCell(MyFontMetrics metrics, int target_col) {
145
	if (metrics.isMultiCell()) {
146
	    int vc = 0;
147
	    for (int bc = 0; bc < target_col; bc++) {
148
		vc += width(metrics, bc);
149
	    }
150
	    return vc;
151
	} else {
152
	    return target_col;
153
	} 
154
    }
155
156
157
113
    public StringBuffer stringBuffer() {
158
    public StringBuffer stringBuffer() {
114
	// only used for word finding
159
	// only used for word finding
115
	// Grrr, why don't we have: new StringBuffer(buf, 0, length);
160
	// Grrr, why don't we have: new StringBuffer(buf, 0, length);
Lines 118-128 Link Here
118
    } 
163
    } 
119
164
120
    /*
165
    /*
121
     * Ensure that our capacity is min_capacity rounded up to 8.
166
     * Ensure that we have at least 'min_capacity'.
122
     */
167
     */
123
    private void ensureCapacity(Buffer lbuf, int min_capacity) {
168
    private void ensureCapacity(Term term, int min_capacity) {
124
169
125
	lbuf.noteColumn(min_capacity);
170
	term.noteColumn(this, min_capacity);
126
171
127
	if (min_capacity <= capacity)
172
	if (min_capacity <= capacity)
128
	    return;	// nothing to do
173
	    return;	// nothing to do
Lines 163-173 Link Here
163
     * Insert character and attribute at 'column' and shift everything 
208
     * Insert character and attribute at 'column' and shift everything 
164
     * past 'column' right.
209
     * past 'column' right.
165
     */
210
     */
166
    public void insertCharAt(Buffer lbuf, char c, int column, int a) {
211
    public void insertCharAt(Term term, char c, int column, int a) {
167
	int new_length = length + 1;
212
	int new_length = length + 1;
168
	ensureCapacity(lbuf, new_length);
213
	ensureCapacity(term, new_length);
214
215
	if (column >= length) {
216
	    // fill any newly opened gap (between length and column) with SP
217
	    for (int fx = length; fx < column; fx++)
218
		buf[fx] = ' ';
219
	}
169
220
170
	System.arraycopy(buf, column, buf, column + 1, length - column);
221
	System.arraycopy(buf, column, buf, column + 1, length - column);
222
	term.checkForMultiCell(c);
171
	buf[column] = c;
223
	buf[column] = c;
172
224
173
	if (haveAttributes(a)) {
225
	if (haveAttributes(a)) {
Lines 182-192 Link Here
182
     * Generic addition and modification.
234
     * Generic addition and modification.
183
     * Line will grow to accomodate column.
235
     * Line will grow to accomodate column.
184
     */
236
     */
185
    public void setCharAt(Buffer lbuf, char c, int column, int a) {
237
    public void setCharAt(Term term, char c, int column, int a) {
186
	if (column >= length) {
238
	if (column >= length) {
187
	    ensureCapacity(lbuf, column+1);
239
	    ensureCapacity(term, column+1);
240
	    // fill any newly opened gap (between length and column) with SP
241
	    for (int fx = length; fx < column; fx++)
242
		buf[fx] = ' ';
188
	    length = column+1;
243
	    length = column+1;
189
	}
244
	}
245
	term.checkForMultiCell(c);
190
	buf[column] = c;
246
	buf[column] = c;
191
	if (haveAttributes(a)) {
247
	if (haveAttributes(a)) {
192
	    attr[column] = a;
248
	    attr[column] = a;
Lines 206-220 Link Here
206
	length--;
262
	length--;
207
    }
263
    }
208
264
209
    public void clearToEndFrom(Buffer lbuf, int col) {
265
    public void clearToEndFrom(Term term, int col) {
210
	ensureCapacity(lbuf, col+1);
266
	ensureCapacity(term, col+1);
211
267
212
	// Grrr, why is there a System.arrayCopy() but no System.arrayClear()?
268
	// Grrr, why is there a System.arrayCopy() but no System.arrayClear()?
213
	for (int cx = col; cx < length; cx++)
269
	for (int cx = col; cx < length; cx++)
214
	    buf[cx] = 0;
270
	    buf[cx] = ' ';
215
	if (attr != null) {
271
	if (attr != null) {
216
	    for (int cx = col; cx < length; cx++)
272
	    for (int cx = col; cx < length; cx++)
217
		attr[cx] = 0;
273
		attr[cx] = ' ';
218
	}
274
	}
219
	length = col;
275
	length = col;
220
    } 
276
    } 
Lines 225-232 Link Here
225
     * If the ecol is past the actual line length a "\n" is appended.
281
     * If the ecol is past the actual line length a "\n" is appended.
226
     */
282
     */
227
    public String text(int bcol, int ecol) {
283
    public String text(int bcol, int ecol) {
228
	// System.out.println("Line.text(bcol " + bcol + " ecol " + ecol + ")");	// NOI18N
284
	/* DEBUG
229
	// System.out.println("\tlength " + length);	// NOI18N
285
	System.out.println("Line.text(bcol " + bcol + " ecol " + ecol + ")");	// NOI18N
286
	System.out.println("\tlength " + length);	// NOI18N
287
	*/
230
288
231
	String newline = "";	// NOI18N
289
	String newline = "";	// NOI18N
232
290
(-)LineDiscipline.java (+33 lines)
Lines 167-174 Link Here
167
	    if (nchars == 0)
167
	    if (nchars == 0)
168
		return;		// nothing left to BS over
168
		return;		// nothing left to BS over
169
169
170
	    char erased_char = ' ';	// The char we're going to erase
171
	    try {
172
		erased_char = line.charAt(nchars-1);
173
	    } catch (Exception x) {
174
		return;		// apparently the 'nchars == 0' test failed above ;-)
175
	    } 
176
	    int cwidth = getTerm().charWidth(erased_char);
177
170
	    // remove from line buffer
178
	    // remove from line buffer
171
	    line.delete(nchars-1, nchars);
179
	    line.delete(nchars-1, nchars);
180
181
	    // HACK 
182
	    // If you play a bit with DtTerm on Solaris in a non-latin locale 
183
	    // you'll see that when you BS over a multi-cell character it
184
	    // doesn't erase the whole character. The character is erased but the
185
	    // cursor moves back only one column. So you usually need to BS twice
186
	    // to get rid of it. If you "fix" Term to do something more reasonable 
187
	    // you'll find out that as you backspace you'll run over the cursor. 
188
	    // that's because the kernel linebuffer accounting assumes the above setup.
189
	    // I"m not sure how all of this came about but we have to mimic similar
190
	    // acounting and we do it by padding the buffer (only) with a bunch of spaces.
191
	    // 
192
	    // NOTE: There are two strong invariants you have to keep in mind:
193
	    // - Solaris, and I assume other unixes, stick to the BS-SP-BS echo
194
	    //   even though they seem to know about character widths.
195
	    // - BS from Term's point of view is _strictly_ a cursor motion operation!
196
	    //   The fact that it erases things has to do with the line discipline
197
	    //   (kernels or this class 'ere)
198
	    //
199
	    // Now I know non-unix people will want BS to behave sanely in non-unix
200
	    // environments, so perhapws we SHOULD have a property to control whether
201
	    // things get erased the unix way or some other way.
202
203
	    while(--cwidth > 0 )
204
		line.append(' ');
172
205
173
	    // erase character on screen
206
	    // erase character on screen
174
	    toDTE.putChars(bs_sequence, 0, 3);
207
	    toDTE.putChars(bs_sequence, 0, 3);
(-)MyFontMetrics.java (-1 / +158 lines)
Lines 22-31 Link Here
22
package org.netbeans.lib.terminalemulator;
22
package org.netbeans.lib.terminalemulator;
23
23
24
import java.awt.*;
24
import java.awt.*;
25
import java.util.AbstractMap;
26
import java.util.HashMap;
25
27
26
class MyFontMetrics {
28
class MyFontMetrics {
29
30
    /**
31
     * WidthCache contains a byte array that maps a character to it's cell width.
32
     * It also keeps track of whether we've discovered that we're dealing with a
33
     * font that has wide characters. This information is kept with WidthCache
34
     * because the caches are shared between MyFontMetrics and we test for
35
     * multi-cellnes only on a cache miss. So we got into a situation where one
36
     * Term got a wide character, missed the cache, figured that it's multi-cell,
37
     * then another Term got the same character didn't miss the cache and didn't
38
     * set it's own multi-cell bit.
39
     *
40
     * The reference counting stuff is explained with CacheFactory.
41
     */
42
43
    static class WidthCache {
44
	byte [] cache = new byte[Character.MAX_VALUE];
45
	int reference_count = 1;
46
47
	public void up() {
48
	    reference_count ++;
49
	    if (reference_count == 1)
50
		cache = new byte[Character.MAX_VALUE];
51
	} 
52
53
	public void down() {
54
	    if (reference_count == 0)
55
		return;
56
	    reference_count --;
57
	    if (reference_count == 0)
58
		cache = null;
59
	}
60
61
	public boolean isMultiCell() {
62
	    return multiCell;
63
	} 
64
	public void setMultiCell(boolean multiCell) {
65
	    if (!this.multiCell && multiCell) {
66
		// first time
67
		/* DEBUG
68
		System.out.println("##########################################");	// NOI18N
69
		System.out.println("#     SWITCHING TO MULTI CELL            #");	// NOI18N
70
		System.out.println("##########################################");	// NOI18N
71
		*/
72
	    } 
73
	    this.multiCell = multiCell;
74
	} 
75
	private boolean multiCell = false;
76
    }
77
78
    /**
79
     *
80
     * CacheFactory doles out WidthCaches.
81
     *
82
     * These caches are 64Kb (Character.MAX_VALUE) and we don't really want 
83
     * Each interp to have it's own. So we share them in a map using FontMetrics
84
     * as a key. Unfortunately stuff will accumulate in the map. A WeakHashMap
85
     * is no good because the keys (FontMetrics) are usually alive. For all I
86
     * know Jave might be cacheing them in turn. I actually tried using a
87
     * WeakHashMap and wouldn't see things going away, even after System.gc().
88
     * <p>
89
     * So we get this slightly more involved manager.
90
     * <br>
91
     * A WidthCache holds on to the actual WidthCache and reference counts it.
92
     * When the count goes to 0 the actual cache array is "free"d be nulling
93
     * it's reference. To make the reference count go down CacheFactory.disposeBy()
94
     * is used. And that is called from MyFontMetrics.finalize().
95
     *
96
     * NOTE: The actual WidthCache's instances _will_ accumulate, but they are small and 
97
     * there are only so many font variations an app can go through. As I
98
     * mentioned above using a WeakHashMap doesn't help much because WidthCache's
99
     * are keyed by relatively persistent FontMetrics.
100
     */
101
102
    private static class CacheFactory {
103
	static synchronized WidthCache cacheForFontMetrics(FontMetrics fm) {
104
	    WidthCache entry = (WidthCache) map.get(fm);
105
	    if (entry == null) {
106
		entry = new WidthCache();
107
		map.put(fm, entry);
108
	    } else {
109
		entry.up();
110
	    }
111
	    return entry;
112
	}
113
114
	static synchronized void disposeBy(FontMetrics fm) {
115
	    WidthCache entry = (WidthCache) map.get(fm);
116
	    if (entry != null)
117
		entry.down();
118
	}
119
120
	private static AbstractMap map = new HashMap();
121
    }
122
123
27
    public MyFontMetrics(Component component, Font font) {
124
    public MyFontMetrics(Component component, Font font) {
28
	FontMetrics fm = component.getFontMetrics(font);
125
	fm = component.getFontMetrics(font);
29
	width = fm.charWidth('a');
126
	width = fm.charWidth('a');
30
	height = fm.getHeight();
127
	height = fm.getHeight();
31
	ascent = fm.getAscent();
128
	ascent = fm.getAscent();
Lines 44-52 Link Here
44
141
45
	height -= leading;
142
	height -= leading;
46
	leading = 0;
143
	leading = 0;
144
145
	cwidth_cache = CacheFactory.cacheForFontMetrics(fm);
146
    }
147
148
    public void finalize() {
149
	CacheFactory.disposeBy(fm);
47
    }
150
    }
151
152
48
    public int width;
153
    public int width;
49
    public int height;
154
    public int height;
50
    public int ascent;
155
    public int ascent;
51
    public int leading;
156
    public int leading;
157
    public FontMetrics fm;
158
159
    private WidthCache cwidth_cache;
160
161
    public boolean isMultiCell() {
162
	return cwidth_cache.isMultiCell();
163
    } 
164
165
    /*
166
     * Called 'wcwidth' for historical reasons. (see wcwidth(3) on unix.)
167
     * Return how many cells this character occupies.
168
     */
169
170
    public int wcwidth(char c) {
171
	int cell_width = cwidth_cache.cache[c];	// how many cells wide
172
173
	if (cell_width == 0) {
174
	    // width not cached yet so figure it out
175
	    int pixel_width = fm.charWidth(c);
176
177
	    if (pixel_width == width) {
178
		cell_width = 1;
179
180
	    } else if (pixel_width == 0) { 
181
		cell_width = 1;
182
183
	    } else {
184
		// round up pixel width to multiple of cell size
185
		// then distill into a width in terms of cells.
186
		int mod = pixel_width % width;
187
		int rounded_width = pixel_width;
188
		if (mod != 0)
189
		    rounded_width = pixel_width + (width - mod);
190
		cell_width = rounded_width/width;
191
		if (cell_width == 0)
192
		    cell_width = 1;
193
194
		cwidth_cache.setMultiCell(true);
195
	    }
196
197
	    cwidth_cache.cache[c] = (byte) cell_width;
198
	}
199
	return cell_width;
200
    }
201
202
    /*
203
     * Shift to the multi-cell character regime as soon as we spot one.
204
     * The actual work is done in wcwidth() itself.
205
     */
206
    void checkForMultiCell(char c) {
207
	wcwidth(c);
208
    }
52
}
209
}
(-)ReleaseNotes.ivan.txt (+213 lines)
Lines 15-20 Link Here
15
15
16
================================================================================
16
================================================================================
17
back to main 3.3. trunk
17
back to main 3.3. trunk
18
=======
19
tag: ivan_13
20
21
- performance - reduce Interp footprint
22
	This was based on an observation made by Tor that each Interp
23
	ends up creating redundant copies of it's tste tables.
24
25
	All Interps now have a static inner class InterpType which
26
	owns the state transition tables and defines the actions..
27
	Multiple instances of Interps of the same type share InterpTypes.
28
29
	Since the state transition actions are now implemented in the
30
	InterpType, they need to receive an instance of an Interp whose state
31
	they will be modifying. This is passed as an AbstractInterp.
32
	Occasionally the passed-in interp has to be cast to the appropriate 
33
	subclass of AbstractInterp.
34
35
	In order to reduce the number of these casts moved number parsing mgmt
36
	from InterpANSI to AbstractInterp.
37
38
	Some Interp subclasses achieved their means by modifying their
39
	state vectors! Since the vectors are now shared that won't do, so a
40
	more appropriate state stack was introduced into InterpDumb.
41
	The stack is cleared in reset().
42
43
	Files:
44
	AbstractInterp.java
45
	InterpANSI.java
46
	InterpDtTerm.java
47
	InterpDumb.java
48
49
50
- performance - user cheaper Interps by default.
51
	Jesse (I think) pointed out that NB in general has no use for 
52
	ANSI emulation, and that Term should by default use a "dumb" terminal.
53
	This should reduce the # of classes that get loaded in.
54
	This happens in the initialization of 'private Term.interp'.
55
56
- I18N
57
	This addresses the following issues:
58
59
	15333 Cursor isn't on end of text after using CTRL+C [V, ...]
60
	19570 I18N - The characters of the error message are overlaped.
61
62
	Basically Term can now properly handle non-latin characters, like
63
	Japanese. These issues were realy only the tip of the iceberg. Term
64
	did not really work with japanese until now.
65
	The following work:
66
		- Proper cursor position.
67
		- Proper handling of line wrapping and backspacing over it
68
		  (for when horizontallyScrollable is false). This is important
69
		  for the proper working of Solaris 'vi' in the ja locale.
70
		- Sane reaction to ANSI terminal control escapes.
71
		- Selection works.
72
		- Active regions work.
73
		- Backspace, TAB etc. work.
74
75
	There are two big parts to this
76
77
	- Rendering characters in grid/cellular fashion.
78
79
	  The book 
80
		Creating Worldwide software (second edition) (Prentice Hall)
81
		Tuthill & Smallberg
82
	  discusses (on p98) how some characters might be double width and
83
	  presents 'wcswidth(3)' and 'wcwidth(3)' to return the _display_
84
	  width of a given character. The underlying assumption here is that 
85
	  fixed width fonts are actually quantized width fonts.
86
87
	  This doesn't seem to be the case for Java fonts. For example the
88
	  default ja font I get has 7pixel wide latin characters and 
89
	  12 pixel wide japanese characters. What to do?
90
91
	  Write our own 'wcwidth' that uses Font.charWidth() and rounds it up
92
	  to a multiple of the width of the latin char sub-set.
93
94
	  But that's not enough. Graphics.drawString() will still advance
95
	  each glyph by the original width of the font, not our rounded-up
96
	  value. One solution is then to use a drawString() per character.
97
	  The adopted solution is instead to use GlyphVector's and
98
	  Graphics2d.drawGlyphVector() as used in Term.myDrawChars() and
99
	  Term.massage_glyphs(). Despite the hairiness of the code there
100
	  it turns out to be faster than a drawString() per char by
101
	  a good margin.
102
103
	- Accounting for the difference in Buffer vs Screen coordinates.
104
	  (A reading of the main javadoc comment for class Term would
105
	  help understand the rest of this).
106
107
	  So now we have a situation where a Line holds characters whose
108
	  positions are not neccessarily in a 1-1 correspondence with their
109
	  cell positions. Mappings are provided in both directions via 
110
	  Line.bufToCell() and Line.cellToBuf(). They are used in the existing
111
	  buffer to view coordinate xform functions (which for example map
112
	  a screen position to a character for the purpose of selection).
113
	  A variety of other locations had to be adjusted to use these for
114
	  proper operation. The driving algorithm for choosing what needs
115
	  attention was occurances of st.cursor.col since the cursor 
116
	  is in cell coordinates.
117
118
	  These function aren't "cheap" because they count from the beginning
119
	  of the line. Cacheing the values is impractical for the following
120
	  reasons:
121
		- You need to cache each mapping since they are used with equal
122
		  frequency.
123
		- Because Term allows horizontal scrolling a line can 
124
		  potentially be very long. The index into a line therefore 
125
		  will range from 0 to Integer.MAX_VALUE. This means
126
		  a cache of short's won't do.
127
		- So now we're talking a fair amount of memory that is 
128
		  probably not justifiable unless we come up with a way to
129
		  quickly dispose of the caches. Cache invalidation is
130
		  always a tricky problem, but I found out something else.
131
		  For a while I installed a wcwidth() cache per line (In
132
		  retrospect having wcwidth() manage the cache of course
133
		  made a lot more sense) but along the way I discovered
134
		  that the per-line cache gets invalidated quite often.
135
		  In effect the cache wouldn't have been helpful.
136
	  There are some pattern that could use improvement, a bufToCell
137
	  immediately followed by a cellToBuf, or a bufToCell(x) followed
138
	  by bufToCell(x+n). These could be collapsed into specialized
139
	  functions.
140
141
	Some neccesssary fallout from all of this ...
142
143
	- MyFontMetrics.wcwidth() is expensive given the number of times it
144
	  gets called so the resultant width is cached. The cache is indexed
145
	  by the char so is naturally Character.MAX_VALUE big. Not a big
146
	  chunk of memory in the big scheme of things but it can add up if you
147
	  have many Term instances. So there's a pool of them indexed by 
148
	  FontMetrics. It's unfortunately trickier than you'd think. 
149
	  See the opening comment in class MyFontMetrics for more info.
150
151
	- LineDiscipline had to be adjusted to do something reasonable
152
	  with backspaces in line buffered mode. There's a big comment in
153
	  LineDiscipline.sendChar(). 
154
	  To do this it reuires to have a back-pointer to the Term so
155
	  we now have StreamTerm.setTerm() which is used in 
156
	  Term.pushStream().
157
158
	- Dealing with double-width is expensive so we don't want to
159
	  compromise speed in 8-bit locales.
160
161
	  One way to deal with this is to query the "file.encoding"
162
	  property but I found that it's value is very variable from
163
	  Java release to Java release and probably from platform to
164
	  platform. In 1.4 class Charset is supposed to deal with this
165
	  but we're not ready for that switch yet.
166
167
	  What I opted for is having MyFontMetrics.wcwidth check for
168
	  variation from an initial width and set a flag (multiCell) 
169
	  on the first deviation. Various parts of the code then check
170
	  MyFontMetrics.isMultiCell(). So, for example, the painting code
171
	  now instead of calling Graphics.drawChars() will call 
172
	  Term.myDrawChars() which will based on this flag do the expensive
173
	  or the cheap thing.
174
175
	A note on ANSI emulation vs double-width characters.
176
	The ANSI standard doesn't talk abut double-width characters! So
177
	dealing with them is AFAIK up to individual vendors. I've
178
	followed Solaris'es DtTerm behaviour and spent a fair amount of
179
	time making sure that Solaris vi (which can excellently edit
180
	wide-char files under DtTerm) works under Term.
181
182
- bug: <noid> Junk characters inserted on character insert.
183
	Occasionally when charactes are shuffled in the Buffer, usually
184
	under vi, junk (usually 0) characters gets inserted into the
185
	Buffer instead of ' ' (ASCII SP)'s. These show up as "squares".
186
	Fixed in Line.insertCharAt(), Line.setCharAt() and
187
	Line.clearToEndFrom()
188
189
	Prior to JDK 1.4 ascii 0 was rendered by Swing as a blank.
190
	But under 1.4 this problem is a whole lot more visible.
191
192
- bug: <noid> Pathologically slow horizontal scrolling on long lines
193
	Was attempting to render all characters even those that are
194
	not in view. Fixed in Term.paint_line_new().
195
196
- bug: <noid> Cursor gets drawn on the glyph gutter on horizontal scroll.
197
	Fixed by adding an additional check in paint_cursor();
198
199
- deprecated: Term.goTo(Coord)
200
	Use Term.setCursorCoord(Coord) which matches getCursorCoord().
201
202
- Misc:
203
	public->private
204
		Buffer.visible_cols
205
	+	Buffer.visibleCols()
206
	+	StreamTerm.BUFSZ	(instead of hard-coded 1024)
207
	+ 	collection of statistics on linefeeds
208
	-	Term.paint_line_old()	// dead code
209
	+	Term.charWidth(char)	// See section above on I18N.
210
211
212
213
================================================================================
214
tag: release33
215
216
- accessibility
217
	Term now implements Accessible and returns an accessible context.
218
	The "accessible description" is set.
219
	The "accessible name" is set from OW to be the same as the tab name.
220
221
- performance
222
	- Added Term.setKeyStrokeSet() in order to allow sharing of,
223
	  sometimes large, sets.
224
	  Added code to OW to take advantage of this.
225
	  See 'updateKeyStrokeSet()' and 'getCommonKeyStrokeSet()'.
226
	  This code also tracks changes to the global keymap so that Term will
227
	  now pass through newly added keyboard accelerators.
228
229
================================================================================
230
back to main 3.3. trunk
18
231
19
- bug: <noid> Missing ANSI escape sequence handling:
232
- bug: <noid> Missing ANSI escape sequence handling:
20
	- ESC [ 4 h     set insert/overstrike mode
233
	- ESC [ 4 h     set insert/overstrike mode
(-)Screen.java (+7 lines)
Lines 44-49 Link Here
44
	Dimension dim = new Dimension(dx, dy);
44
	Dimension dim = new Dimension(dx, dy);
45
	setSize(dim);
45
	setSize(dim);
46
	setPreferredSize(dim);
46
	setPreferredSize(dim);
47
	// setOpaque(true);	// see comment in Term.repaint()
47
48
48
	if (debug) {
49
	if (debug) {
49
	    // Just turning our double buffering isn't enough, need to
50
	    // Just turning our double buffering isn't enough, need to
Lines 58-66 Link Here
58
    } 
59
    } 
59
60
60
61
62
    /* OLD deprecated 
63
    */
61
    public boolean isManagingFocus() {
64
    public boolean isManagingFocus() {
62
	// So we see TABs
65
	// So we see TABs
63
	// Except it doesn't work as advertised
66
	// Except it doesn't work as advertised
67
	// Actually, if I don't do this I get no notification of TAB keys,
68
	// so leave it in. 
69
	// This function is deprecated under 1.4. Need to use
70
	// Component.setFocusTraversalKeysEnabled() instead.
64
	return true;
71
	return true;
65
    } 
72
    } 
66
73
(-)Sel.java (-8 / +14 lines)
Lines 105-111 Link Here
105
     * Adjust the selection against 'bias'.
105
     * Adjust the selection against 'bias'.
106
     * <p>
106
     * <p>
107
     * As the selection reaches the top of the history buffer it will get
107
     * As the selection reaches the top of the history buffer it will get
108
     * trimmed until eventually allof it will go away.
108
     * trimmed until eventually all of it will go away.
109
     *
109
     *
110
     * This form doesn't work if the selection is "split" by insertion of
110
     * This form doesn't work if the selection is "split" by insertion of
111
     * lines. Maybe we SHOULD have two arguments, adjust origin and adjust
111
     * lines. Maybe we SHOULD have two arguments, adjust origin and adjust
Lines 260-266 Link Here
260
	 * The string created in sel_done should be retained until
260
	 * The string created in sel_done should be retained until
261
	 * this function called.
261
	 * this function called.
262
	 */
262
	 */
263
	// System.out.println("lostOwnership()");	// NOI18N
263
	/* DEBUG
264
	System.out.println("lostOwnership()");	// NOI18N
265
	*/
264
	if (cancel(true))
266
	if (cancel(true))
265
	    term.repaint(false);
267
	    term.repaint(false);
266
    } 
268
    } 
Lines 288-300 Link Here
288
     * added, removed or cleared.
290
     * added, removed or cleared.
289
     */
291
     */
290
    int intersection(int line) {
292
    int intersection(int line) {
291
	/*
293
	/* DEBUG
292
	if (sel_origin == null) {
294
	if (sel_origin == null) {
293
	    System.out.println("Sel.intersection(" + line + ") no selection");
295
	    System.out.println("Sel.intersection(" + line + ") no selection");	// NOI18N
294
	} else {
296
	} else {
295
	    System.out.println("Sel.intersection(" + line + ")" +
297
	    System.out.println("Sel.intersection(" + line + ")" +	// NOI18N
296
		"  sel_origin.row = " + sel_origin.row + 
298
		"  sel_origin.row = " + sel_origin.row + 	// NOI18N
297
		"  sel_extent.row = " + sel_extent.row);
299
		"  sel_extent.row = " + sel_extent.row);	// NOI18N
298
	}
300
	}
299
	*/
301
	*/
300
302
Lines 331-340 Link Here
331
	begin = term.toViewCoord(begin);
333
	begin = term.toViewCoord(begin);
332
	end = term.toViewCoord(end);
334
	end = term.toViewCoord(end);
333
335
336
	int lw;		// width of last character in selection
337
	Line l = term.buf.lineAt(row);
338
	lw = l.width(term.metrics, ecol);
339
334
	Point pbegin = term.toPixel(begin);
340
	Point pbegin = term.toPixel(begin);
335
	Point pend = term.toPixel(end);
341
	Point pend = term.toPixel(end);
336
	pend.y += term.metrics.height;
342
	pend.y += term.metrics.height;
337
	pend.x += term.metrics.width;	// xterm actually doesn't do this
343
	pend.x += term.metrics.width * lw;	// xterm actually doesn't do this
338
344
339
	Dimension dim = new Dimension(pend.x - pbegin.x,
345
	Dimension dim = new Dimension(pend.x - pbegin.x,
340
				      pend.y - pbegin.y);
346
				      pend.y - pbegin.y);
(-)State.java (+1 lines)
Lines 28-33 Link Here
28
    public int firstx;
28
    public int firstx;
29
    public int firsty;
29
    public int firsty;
30
30
31
    // Cursor is in "cell" coordinates
31
    public BCoord cursor = new BCoord();
32
    public BCoord cursor = new BCoord();
32
33
33
    public void adjust(int amount) {
34
    public void adjust(int amount) {
(-)StreamTerm.java (-4 / +5 lines)
Lines 111-117 Link Here
111
     * Monitor output from process and forward to terminal
111
     * Monitor output from process and forward to terminal
112
     */
112
     */
113
    private class OutputMonitor extends Thread {
113
    private class OutputMonitor extends Thread {
114
	private char[] buf = new char[1024];
114
	private static final int BUFSZ = 1024;
115
	private char[] buf = new char[BUFSZ];
115
	private Term term;
116
	private Term term;
116
	private InputStreamReader reader;
117
	private InputStreamReader reader;
117
118
Lines 163-176 Link Here
163
164
164
	    try {
165
	    try {
165
		while(true) {
166
		while(true) {
166
		    int nread = reader.read(buf, 0, 1024);
167
		    int nread = reader.read(buf, 0, BUFSZ);
167
		    if (nread == -1) {
168
		    if (nread == -1) {
168
			// This happens if someone closes the input stream,
169
			// This happens if someone closes the input stream,
169
			// say the master end of the pty.
170
			// say the master end of the pty.
170
			/* When we clean up this gets closed so it's not
171
			/* When we clean up this gets closed so it's not
171
			   always an error.
172
			   always an error.
172
			System.err.println("com.sun.spro.Term.OutputMonitor: " +
173
			System.err.println("com.sun.spro.Term.OutputMonitor: " +	// NOI18N
173
			    "Input stream closed");inp
174
			    "Input stream closed");inp	// NOI18N
174
			*/
175
			*/
175
			break;
176
			break;
176
		    }
177
		    }
(-)Term.java (-303 / +675 lines)
Lines 29-34 Link Here
29
import javax.swing.*;
29
import javax.swing.*;
30
import javax.accessibility.*;
30
import javax.accessibility.*;
31
31
32
import java.awt.font.*;
33
import java.awt.geom.Point2D;
34
32
import java.util.HashSet;
35
import java.util.HashSet;
33
import java.util.Date;
36
import java.util.Date;
34
import java.util.LinkedList;
37
import java.util.LinkedList;
Lines 48-83 Link Here
48
    <li>History buffer.
51
    <li>History buffer.
49
    <li>Support for nested pickable regions in order to support hyperlinked
52
    <li>Support for nested pickable regions in order to support hyperlinked
50
	views or more complex active text utilities.
53
	views or more complex active text utilities.
54
    <li>Support for double-width Oriental characters.
51
</ul>
55
</ul>
52
<p>
56
<p>
53
<h2>Coordinate systems</h2>
57
<h2>Coordinate systems</h2>
54
Two coordinate systems are used with Term. They are both cartesian and
58
The following coordinate systems are used with Term.
55
have their origin at the top left. But they differ in all other respects:
59
They are all cartesian and have their origin at the top left.
60
All but the first are 0-origin.
61
But they differ in all other respects:
56
<dl>
62
<dl>
57
<dt>Screen coordinates
63
64
<dt>ANSI Screen coordinates
58
    <dd>
65
    <dd>
59
    Address only the visible portion of the screen.
66
    Address only the visible portion of the screen.
60
    They are 1-origin and extend thru the width and height of the visible
67
    They are 1-origin and extend thru the width and height of the visible
61
    portion of the screen per getColumns() and getRows(). 
68
    portion of the screen per getColumns() and getRows(). 
62
    <p>
69
    <p>
63
    This coordinate system is used mostly by the screen Interp classes and
70
    This is how an application (like 'vi' etc) views the screen.
64
    Ops.
71
    This coordinate system primarily comes into play in the cursor addressing
72
    directive, op_cm() and otherwise is not really used in the implementation.
73
<p>
74
75
<dt>Cell coordinates
76
    <dd>
77
    Each character usually takes one cell, and all placement on the screen
78
    is in terms of a grid of cells getColumns() wide This cellular nature
79
    is why fixed font is "required". In some locales some characters may
80
    be double-width.
81
    Japanese characters are like this, so they take up two cells.
82
    There are no double-height characters (that I know of).
83
    <p>
84
    Cursor motion is in cell coordinates, so to move past a Japanese character
85
    you need the cursor to move right twice. A cursor can also be placed on
86
    the second cell of a double-width character.
87
    <p>
88
    Note that this is strictly an internal coordinate system. For example
89
    Term.getCursorCol() and getCursorCoord() return buffer coordinates.
90
    <p>
91
    The main purpose of this coordinate system is to capture columns. 
92
    In the vertical direction sometimes it extends only the height of the
93
    screen and sometimes the height of the buffer.
65
<p>
94
<p>
66
<dt>Buffer coordinates
95
96
<dt>Buffer coordinates ...
67
    <dd>
97
    <dd>
68
    Address the whole history buffer.
98
    ... address the whole history character buffer.
69
    These are 0-origin and extend thru the width 
99
    These are 0-origin and extend thru the width 
70
    of the screen per getColumns() and the whole history (for which
100
    of the screen per getColumns(), or more if horizontal scrolling is
71
    there is no property yet. getHistorySize() isn't it).
101
    enabled, and the whole history (that's getHistorySize()+getRows()).
72
    <p>
102
    <p>
73
    The Coord class captures the value of such coordinates.
103
    The BCoord class captures the value of such coordinates.
74
    It is more akin to the 'int offset' used in the Java text package
104
    It is more akin to the 'int offset' used in the Java text package
75
    as opposed to javax.swing.text.Position.
105
    as opposed to javax.swing.text.Position.
106
    <p> 
107
    If there are no double-width characters the buffer coords pretty much
108
    overlap with cell coords. If double-width characters are added then
109
    the buffer column and cell column will have a larger skew the more right
110
    you go.
111
<p>
112
<dt>Absolute coordinates ...
113
    <dd>
114
    ... are like Buffer coordinates in the horizontal direction. 
115
    In the vertical direction their origin is the first line that was
116
    sent to the terminal. This line might have scrolled out of history and
117
    might no longer be in the buffer. In effect each line ever printed by 
118
    Term gets a unique Absolute row.
76
    <p>
119
    <p>
77
    Most, but not all, of the methods against Term and friends use the
120
    What good is this? The ActiveRegion mechanism maintains coordinates
78
    buffer coordinate system, but it hasn't all yet been regularized
121
    for its' boundaries. As text scrolls out of history buffer row coordinates
79
    so keep an eye out for unexpected use of screen coordinates.
122
    have to shift and all ActiveRegions' coords need to be relocated. This
80
123
    can get expensive because as soon as the history buffer becomes full
124
    each newline will require a relocation. This is the approach that
125
    javax.swing.text.Position implements and it's justified there because
126
    no Swing component has a "history buffer".
127
    However, if you use absolute coordinates you'll never have to 
128
    relocate anything! Simple and effective.
129
    <p>
130
    Well almost. What happens when you reach Integer.MAX_VALUE? You wrap and
131
    that can confuse everything. What are the chances of this happening?
132
    Suppose term can process 4000 lines per second. A runaway process will
133
    produce Integer.MAX_VALUE lines in about 4 days. That's too close
134
    for comfort, so Term does detect the wrap and only then goes and 
135
    relocates stuff. This, however, causes a secondary problem with
136
    testability since no-one wants to wait 4 days for a single wrap.
137
    So what I've done is periodically set Term.modulo to something
138
    smaller and tested stuff.
139
    <p>
140
    I'm indebted to Alan Kostinsky for this bit of lateral thinking.
81
</dl>
141
</dl>
82
142
83
143
Lines 110-118 Link Here
110
    This is the primary facility that XTerm and other derivatives provide. The
170
    This is the primary facility that XTerm and other derivatives provide. The
111
    screen has a history buffer in the vertical dimension.
171
    screen has a history buffer in the vertical dimension.
112
    <p>
172
    <p>
113
    Buffer coordinates play a role in this mode and it it crucial to 
173
    Because of limited history active regions can scroll out of history and
114
    remember that as the contents of the buffer scrolls and old
174
    while the coordinate invalidation problem is not addressed by absolute
115
    lines wink out of history coordinates become invalidated.
175
    coordiantes sometimes we don't want stuff to wink out.
116
    <br>
176
    <br>
117
    Which is why we have ...
177
    Which is why we have ...
118
178
Lines 120-129 Link Here
120
<dt>Page mode
180
<dt>Page mode
121
    <dd>
181
    <dd>
122
    It is possible to "anchor" a location in the buffer and prevent it 
182
    It is possible to "anchor" a location in the buffer and prevent it 
123
    from going out of history. While this can be helpful in having the
183
    from going out of history. This can be helpful in having the
124
    client of Term make sure that crucial output doesn't get lost due to
184
    client of Term make sure that crucial output doesn't get lost due to
125
    short-sighted history settings on the part of the user, the main reason
185
    short-sighted history settings on the part of the user.
126
    is to allow for persistence of coordinate settings.
127
    <p>
186
    <p>
128
    To use Term 
187
    To use Term 
129
    in this mode you can use setText() or appendText() instead of
188
    in this mode you can use setText() or appendText() instead of
Lines 146-154 Link Here
146
Term is not a document editing widget.
205
Term is not a document editing widget.
147
<p>
206
<p>
148
<li>
207
<li>
149
Term is also not a command line processor in the sense that a Windows
208
Term is also not a command line processor in the sense that a MS Windows
150
console is. Its shuttling of keyboard events to an output stream and
209
console is. Its shuttling of keyboard events to an output stream and
151
rendering of characters on the input stream unto the screen are completely
210
rendering of characters from the input stream unto the screen are completely
152
independent activities.
211
independent activities.
153
<p>
212
<p>
154
This is due to Terms unix heritage where shells (ksh, bash etc) do their own
213
This is due to Terms unix heritage where shells (ksh, bash etc) do their own
Lines 183-188 Link Here
183
    // statistics
242
    // statistics
184
    private int n_putchar;
243
    private int n_putchar;
185
    private int n_putchars;
244
    private int n_putchars;
245
    private int n_linefeeds;
186
    private int n_repaint;
246
    private int n_repaint;
187
    private int n_paint;
247
    private int n_paint;
188
248
Lines 352-357 Link Here
352
	    stream.setToDTE(dce_end);
412
	    stream.setToDTE(dce_end);
353
	    dce_end = stream;
413
	    dce_end = stream;
354
	}
414
	}
415
416
	stream.setTerm(this);
355
    }
417
    }
356
418
357
    /*
419
    /*
Lines 587-593 Link Here
587
    public void clearHistoryNoRefresh() {
649
    public void clearHistoryNoRefresh() {
588
	sel.cancel(true);
650
	sel.cancel(true);
589
651
590
	int old_cols = buf.visible_cols;
652
	int old_cols = buf.visibleCols();
591
	buf = new Buffer(old_cols);
653
	buf = new Buffer(old_cols);
592
654
593
	st.firstx = 0;
655
	st.firstx = 0;
Lines 943-948 Link Here
943
1005
944
	// vertical (row) dimension
1006
	// vertical (row) dimension
945
	if (st.cursor.row >= st.firstx && st.cursor.row < st.firstx + st.rows) {
1007
	if (st.cursor.row >= st.firstx && st.cursor.row < st.firstx + st.rows) {
1008
	    ;
946
	} else {
1009
	} else {
947
	    st.firstx = buf.nlines - st.rows;
1010
	    st.firstx = buf.nlines - st.rows;
948
	    repaint(true);
1011
	    repaint(true);
Lines 998-1015 Link Here
998
	    }
1061
	    }
999
	}
1062
	}
1000
1063
1001
	// System.out.println("Checking hscroll cursor.col " + st.cursor.col + 
1064
	/* DEBUG
1002
	//    " firsty " + st.firsty + " visible_cols " + buf.visible_cols);
1065
	System.out.println("Checking hscroll cursor.col " + st.cursor.col + 	// NOI18N
1066
	                   " firsty " + st.firsty 	// NOI18N
1067
			   " visibleCols " + buf.visibleCols());	// NOI18N
1068
	*/
1003
1069
1004
	// horizontal (col) dimension
1070
	// horizontal (col) dimension
1005
	if (st.cursor.col >= st.firsty + buf.visible_cols) {
1071
	if (st.cursor.col >= st.firsty + buf.visibleCols()) {
1006
	    // System.out.println("Need to scroll right");
1072
	    /* DEBUG
1007
	    st.firsty = st.cursor.col - buf.visible_cols + 1;
1073
	    System.out.println("Need to scroll right");	// NOI18N
1074
	    */
1075
	    st.firsty = st.cursor.col - buf.visibleCols() + 1;
1008
	    repaint(true);
1076
	    repaint(true);
1009
1077
1010
	} else if (st.cursor.col - buf.visible_cols < st.firsty) {
1078
	} else if (st.cursor.col - buf.visibleCols() < st.firsty) {
1011
	    // System.out.println("Need to scroll left");
1079
	    /* DEBUG
1012
	    st.firsty = st.cursor.col - buf.visible_cols + 1;
1080
	    System.out.println("Need to scroll left");	// NOI18N
1081
	    */
1082
	    st.firsty = st.cursor.col - buf.visibleCols() + 1;
1013
	    if (st.firsty < 0)
1083
	    if (st.firsty < 0)
1014
		st.firsty = 0;
1084
		st.firsty = 0;
1015
	    else
1085
	    else
Lines 1097-1103 Link Here
1097
	    // Really weird I seem to get the same results regardless of
1167
	    // Really weird I seem to get the same results regardless of
1098
	    // whether I use orows or buf.nlines. SHOULD investigate more.
1168
	    // whether I use orows or buf.nlines. SHOULD investigate more.
1099
1169
1100
	    // int allowed = orows - st.cursor.row - 1;
1101
	    int allowed = buf.nlines - st.cursor.row - 1;
1170
	    int allowed = buf.nlines - st.cursor.row - 1;
1102
1171
1103
	    if (allowed < 0)
1172
	    if (allowed < 0)
Lines 1173-1179 Link Here
1173
1242
1174
	    // cull any regions that are no longer in history
1243
	    // cull any regions that are no longer in history
1175
	    if (++cull_count % cull_frequency == 0) {
1244
	    if (++cull_count % cull_frequency == 0) {
1176
		// System.out.println("Culling regions ..."); // NOI18N
1245
		/* DEBUG
1246
		System.out.println("Culling regions ..."); // NOI18N
1247
		*/
1177
		region_manager.cull(firsta);
1248
		region_manager.cull(firsta);
1178
	    }
1249
	    }
1179
1250
Lines 1244-1255 Link Here
1244
		    c = 0;
1315
		    c = 0;
1245
		} else if ((direction & RIGHT) == RIGHT) {
1316
		} else if ((direction & RIGHT) == RIGHT) {
1246
		    st.firsty ++;
1317
		    st.firsty ++;
1247
		    int limit = buf.totalCols() - buf.visible_cols;
1318
		    int limit = buf.totalCols() - buf.visibleCols();
1248
		    if (limit < 0)
1319
		    if (limit < 0)
1249
			limit = 0;
1320
			limit = 0;
1250
		    if (st.firsty > limit)
1321
		    if (st.firsty > limit)
1251
			st.firsty = limit;
1322
			st.firsty = limit;
1252
		    c = st.firsty + buf.visible_cols;
1323
		    c = st.firsty + buf.visibleCols();
1253
		}
1324
		}
1254
1325
1255
		BCoord vc = new BCoord(r, c);
1326
		BCoord vc = new BCoord(r, c);
Lines 1263-1278 Link Here
1263
	public void run() {
1334
	public void run() {
1264
	    while (true) {
1335
	    while (true) {
1265
1336
1266
		// System.out.print("Scrolling ");
1337
		/* DEBUG
1267
		// if ((direction & UP) == UP)
1338
		System.out.print("Scrolling ");	// NOI18N
1268
		// 	System.out.print("UP ");
1339
		if ((direction & UP) == UP)
1269
		// if ((direction & DOWN) == DOWN)
1340
			System.out.print("UP ");	// NOI18N
1270
		// 	System.out.print("DOWN ");
1341
		if ((direction & DOWN) == DOWN)
1271
		// if ((direction & LEFT) == LEFT)
1342
			System.out.print("DOWN ");	// NOI18N
1272
		// 	System.out.print("LEFT ");
1343
		if ((direction & LEFT) == LEFT)
1273
		// if ((direction & RIGHT) == RIGHT)
1344
			System.out.print("LEFT ");	// NOI18N
1274
		// 	System.out.print("RIGHT ");
1345
		if ((direction & RIGHT) == RIGHT)
1275
		// System.out.println();
1346
			System.out.print("RIGHT ");	// NOI18N
1347
		System.out.println();
1348
		*/
1276
1349
1277
		extend();
1350
		extend();
1278
1351
Lines 1282-1288 Link Here
1282
		    break;
1355
		    break;
1283
		} 
1356
		} 
1284
	    }
1357
	    }
1285
	    // System.out.println("Done with Scrolling");
1358
	    /* DEBUG
1359
	    System.out.println("Done with Scrolling");	// NOI18N
1360
	    */
1286
	}
1361
	}
1287
    }
1362
    }
1288
1363
Lines 1354-1360 Link Here
1354
	BorderLayout layout = new BorderLayout();
1429
	BorderLayout layout = new BorderLayout();
1355
	setLayout(layout);
1430
	setLayout(layout);
1356
	screen = new Screen(this,
1431
	screen = new Screen(this,
1357
			    (buf.visible_cols * metrics.width +
1432
			    (buf.visibleCols() * metrics.width +
1358
			     glyph_gutter_width +
1433
			     glyph_gutter_width +
1359
			     debug_gutter_width),
1434
			     debug_gutter_width),
1360
			    st.rows * metrics.height);
1435
			    st.rows * metrics.height);
Lines 1389-1399 Link Here
1389
1464
1390
			// deal with the user moving the thumb
1465
			// deal with the user moving the thumb
1391
			st.firstx = pos;
1466
			st.firstx = pos;
1467
			/* DEBUG
1468
			if (st.firstx + st.rows > buf.nlines) {
1469
			    Thread.dumpStack();
1470
			    printStats("bad scroll value");	// NOI18N
1471
			}
1472
			*/
1392
			repaint(false);
1473
			repaint(false);
1393
			break;
1474
			break;
1394
1475
1395
		    default:
1476
		    default:
1396
			// System.out.println("adjustmentValueChanged: " + e); // NOI18N
1477
			/* DEBUG
1478
			System.out.println("adjustmentValueChanged: " + e); // NOI18N
1479
			*/
1397
			break;
1480
			break;
1398
		}
1481
		}
1399
	    }
1482
	    }
Lines 1429-1435 Link Here
1429
			break;
1512
			break;
1430
1513
1431
		    default:
1514
		    default:
1432
			// System.out.println("adjustmentValueChanged: " + e); // NOI18N
1515
			/* DEBUG
1516
			System.out.println("adjustmentValueChanged: " + e); // NOI18N
1517
			*/
1433
			break;
1518
			break;
1434
		}
1519
		}
1435
	    }
1520
	    }
Lines 1483-1489 Link Here
1483
	    }
1568
	    }
1484
1569
1485
	    public void keyPressed(KeyEvent e) {
1570
	    public void keyPressed(KeyEvent e) {
1486
		// System.out.println("keyPressed " + e); // NOI18N
1571
		/* DEBUG
1572
		System.out.println("keyPressed " + e); // NOI18N
1573
		*/
1487
1574
1488
		switch (e.getKeyCode()) {
1575
		switch (e.getKeyCode()) {
1489
		    case KeyEvent.VK_COPY:
1576
		    case KeyEvent.VK_COPY:
Lines 1508-1516 Link Here
1508
	    }
1595
	    }
1509
1596
1510
	    public void keyReleased(KeyEvent e) {
1597
	    public void keyReleased(KeyEvent e) {
1511
		// System.out.println("keyReleased"); // NOI18N
1598
		/* DEBUG
1599
		System.out.println("keyReleased"); // NOI18N
1600
		*/
1601
1512
		if (e.getKeyCode() == KeyEvent.VK_ENTER) {
1602
		if (e.getKeyCode() == KeyEvent.VK_ENTER) {
1513
		    // System.out.println("keyReleased VK_ENTER"); // NOI18N
1603
		    /* DEBUG
1604
		    System.out.println("keyReleased VK_ENTER"); // NOI18N
1605
		    */
1514
		    saw_return = false;
1606
		    saw_return = false;
1515
		}
1607
		}
1516
		maybeConsume(e);
1608
		maybeConsume(e);
Lines 1520-1533 Link Here
1520
	screen.addMouseMotionListener(new MouseMotionListener() { 
1612
	screen.addMouseMotionListener(new MouseMotionListener() { 
1521
1613
1522
	    public void mouseDragged(MouseEvent e) {
1614
	    public void mouseDragged(MouseEvent e) {
1523
		// System.out.println("mouseDragged"); // NOI18N
1615
		/* DEBUG
1616
		System.out.println("mouseDragged"); // NOI18N
1617
		*/
1524
		if (left_down_point != null) {
1618
		if (left_down_point != null) {
1525
		    BCoord bc = toBufCoords(toViewCoord(left_down_point));
1619
		    BCoord bc = toBufCoords(toViewCoord(left_down_point));
1526
		    sel.track(new Coord(bc, firsta));
1620
		    sel.track(new Coord(bc, firsta));
1527
		    left_down_point = null;
1621
		    left_down_point = null;
1528
		} 
1622
		} 
1529
		drag_point = e.getPoint();
1623
		drag_point = e.getPoint();
1530
		// System.out.println("mouseDrag: " + drag_point); // NOI18N
1624
		/* DEBUG
1625
		System.out.println("mouseDrag: " + drag_point); // NOI18N
1626
		*/
1531
1627
1532
		int scroll_direction = 0;
1628
		int scroll_direction = 0;
1533
1629
Lines 1547-1561 Link Here
1547
	    } 
1643
	    } 
1548
1644
1549
	    public void mouseMoved(MouseEvent e) {
1645
	    public void mouseMoved(MouseEvent e) {
1550
		/*
1646
		/* DEBUG
1551
		Point p = (Point) e.getPoint().clone();
1647
		Point p = (Point) e.getPoint().clone();
1552
		BCoord bc = toBufCoords(toViewCoord(p));
1648
		BCoord bc = toBufCoords(toViewCoord(p));
1553
		Coord c = new Coord(bc, firsta);
1649
		Coord c = new Coord(bc, firsta);
1554
		Extent x = sel.getExtent();
1650
		Extent x = sel.getExtent();
1555
		if (x == null) {
1651
		if (x == null) {
1556
		    // System.out.println("sel intersect: no extent");
1652
		    System.out.println("sel intersect: no extent");	// NOI18N
1557
		} else {
1653
		} else {
1558
		    // System.out.println("sel intersect: " + (x.intersects(c.row, c.col)? "intersects": "doesn't intersect"));
1654
		    System.out.println("sel intersect: " +	// NOI18N
1655
		    (x.intersects(c.row, c.col)? "intersects"	// NOI18N
1656
						 "doesn't intersect"));	// NOI18N
1559
		}
1657
		}
1560
		*/
1658
		*/
1561
	    } 
1659
	    } 
Lines 1564-1570 Link Here
1564
	screen.addMouseListener(new MouseListener() {
1662
	screen.addMouseListener(new MouseListener() {
1565
1663
1566
	    public void mouseClicked(MouseEvent e) {
1664
	    public void mouseClicked(MouseEvent e) {
1567
		// System.out.println("mouseClicked"); // NOI18N
1665
		/* DEBUG
1666
		System.out.println("mouseClicked"); // NOI18N
1667
		*/
1568
		BCoord bcoord = toBufCoords(toViewCoord(e.getPoint()));
1668
		BCoord bcoord = toBufCoords(toViewCoord(e.getPoint()));
1569
1669
1570
		if (SwingUtilities.isLeftMouseButton(e)) {
1670
		if (SwingUtilities.isLeftMouseButton(e)) {
Lines 1573-1580 Link Here
1573
			screen.requestFocus();
1673
			screen.requestFocus();
1574
1674
1575
		} else if ( SwingUtilities.isMiddleMouseButton(e)) {
1675
		} else if ( SwingUtilities.isMiddleMouseButton(e)) {
1576
		    // System.out.println("MIDDLE click"); // NOI18N
1676
		    /* DEBUG
1577
		    // System.out.println("Selection: '" + sel.sel_get() + "'"); // NOI18N
1677
		    System.out.println("MIDDLE click"); // NOI18N
1678
		    System.out.println("Selection: '" + sel.sel_get() + "'"); // NOI18N
1679
		    */
1578
		    paste();
1680
		    paste();
1579
1681
1580
		} else if (SwingUtilities.isRightMouseButton(e)) {
1682
		} else if (SwingUtilities.isRightMouseButton(e)) {
Lines 1703-1710 Link Here
1703
1805
1704
	if (message != null)
1806
	if (message != null)
1705
	    System.out.print("\t");	// NOI18N
1807
	    System.out.print("\t");	// NOI18N
1706
	System.out.println("rows " + st.rows +
1808
	System.out.println("rows " + st.rows +	// NOI18N
1707
	    "  v cols " + buf.visible_cols + // NOI18N
1809
	    "  v cols " + buf.visibleCols() + // NOI18N
1708
	    "  t cols " + buf.totalCols() + // NOI18N
1810
	    "  t cols " + buf.totalCols() + // NOI18N
1709
	    "  history " + history_size +	// NOI18N
1811
	    "  history " + history_size +	// NOI18N
1710
	    "  firstx " + st.firstx +	// NOI18N
1812
	    "  firstx " + st.firstx +	// NOI18N
Lines 1722-1727 Link Here
1722
	    System.out.print("\t");	// NOI18N
1824
	    System.out.print("\t");	// NOI18N
1723
	System.out.println("putChar " + n_putchar + // NOI18N
1825
	System.out.println("putChar " + n_putchar + // NOI18N
1724
			   "  putChars " + n_putchars +	// NOI18N
1826
			   "  putChars " + n_putchars +	// NOI18N
1827
		           "  linefeeds " + n_linefeeds +	// NOI18N
1725
		           "  repaint " + n_repaint +	// NOI18N
1828
		           "  repaint " + n_repaint +	// NOI18N
1726
			   "  paint " + n_paint);	// NOI18N
1829
			   "  paint " + n_paint);	// NOI18N
1727
    } 
1830
    } 
Lines 1813-1822 Link Here
1813
    }
1916
    }
1814
1917
1815
    /**
1918
    /**
1919
     * Trampoline from Line.ensureCapacity() to Buffer.noteColumn()
1920
     */
1921
    void noteColumn(Line l, int capacity) {
1922
	int vcapacity = l.bufToCell(metrics, capacity);
1923
	buf.noteColumn(vcapacity);
1924
    }
1925
1926
    /**
1927
     * Trampoline from Line to MyFontMetrics.checkForMultiCell()
1928
     */
1929
    void checkForMultiCell(char c) {
1930
	metrics.checkForMultiCell(c);
1931
    }
1932
1933
    /**
1816
     * Get the number of character columns in the screen
1934
     * Get the number of character columns in the screen
1817
     */
1935
     */
1818
    public int getColumns() {
1936
    public int getColumns() {
1819
	return buf.visible_cols;
1937
	return buf.visibleCols();
1820
    } 
1938
    } 
1821
1939
1822
    /**
1940
    /**
Lines 1892-1898 Link Here
1892
     */
2010
     */
1893
    public void fillSizeInfo(Dimension cells, Dimension pixels) {
2011
    public void fillSizeInfo(Dimension cells, Dimension pixels) {
1894
	cells.height = st.rows;
2012
	cells.height = st.rows;
1895
	cells.width = buf.visible_cols;
2013
	cells.width = buf.visibleCols();
1896
	Dimension cpixels = screen.getSize();
2014
	Dimension cpixels = screen.getSize();
1897
	pixels.width = cpixels.width - glyph_gutter_width - debug_gutter_width;
2015
	pixels.width = cpixels.width - glyph_gutter_width - debug_gutter_width;
1898
	pixels.height = cpixels.height;
2016
	pixels.height = cpixels.height;
Lines 1904-1910 Link Here
1904
     */
2022
     */
1905
    protected void updateTtySize() {
2023
    protected void updateTtySize() {
1906
	if (screen != null) {
2024
	if (screen != null) {
1907
	    Dimension cells = new Dimension(buf.visible_cols, st.rows);
2025
	    Dimension cells = new Dimension(buf.visibleCols(), st.rows);
1908
	    Dimension pixels = screen.getSize();
2026
	    Dimension pixels = screen.getSize();
1909
	    fireSizeChanged(cells, pixels);
2027
	    fireSizeChanged(cells, pixels);
1910
	}
2028
	}
Lines 1918-1924 Link Here
1918
	/*
2036
	/*
1919
	 * Convert from buffer coords to view coords
2037
	 * Convert from buffer coords to view coords
1920
	 */
2038
	 */
1921
	BCoord v = new BCoord(b.row - st.firstx, b.col - st.firsty);
2039
	int vc = buf.lineAt(b.row).bufToCell(metrics, b.col);
2040
	BCoord v = new BCoord(b.row - st.firstx, vc - st.firsty);
1922
	return v;
2041
	return v;
1923
    }
2042
    }
1924
2043
Lines 1949-1955 Link Here
1949
    private BCoord toViewCoord(Point p) {
2068
    private BCoord toViewCoord(Point p) {
1950
	BCoord v = new BCoord(p.y / metrics.height,
2069
	BCoord v = new BCoord(p.y / metrics.height,
1951
			    (p.x - glyph_gutter_width - debug_gutter_width)  / metrics.width);
2070
			    (p.x - glyph_gutter_width - debug_gutter_width)  / metrics.width);
1952
	v.clip(st.rows, buf.visible_cols);
2071
	v.clip(st.rows, buf.visibleCols());
1953
	// System.out.println("toViewCoord() -> " + v); // NOI18N
2072
	// System.out.println("toViewCoord() -> " + v); // NOI18N
1954
	return v;
2073
	return v;
1955
    } 
2074
    } 
Lines 1962-1969 Link Here
1962
	int brow = st.firstx + v.row;
2081
	int brow = st.firstx + v.row;
1963
	if (brow >= buf.nlines)
2082
	if (brow >= buf.nlines)
1964
	    brow = buf.nlines-1;
2083
	    brow = buf.nlines-1;
1965
	BCoord b = new BCoord(brow, st.firsty + v.col);
2084
	int bc = buf.lineAt(brow).cellToBuf(metrics, st.firsty + v.col);
1966
	// System.out.println("toBufCoords() -> " + b); // NOI18N
2085
	BCoord b = new BCoord(brow, bc);
2086
	// System.out.println("toBufCoords(" + v + ") -> " + b); // NOI18N
1967
	return b;
2087
	return b;
1968
    } 
2088
    } 
1969
2089
Lines 2013-2036 Link Here
2013
	} 
2133
	} 
2014
    }
2134
    }
2015
2135
2136
2016
    private Color actual_foreground;
2137
    private Color actual_foreground;
2017
    private Color actual_background;
2138
    private Color actual_background;
2018
    private boolean check_selection;
2139
    private boolean check_selection;
2019
    private int totcols;
2140
    private int totcols;
2020
2141
2021
    private void do_run(Graphics g, int yoff, int xoff, int baseline,
2142
    private void do_run(Graphics g, int yoff, int xoff, int baseline,
2022
			int brow, char buf[],
2143
			int brow, char buf[], Line l,
2023
			int attr, int rbegin, int rend) {
2144
			int attr, int rbegin, int rend) {
2024
2145
2025
	// System.out.println("do_run(" + rbegin + ", " + rend + ")");
2146
	// System.out.println("do_run(" + rbegin + ", " + rend + ")");	// NOI18N
2026
2147
2027
	int x = xoff + (rbegin - st.firsty) * metrics.width;
2148
	int x;
2028
	int rlength = rend - rbegin + 1;
2149
	int rlength;
2029
	if (rlength <= 0) {
2150
	int xlength;
2030
	    System.out.println("do_run(" + rbegin + ", " + rend + ")");
2151
2031
	    return;
2152
	if (metrics.isMultiCell()) {
2153
	    int vbegin = l.bufToCell(metrics, rbegin);
2154
	    int vend = l.bufToCell(metrics, rend+1)-1;
2155
	    x = xoff + (vbegin - st.firsty) * metrics.width;
2156
	    int vlength = vend - vbegin + 1;
2157
	    if (vlength <= 0) {
2158
		/* DEBUG
2159
		System.out.println("do_run(" + rbegin + ", " + rend + ")");	// NOI18N
2160
		*/
2161
		return;
2162
	    }
2163
	    rlength = rend - rbegin + 1;
2164
	    xlength = vlength * metrics.width;
2165
2166
	} else {
2167
	    x = xoff + (rbegin - st.firsty) * metrics.width;
2168
	    rlength = rend - rbegin + 1;
2169
	    if (rlength <= 0) {
2170
		/* DEBUG
2171
		System.out.println("do_run(" + rbegin + ", " + rend + ")");	// NOI18N
2172
		*/
2173
		return;
2174
	    }
2175
	    xlength = rlength * metrics.width;
2032
	}
2176
	}
2033
	int xlength = rlength * metrics.width;
2034
2177
2035
	boolean reverse = ((attr & Attr.REVERSE) == Attr.REVERSE);
2178
	boolean reverse = ((attr & Attr.REVERSE) == Attr.REVERSE);
2036
	boolean active = ((attr & Attr.ACTIVE) == Attr.ACTIVE);
2179
	boolean active = ((attr & Attr.ACTIVE) == Attr.ACTIVE);
Lines 2097-2126 Link Here
2097
	}
2240
	}
2098
2241
2099
	// Draw the foreground character glyphs
2242
	// Draw the foreground character glyphs
2100
	g.drawChars(buf, rbegin, rlength, x, baseline);
2243
	myDrawChars(g, buf, l, rbegin, rlength, x, baseline);
2101
2244
2102
	// Draw fake bold characters by redrawing one pixel to the right
2245
	// Draw fake bold characters by redrawing one pixel to the right
2103
	if ( (attr & Attr.BRIGHT) == Attr.BRIGHT) {
2246
	if ( (attr & Attr.BRIGHT) == Attr.BRIGHT) {
2104
	    g.drawChars(buf, rbegin, rlength, x+1, baseline);
2247
	    myDrawChars(g, buf, l, rbegin, rlength, x+1, baseline);
2248
	}
2249
    }
2250
2251
2252
2253
    private final Point newp = new Point();
2254
2255
    /*
2256
     * Tweak glyph X positions so they fall on cell/grid/column boundries.
2257
     */
2258
    private void massage_glyphs(GlyphVector gv, int start, int n, Line l) {
2259
	Point2D pos0 = gv.getGlyphPosition(0);
2260
2261
	// There's one big assumption here that in a monospaced font all the
2262
	// Y placements are identical. So we use the placement for the first
2263
	// glyph only.
2264
	newp.y = (int) pos0.getY();
2265
2266
	int col = (int) pos0.getX();
2267
	for (int gx = 0; gx < n; gx++) {
2268
	    newp.x = col;
2269
	    gv.setGlyphPosition(gx, newp);
2270
	    col += l.width(metrics, start + gx) * metrics.width;
2271
	}
2272
    }
2273
2274
    /**
2275
     * Draw characters in cells.
2276
     *
2277
     * Fixed width or monospaced fonts implies that the glyphs of all characters
2278
     * have the same width. Some non-latin characters (japanese) might have 
2279
     * glyph widths that are an _integer multiple_ of the latin glyphs. Thus
2280
     * cellular (grid based) text widget like this termulator can still place
2281
     * all characters nicely. There is a 'C' function wcwidth() which
2282
     * ... determines the number of _column_ positions ... and CDE's DtTrem
2283
     * ultimately depends on it to place things. (See also Tuthill & Smallberg,
2284
     * "Creating worldwide software" PrenticeHall 2nd ed. p98)
2285
     *
2286
     * Unfortunately the fonts used by Java, even the "monospaced" fonts, do
2287
     * not abide by the above convention. I measured a 10pt ja locale latin
2288
     * character at 7 pixels wide and a japanese character at 12 pixels wide,
2289
     * instead of 14. A similar problem existed with respect to the "unprintbale"
2290
     * placeholder square. Until Java 1.4 it used to be 9 or 10 pixels wide!
2291
     * The square is fixed, but I"m not sure the above will be anytime soon.
2292
     *
2293
     * What this means is that Graphics.drawString() when given a mix and match
2294
     * of latin and japanese characters will not place them right. Selection
2295
     * doesn't work etc. 
2296
     *
2297
     * Nor does Java provide anything resembling wcwidth() so we're rolling
2298
     * our own here. That's done in Line.width().
2299
     * 
2300
     * So one approach would be to place each character individually, but it's
2301
     * rather slow. Fortunately Java provides a GlyphVector class that allows
2302
     * us to tweak the positions of the glyphs. The timing I"ve gotten are
2303
     *		50	for one drawChars() per charactr. (SLOWER below)
2304
     *		15	using the GlyphVector technique
2305
     *		8	using plain drawChars
2306
     * Unfortunately GlyphVector's interface leaves a bit to be desired.
2307
     * - It does not take a (char [], offset, length) triple and depends 
2308
     *   on the length of the char array passed in. Since our Line char arrays
2309
     *   have some slop in them we can't pass them directly. Hence the 
2310
     *	 "new char[]" and the "System.arraycopy".
2311
     * - The interface for getting and setting positions is also a bit
2312
     *	 awkward as you may notice from massage_glyphs().
2313
     *
2314
     * We SHOULD fall back on plain drawChars() if the host charset is an
2315
     * 8 bit encoding like ASCII or ISO 8859. This encoding is available
2316
     * via System.getProperty("file.encoding") but there are so many aliases
2317
     * for each that I"m wary of hardcoding tests. See
2318
     * http://www.iana.org/assignments/character-sets 
2319
     * Java 1.4 has class Charset that helps with the aliases but we can't
2320
     * yet lock into 1.4.
2321
     */
2322
2323
    private void myDrawChars(Graphics g, char buf[], Line l,
2324
			     int start, int howmany, int xoff, int baseline) {
2325
	if (metrics.isMultiCell()) {
2326
	    // slow way
2327
	    // This looks expensive but it is in fact a whole lot faster
2328
	    // than issuing a g.drawChars() _per_ character
2329
2330
	    Graphics2D g2 = (Graphics2D) g;
2331
	    FontRenderContext frc = g2.getFontRenderContext();
2332
	    // Gaaah, why doesn't createGlyphVector() take a (char[],offset,len)
2333
	    // triple?
2334
	    char[] tmp = new char[howmany];
2335
	    System.arraycopy(buf, start, tmp, 0, howmany);
2336
	    GlyphVector gv = getFont().createGlyphVector(frc, tmp);
2337
	    massage_glyphs(gv, start, howmany, l);
2338
	    g2.drawGlyphVector(gv, xoff, baseline);
2339
	} else {
2340
	    // fast way
2341
	    g.drawChars(buf, start, howmany, xoff, baseline);
2105
	}
2342
	}
2106
    }
2343
    }
2107
2344
2108
    /*
2345
    /*
2109
     * Render one line
2346
     * Render one line
2347
     * Draw the line on this brow (buffer row 0-origin)
2110
     */
2348
     */
2111
2349
2112
    private void paint_line_new(Graphics g, Line l, int brow,
2350
    private void paint_line_new(Graphics g, Line l, int brow,
2113
			   int xoff, int yoff, int baseline,
2351
			   int xoff, int yoff, int baseline,
2114
			   Extent selx) {
2352
			   Extent selx) {
2115
	// draw the line on this brow (buffer row 0-origin)
2116
2353
2117
	int length = l.length();
2354
	int length = l.length();
2118
	if (length == 0)
2355
	if (length == 0)
2119
	    return;
2356
	    return;
2120
2357
2121
	int howmany = length-st.firsty;
2358
	int lastcol;
2122
	if (howmany <= 0)
2359
	int firstcol;
2360
2361
	if (metrics.isMultiCell()) {
2362
2363
	    // Figure what buffer column is the first visible one (moral
2364
	    // equivalent of st.firsty)
2365
2366
	    // SHOULD replace with something that does cellToBuf/bufToCell
2367
	    // all at once. There are a couple of other occurances of this
2368
	    // pattern.
2369
2370
	    firstcol = l.cellToBuf(metrics, st.firsty);
2371
	    int inverse_firstcol = l.bufToCell(metrics, firstcol);
2372
	    int delta = st.firsty - inverse_firstcol;
2373
	    if (delta > 0) {
2374
		/* This is what to do if we want to draw the right half of the
2375
		 * glyph. However the left half of it will end up in the glyph
2376
		 * gutter and to compensate for thet we'll need to tweak the
2377
		 * clip region. For now taking the easy way out>
2378
2379
		int pdelta = delta * metrics.width;	// pixel delta
2380
		xoff -= pdelta;
2381
2382
		*/
2383
2384
		firstcol++;
2385
		int pdelta = delta * metrics.width;	// pixel delta
2386
		xoff += pdelta;
2387
	    }
2388
2389
	    lastcol = l.cellToBuf(metrics, st.firsty + buf.visibleCols() - 1);
2390
2391
	    /* DEBUG
2392
	    System.out.print
2393
		("firstcol = " + firstcol + " for firsty " + st.firsty); // NOI18N
2394
	    System.out.print
2395
		(" delta = " + delta); // NOI18N
2396
	    System.out.println
2397
		(" lastcol = " + lastcol +	// NOI18N
2398
		 " for visibleCols " + buf.visibleCols()); // NOI18N
2399
	    */
2400
2401
	} else {
2402
	    lastcol = st.firsty + buf.visibleCols() - 1;
2403
	    firstcol = st.firsty;
2404
	}
2405
2406
2407
	lastcol = Math.min(lastcol, length-1);
2408
	if (firstcol > lastcol)
2123
	    return;
2409
	    return;
2410
	int howmany = lastcol - firstcol + 1;
2411
2412
2413
	// 'length' is not used from here on down
2124
2414
2125
	char buf[] = l.charArray();
2415
	char buf[] = l.charArray();
2126
2416
Lines 2130-2141 Link Here
2130
		if (l.isWrapped() && l.isAboutToWrap())
2420
		if (l.isWrapped() && l.isAboutToWrap())
2131
		    g.setColor(Color.red);	// not a good state to be in
2421
		    g.setColor(Color.red);	// not a good state to be in
2132
		else if (l.isAboutToWrap())
2422
		else if (l.isAboutToWrap())
2133
		    g.setColor(Color.pink);
2423
		    g.setColor(Color.orange);
2134
		else if (l.isWrapped())
2424
		else if (l.isWrapped())
2135
		    g.setColor(Color.magenta);
2425
		    g.setColor(Color.magenta);
2136
	    }
2426
	    }
2137
2427
2138
	    g.drawChars(buf, st.firsty, howmany, xoff, baseline);
2428
	    myDrawChars(g, buf, l, firstcol, howmany, xoff, baseline);
2429
2430
2139
	    return;
2431
	    return;
2140
	}
2432
	}
2141
2433
Lines 2166-2174 Link Here
2166
	}
2458
	}
2167
2459
2168
	// iterate through runs
2460
	// iterate through runs
2169
	int lastcol = st.firsty + howmany;
2170
2461
2171
	int rbegin = st.firsty;
2462
	int rbegin = firstcol;
2172
	int rend = rbegin;
2463
	int rend = rbegin;
2173
2464
2174
	while (true) {
2465
	while (true) {
Lines 2179-2185 Link Here
2179
2470
2180
	    int attr = attrs[rbegin];
2471
	    int attr = attrs[rbegin];
2181
	    rend = rbegin+1;
2472
	    rend = rbegin+1;
2182
	    while (rend < lastcol) {
2473
	    while (rend <= lastcol) {
2183
		if (attrs[rend] != attr)
2474
		if (attrs[rend] != attr)
2184
		    break;
2475
		    break;
2185
		rend++;
2476
		rend++;
Lines 2195-2239 Link Here
2195
	    if (sbegin == -1 || send < rbegin || sbegin > rend) {
2486
	    if (sbegin == -1 || send < rbegin || sbegin > rend) {
2196
		// run is not in selection
2487
		// run is not in selection
2197
		do_run(g, yoff, xoff,
2488
		do_run(g, yoff, xoff,
2198
		       baseline, brow, buf, attr, rbegin, rend);
2489
		       baseline, brow, buf, l, attr, rbegin, rend);
2199
2490
2200
	    } else if (sbegin <= rbegin && send >= rend) {
2491
	    } else if (sbegin <= rbegin && send >= rend) {
2201
		// run entirely in selection
2492
		// run entirely in selection
2202
		// System.out.println("run entirely in selection");
2493
		/* DEBUG
2494
		System.out.println("run entirely in selection");	// NOI18N
2495
		*/
2203
		do_run(g, yoff, xoff,
2496
		do_run(g, yoff, xoff,
2204
		       baseline, brow, buf, alt_attr, rbegin, rend);
2497
		       baseline, brow, buf, l, alt_attr, rbegin, rend);
2205
2498
2206
	    } else if (sbegin > rbegin && send < rend) {
2499
	    } else if (sbegin > rbegin && send < rend) {
2207
		// selection fully within run
2500
		// selection fully within run
2208
		// split into three parts
2501
		// split into three parts
2209
		// System.out.println("run selection fully within run");
2502
		/* DEBUG
2503
		System.out.println("run selection fully within run");	// NOI18N
2504
		*/
2210
		do_run(g, yoff, xoff,
2505
		do_run(g, yoff, xoff,
2211
		       baseline, brow, buf, attr, rbegin, sbegin-1);
2506
		       baseline, brow, buf, l, attr, rbegin, sbegin-1);
2212
		do_run(g, yoff, xoff,
2507
		do_run(g, yoff, xoff,
2213
		       baseline, brow, buf, alt_attr, sbegin, send);
2508
		       baseline, brow, buf, l, alt_attr, sbegin, send);
2214
		do_run(g, yoff, xoff,
2509
		do_run(g, yoff, xoff,
2215
		       baseline, brow, buf, attr, send+1, rend);
2510
		       baseline, brow, buf, l, attr, send+1, rend);
2216
2511
2217
	    } else if (sbegin <= rbegin) {
2512
	    } else if (sbegin <= rbegin) {
2218
		// selection covers left portion of run
2513
		// selection covers left portion of run
2219
		// System.out.println("selection covers left portion of run");
2514
		/* DEBUG
2515
		System.out.println("selection covers left portion of run");	// NOI18N
2516
		*/
2220
		// split into two parts
2517
		// split into two parts
2221
		do_run(g, yoff, xoff,
2518
		do_run(g, yoff, xoff,
2222
		       baseline, brow, buf, alt_attr, rbegin, send);
2519
		       baseline, brow, buf, l, alt_attr, rbegin, send);
2223
		do_run(g, yoff, xoff,
2520
		do_run(g, yoff, xoff,
2224
		       baseline, brow, buf, attr, send+1, rend);
2521
		       baseline, brow, buf, l, attr, send+1, rend);
2225
2522
2226
	    } else if (send >= rend) {
2523
	    } else if (send >= rend) {
2227
		// selection covers right portion of run
2524
		// selection covers right portion of run
2228
		// split into two parts
2525
		// split into two parts
2229
		// System.out.println("selection covers right portion of run");
2526
		/* DEBUG
2527
		System.out.println("selection covers right portion of run");	// NOI18N
2528
		*/
2230
		do_run(g, yoff, xoff,
2529
		do_run(g, yoff, xoff,
2231
		       baseline, brow, buf, attr, rbegin, sbegin-1);
2530
		       baseline, brow, buf, l, attr, rbegin, sbegin-1);
2232
		do_run(g, yoff, xoff,
2531
		do_run(g, yoff, xoff,
2233
		       baseline, brow, buf, alt_attr, sbegin, rend);
2532
		       baseline, brow, buf, l, alt_attr, sbegin, rend);
2234
2533
2235
	    } else {
2534
	    } else {
2236
		// System.out.println("Odd run/selection overlap");
2535
		// System.out.println("Odd run/selection overlap");	// NOI18N
2237
	    }
2536
	    }
2238
2537
2239
	    if (rend+1 >= lastcol)
2538
	    if (rend+1 >= lastcol)
Lines 2244-2381 Link Here
2244
	}
2543
	}
2245
    }
2544
    }
2246
2545
2247
    private void paint_line_old(Graphics g, Line l, int brow,
2248
			   int xoff, int yoff, int baseline,
2249
			   Extent selx) {
2250
	// draw the line on this brow (buffer row 0-origin)
2251
2252
	int length = l.length();
2253
	if (length == 0)
2254
	    return;
2255
2256
	int howmany = length-st.firsty;
2257
	if (howmany <= 0)
2258
	    return;
2259
2260
	char buf[] = l.charArray();
2261
2262
	if (! l.hasAttributes()) {
2263
2264
	    if (debugWrap()) {
2265
		if (l.isWrapped() && l.isAboutToWrap())
2266
		    g.setColor(Color.red);	// not a good state to be in
2267
		else if (l.isAboutToWrap())
2268
		    g.setColor(Color.pink);
2269
		else if (l.isWrapped())
2270
		    g.setColor(Color.magenta);
2271
	    }
2272
2273
	    g.drawChars(buf, st.firsty, howmany, xoff, baseline);
2274
	    return;
2275
	}
2276
2277
	int attrs[] = l.attrArray();
2278
2279
	int lastcol = st.firsty + howmany;
2280
	int x = xoff;
2281
2282
	for (int col = st.firsty; col < lastcol; col++) {
2283
	    int attr = attrs[col];
2284
	    boolean reverse = ((attr & Attr.REVERSE) == Attr.REVERSE);
2285
	    boolean active = ((attr & Attr.ACTIVE) == Attr.ACTIVE);
2286
	    boolean need_rect = reverse || active;
2287
	    boolean override_fg = false;
2288
2289
	    // choose background color
2290
	    // If we're doing 'reverse' video then we use FG colors for BG.
2291
	    Color bg;
2292
	    if (reverse) {
2293
		int fcx = Attr.foregroundColor(attr);
2294
		if (fcx != 0 && fcx <= 8) {
2295
                    bg = standard_color[fcx-1];
2296
                    need_rect = true;
2297
                } else if (fcx != 0 && fcx > 8) {
2298
                    bg = custom_color[fcx-9];
2299
                    need_rect = true;
2300
                } else {
2301
		    bg = actual_foreground;
2302
		}
2303
2304
	    } else {
2305
		int bcx = Attr.backgroundColor(attr);
2306
                if (bcx != 0 && bcx <= 8) {
2307
                    bg = standard_color[bcx-1];
2308
                    need_rect = true;
2309
                } else if (bcx > 8) {
2310
                    bg = custom_color[bcx-9];
2311
                    need_rect = true;
2312
                } else {
2313
		    bg = actual_background;
2314
		}
2315
	    }
2316
2317
	    if (check_selection &&
2318
		selx.intersects(firsta + brow, col)) {
2319
2320
		need_rect = false;
2321
		override_fg = true;
2322
	    }
2323
2324
	    if (need_rect) {
2325
		// Draw any background
2326
		if (active) {
2327
		    g.setColor(active_color);
2328
		} else {
2329
		    g.setColor(bg);
2330
		}
2331
		g.fillRect(x, yoff,
2332
			   metrics.width, metrics.height - metrics.leading);
2333
	    }
2334
2335
	    // Set foreground color
2336
	    Color fg;
2337
	    if (override_fg) {
2338
		fg = actual_foreground;
2339
	    } else if (reverse) {
2340
		int bcx = Attr.backgroundColor(attr);
2341
                if (bcx != 0 && bcx <= 8) {
2342
                    fg = standard_color[bcx-1];
2343
                } else if (bcx > 8) {
2344
                    fg = custom_color[bcx-9];
2345
                } else {
2346
		    fg = actual_background;
2347
		}
2348
2349
	    } else {
2350
		int fcx = Attr.foregroundColor(attr);
2351
		if (fcx != 0 && fcx <= 8) {
2352
                    fg = standard_color[fcx-1];
2353
                } else if (fcx != 0 && fcx > 8) {
2354
                    fg = custom_color[fcx-9];
2355
                } else {
2356
		    fg = actual_foreground;
2357
		}
2358
	    }
2359
	    g.setColor(fg);
2360
2361
	    // draw any underscores
2362
	    if ( (attr & Attr.UNDERSCORE) == Attr.UNDERSCORE) {
2363
		int h = metrics.height - metrics.leading - 1;
2364
		g.drawLine(x, yoff+h, x + metrics.width, yoff+h);
2365
	    }
2366
2367
	    // Draw the foreground character glyphs
2368
	    g.drawChars(buf, col, 1, x, baseline);
2369
2370
	    // Draw fake bold characters by redrawing one pixel to the right
2371
	    if ( (attr & Attr.BRIGHT) == Attr.BRIGHT) {
2372
		g.drawChars(buf, col, 1, x+1, baseline);
2373
	    }
2374
2375
	    x += metrics.width;
2376
	}
2377
    }
2378
2379
    synchronized void do_paint(Graphics g) {
2546
    synchronized void do_paint(Graphics g) {
2380
2547
2381
	/*
2548
	/*
Lines 2391-2397 Link Here
2391
	    return;
2558
	    return;
2392
	}
2559
	}
2393
2560
2394
	// long paint_start_time = System.currentTimeMillis();
2561
	/* DEBUG
2562
	long paint_start_time = System.currentTimeMillis();
2563
	*/
2564
2565
	// If Screen is opaque it seems that there is a bug in Swing where 
2566
	// the Graphics that we get here ends up with fonts other than what
2567
	// we assigned to Term. So we make doubly sure here.
2568
	g.setFont(getFont());
2395
2569
2396
	n_paint++;
2570
	n_paint++;
2397
2571
Lines 2456-2462 Link Here
2456
	for (int vrow = 0; vrow < st.rows; vrow++) {
2630
	for (int vrow = 0; vrow < st.rows; vrow++) {
2457
	    Line l = buf.lineAt(lx);
2631
	    Line l = buf.lineAt(lx);
2458
	    if (l == null) {
2632
	    if (l == null) {
2633
		/* DEBUG
2459
		System.out.println("vrow " + vrow + "  lx " + lx); // NOI18N
2634
		System.out.println("vrow " + vrow + "  lx " + lx); // NOI18N
2635
		*/
2460
		printStats(null);
2636
		printStats(null);
2461
		break;
2637
		break;
2462
	    }
2638
	    }
Lines 2498-2506 Link Here
2498
	if (debugMargins())
2674
	if (debugMargins())
2499
	    paint_margins(g);
2675
	    paint_margins(g);
2500
2676
2501
	// long paint_stop_time = System.currentTimeMillis();
2677
	/* DEBUG
2502
	// long paint_time = paint_stop_time - paint_start_time;
2678
	long paint_stop_time = System.currentTimeMillis();
2503
	// System.out.println("paint_time = " + paint_time);
2679
	long paint_time = paint_stop_time - paint_start_time;
2680
	System.out.println("paint_time = " + paint_time);	// NOI18N
2681
	*/
2504
    }
2682
    }
2505
2683
2506
    private void paint_margins(Graphics g) {
2684
    private void paint_margins(Graphics g) {
Lines 2523-2529 Link Here
2523
	}
2701
	}
2524
2702
2525
	int cursor_col = st.cursor.col - st.firsty;
2703
	int cursor_col = st.cursor.col - st.firsty;
2526
	if (cursor_col >= buf.visible_cols) {
2704
	if (cursor_col >= buf.visibleCols()) {
2705
	    return;		// cursor not visible
2706
	} else if (cursor_col < 0) {
2527
	    return;		// cursor not visible
2707
	    return;		// cursor not visible
2528
	}
2708
	}
2529
2709
Lines 2532-2537 Link Here
2532
		     glyph_gutter_width +
2712
		     glyph_gutter_width +
2533
		     debug_gutter_width;
2713
		     debug_gutter_width;
2534
	int rect_y = cursor_row * metrics.height;
2714
	int rect_y = cursor_row * metrics.height;
2715
	// we _don't_ make cursor as wide as underlying character
2535
	int rect_width = metrics.width;
2716
	int rect_width = metrics.width;
2536
	int rect_height = metrics.height - metrics.leading;
2717
	int rect_height = metrics.height - metrics.leading;
2537
	if (has_focus)
2718
	if (has_focus)
Lines 2545-2551 Link Here
2545
    private boolean possiblyScrollDown() {
2726
    private boolean possiblyScrollDown() {
2546
	/*
2727
	/*
2547
	 * If cursor has moved below the scrollable region scroll down.
2728
	 * If cursor has moved below the scrollable region scroll down.
2548
	 * Buffer manipulation is party done here or at the callsite if 
2729
	 * Buffer manipulation is partly done here or at the callsite if 
2549
	 * 'true' is returned.
2730
	 * 'true' is returned.
2550
	 */
2731
	 */
2551
2732
Lines 2619-2625 Link Here
2619
     * Perhaps SHOULD lock out sendChar() so user input doesn't interfere.
2800
     * Perhaps SHOULD lock out sendChar() so user input doesn't interfere.
2620
     */
2801
     */
2621
    private void reply(String str) {
2802
    private void reply(String str) {
2622
	// System.out.println("replying " + str);
2803
	// System.out.println("replying " + str);	// NOI18N
2623
	for (int sx = 0; sx < str.length(); sx++)
2804
	for (int sx = 0; sx < str.length(); sx++)
2624
	    sendChar(str.charAt(sx));
2805
	    sendChar(str.charAt(sx));
2625
    }
2806
    }
Lines 2653-2667 Link Here
2653
2834
2654
	public void op_char(char c) {
2835
	public void op_char(char c) {
2655
	    if (debugOps())
2836
	    if (debugOps())
2656
		System.out.println("op_char('" + c + "')"); // NOI18N
2837
		System.out.println("op_char('" + c + "') = " + (int) c); // NOI18N
2657
2838
2658
	    // generic character printing
2839
	    // generic character printing
2659
	    Line l = cursor_line();
2840
	    Line l = cursor_line();
2660
2841
2661
	    if (!st.overstrike)
2842
	    int insertion_col = l.cellToBuf(metrics, st.cursor.col);
2662
		l.insertCharAt(buf, ' ', st.cursor.col, st.attr);
2843
	    if (debugOps()) {
2844
		System.out.println("op_char(): st.cursor.col " + st.cursor.col + 	// NOI18N
2845
		    " insertion_col " + insertion_col);	// NOI18N
2846
	    }
2847
	    if (!st.overstrike) {
2848
		// This just shifts stuff the actual character gets put in below.
2849
		l.insertCharAt(Term.this, ' ', insertion_col, st.attr);
2850
	    }
2851
2852
	    int cwidth = metrics.wcwidth(c);
2853
	    if (l.isAboutToWrap() ||
2854
		(cwidth > 1 && 
2855
		 st.cursor.col + cwidth > buf.visibleCols() &&
2856
		 !horizontally_scrollable)) {
2663
2857
2664
	    if (l.isAboutToWrap()) {
2665
		// 'wrap' the line
2858
		// 'wrap' the line
2666
		if (debugOps())
2859
		if (debugOps())
2667
		    System.out.println("\twrapping it"); // NOI18N
2860
		    System.out.println("\twrapping it"); // NOI18N
Lines 2670-2686 Link Here
2670
		op_line_feed();
2863
		op_line_feed();
2671
		op_carriage_return();
2864
		op_carriage_return();
2672
		l = cursor_line();
2865
		l = cursor_line();
2866
		insertion_col = 0;
2673
		// Fall thru
2867
		// Fall thru
2674
	    }
2868
	    }
2675
2869
2676
	    l.setCharAt(buf, c, st.cursor.col, st.attr);	// overstrike
2870
	    l.setCharAt(Term.this, c, insertion_col, st.attr);	// overstrike
2677
	    st.cursor.col++;
2871
	    st.cursor.col += cwidth;
2678
2872
2679
	    if (st.cursor.col >= buf.visible_cols && !horizontally_scrollable) {
2873
	    if (st.cursor.col >= buf.visibleCols() && !horizontally_scrollable) {
2680
		if (debugOps())
2874
		if (debugOps())
2681
		    System.out.println("\tabout to wrap"); // NOI18N
2875
		    System.out.println("\tabout to wrap"); // NOI18N
2682
		l.setAboutToWrap(true);
2876
		l.setAboutToWrap(true);
2683
		st.cursor.col--;
2877
		st.cursor.col -= cwidth;
2684
	    }
2878
	    }
2685
	}
2879
	}
2686
2880
Lines 2701-2712 Link Here
2701
		System.out.println("op_back_space"); // NOI18N
2895
		System.out.println("op_back_space"); // NOI18N
2702
2896
2703
	    if (st.cursor.col > 0) {
2897
	    if (st.cursor.col > 0) {
2704
		if (! cursor_line().isAboutToWrap())
2898
		if (! cursor_line().isAboutToWrap()) {
2705
		    st.cursor.col--;
2899
		    st.cursor.col--;
2900
		}
2706
		cursor_line().setAboutToWrap(false);
2901
		cursor_line().setAboutToWrap(false);
2707
2902
2708
		// If we' backed up to column 0, maybe we need to consider
2903
		// If we' backed up to column 0, maybe we need to consider
2709
		// whether the previous line was wrapped. Oldr xterms aren't
2904
		// whether the previous line was wrapped. Older xterms aren't
2710
		// this clever, newer ones (Solaris 8+?) are.
2905
		// this clever, newer ones (Solaris 8+?) are.
2711
2906
2712
		if (st.cursor.col == 0) {
2907
		if (st.cursor.col == 0) {
Lines 2719-2726 Link Here
2719
			    if (debugOps())
2914
			    if (debugOps())
2720
				System.out.println("\tit is"); // NOI18N
2915
				System.out.println("\tit is"); // NOI18N
2721
			    st.cursor.row--;
2916
			    st.cursor.row--;
2722
			    st.cursor.col = prev.length()-1;
2917
2918
			    // The below is done in a roundabout way because BS doesn't
2919
			    // really reduce length. So, suppose we went to the end with
2920
			    // latin chars that makes the line 80 long. Then we backspace
2921
			    // to column 78 and enter one 2-cell japanese character. Now
2922
			    // the line is conceptually 79 long, but it still remembers
2923
			    // the 80. So we don't use 'prev.length()' directly.
2924
2925
			    // st.cursor.col = prev.bufToCell(metrics, prev.length()-1);
2926
2927
			    int last_col = prev.cellToBuf(metrics, buf.visibleCols()-1);
2928
			    st.cursor.col = prev.bufToCell(metrics, last_col);
2929
2723
			    prev.setWrapped(false);
2930
			    prev.setWrapped(false);
2931
2932
			    // The following isn't entirely correct when we backspaced
2933
			    // over a multi-celled character. SHOULD either note
2934
			    // what we BS'ed over or note the slop at the end of the line.
2724
			    prev.setAboutToWrap(true);
2935
			    prev.setAboutToWrap(true);
2725
			}
2936
			}
2726
		    }
2937
		    }
Lines 2735-2740 Link Here
2735
	    if (debugOps())
2946
	    if (debugOps())
2736
		System.out.println("op_line_feed"); // NOI18N
2947
		System.out.println("op_line_feed"); // NOI18N
2737
	    Line last_line = cursor_line();
2948
	    Line last_line = cursor_line();
2949
	    /* DEBUG
2950
	    if (last_line == null) {
2951
		Thread.dumpStack();
2952
		printStats("last_line == null in op_line_feed()");// NOI18N
2953
	    }
2954
	    */
2738
	    st.cursor.row++;
2955
	    st.cursor.row++;
2739
	    if (possiblyScrollDown()) {
2956
	    if (possiblyScrollDown()) {
2740
		buf.addLineAt(st.cursor.row);
2957
		buf.addLineAt(st.cursor.row);
Lines 2743-2750 Link Here
2743
		    System.out.println("op_line_feed ADJUSTED"); // NOI18N
2960
		    System.out.println("op_line_feed ADJUSTED"); // NOI18N
2744
	    }
2961
	    }
2745
	    // have new line inherit cursorAtEnd
2962
	    // have new line inherit cursorAtEnd
2746
	    cursor_line().setAboutToWrap(last_line.isAboutToWrap());
2963
	    boolean atw = last_line.isAboutToWrap();
2964
	    cursor_line().setAboutToWrap(atw);
2747
	    last_line.setAboutToWrap(false);
2965
	    last_line.setAboutToWrap(false);
2966
2967
	    n_linefeeds++;
2968
2969
	    // See repaint() for an explanation of this.
2970
	    // repaint(false);
2748
	}
2971
	}
2749
2972
2750
	public void op_tab() {
2973
	public void op_tab() {
Lines 2756-2770 Link Here
2756
	    if (debugOps())
2979
	    if (debugOps())
2757
		System.out.println("op_tab"); // NOI18N
2980
		System.out.println("op_tab"); // NOI18N
2758
2981
2759
	    if (st.cursor.col == buf.visible_cols-1 && !horizontally_scrollable)
2982
	    if (st.cursor.col == buf.visibleCols()-1 && !horizontally_scrollable)
2760
		return;
2983
		return;
2761
2984
2762
	    cursor_line().setCharAt(buf, ' ', st.cursor.col, st.attr);
2985
	    Line l = cursor_line();
2986
	    int insert_col = l.cellToBuf(metrics, st.cursor.col);
2987
	    l.setCharAt(Term.this, ' ', insert_col, st.attr);
2763
	    st.cursor.col++;
2988
	    st.cursor.col++;
2764
	    while ((st.cursor.col < buf.visible_cols-1 || horizontally_scrollable) &&
2989
	    insert_col++;
2990
	    // no need to re-apply cellToBuf to cursor since we're only adding 1-wide ' '
2991
	    while ((st.cursor.col < buf.visibleCols()-1 || horizontally_scrollable) &&
2765
		   (st.cursor.col % tab_size) != 0) {
2992
		   (st.cursor.col % tab_size) != 0) {
2766
		cursor_line().setCharAt(buf, ' ', st.cursor.col, st.attr);
2993
		cursor_line().setCharAt(Term.this, ' ', insert_col, st.attr);
2767
		st.cursor.col++;
2994
		st.cursor.col++;
2995
		insert_col++;
2768
	    }
2996
	    }
2769
	}
2997
	}
2770
2998
Lines 2782-2800 Link Here
2782
3010
2783
	    Line l;
3011
	    Line l;
2784
	    while (count-- > 0) {
3012
	    while (count-- > 0) {
2785
		boolean old_cae = cursor_line().setAboutToWrap(false);
3013
		boolean old_atw = cursor_line().setAboutToWrap(false);
2786
3014
2787
		// reverse of op_dl()
3015
		// reverse of op_dl()
2788
		// Rotate a line from bottom to top
3016
		// Rotate a line from bottom to top
2789
		if (!do_margins) {
3017
		if (!do_margins) {
2790
		    l = buf.moveLineFromTo(buf.nlines-1, st.cursor.row);
3018
		    l = buf.moveLineFromTo(buf.nlines-1, st.cursor.row);
2791
		} else { 
3019
		} else { 
2792
		    l = buf.moveLineFromTo(st.firstx + botMargin(),
3020
		    l = buf.moveLineFromTo(st.firstx + botMargin(), st.cursor.row);
2793
					   st.cursor.row);
2794
		}
3021
		}
2795
		l.reset();
3022
		l.reset();
2796
3023
2797
		cursor_line().setAboutToWrap(old_cae);
3024
		cursor_line().setAboutToWrap(old_atw);
2798
	    }
3025
	    }
2799
3026
2800
	    switch(sel.intersection(st.cursor.row - 1)) {
3027
	    switch(sel.intersection(st.cursor.row - 1)) {
Lines 2817-2823 Link Here
2817
	    if (debugOps())
3044
	    if (debugOps())
2818
		System.out.println("op_bc(" + count + ")"); // NOI18N
3045
		System.out.println("op_bc(" + count + ")"); // NOI18N
2819
3046
2820
	    while(count-- > 0) {
3047
	    while (count-- > 0) {
2821
		if (st.cursor.col <= 0)
3048
		if (st.cursor.col <= 0)
2822
		    return;
3049
		    return;
2823
		st.cursor.col--;
3050
		st.cursor.col--;
Lines 2841-2848 Link Here
2841
	    // deal with overflow
3068
	    // deal with overflow
2842
	    if (row > st.rows)
3069
	    if (row > st.rows)
2843
		row = st.rows;
3070
		row = st.rows;
2844
	    if (col > buf.visible_cols)
3071
	    if (col > buf.visibleCols())
2845
		col = buf.visible_cols;
3072
		col = buf.visibleCols();
2846
3073
2847
	    cursor_line().setAboutToWrap(false);
3074
	    cursor_line().setAboutToWrap(false);
2848
	    st.cursor.row = beginx() + row - 1;
3075
	    st.cursor.row = beginx() + row - 1;
Lines 2865-2872 Link Here
2865
	    if (debugOps())
3092
	    if (debugOps())
2866
		System.out.println("op_ce"); // NOI18N
3093
		System.out.println("op_ce"); // NOI18N
2867
3094
2868
	    Line l = buf.lineAt(st.cursor.row);
3095
	    Line l = cursor_line();
2869
	    l.clearToEndFrom(buf, st.cursor.col);
3096
	    l.clearToEndFrom(Term.this, l.cellToBuf(metrics, st.cursor.col));
2870
3097
2871
	    switch(sel.intersection(st.cursor.row)) {
3098
	    switch(sel.intersection(st.cursor.row)) {
2872
		case Sel.INT_NONE:
3099
		case Sel.INT_NONE:
Lines 2912-2918 Link Here
2912
		count = 1;
3139
		count = 1;
2913
	    Line l = cursor_line();
3140
	    Line l = cursor_line();
2914
	    while (count-- > 0)
3141
	    while (count-- > 0)
2915
		cursor_line().deleteCharAt(st.cursor.col);
3142
		l.deleteCharAt(l.cellToBuf(metrics, st.cursor.col));
2916
	} 
3143
	} 
2917
3144
2918
	public void op_dl(int count) {
3145
	public void op_dl(int count) {
Lines 2923-2929 Link Here
2923
3150
2924
	    Line l;
3151
	    Line l;
2925
	    while (count-- > 0) {
3152
	    while (count-- > 0) {
2926
		boolean old_cae = cursor_line().setAboutToWrap(false);
3153
		boolean old_atw = cursor_line().setAboutToWrap(false);
2927
3154
2928
		// reverse of op_al()
3155
		// reverse of op_al()
2929
		// Rotate a line from top to bottom
3156
		// Rotate a line from top to bottom
Lines 2936-2942 Link Here
2936
		}
3163
		}
2937
		l.reset();
3164
		l.reset();
2938
3165
2939
		cursor_line().setAboutToWrap(old_cae);
3166
		cursor_line().setAboutToWrap(old_atw);
2940
	    }
3167
	    }
2941
3168
2942
	    switch(sel.intersection(st.cursor.row)) {
3169
	    switch(sel.intersection(st.cursor.row)) {
Lines 2955-2973 Link Here
2955
	} 
3182
	} 
2956
3183
2957
	public void op_do(int count) {
3184
	public void op_do(int count) {
3185
	    // down count lines
2958
	    // SHOULD add a mode: {scroll, warp, stay} for cases where
3186
	    // SHOULD add a mode: {scroll, warp, stay} for cases where
2959
	    // cursor is on the bottom line.
3187
	    // cursor is on the bottom line.
2960
3188
2961
	    // down count lines
2962
	    if (debugOps())
3189
	    if (debugOps())
2963
		System.out.println("op_do(" + count + ") -- down"); // NOI18N
3190
		System.out.println("op_do(" + count + ") -- down"); // NOI18N
2964
3191
2965
	    boolean old_cae = cursor_line().setAboutToWrap(false);
3192
	    boolean old_atw = cursor_line().setAboutToWrap(false);
2966
3193
2967
	    while (count-- > 0) {
3194
	    while (count-- > 0) {
2968
		st.cursor.row++;
3195
		st.cursor.row++;
2969
		if (st.cursor.row >= buf.nlines) {
3196
		if (st.cursor.row >= buf.nlines) {
2970
		    // st.cursor.row--;	// don't go beyond bottomline
2971
3197
2972
		    // equivalent of op_newline:
3198
		    // equivalent of op_newline:
2973
		    if (possiblyScrollDown()) {
3199
		    if (possiblyScrollDown()) {
Lines 2978-2984 Link Here
2978
		    }
3204
		    }
2979
		}
3205
		}
2980
	    }
3206
	    }
2981
	    cursor_line().setAboutToWrap(old_cae);
3207
	    cursor_line().setAboutToWrap(old_atw);
2982
	}
3208
	}
2983
3209
2984
	public void op_ho() {
3210
	public void op_ho() {
Lines 2995-3002 Link Here
2995
	    if (debugOps())
3221
	    if (debugOps())
2996
		System.out.println("op_ic(" + count + ")"); // NOI18N
3222
		System.out.println("op_ic(" + count + ")"); // NOI18N
2997
3223
2998
	    while (count-- > 0)
3224
	    Line l = cursor_line();
2999
		cursor_line().insertCharAt(buf, ' ', st.cursor.col, st.attr);
3225
	    int insertion_col = l.cellToBuf(metrics, st.cursor.col);
3226
	    while (count-- > 0) {
3227
		l.insertCharAt(Term.this, ' ', insertion_col, st.attr);
3228
	    }
3229
	    // SHOULD worry about line wrapping
3000
	} 
3230
	} 
3001
3231
3002
	public void op_nd(int count) {
3232
	public void op_nd(int count) {
Lines 3004-3018 Link Here
3004
	    if (debugOps())
3234
	    if (debugOps())
3005
		System.out.println("op_nd(" + count + ")"); // NOI18N
3235
		System.out.println("op_nd(" + count + ")"); // NOI18N
3006
3236
3237
	    int vc = st.cursor.col;
3007
	    while (count-- > 0) {
3238
	    while (count-- > 0) {
3008
		st.cursor.col++;
3239
		vc++;
3009
		if (st.cursor.col >= buf.visible_cols) {
3240
		if (vc >= buf.visibleCols()) {
3010
		    if (debugOps())
3241
		    if (debugOps())
3011
			System.out.println("\tbailing out at count " + count); // NOI18N
3242
			System.out.println("\tbailing out at count " + count); // NOI18N
3012
		    st.cursor.col--;
3243
		    vc--;
3013
		    return;
3244
		    break;
3014
		}
3245
		}
3015
	    }
3246
	    }
3247
	    st.cursor.col = vc;
3016
	}
3248
	}
3017
3249
3018
	public void op_up(int count) {
3250
	public void op_up(int count) {
Lines 3020-3026 Link Here
3020
	    if (debugOps())
3252
	    if (debugOps())
3021
		System.out.println("op_up(" + count + ")"); // NOI18N
3253
		System.out.println("op_up(" + count + ")"); // NOI18N
3022
3254
3023
	    boolean old_cae = cursor_line().setAboutToWrap(false);
3255
	    boolean old_atw = cursor_line().setAboutToWrap(false);
3024
	    Line l;
3256
	    Line l;
3025
	    while (count-- > 0) {
3257
	    while (count-- > 0) {
3026
		st.cursor.row--;
3258
		st.cursor.row--;
Lines 3030-3043 Link Here
3030
		    if (!do_margins) {
3262
		    if (!do_margins) {
3031
			l = buf.moveLineFromTo(buf.nlines-1, st.cursor.row);
3263
			l = buf.moveLineFromTo(buf.nlines-1, st.cursor.row);
3032
		    } else {
3264
		    } else {
3033
			l = buf.moveLineFromTo(st.firstx + botMargin(),
3265
			l = buf.moveLineFromTo(st.firstx + botMargin(), st.cursor.row);
3034
					       st.cursor.row);
3035
		    }
3266
		    }
3036
		    l.reset();
3267
		    l.reset();
3037
		    // SHOULD note and do something about the selection?
3268
		    // SHOULD note and do something about the selection?
3038
		}
3269
		}
3039
	    }
3270
	    }
3040
	    cursor_line().setAboutToWrap(old_cae);
3271
	    cursor_line().setAboutToWrap(old_atw);
3041
	} 
3272
	} 
3042
3273
3043
	public void op_sc() {
3274
	public void op_sc() {
Lines 3072-3078 Link Here
3072
	}
3303
	}
3073
3304
3074
	public void op_margin(int from, int to) {
3305
	public void op_margin(int from, int to) {
3075
	    // System.out.println("op_margin(" + from + ", " + to + ")"); // NOI18N
3306
	    if (debugOps()) {
3307
		System.out.println("op_margin(" + from + ", " +	// NOI18N
3308
				    to + ")"); // NOI18N
3309
	    }
3076
3310
3077
	    if (from < 0)
3311
	    if (from < 0)
3078
		top_margin = 0;
3312
		top_margin = 0;
Lines 3106-3111 Link Here
3106
	    String output1 = date_str + " Elapsed (sec): " + elapsed_str;// NOI18N
3340
	    String output1 = date_str + " Elapsed (sec): " + elapsed_str;// NOI18N
3107
	    String output2 = "putChar " + n_putchar +		// NOI18N
3341
	    String output2 = "putChar " + n_putchar +		// NOI18N
3108
			     "  putChars " + n_putchars +	// NOI18N
3342
			     "  putChars " + n_putchars +	// NOI18N
3343
		             "  linefeeds " + n_linefeeds +	// NOI18N
3109
		             "  repaint " + n_repaint +		// NOI18N
3344
		             "  repaint " + n_repaint +		// NOI18N
3110
			     "  paint " + n_paint;		// NOI18N
3345
			     "  paint " + n_paint;		// NOI18N
3111
3346
Lines 3125-3130 Link Here
3125
	    last_time = time;
3360
	    last_time = time;
3126
	    n_putchar = 0;
3361
	    n_putchar = 0;
3127
	    n_putchars = 0;
3362
	    n_putchars = 0;
3363
	    n_linefeeds = 0;
3128
	    n_paint = 0;
3364
	    n_paint = 0;
3129
	    n_repaint = 0;
3365
	    n_repaint = 0;
3130
3366
Lines 3133-3139 Link Here
3133
	}
3369
	}
3134
3370
3135
	public int op_get_width() {
3371
	public int op_get_width() {
3136
	    return horizontally_scrollable? buf.totalCols(): buf.visible_cols;
3372
	    return horizontally_scrollable? buf.totalCols(): buf.visibleCols();
3137
	}
3373
	}
3138
3374
3139
	public int op_get_column() {
3375
	public int op_get_column() {
Lines 3228-3236 Link Here
3228
	// So extent has to be set to visible-range - 1:
3464
	// So extent has to be set to visible-range - 1:
3229
3465
3230
	// It's important that we do this from within the AWT event thread.
3466
	// It's important that we do this from within the AWT event thread.
3231
	// This is primarily ensured by the use of Swing.invokeAndWait()
3232
	// in StreamTerm.
3233
3467
3468
        if (SwingUtilities.isEventDispatchThread()) {
3469
            adjust_scrollbar_impl();
3470
        }
3471
        else {
3472
            SwingUtilities.invokeLater(new Runnable() {
3473
                public void run() {
3474
                    adjust_scrollbar_impl();
3475
                }
3476
            });
3477
        }
3478
    }
3479
3480
    private void adjust_scrollbar_impl() {
3234
	if (vscroll_bar != null) {
3481
	if (vscroll_bar != null) {
3235
	    int value = st.firstx;
3482
	    int value = st.firstx;
3236
	    int extent = st.rows-1;
3483
	    int extent = st.rows-1;
Lines 3245-3255 Link Here
3245
3492
3246
	if (hscroll_bar != null && horizontally_scrollable) {
3493
	if (hscroll_bar != null && horizontally_scrollable) {
3247
	    int value = st.firsty;
3494
	    int value = st.firsty;
3248
	    int extent = buf.visible_cols-1;
3495
	    int extent = buf.visibleCols()-1;
3249
	    int min = 0;
3496
	    int min = 0;
3250
	    int max;
3497
	    int max;
3251
	    if (buf.totalCols() <= buf.visible_cols)
3498
	    if (buf.totalCols() <= buf.visibleCols())
3252
		max = buf.visible_cols - 1;
3499
		max = buf.visibleCols() - 1;
3253
	    else
3500
	    else
3254
		max = buf.totalCols() - 1;
3501
		max = buf.totalCols() - 1;
3255
	    hscroll_bar.setValues(value, extent, min, max);
3502
	    hscroll_bar.setValues(value, extent, min, max);
Lines 3260-3266 Link Here
3260
     * Figure the pixel size of the screen based on various properties.
3507
     * Figure the pixel size of the screen based on various properties.
3261
     */
3508
     */
3262
    private Dimension calculateSize() {
3509
    private Dimension calculateSize() {
3263
	int dx = buf.visible_cols * metrics.width +
3510
	int dx = buf.visibleCols() * metrics.width +
3264
		 glyph_gutter_width +
3511
		 glyph_gutter_width +
3265
		 debug_gutter_width;
3512
		 debug_gutter_width;
3266
	int dy = st.rows * metrics.height;
3513
	int dy = st.rows * metrics.height;
Lines 3306-3312 Link Here
3306
     */
3553
     */
3307
3554
3308
    void sizeChanged(int newWidth, int newHeight) {
3555
    void sizeChanged(int newWidth, int newHeight) {
3309
	/*
3556
	/* DEBUG
3310
	System.out.println("sizeChanged(newheight " + newHeight + // NOI18N
3557
	System.out.println("sizeChanged(newheight " + newHeight + // NOI18N
3311
	    ", newWidth " + newWidth + ")");
3558
	    ", newWidth " + newWidth + ")");
3312
	*/
3559
	*/
Lines 3379-3388 Link Here
3379
	repaint(adjust_scrollbar);
3626
	repaint(adjust_scrollbar);
3380
    }
3627
    }
3381
3628
3629
    /**
3630
     * Model and or view settings have changed, redraw everything.
3631
     */
3382
    protected void repaint(boolean adjust_scrollbar) {
3632
    protected void repaint(boolean adjust_scrollbar) {
3383
3633
3384
	/*
3634
	/*
3385
	 * Model and or view settings have changed, redraw everything.
3635
	 * A long discussion on performance and smooth vs jump vs jerky
3636
	 * scrolling ... (note: a lot of this is based on experiments with
3637
	 * Term as a unix terminal emulator application as opposed to
3638
	 * within the context of NetBeans).
3639
	 *
3640
	 * Term spends it's time between collecting and deciphering input
3641
	 * and repainting the screen. Input processing always goes on, but
3642
	 * screen repainitng can be done more or less often to trade off
3643
	 * smoothness of scrolling vs speed.
3644
	 *
3645
	 * At one end is so-called smooth scrolling. This is where the
3646
	 * screen is redrawn on every linefeed. That's a lot of painting.
3647
	 * To get into that mode use the paintImmediately() below and
3648
	 * uncomment the call to us in op_line_feed(). Also
3649
	 * paintImmediately() doesn't really work unless the Screen is
3650
	 * opaque. I think that is because the paint request comes
3651
	 * to us and we don't forward it to screen; but it could be a 
3652
	 * Swing bug too. Term is very slow in this. For example I"ve
3653
	 * time xterm and DtTerm dealing with "cat /etc/termcap" in 2-3
3654
	 * seconds while Term takes 20-25 seconds. Part of this is
3655
	 * attributed to the fact that Term doesn't take advantage of 
3656
	 * bitBlitting when it's adding one line at a time and still
3657
	 * redraws everything. However I'll make a case below that this
3658
	 * isn't that important.
3659
	 *
3660
	 * Then there is so-called jump scrolling. In this regime terminal
3661
	 * emulators redraw the screen "as time permits". This is in effect
3662
	 * what the swing repaint manager helps with. Multiple repaint()
3663
	 * requests translate to one actual paint(). With todays computers
3664
	 * it's very hard to tell visually that you're jump scrolling
3665
	 * things go by so fast (yes, even under Swing), so this is the
3666
	 * preferred setup.
3667
	 * Here term does a bit better. To deal with a cat'ed 100,000
3668
	 * line file DtTerm takes 8 seconds, while Term takes 22 seconds.
3669
	 * (That's 3 times slower vs 8 times). From some measurements
3670
	 * I've made the number of linefeeds per actual paints has
3671
	 * ranged from > 100 to upper 30's. These numbers are sufficiently
3672
	 * high that the whole screen has to be repained everytime.
3673
	 * I.e. blitting to scroll and drawing only what's new isn't
3674
	 * going to help here. To get reasonable jump-scrolling, you need
3675
	 * to make sure that the Screen is opaque because if you don't 
3676
	 * you will get ...
3677
	 *
3678
	 * Jerky scrolling. If Term is not opaque, the number of actual
3679
	 * paints per repaint() requests diminishes drastically. 'cat' of
3680
	 * etc/termcap (once the code has been warmed up) sometimes causes
3681
	 * a single refresh at the end in contrast to ~100 when Screen
3682
	 * is opaque. Naturally Term in this mode can eat up input at
3683
	 * a rate comparable to dtterm etc, but the jerkiness is very
3684
	 * ugly.
3685
	 * Opacity isn't the only criterion. Term, when embeded inside a 
3686
	 * tabbed pane (like it is in NetBeans) will also act as if it's
3687
	 * opaque and you get more frequent refreshes, as in the
3688
	 * jump-scrolling regime. But that was way too slow for the
3689
	 * taste of NB users which is why OutputTab window calls us on a
3690
	 * timer. That brings it's own jerkiness of a different sort.
3691
	 *
3692
	 * There is a third factor that contributes to slowness. If you 
3693
	 * just 'cat' a file you get the numbers I presneted above. But
3694
	 * if you run an app that actually puts out the 100,000 lines
3695
	 * some sort of timing interaction forces Term into near smooth
3696
	 * scrolling and as a result things slow down a lot! For example,
3697
	 * 	$ generate_100K_lines > /tmp/bag	00:08 sec
3698
	 *	$ cat /tmp/bag				00:20 sec
3699
	 *	$ generate_100K_lines			03:42 sec (opaque)
3700
	 *	$ generate_100K_lines			01:58 sec (!opaque)
3701
	 * This happens even if the generating program is a lightweight 
3702
	 * native application. In fact I believe it is this effect that
3703
	 * forced NB's OutputTab to adopt the timer. I believe there are two
3704
	 * factors that contrinute to this. 
3705
	 * a) Running applications are line buffered so putChars(), with
3706
	 *    it's attendant repaint(), gets called once per line pushing
3707
	 *    us into the smooth scrolling regime. (But why then doesn't
3708
	 *    DtTerm suffer from this?)
3709
	 * b) timeslicing gives enough time to the repaint manager such
3710
	 *    that it converts evey repaint() to a paint.
3711
	 * I know (b) is a factor since if I "simulate" (a) by issueing 
3712
	 * repaints() from op_line_feed() while keeping this function from
3713
	 * using paintImmediately() I don't get that many paints. 
3714
	 * The combined case has 44 paints per repaint as does simulated (a).
3715
	 * So ain increased number of paints per repaint doesn't
3716
	 * explain this.
3717
	 *
3718
	 * In the end, currently since jump scrolling is still not very
3719
	 * fast and since NB has the timer anyway, Screen is not opaque.
3720
	 *
3721
	 * A useful quantitative measure is the number of linefeeds vs
3722
	 * the number of repaint requests vs the number of actual paints.
3723
	 * All these are collected and can be dumped via op_time() or 
3724
	 * printStats().
3386
	 */
3725
	 */
3387
3726
3388
	n_repaint++;
3727
	n_repaint++;
Lines 3394-3399 Link Here
3394
	// The following causes Screen.paint() to get called by the Swing
3733
	// The following causes Screen.paint() to get called by the Swing
3395
	// repaint manager which in turn calls back to term.paint(Graphics).
3734
	// repaint manager which in turn calls back to term.paint(Graphics).
3396
	screen.repaint();
3735
	screen.repaint();
3736
3737
3738
	// The following should cause an immediate paint. It doesn't
3739
	// always though!
3740
	// I've found that for it to be effective Screen needs to be opaque.
3741
3742
	/*
3743
	NOTE: paintImmediately() is probably not the best thing to use.
3744
	// RepaintManager.currentManager(screen).paintDirtyRegions();
3745
	screen.paintImmediately(0, 0, screen.getWidth(), screen.getHeight());
3746
	*/
3397
    }
3747
    }
3398
3748
3399
    /*
3749
    /*
Lines 3560-3566 Link Here
3560
	return interp;
3910
	return interp;
3561
    } 
3911
    } 
3562
3912
3563
    private Interp interp = new InterpANSI(ops);
3913
    private Interp interp = new InterpDumb(ops);	// used to InterpANSI
3564
3914
3565
3915
3566
    /**
3916
    /**
Lines 3644-3672 Link Here
3644
    }
3994
    }
3645
3995
3646
    /**
3996
    /**
3647
     * Get cursor column (0-origin)
3997
     * Get cursor column in buffer coordinates (0-origin)
3648
     */
3998
     */
3649
    public int getCursorCol() {
3999
    public int getCursorCol() {
3650
	return st.cursor.col;
4000
	return cursor_line().cellToBuf(metrics, st.cursor.col);
3651
    } 
4001
    } 
3652
4002
3653
    /**
4003
    /**
3654
     * Get (view) cursor coordinates.
4004
     * Get (absolute) cursor coordinates.
3655
     * <p>
4005
     * <p>
3656
     * The returned Coord is newly allocated and need not be cloned.
4006
     * The returned Coord is newly allocated and need not be cloned.
3657
     */
4007
     */
3658
    public Coord getCursorCoord() {
4008
    public Coord getCursorCoord() {
3659
	return new Coord(new BCoord(st.cursor.row, st.cursor.col), firsta);
4009
	Line l = buf.lineAt(st.cursor.row);
4010
	return new Coord(new BCoord(st.cursor.row,
4011
				    l.cellToBuf(metrics, st.cursor.col)),
4012
			 firsta);
4013
    }
4014
4015
    /*
4016
     * 
4017
     * Move the cursor to the given (absolute) coordinates
4018
     *
4019
     * @deprecated, replaced by{@link #setCursorCoord(Coord)}
4020
     */
4021
    public void goTo(Coord coord) {
4022
	setCursorCoord(coord);
3660
    }
4023
    }
3661
4024
3662
    /**
4025
    /**
3663
     * Move the cursor to the given (view) coordinates
4026
     * Move the cursor to the given (absolute) coordinates
3664
     * SHOULD be setCursorCoord!
4027
     * SHOULD be setCursorCoord!
3665
     */
4028
     */
3666
    public void goTo(Coord coord) {
4029
    public void setCursorCoord(Coord coord) {
3667
	Coord c = (Coord) coord.clone();
4030
	Coord c = (Coord) coord.clone();
3668
	c.clip(st.rows, buf.visible_cols, firsta);
4031
	c.clip(st.rows, buf.visibleCols(), firsta);
3669
	st.cursor = c.toBCoord(firsta);
4032
	st.cursor = c.toBCoord(firsta);
4033
	st.cursor.col = cursor_line().bufToCell(metrics, st.cursor.col);
3670
	repaint(true);
4034
	repaint(true);
3671
    }
4035
    }
3672
4036
Lines 4012-4019 Link Here
4012
    public void columnRight(int n) {
4376
    public void columnRight(int n) {
4013
	synchronized(this) {
4377
	synchronized(this) {
4014
	    st.firsty += n;
4378
	    st.firsty += n;
4015
	    if (st.firsty + buf.visible_cols > buf.totalCols())
4379
	    if (st.firsty + buf.visibleCols() > buf.totalCols())
4016
		st.firsty = buf.totalCols() - buf.visible_cols;
4380
		st.firsty = buf.totalCols() - buf.visibleCols();
4017
	}
4381
	}
4018
	repaint(true);
4382
	repaint(true);
4019
    }
4383
    }
Lines 4030-4035 Link Here
4030
	repaint(true);
4394
	repaint(true);
4031
    }
4395
    }
4032
4396
4397
    /**
4398
     * Return the cell width of the given character.
4399
     */
4400
    public int charWidth(char c) {
4401
	return metrics.wcwidth(c);
4402
    } 
4403
4033
    /*
4404
    /*
4034
     * The following are overrides of JComponent/Component
4405
     * The following are overrides of JComponent/Component
4035
     */
4406
     */
Lines 4050-4056 Link Here
4050
	super.setFont(font);	// This should invalidate us, which
4421
	super.setFont(font);	// This should invalidate us, which
4051
				// ultimately will cause a repaint
4422
				// ultimately will cause a repaint
4052
4423
4053
	/*
4424
	/* DEBUG
4054
	System.out.println("Font info:"); // NOI18N
4425
	System.out.println("Font info:"); // NOI18N
4055
	System.out.println("\tlogical name: " + font.getName()); // NOI18N
4426
	System.out.println("\tlogical name: " + font.getName()); // NOI18N
4056
	System.out.println("\tfamily name: " + font.getFamily()); // NOI18N
4427
	System.out.println("\tfamily name: " + font.getFamily()); // NOI18N
Lines 4062-4067 Link Here
4062
4433
4063
	updateScreenSize();
4434
	updateScreenSize();
4064
    }
4435
    }
4436
4065
4437
4066
    /**
4438
    /**
4067
     * Override of JComponent
4439
     * Override of JComponent
(-)TermStream.java (+8 lines)
Lines 48-53 Link Here
48
	this.toDTE = toDTE;
48
	this.toDTE = toDTE;
49
    }
49
    }
50
50
51
    void setTerm(Term term) {
52
	this.term = term;
53
    } 
54
    protected Term getTerm() {
55
	return term;
56
    } 
57
    private Term term;
58
51
59
52
    // From world (DCE) to terminal (DTE) screen
60
    // From world (DCE) to terminal (DTE) screen
53
    public abstract void flush();
61
    public abstract void flush();
(-)build.xml (-1 / +12 lines)
Lines 14-23 Link Here
14
14
15
<project name="terminalemulator" default="jarfiles" basedir=".">
15
<project name="terminalemulator" default="jarfiles" basedir=".">
16
16
17
	       <!--
18
	       deprecation="${build.compiler.deprecation}"
19
	       -->
17
    <target name="compile">
20
    <target name="compile">
18
	<javac srcdir="."
21
	<javac srcdir="."
19
	       destdir="../../../.." 
22
	       destdir="../../../.." 
20
	       deprecation="${build.compiler.deprecation}"
23
	       deprecation="on"
24
	       excludes="test"
21
	       debug="on"
25
	       debug="on"
22
	/>
26
	/>
23
    </target>
27
    </target>
Lines 28-33 Link Here
28
		compress="false"
32
		compress="false"
29
		includes="org/netbeans/lib/terminalemulator/*.class"
33
		includes="org/netbeans/lib/terminalemulator/*.class"
30
	/>
34
	/>
35
    </target>
36
37
    <target name="install" depends="jarfiles">
38
	<copy	file="terminalemulator.jar"
39
		todir="../../../../../../nbbuild/netbeans/lib/ext"
40
	/>
41
	    
31
    </target>
42
    </target>
32
43
33
    <target name="clean">
44
    <target name="clean">

Return to bug 19570