1 package gnu.jemacs.swing; 2 import gnu.jemacs.buffer.*; 3 import javax.swing.text.*; 4 import javax.swing.undo.*; 5 import gnu.lists.*; 6 7 /** A Content class that supports Emacs-style Markers. 8 * The standard GapContent is close, but unfortunately it only 9 * supports inserting *before* marks, which is not the Emacs default. 10 * This provides a superset of the Position functionality (except for undo). 11 */ 12 13 public class BufferContent extends gnu.kawa.swingviews.SwingContent 14 { BufferContent()15 public BufferContent() 16 { 17 this(100); 18 } 19 BufferContent(int initialSize)20 public BufferContent(int initialSize) 21 { 22 super(initialSize); 23 } 24 indexOf(char[] buffer, int start, int limit, char ch)25 public static int indexOf(char[] buffer, int start, int limit, char ch) 26 { 27 for (int i = start; i < limit; i++) 28 { 29 if (buffer[i] == ch) 30 return i; 31 } 32 return -1; 33 } 34 35 /** Search for the last occurrence of a character 36 * in buffer[limit..start]. */ lastIndexOf(char[] buffer, int start, int limit, char ch)37 public static int lastIndexOf(char[] buffer, int start, int limit, char ch) 38 { 39 for (int i = start; i >= limit; i--) 40 { 41 if (buffer[i] == ch) 42 return i; 43 } 44 return -1; 45 } 46 47 /** Search in BUF for COUNT instances of the character TARGET between START and END. 48 * If COUNT is positive, search forwards; requires {@code END >= START}. 49 * If COUNT is negative, search backwards for the -COUNTth instance; 50 * requires {@code END <= START}. 51 * If COUNT is zero, do anything you please; run rogue, for all I care. 52 * START and END are both 0-origin. 53 * 54 * If we find COUNT instances, SHORTAGE is zero, and return the 55 * (0-origin) position after the COUNTth match. Note that for reverse motion 56 * this is not the same as the usual convention for Emacs motion commands. 57 58 * If we don't find COUNT instances before reaching END, set SHORTAGE 59 * to the number of TARGETs left unfound, and return {@code (shortage<<32|END)}. 60 * @return {@code(SHORTAGE<<32|POS)} 61 */ scan(char target, int start, int end, int count, boolean allowQuit)62 public final long scan(char target, int start, int end, 63 int count, boolean allowQuit) { 64 CharBuffer b = buffer; 65 if (count > 0) { 66 while (start < end && count > 0) { 67 char[] data = b.getBuffer(); 68 long result = b.getSegment(start); 69 int where = (int) result; 70 int size = (int) (result >> 32); 71 if (size > (end-start)) 72 size = end-start; 73 if (allowQuit) { 74 if (size > 10000) 75 size = 10000; 76 Signal.checkQuit(); 77 } 78 int i = indexOf(data, where, where+size, target); 79 if (i >= 0) { 80 count--; 81 start += i + 1; 82 } else 83 start += size; 84 } 85 return ((long) count << 32) | start; 86 } else { 87 int sinceCheck = 0; 88 while (start > end && count < 0) { 89 char ch = b.charAt(--start); 90 if (ch == target) { 91 count++; 92 } 93 if (allowQuit && ++sinceCheck > 10000) { 94 Signal.checkQuit(); 95 sinceCheck = 0; 96 } 97 } 98 99 if (count != 0) 100 return ((long) (- count) << 32) | end; 101 else { 102 // We found the character we were looking for; we have to 103 // return the position *after* it due to the strange way 104 // that the return value is defined. 105 return start + 1; 106 } 107 } 108 } 109 } 110