wmii/cmd/menu/caret.c
2010-07-31 19:11:45 -04:00

165 lines
2.8 KiB
C

#include "dat.h"
#include <ctype.h>
#include <string.h>
#include "fns.h"
static int
iswordrune(Rune r) {
if(isalpharune(r))
return 1;
return r < 0x80 && (r == '_' || isdigit(r));
}
static char*
prev_rune(char *start, char *p, Rune *r) {
*r = 0;
if(p == start)
return p;
while(p > start && (*(--p)&0xC0) == 0x80)
;
chartorune(r, p);
return p;
}
static char*
next_rune(char *p, Rune *r) {
int i;
*r = 0;
if(!*p)
return p;
i = chartorune(r, p);
return p + i;
}
void
caret_set(int start, int end) {
int len;
len = input.end - input.string;
start = max(0, min(len, start));
input.pos = input.string + start;
if(end < 0)
input.pos_end = nil;
else
input.pos_end = input.string + max(start, end);
}
char*
caret_find(int dir, int type) {
char *end;
char *next, *p;
Rune r;
int res;
p = input.pos;
if(dir == FORWARD) {
end = input.end;
switch(type) {
case LINE:
return end;
case WORD:
chartorune(&r, p);
res = iswordrune(r);
while(next=next_rune(p, &r), r && iswordrune(r) == res && !isspacerune(r))
p = next;
while(next=next_rune(p, &r), r && isspacerune(r))
p = next;
return p;
case CHAR:
if(p < end)
return p+1;
return p;
}
}
else if(dir == BACKWARD) {
end = input.string;
switch(type) {
case LINE:
return end;
case WORD:
while(next=prev_rune(end, p, &r), r && isspacerune(r))
p = next;
prev_rune(end, p, &r);
res = iswordrune(r);
while(next=prev_rune(end, p, &r), r && iswordrune(r) == res && !isspacerune(r))
p = next;
return p;
case CHAR:
if(p > end)
return prev_rune(end, p, &r);
return end;
}
}
input.pos_end = nil;
return input.pos;
}
void
caret_move(int dir, int type) {
input.pos = caret_find(dir, type);
input.pos_end = nil;
}
void
caret_delete(int dir, int type) {
char *pos, *p;
int n;
if(input.pos_end)
p = input.pos_end;
else
p = caret_find(dir, type);
pos = input.pos;
if(p == input.end)
input.end = pos;
else {
if(p < pos) {
pos = p;
p = input.pos;
}
n = input.end - p;
memmove(pos, p, n);
input.pos = pos;
input.end = pos + n;
}
*input.end = '\0';
input.pos_end = nil;
}
void
caret_insert(char *s, bool clear) {
int pos, end, len, size;
if(s == nil)
return;
if(clear) {
input.pos = input.string;
input.end = input.string;
}else if(input.pos_end)
caret_delete(0, 0);
len = strlen(s);
pos = input.pos - input.string;
end = input.end - input.string;
size = input.size;
if(input.size == 0)
input.size = 1;
while(input.size < end + len + 1)
input.size <<= 2;
if(input.size != size)
input.string = erealloc(input.string, input.size);
input.pos = input.string + pos;
input.end = input.string + end + len;
*input.end = '\0';
memmove(input.pos + len, input.pos, end - pos);
memmove(input.pos, s, len);
input.pos += len;
input.pos_end = nil;
}