caret.c (2820B)
1 #include "dat.h" 2 #include <ctype.h> 3 #include <string.h> 4 #include "fns.h" 5 6 static int 7 iswordrune(Rune r) { 8 if(isalpharune(r)) 9 return 1; 10 return r < 0x80 && (r == '_' || isdigit(r)); 11 } 12 13 static char* 14 prev_rune(char *start, char *p, Rune *r) { 15 16 *r = 0; 17 if(p == start) 18 return p; 19 while(p > start && (*(--p)&0xC0) == 0x80) 20 ; 21 chartorune(r, p); 22 return p; 23 } 24 25 static char* 26 next_rune(char *p, Rune *r) { 27 int i; 28 29 *r = 0; 30 if(!*p) 31 return p; 32 i = chartorune(r, p); 33 return p + i; 34 } 35 36 void 37 caret_set(int start, int end) { 38 int len; 39 40 len = input.end - input.string; 41 start = max(0, min(len, start)); 42 43 input.pos = input.string + start; 44 if(end < 0) 45 input.pos_end = nil; 46 else 47 input.pos_end = input.string + max(start, end); 48 } 49 50 char* 51 caret_find(int dir, int type) { 52 char *end; 53 char *next, *p; 54 Rune r; 55 int res; 56 57 p = input.pos; 58 if(dir == FORWARD) { 59 end = input.end; 60 switch(type) { 61 case LINE: 62 return end; 63 case WORD: 64 chartorune(&r, p); 65 res = iswordrune(r); 66 while(next=next_rune(p, &r), r && iswordrune(r) == res && !isspacerune(r)) 67 p = next; 68 while(next=next_rune(p, &r), r && isspacerune(r)) 69 p = next; 70 return p; 71 case CHAR: 72 return next_rune(p, &r); 73 } 74 } 75 else if(dir == BACKWARD) { 76 end = input.string; 77 switch(type) { 78 case LINE: 79 return end; 80 case WORD: 81 while(next=prev_rune(end, p, &r), r && isspacerune(r)) 82 p = next; 83 prev_rune(end, p, &r); 84 res = iswordrune(r); 85 while(next=prev_rune(end, p, &r), r && iswordrune(r) == res && !isspacerune(r)) 86 p = next; 87 return p; 88 case CHAR: 89 return prev_rune(end, p, &r); 90 } 91 } 92 input.pos_end = nil; 93 return input.pos; 94 } 95 96 void 97 caret_move(int dir, int type) { 98 input.pos = caret_find(dir, type); 99 input.pos_end = nil; 100 } 101 102 void 103 caret_delete(int dir, int type) { 104 char *pos, *p; 105 int n; 106 107 if(input.pos_end) 108 p = input.pos_end; 109 else 110 p = caret_find(dir, type); 111 pos = input.pos; 112 if(p == input.end) 113 input.end = pos; 114 else { 115 if(p < pos) { 116 pos = p; 117 p = input.pos; 118 } 119 n = input.end - p; 120 memmove(pos, p, n); 121 input.pos = pos; 122 input.end = pos + n; 123 } 124 *input.end = '\0'; 125 input.pos_end = nil; 126 } 127 128 void 129 caret_insert(char *s, bool clear) { 130 int pos, end, len, size; 131 132 if(s == nil) 133 return; 134 if(clear) { 135 input.pos = input.string; 136 input.end = input.string; 137 }else if(input.pos_end) 138 caret_delete(0, 0); 139 140 len = strlen(s); 141 pos = input.pos - input.string; 142 end = input.end - input.string; 143 144 size = input.size; 145 if(input.size == 0) 146 input.size = 1; 147 while(input.size < end + len + 1) 148 input.size <<= 2; 149 if(input.size != size) 150 input.string = erealloc(input.string, input.size); 151 152 input.pos = input.string + pos; 153 input.end = input.string + end + len; 154 *input.end = '\0'; 155 memmove(input.pos + len, input.pos, end - pos); 156 memmove(input.pos, s, len); 157 input.pos += len; 158 input.pos_end = nil; 159 } 160