Skip to content

Commit

Permalink
fix: data() x=middle, offset calc for wrapped lines with tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
ikozyris committed Aug 23, 2024
1 parent 166f733 commit 97b68be
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 78 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Yocto
[![C/C++ CI](https://github.com/ikozyris/yocto/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/ikozyris/yocto/actions/workflows/c-cpp.yml)
A simple, compact and *fast* text editor using ncurses and a gap buffer, written in C++, in <1k lines of code.
A simple, compact and *fast* text editor using ncurses and a gap buffer, written in C++, in ~1k lines of code.
More information is available on the [wiki](https://github.com/ikozyris/yocto/wiki).

![A C++ file in Yocto](https://github.com/ikozyris/yocto/assets/80053394/8fa12952-272f-41e0-9535-0a77f3652286)
Expand All @@ -11,12 +11,12 @@ make build
sudo make install
```

Or use the user-friendly dialog utility (`wizard.sh`)
Or use the user-friendly dialog utility `wizard.sh`
which also supports configuring yocto

### Keybindings
* Save: Ctrl-S
* Exit: Ctrl-C
* Exit: Ctrl-X
* Go to start of line: Ctrl-A
* Go to end of line: Ctrl-E
* Open other file Alt-R
Expand All @@ -25,7 +25,7 @@ which also supports configuring yocto
* Show info: Alt-I (also command _stats_ in built-in terminal)

### How fast is it?
Yocto is more than 3x faster than emacs, 4x vim and 6x nano at reading a file.
Yocto is several times faster than any other text editor at reading files and other operations.
See the [benchmarks](https://github.com/ikozyris/yocto/wiki/Performance-&-Benchmarks) for more.

### About the name
Expand Down
33 changes: 12 additions & 21 deletions headers/gapbuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ unsigned lnbf_cpt; // linebuff capacity
#define max(a, b) ((a) > (b) ? (a) : (b))

struct gap_buf {
unsigned cpt; // allocated size (1)
unsigned cpt; // allocated size (1-based)
unsigned len; // length of line (1)
unsigned gps; // gap start (first element of gap) (0)
unsigned gps; // gap start (first element of gap) (0-based)
unsigned gpe; // gap end (last element of gap) (0)
char *buffer;

Expand Down Expand Up @@ -146,40 +146,32 @@ inline void eras(gap_buf &a)
// NOTE: destination buffer is lnbuf
unsigned data(const gap_buf &src, unsigned from, unsigned to)
{
if (src.len == 0) {
lnbuf[0] = 0;
return 0;
}
if (src.len == 0)
return lnbuf[0] = 0;
if (lnbf_cpt < to - from + 3) {
free(lnbuf);
lnbf_cpt = to - from + 10;
lnbuf = (char*)malloc(lnbf_cpt);
}
lnbuf[to - from] = 0;
lnbuf[to - from + 1] = 0;
lnbuf[to - from + 1] = lnbuf[to - from] = 0;
// try some special cases where 1 copy is required
if (src.gps == src.len && src.gpe == src.cpt - 1) // gap ends at end
memcpy(lnbuf, src.buffer + from, min(to, src.gps));
else if (src.gps == 0) // x = 0; gap at start
memcpy(lnbuf, src.buffer + from + src.gpe + 1, min(to, src.len) - from);
else {
if (from < src.gps) { // worst case
for (unsigned i = from; i < src.gps; ++i)
lnbuf[i] = src[i];
for (unsigned i = src.gpe + 1; i < gaplen(src) + to; ++i)
lnbuf[i - gaplen(src)] = src[i];
//memcpy(tmp, src.buffer + from, min(to, src.gps));
//memcpy(tmp + min(to, src.gps), src.buffer +, src.gps - to - 1);
if (from < src.gps) {
memcpy(lnbuf, src.buffer + from, min(to, src.gps) - from);
if (to > src.gps - 1)
memcpy(lnbuf + src.gps, src.buffer + src.gpe + 1, to - from - src.gps);
} else
for (unsigned i = gaplen(src) + src.gps; i < gaplen(src) + to; ++i)
lnbuf[i - gaplen(src) - 1] = src[i];
//memcpy(tmp, src.buffer + src.gpe + 1, src.gps - to);
memcpy(lnbuf, src.buffer + from + gaplen(src), (to - from) + gaplen(src));
}
lnbuf[to - from + 2] = 0;
return to - from;
}

// naive, simplier, slower, should be bug free, implementation of above function
// naive, simplier, slower, implementation of above function
unsigned data2(const gap_buf &src, const unsigned from, const unsigned to) {
char *buffer = (char*)malloc(src.len + 3);
memcpy(buffer, src.buffer, src.gps);
Expand All @@ -194,8 +186,7 @@ unsigned data2(const gap_buf &src, const unsigned from, const unsigned to) {
}
memcpy(lnbuf, buffer + from, to - from);
free(buffer);
lnbuf[to - from + 1] = 0;
lnbuf[to - from + 2] = 0;
lnbuf[to - from + 1] = lnbuf[to - from + 2] = 0;
return to - from;
}

Expand Down
2 changes: 1 addition & 1 deletion headers/keybindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#define ENTER KEY_ENTER
#define SAVE ctrl('S')
#define EXIT ctrl('C')
#define EXIT ctrl('X')
#define UP KEY_UP
#define DOWN KEY_DOWN
#define LEFT KEY_LEFT
Expand Down
4 changes: 2 additions & 2 deletions headers/vars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ WINDOW *header_win, *ln_win, *text_win;
wchar_t s[6];
char s2[6];
unsigned char y, x, len;
// offset in y axis of text and screen, x axis equivalents are in gapbuffer
long ofy;
long ofy; // offset in y axis of text and screen, x axis is in gapbuffer
long ofx2; // this is last change in ofx
unsigned ry, rx;
unsigned buf_indx, printed, previndx, ppi;
unsigned maxy, maxx; // to store the maximum rows and columns
Expand Down
43 changes: 11 additions & 32 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ int main(int argc, char *argv[])

it = text.begin();
loop:
//goto stop;
while (1) {
getyx(text_win, y, x);
ry = y + ofy;
Expand All @@ -89,12 +88,10 @@ int main(int argc, char *argv[])

#ifdef DEBUG
print_text(y); // debug only
char tmp[80];
snprintf(tmp, 79, "st %u | end %u | cpt %u | len %u | maxx %u | ofx %ld ",
it->gps, it->gpe, it->cpt, it->len, maxx, ofx);
print2header(tmp, 1);
stats();
wmove(text_win, y, x);
#endif
//goto stop;
wget_wch(text_win, (wint_t*)s);
switch (s[0]) {
case DOWN:
Expand All @@ -119,36 +116,18 @@ int main(int argc, char *argv[])
break;

case LEFT:
if (x == 0 && ofx > 0) { // line has been wrapped
wmove(text_win, y, 0);
wclrtoeol(text_win);
print_line(*it);
#ifdef HIGHLIGHT
wmove(text_win, y, 0);
apply(y);
#endif
ofx -= maxx - 1;
wmove(text_win, y, maxx - 1);
} else if (x > 0) {
if (it->buffer[it->gps - 1] == '\t') {
wmove(text_win, y, x - 8);
ofx += 7;
break;
}
wmove(text_win, y, x - 1);
if (it->buffer[it->gps - 1] < 0)
--ofx;
} else if (y > 0) { // x = 0
if (ofx > 0) // revert wrap
print_line(*it);
--it;
--y;
eol();
}
if (x == 0 && ofx == 0 && ofy > 0 && y == 0)
scrollup();
else
left();
break;

case RIGHT:
right();
if (y == maxy - 1 && rx == it->len - 1) {
++it;
scrolldown();
} else
right();
break;

case BACKSPACE:
Expand Down
9 changes: 5 additions & 4 deletions utils/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,16 @@ char *input_header(const char *q)
return tmp;
}

unsigned print_line(const gap_buf &buffer, unsigned from = 0, unsigned to = -1)
unsigned print_line(const gap_buf &buffer, unsigned from = 0, unsigned to = 0xffffffff)
{
if (to == -1)
to = buffer.len;
if (buffer.len == 0)
return 0;
unsigned rlen = data2(buffer, from, min(to, maxx * 2));
if (to == 0xffffffff) // 2^32-1
to = buffer.len;
unsigned rlen = data(buffer, from, min(to, maxx * 2));
if (lnbuf[rlen - 1] == '\n')
--rlen;
// TODO: is there a faster way?
waddnstr(text_win, lnbuf, min(maxy / 2, rlen));
// make sure we don't print more than needed (utf8, tabs...)
for (unsigned i = maxy / 2; i < rlen && (unsigned)getcurx(text_win) < maxx - 1; ++i)
Expand Down
51 changes: 42 additions & 9 deletions utils/key_func.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ void stats()
unsigned sumlen = 0;
for (auto &i : text)
sumlen += i.len;
//snprintf(_tmp, maxx, "st %u | end %u | cpt %u | len %u | maxx %u | ofx %ld ",
// it->gps, it->gpe, it->cpt, it->len, maxx, ofx);
snprintf(_tmp, maxx, "length %u y %u x %u sum len %u lines %lu ofx %ld ",
it->len, ry, x, sumlen, curnum, ofx);
print2header(_tmp, 1);
Expand Down Expand Up @@ -121,8 +123,8 @@ void enter()

gap_buf *t = (gap_buf*)malloc(sizeof(gap_buf));
init(*t);
if (it->gpe < it->cpt - 1) { // newline is not at the end
data2(*it, rx + 1, it->len + 1);
if (it->gpe < it->cpt - 2) { // newline is not at the end
data(*it, rx + 1, it->len + 1);
apnd_s(*t, lnbuf, it->len - rx - 1);
it->gps = rx + 1;
it->len = rx + 1;
Expand Down Expand Up @@ -157,25 +159,24 @@ void eol()
} else { // wrap line
wmove(text_win, y, 0);
wclrtoeol(text_win);
// TODO: use actual printline()
print_line(*it, it->len - maxx - ofx, it->len);
ofx = (long)it->len - (long)maxx - ofx;
ofx = (ofx2 = (long)it->len - (long)maxx - ofx);
}
}

void sol()
{
wmove(text_win, y, 0);
if (ofx < 0)
ofx = 0;
ofx2 = ofx = 0;
else if (ofx >= (long)it->len - maxx) { // line has been wrapped
wclrtoeol(text_win);
print_line(*it);
print_line(*it, 0, maxx);
#ifdef HIGHLIGHT
wmove(text_win, y, 0);
apply(y);
#endif
ofx = 0;
ofx2 = ofx = 0;
wmove(text_win, y, 0);
}
}
Expand Down Expand Up @@ -216,6 +217,38 @@ void scrollup()
}

// TODO: is all this complexity needed?
void left()
{
if (x == 0 && ofx > 0) { // line has been wrapped
wmove(text_win, y, 0);
wclrtoeol(text_win);
print_line(*it);
#ifdef HIGHLIGHT
wmove(text_win, y, 0);
apply(y);
#endif
ofx -= ofx2;
ofx2 = 0;
wmove(text_win, y, maxx - 1);
} else if (x > 0) {
// TODO: use nextword() to get actual offset
if (it->buffer[it->gps - 1] == '\t') {
wmove(text_win, y, x - 8);
ofx += 7;
return;
}
wmove(text_win, y, x - 1);
if (it->buffer[it->gps - 1] < 0)
--ofx;
} else if (y > 0) { // x = 0
if (ofx > 0) // revert wrap
print_line(*it);
--it;
--y;
eol();
}
}

void right()
{
if (it->buffer[it->gpe + 1] == '\t') {
Expand All @@ -229,9 +262,9 @@ void right()
wclrtoeol(text_win);
// TODO: use print_line()
//print_line(*it, ofx + maxx - 1, it->len - maxx - ofx);
data2(*it, ofx + maxx - 1, ofx + maxx * 2);
data(*it, ofx + maxx - 1, ofx + maxx * 2);
waddnstr(text_win, lnbuf, it->len - maxx - ofx);
ofx += maxx - 1;
ofx2 = (ofx += maxx - 1);
wmove(text_win, y, 0);
} else {
if (ry < curnum) {
Expand Down
8 changes: 4 additions & 4 deletions utils/sizes.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ const char *itoa(long a)
return b;
}

// convert bytes to base-10 human-readable string e.g 1024 = 1.024KB = 1KiB
// convert bytes to base-10 (SI) human-readable string e.g 1000B = 1kB
const char *hrsize(size_t bytes)
{
const char *suffix[] = {"B", "KB", "MB", "GB", "TB"};
const char *suffix[] = {"B", "kB", "MB", "GB", "TB"};
unsigned char length = sizeof(suffix) / sizeof(suffix[0]);

double dblBytes = bytes;
Expand All @@ -26,10 +26,10 @@ const char *hrsize(size_t bytes)

// get length of line y
unsigned sizeofline(unsigned y) {
unsigned i = maxx - 1;
short i = maxx - 1;
wmove(text_win, y, i);
while ((winch(text_win) & A_CHARTEXT) == ' '
&& getcurx(text_win) >= it->len - 1)
&& (unsigned)getcurx(text_win) >= it->len - 1 && i >= 0)
wmove(text_win, y, --i);
wmove(text_win, y, i + 1);
return i + 2;
Expand Down
2 changes: 1 addition & 1 deletion wizard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ display_result() {
}

KEY_SAVE="ctrl('S')"
KEY_EXIT="ctrl('C')"
KEY_EXIT="ctrl('X')"
KEY_INFO="'i'"
KEY_REFRESH="ctrl('R')"
KEY_HOME="ctrl('A')"
Expand Down

0 comments on commit 97b68be

Please sign in to comment.