KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > jemacs > buffer > Buffer


1 // Copyright (c) 2002, 2005 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.jemacs.buffer;
5 import java.io.*;
6 import gnu.mapping.*;
7 import gnu.lists.*;
8 import gnu.text.Char;
9 import gnu.commonlisp.lang.Symbols; // FIXME
10

11 public abstract class Buffer extends AbstractSequence implements CharSeq
12 {
13   String JavaDoc name;
14   String JavaDoc filename;
15   String JavaDoc encoding;
16   //boolean modified;
17

18   static Buffer current;
19
20   public Marker pointMarker;
21   public Marker markMarker;
22
23   /** Buffer-local variable bindings.
24    * Represented as pairs of (<code>Symbol</code>, value)-pairs:
25    * For an even integer <code>i</code>, if <code>localBindings[i]</code>
26    * is a <code>Symbol</code>, there is a buffer-local binding
27    * whose value is <code>localBindings{i+1]</code>. */

28   Object JavaDoc[] localBindings;
29
30   /** List of modes active for this buffer, major mode first. */
31   Mode modes;
32
33   /** Map buffer names to buffers. */
34   public static java.util.Hashtable JavaDoc buffers
35   = new java.util.Hashtable JavaDoc(100);
36
37   /** Map file names to buffer.s */
38   public static java.util.Hashtable JavaDoc fileBuffers
39   = new java.util.Hashtable JavaDoc(100);
40
41   EKeymap localKeymap;
42   public EKeymap[] activeKeymaps;
43   int activeLength;
44   // private EKeymap actual;
45
/* Count of initial Keymaps in activeKeymaps that have been eliminated,
46    * because of previous prefix keys. */

47   int eliminated = 0;
48
49   public String JavaDoc getName() { return name; }
50
51   public String JavaDoc getFileName() { return filename; }
52
53   public void setFileName(String JavaDoc fname)
54   {
55     if (filename != null && fileBuffers.get(filename) == this)
56       fileBuffers.remove(filename);
57     if (name != null && buffers.get(name) == this)
58       buffers.remove(name);
59     filename = fname;
60     name = generateNewBufferName(new java.io.File JavaDoc(fname).getName());
61     buffers.put(name, this);
62     fileBuffers.put(filename, this);
63     redrawModeline();
64   }
65
66   public abstract CharSeq getStringContent ();
67
68   /**
69    * @see gnu.lists.CharSeq#charAt(int)
70    */

71   public char charAt(int index)
72   {
73     return getStringContent().charAt(index);
74   }
75
76   /**
77    * @see gnu.lists.CharSeq#setCharAt(int, char)
78    */

79   public void setCharAt(int index, char ch)
80   {
81     getStringContent().setCharAt(index, ch);
82   }
83
84   /**
85    * @see gnu.lists.CharSeq#fill(char)
86    */

87   public void fill(char value)
88   {
89     getStringContent().fill(value);
90   }
91
92   /**
93    * @see gnu.lists.CharSeq#fill(int, int, char)
94    */

95   public void fill(int fromIndex, int toIndex, char value)
96   {
97     getStringContent().fill(fromIndex, toIndex, value);
98   }
99
100   /**
101    * @see gnu.lists.CharSeq#getChars(int, int, char[], int)
102    */

103   public void getChars (int srcBegin, int srcEnd, char[] dst, int dstBegin)
104   {
105     getStringContent().getChars(srcBegin, srcEnd, dst, dstBegin);
106   }
107
108   /* #ifdef use:java.lang.CharSequence */
109   public CharSequence JavaDoc subSequence(int start, int end)
110   {
111     return getStringContent().subSequence(start, end);
112   }
113   /* #endif */
114   /* #ifdef JAVA5 */
115   // /**
116
// * @see gnu.lists.CharSeq#writeTo(int, int, Appendable)
117
// */
118
// public void writeTo(int start, int count, Appendable dest)
119
// throws java.io.IOException
120
// {
121
// getStringContent().writeTo(start, count, dest);
122
// }
123

124   // public void writeTo(Appendable dest)
125
// throws java.io.IOException
126
// {
127
// writeTo(0, length(), dest);
128
// }
129
/* #else */
130   /**
131    * @see gnu.lists.CharSeq#writeTo(int, int, java.io.Writer)
132    */

133   public void writeTo(int start, int count, java.io.Writer JavaDoc dest)
134     throws java.io.IOException JavaDoc
135   {
136     getStringContent().writeTo(start, count, dest);
137   }
138
139   public void writeTo(java.io.Writer JavaDoc str) throws java.io.IOException JavaDoc
140   {
141     writeTo(0, length(), str);
142   }
143   /* #endif */
144
145   /**
146    * @see gnu.lists.CharSeq#consume(int, int, gnu.lists.Consumer)
147    */

148   public void consume(int start, int count, gnu.lists.Consumer out)
149   {
150     getStringContent().consume(start, count, out);
151   }
152
153   public static Buffer findFile(String JavaDoc fname)
154   {
155     Buffer buffer = (Buffer) fileBuffers.get(fname);
156     if (buffer == null)
157       {
158         buffer = EToolkit.getInstance().newBuffer(null);
159         buffer.setFileName(fname);
160     buffer.encoding = System.getProperty("file.encoding", "UTF8");
161         try
162           {
163         Reader in = new InputStreamReader(new FileInputStream(fname),
164                           buffer.encoding);
165             buffer.insertFile(in);
166             in.close();
167           }
168         catch (java.io.FileNotFoundException JavaDoc ex)
169           {
170             Signal.message("New file");
171           }
172         catch (Exception JavaDoc ex)
173           {
174             throw new RuntimeException JavaDoc("error reading file \"" + fname
175                                        + "\": " + ex);
176           }
177       }
178     return buffer;
179   }
180
181   public static Buffer getBuffer(String JavaDoc name)
182   {
183     return (Buffer) buffers.get(name);
184   }
185
186   public static Buffer coerceBuffer(Object JavaDoc buf)
187   {
188     if (buf instanceof Buffer)
189       return (Buffer) buf;
190     return getBuffer(buf.toString());
191   }
192
193   public static String JavaDoc generateNewBufferName(String JavaDoc start)
194   {
195     Buffer buf = getBuffer(start);
196     if (buf == null)
197       return start;
198     int len = start.length();
199     StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc(len + 5);
200     sbuf.append(start);
201     sbuf.append('<');
202     for (int i = 2; ; i++)
203       {
204     sbuf.append(i);
205     sbuf.append('>');
206     String JavaDoc name = sbuf.toString();
207     buf = getBuffer(name);
208     if (buf == null)
209       return name;
210     sbuf.setLength(len+1);
211       }
212   }
213
214
215   public abstract void redrawModeline ();
216
217   public Buffer (String JavaDoc name)
218   {
219     this.name = name;
220
221     activeKeymaps = new EKeymap[6];
222     activeLength = 1;
223     activeKeymaps[0] = EKeymap.globalKeymap;
224   }
225
226   public int checkMark()
227   {
228     return markMarker.getOffset();
229   }
230
231   public static Buffer getCurrent()
232   {
233     return current;
234   }
235
236   public static void setCurrent(Buffer buffer)
237   {
238     current = buffer;
239   }
240
241   public int getDot()
242   {
243     return pointMarker.getOffset();
244   }
245
246   public int getPoint()
247   {
248     return 1 + getDot();
249   }
250
251   public void setDot(int i)
252   {
253     if (i > maxDot())
254       throw new Error JavaDoc("set dot to "+i+ " max:"+maxDot());
255     pointMarker.set(this, i);
256   }
257
258   public final void setPoint(int i)
259   {
260     setDot(i - 1);
261   }
262
263   public int minDot()
264   {
265     return 0;
266   }
267
268   public abstract int getLength();
269
270   public final int length() { return getLength(); }
271
272   public abstract int maxDot();
273
274   public void forwardChar(int i)
275   {
276     pointMarker.forwardChar(i);
277   }
278
279   public void backwardChar(int i)
280   {
281     pointMarker.backwardChar(i);
282   }
283
284   public String JavaDoc toString()
285   {
286     return "#<buffer \"" + name + "\">";
287   }
288
289   /** Insert count copies of ch at Pos ipos. */
290   /*
291   public void insert (char ch, int count, Object style, int ipos)
292   {
293   }
294   */

295
296   /** Insert string with given style at position pair. */
297   public abstract void insert (String JavaDoc string, Object JavaDoc style, int ipos);
298
299   /** Insert character with given style at position pair. */
300   public void insert (char[] chars, int offset, int count, Object JavaDoc style,
301               int ipos)
302   {
303     insert(new String JavaDoc(chars, offset, count), style, ipos);
304   }
305
306   public void insertAll (Object JavaDoc[] values, Object JavaDoc style)
307   {
308     int len = values.length;
309     for (int i = 0; i < len; i++)
310       {
311     Object JavaDoc value = values[i];
312     if (value instanceof Char)
313       insert(((Char) value).charValue(), 1, style);
314     else
315       pointMarker.insert(value.toString(), style);
316       }
317   }
318
319   public void insert (String JavaDoc string, Object JavaDoc style)
320   {
321     pointMarker.insert(string, style);
322   }
323
324   public void insert (Object JavaDoc value, Object JavaDoc style)
325   {
326     if (value instanceof Char)
327       insert(((Char) value).charValue(), 1, style);
328     else
329       pointMarker.insert(value.toString(), style);
330   }
331
332   /** Insert count copies of ch at point. */
333   public void insert (char ch, int count)
334   {
335     pointMarker.insert(ch, count, null);
336   }
337
338   /** Insert count copies of ch at point. */
339   public void insert (char ch, int count, Object JavaDoc style)
340   {
341     pointMarker.insert(ch, count, style);
342   }
343
344   public void removeChar (int count)
345   {
346     pointMarker.removeChar(count);
347   }
348
349   public abstract void removeAll ();
350
351   public Marker getPointMarker (boolean share)
352   {
353     return share ? pointMarker : new Marker(pointMarker);
354   }
355
356   public Marker getMarkMarker (boolean force)
357   {
358     return markMarker;
359   }
360
361   /** Convert an Emacs position (Marker, or 1-origin integer)
362    * to a (0-origin) buffer offset. */

363   public int positionToOffset (Object JavaDoc position)
364   {
365     if (position instanceof Number JavaDoc)
366       {
367     int min = minDot();
368     int max = maxDot();
369     int goal = ((Number JavaDoc) position).intValue() - 1;
370     return goal < min ? min : goal > max ? max : goal;
371       }
372     return ((Marker) position).getOffset();
373   }
374
375   public abstract void insertFile(Reader in) throws Exception JavaDoc;
376
377   public abstract void save(Writer out) throws Exception JavaDoc;
378
379   public void save()
380   {
381     try
382       {
383     if (encoding == null)
384       encoding = System.getProperty("file.encoding", "UTF8");
385     Writer out = new OutputStreamWriter(new FileOutputStream(filename),
386                         encoding);
387         save(out);
388         out.close();
389       }
390     catch (Exception JavaDoc ex)
391       {
392         throw new RuntimeException JavaDoc("error save-buffer: "+ex);
393       }
394   }
395
396   public void insertFile(String JavaDoc filename)
397   {
398     try
399       {
400     if (encoding == null)
401       encoding = System.getProperty("file.encoding", "UTF8");
402         Reader in = new InputStreamReader(new FileInputStream(filename),
403                       encoding);
404         insertFile(in);
405         in.close();
406       }
407     catch (Exception JavaDoc ex)
408       {
409         throw new RuntimeException JavaDoc("error reading file \""+filename+"\": "+ex);
410       }
411   }
412
413   int tabWidth = 8;
414
415   public int charWidth (char ch, int column)
416   {
417     if (ch < 0x3000)
418       {
419     // Combining forma should probably be 0.
420
if (ch < ' ')
421       {
422         if (ch == '\t')
423           return (((column + tabWidth) / tabWidth) * tabWidth) - column;
424         return 0;
425       }
426       }
427     else
428       {
429     if (ch < 0xD800 // CJK Ideographs
430
|| (ch >= 0xFF01 && ch <= 0xFF5E) // Fullwidth ASCII.
431
|| (ch >= 0xFFe0 && ch <= 0xFFE6)) // Fullwidth punctuation.
432
return 2;
433     if (ch < 0xE000)
434       return 0; // Surrogates.
435
}
436     return 1;
437   }
438
439   public int countColumns(char[] chars, int start, int count, int initial)
440   {
441     while (--count >= 0)
442       initial += charWidth (chars[start++], initial);
443     return initial;
444   }
445
446   public int currentColumn()
447   {
448     return currentColumn(getDot());
449   }
450
451   /** Return the column number at a specified offset. */
452   public int currentColumn(int offset)
453   {
454     try
455       {
456     int lineStart = lineStartOffset(offset);
457     InPort port = openReader(lineStart, offset - lineStart);
458     int column = 0;
459     while (port.read() >= 0)
460       {
461         // Subtract one from pos, to undo the read we just did.
462
int start = port.pos - 1;
463         column = countColumns(port.buffer, start, port.limit - start, column);
464         port.pos = port.limit;
465       }
466     return column;
467       }
468     catch (java.io.IOException JavaDoc ex)
469       {
470     throw new WrappedException(ex);
471       }
472   }
473
474   public int moveToColumn(int column, boolean force)
475   {
476     return pointMarker.moveToColumn(column, force);
477   }
478
479   public abstract int lineStartOffset(int offset);
480
481   public int lineStartOffset()
482   {
483     return lineStartOffset(getDot());
484   }
485
486   /** Search in BUF for COUNT instances of the character TARGET between START and END.
487    * If COUNT is positive, search forwards; END must be >= START.
488    * If COUNT is negative, search backwards for the -COUNTth instance;
489    * END must be <= START.
490    * If COUNT is zero, do anything you please; run rogue, for all I care.
491    * If END is zero, use beginning or end of (FIXME: accessible part of)
492    * the buffer, as appropriate for the direction indicated by COUNT.
493    *
494    * If we find COUNT instances, SHORTAGE is zero, and return the
495    * position after the COUNTth match. Note that for reverse motion
496    * this is not the same as the usual convention for Emacs motion commands.
497
498    * If we don't find COUNT instances before reaching END, set SHORTAGE
499    * to the number of TARGETs left unfound, and return (shortage<<32|END).
500    * @return (SHORTAGE<<32|POS)
501   */

502   public abstract long scan(char target, int start, int end,
503                 int count, boolean allowQuit);
504   
505   /** Find the position a give number of lines forward or backward.
506    * A side-effect-free version of Emacs's forward-line function.
507    * @param lines number of lines forward (or backward if negative)
508    * @param start initial position (buffer offset)
509    * @return (SHORTAGE<<32|POS)
510    */

511   public final long forwardLine(int lines, int start)
512   {
513     boolean neg = lines <= 0;
514     long scanned = scan('\n', start, 0, lines - (neg ? 1 : 0), true);
515     int shortage = (int) (scanned >> 32);
516     int pos = (int) scanned;
517     if (shortage > 0
518     && (neg
519         || (maxDot() > minDot() && pos != start
520         && charAt(pos - 1) != '\n')))
521       shortage--;
522     return ((long) (neg ? -shortage : shortage) << 32) | (long) pos;
523   }
524
525   public int forwardLine(int lines)
526   {
527     long value = forwardLine(lines, getDot());
528     setDot((int) value);
529     return (int) (value >> 32);
530   }
531
532   public EWindow display(boolean notThisWindow, EFrame frame)
533   {
534     if (frame == null)
535       frame = EFrame.getSelectedFrame();
536     EWindow selected = frame.getSelectedWindow();
537     EWindow window = frame.otherWindow(1);
538     if (selected == window && notThisWindow)
539       window = selected.split(-1, false);
540     window.setBuffer(this);
541     return window;
542   }
543
544   /*
545   public Element createLeafElement(Element parent, AttributeSet attributes,
546                                    int p0, int p1)
547   {
548     p0 = content.createPosition(p0, p0!=0);
549     p1 = content.createPosition(p1, true);
550     return new Leaf(this, parent, attributes, p0, p1);
551   }
552   */

553
554   /**
555    * @param all true if make-variable-buffer-local,
556    * false if make-local-variable FIXME
557    */

558   public static void makeBufferLocal(Object JavaDoc symbol, boolean all)
559   {
560     BufferLocal.make(Symbols.getSymbol(symbol), all);
561   }
562
563   public EKeymap getLocalKeymap() { return localKeymap; }
564
565   public void setLocalKeymap(EKeymap map)
566   {
567     // First remove the old local map.
568
if (localKeymap != null)
569       {
570         activeKeymaps[activeLength-2] = activeKeymaps[activeLength-1];
571         activeLength--;
572         localKeymap = null;
573       }
574     if (map != null)
575       {
576         activeKeymaps[activeLength] = activeKeymaps[activeLength-1];
577         activeKeymaps[activeLength-1]= map;
578         activeLength++;
579         localKeymap = map;
580       }
581   }
582
583   public abstract InPort openReader (int start, int count);
584
585   public abstract long savePointMark ();
586   
587   public abstract void restorePointMark (long pointMark);
588
589   /**
590    * This is intended for Runnable's that may affect the state of the buffer.
591    * The implementation should make shure that the GUI is properly updated before
592    * control returns
593    *
594    * @param doRun
595    */

596   public abstract void invoke(Runnable JavaDoc doRun);
597
598 }
599
Popular Tags