328 lines
5.8 KiB
C
328 lines
5.8 KiB
C
#include "init.h"
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "View.h"
|
|
|
|
View View_create(Window window, Text text, int tabWidth)
|
|
{
|
|
View this;
|
|
|
|
this = malloc(sizeof(struct View_struct));
|
|
if (this == NULL) {
|
|
fprintf(stderr, "malloc failed\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
this->window = window;
|
|
this->text = text;
|
|
this->tabWidth = tabWidth;
|
|
this->origin = 0;
|
|
this->cursorLine = 0;
|
|
this->cursorCharacter = 0;
|
|
|
|
return this;
|
|
}
|
|
|
|
void View_destroy(View this)
|
|
{
|
|
if (this == NULL) {
|
|
return;
|
|
}
|
|
|
|
free(this);
|
|
}
|
|
|
|
void View_setTabWidth(View this, int tabWidth)
|
|
{
|
|
this->tabWidth = tabWidth;
|
|
}
|
|
|
|
static void toView(View this, int lineIndex, int characterIndex, int *resultX, int *resultY)
|
|
{
|
|
int x;
|
|
int y;
|
|
int j;
|
|
|
|
assert(lineIndex >= this->origin);
|
|
|
|
y = 0;
|
|
for (j = this->origin; j <= lineIndex; j++) {
|
|
Line line;
|
|
int i;
|
|
|
|
line = Text_getLine(this->text, j);
|
|
x = 0;
|
|
for (i = 0; i < Line_size(line); i++) {
|
|
Character c;
|
|
|
|
if (j == lineIndex && i == characterIndex) {
|
|
break;
|
|
}
|
|
|
|
c = Line_getCharacter(line, i);
|
|
if (c == '\t') {
|
|
x = x / this->tabWidth * this->tabWidth + this->tabWidth;
|
|
} else {
|
|
x += Character_width(c);
|
|
}
|
|
if (x >= Window_width(this->window)) {
|
|
x = 0;
|
|
y++;
|
|
}
|
|
}
|
|
if (j < lineIndex) {
|
|
y++;
|
|
}
|
|
}
|
|
*resultX = x;
|
|
*resultY = y;
|
|
}
|
|
|
|
void View_updateCursorPosition(View this)
|
|
{
|
|
int x;
|
|
int y;
|
|
|
|
if (Text_size(this->text) < 1) {
|
|
x = 0;
|
|
y = 0;
|
|
} else {
|
|
toView(this, this->cursorLine, this->cursorCharacter, &x, &y);
|
|
}
|
|
Window_setCursorPosition(this->window, x, y);
|
|
}
|
|
|
|
void View_paint(View this)
|
|
{
|
|
int lineIndex;
|
|
int y;
|
|
int i;
|
|
|
|
lineIndex = this->origin;
|
|
y = 0;
|
|
for (;;) {
|
|
int x;
|
|
int k;
|
|
|
|
Window_setCursorPosition(this->window, 0, y);
|
|
x = 0;
|
|
if (lineIndex < Text_size(this->text)) {
|
|
Line line;
|
|
|
|
line = Text_getLine(this->text, lineIndex);
|
|
lineIndex++;
|
|
for (i = 0; i < Line_size(line); i++) {
|
|
Character c;
|
|
|
|
c = Line_getCharacter(line, i);
|
|
if (c == '\t') {
|
|
int x2;
|
|
int l;
|
|
|
|
x2 = x / this->tabWidth * this->tabWidth + this->tabWidth;
|
|
for (l = x; l < x2; l++) {
|
|
fputc(' ', stdout);
|
|
}
|
|
x = x2;
|
|
} else {
|
|
Character_write(c, stdout);
|
|
x += Character_width(c);
|
|
}
|
|
|
|
if (x >= Window_width(this->window)) {
|
|
x = 0;
|
|
y++;
|
|
if (y >= Window_height(this->window)) {
|
|
break;
|
|
}
|
|
Window_setCursorPosition(this->window, 0, y);
|
|
}
|
|
}
|
|
} else {
|
|
fputc('~', stdout);
|
|
x++;
|
|
}
|
|
|
|
for (k = x; k < Window_width(this->window); k++) {
|
|
fputc(' ', stdout);
|
|
}
|
|
|
|
y++;
|
|
if (y >= Window_height(this->window)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int View_lastLineIndex(View this)
|
|
{
|
|
int x;
|
|
int y;
|
|
int j;
|
|
|
|
if (Text_size(this->text) < 1) {
|
|
return 0;
|
|
}
|
|
|
|
y = 0;
|
|
j = this->origin;
|
|
for (;;) {
|
|
Line line;
|
|
int i;
|
|
|
|
line = Text_getLine(this->text, j);
|
|
x = 0;
|
|
for (i = 0; i < Line_size(line); i++) {
|
|
Character c;
|
|
|
|
c = Line_getCharacter(line, i);
|
|
if (c == '\t') {
|
|
x = x / this->tabWidth * this->tabWidth + this->tabWidth;
|
|
} else {
|
|
x++;
|
|
}
|
|
if (x >= Window_width(this->window)) {
|
|
x = 0;
|
|
y++;
|
|
}
|
|
}
|
|
y++;
|
|
if (y == Window_height(this->window)) {
|
|
break;
|
|
} else if (y > Window_height(this->window)) {
|
|
j--;
|
|
break;
|
|
} else if (j >= Text_size(this->text) - 1) {
|
|
break;
|
|
} else {
|
|
j++;
|
|
}
|
|
}
|
|
return j;
|
|
}
|
|
|
|
void View_moveToTop(View this)
|
|
{
|
|
this->cursorLine = 0;
|
|
this->cursorCharacter = 0;
|
|
this->origin = 0;
|
|
View_paint(this);
|
|
View_updateCursorPosition(this);
|
|
}
|
|
|
|
void View_moveToLine(View this, int index)
|
|
{
|
|
if (Text_size(this->text) < 1) {
|
|
return;
|
|
}
|
|
|
|
assert(index >= 0 && index < Text_size(this->text));
|
|
|
|
this->cursorLine = index;
|
|
this->cursorCharacter = 0;
|
|
this->origin = this->cursorLine;
|
|
View_paint(this);
|
|
View_updateCursorPosition(this);
|
|
}
|
|
|
|
void View_moveToHead(View this)
|
|
{
|
|
this->cursorCharacter = 0;
|
|
View_updateCursorPosition(this);
|
|
}
|
|
|
|
void View_moveToTail(View this)
|
|
{
|
|
Line line;
|
|
|
|
if (Text_size(this->text) < 1) {
|
|
return;
|
|
}
|
|
line = Text_getLine(this->text, this->cursorLine);
|
|
if (Line_size(line) < 1) {
|
|
return;
|
|
}
|
|
this->cursorCharacter = Line_size(line) - 1;
|
|
View_updateCursorPosition(this);
|
|
}
|
|
|
|
void View_moveUp(View this, int repeat)
|
|
{
|
|
int size;
|
|
|
|
if (Text_size(this->text) < 1) {
|
|
return;
|
|
}
|
|
|
|
this->cursorLine -= repeat;
|
|
if (this->cursorLine < 0) {
|
|
this->cursorLine = 0;
|
|
}
|
|
size = Line_size(Text_getLine(this->text, this->cursorLine));
|
|
if (size < 1) {
|
|
this->cursorCharacter = 0;
|
|
} else if (this->cursorCharacter >= size) {
|
|
this->cursorCharacter = size - 1;
|
|
}
|
|
if (this->cursorLine < this->origin) {
|
|
this->origin = this->cursorLine;
|
|
View_paint(this);
|
|
}
|
|
View_updateCursorPosition(this);
|
|
}
|
|
|
|
void View_moveDown(View this, int repeat)
|
|
{
|
|
int size;
|
|
int lastLine;
|
|
|
|
if (this->cursorLine >= Text_size(this->text) - 1) {
|
|
return;
|
|
}
|
|
|
|
this->cursorLine += repeat;
|
|
if (this->cursorLine >= Text_size(this->text)) {
|
|
this->cursorLine = Text_size(this->text) - 1;
|
|
if (this->cursorLine < 0) {
|
|
this->cursorLine = 0;
|
|
}
|
|
}
|
|
size = Line_size(Text_getLine(this->text, this->cursorLine));
|
|
if (size < 1) {
|
|
this->cursorCharacter = 0;
|
|
} else if (this->cursorCharacter >= size) {
|
|
this->cursorCharacter = size - 1;
|
|
}
|
|
lastLine = View_lastLineIndex(this);
|
|
if (this->cursorLine > lastLine) {
|
|
this->origin += this->cursorLine - lastLine;
|
|
View_paint(this);
|
|
}
|
|
View_updateCursorPosition(this);
|
|
}
|
|
|
|
void View_moveLeft(View this, int repeat)
|
|
{
|
|
this->cursorCharacter -= repeat;
|
|
if (this->cursorCharacter < 0) {
|
|
this->cursorCharacter = 0;
|
|
}
|
|
View_updateCursorPosition(this);
|
|
}
|
|
|
|
void View_moveRight(View this, int repeat)
|
|
{
|
|
if (Text_size(this->text) < 1) {
|
|
return;
|
|
}
|
|
this->cursorCharacter += repeat;
|
|
if (this->cursorCharacter >= Line_size(Text_getLine(this->text, this->cursorLine))) {
|
|
this->cursorCharacter = Line_size(Text_getLine(this->text, this->cursorLine)) - 1;
|
|
if (this->cursorCharacter < 0) {
|
|
this->cursorCharacter = 0;
|
|
}
|
|
}
|
|
View_updateCursorPosition(this);
|
|
}
|