Files
degvi/Editor.c
2013-02-10 23:54:06 +09:00

525 lines
13 KiB
C

#include "init.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "Editor.h"
static int copyMode;
static Text copy;
void Editor_static_initialize(void)
{
copyMode = EDITOR_COPY_MODE_NONE;
copy = NULL;
}
Editor Editor_create(Window window, Text text, int tabWidth, Input input, KeyCommand keyCommand)
{
Editor this;
this = malloc(sizeof(struct Editor_struct));
if (this == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
this->view = View_create(window, text, tabWidth);
this->text = text;
this->input = input;
this->keyCommand = keyCommand;
this->mode = EDITOR_MODE_COMMAND;
this->filename = NULL;
return this;
}
void Editor_destroy(Editor this)
{
if (this == NULL) {
return;
}
View_destroy(this->view);
free(this->filename);
free(this);
}
void Editor_updateCursorPosition(Editor this)
{
View_updateCursorPosition(this->view);
}
void Editor_paint(Editor this)
{
View_paint(this->view);
}
static void runInput(Editor this)
{
char *string;
string = Line_toString(this->input->line);
if (strlen(string) < 1) {
goto finish;
}
if (strcmp(string, ":") == 0) {
goto finish;
}
if (strcmp(string + 1, "q") == 0) {
exit(EXIT_SUCCESS);
} else if (strcmp(string + 1, "w") == 0) {
Editor_save(this);
} else if (strcmp(string + 1, "wq") == 0) {
Editor_save(this);
exit(EXIT_SUCCESS);
}
finish:
free(string);
}
static void runKeyCommand(Editor this)
{
if (this->keyCommand->edit != 0) {
switch (this->keyCommand->edit) {
default:
assert(0);
case '\f': /* repaint */
Editor_paint(this);
Editor_updateCursorPosition(this);
break;
case ':': /* input command line */
this->mode = EDITOR_MODE_FIELD;
Input_keyTyped(this->input, ':');
Input_paint(this->input);
Input_updateCursorPosition(this->input);
break;
case 'i': /* insert */
this->mode = EDITOR_MODE_INSERT;
Editor_updateCursorPosition(this);
break;
case 'a': /* insert after */
this->mode = EDITOR_MODE_INSERT;
if (Text_size(this->text) > 0) {
if (Line_size(Text_getLine(this->text, this->view->cursorLine)) > 0) {
this->view->cursorCharacter++;
}
}
Editor_updateCursorPosition(this);
break;
case 'I': /* insert at head */
this->mode = EDITOR_MODE_INSERT;
this->view->cursorCharacter = 0;
Editor_updateCursorPosition(this);
break;
case 'A': /* insert at tail */
this->mode = EDITOR_MODE_INSERT;
if (Text_size(this->text) > 0) {
this->view->cursorCharacter = Line_size(Text_getLine(this->text, this->view->cursorLine));
}
Editor_updateCursorPosition(this);
break;
case 'o': /* open line */
this->mode = EDITOR_MODE_INSERT;
if (Text_size(this->text) > 0) {
this->view->cursorLine++;
}
this->view->cursorCharacter = 0;
Text_addLine(this->text, this->view->cursorLine, Line_create());
Editor_paint(this);
Editor_updateCursorPosition(this);
break;
case 'O': /* open previous line */
this->mode = EDITOR_MODE_INSERT;
this->view->cursorCharacter = 0;
Text_addLine(this->text, this->view->cursorLine, Line_create());
Editor_paint(this);
Editor_updateCursorPosition(this);
break;
case 'x': { /* delete character */
Line line;
int repeat;
int i;
line = Text_getLine(this->text, this->view->cursorLine);
repeat = this->keyCommand->count1;
if (repeat == 0) {
repeat = 1;
}
if (repeat > Line_size(line)) {
repeat = Line_size(line);
}
for (i = 0; i < repeat; i++) {
int size;
Line_removeCharacter(line, this->view->cursorCharacter);
size = Line_size(line);
if (size > 0 && this->view->cursorCharacter >= size) {
this->view->cursorCharacter = size - 1;
}
}
Editor_paint(this);
Editor_updateCursorPosition(this);
} break;
case 'd': { /* delete line */
int repeat;
int i;
int size;
repeat = this->keyCommand->count1;
if (repeat == 0) {
repeat = 1;
}
if (repeat > Text_size(this->text) - this->view->cursorLine) {
repeat = Text_size(this->text) - this->view->cursorLine;
}
if (repeat < 1) {
break;
}
Text_destroy(copy);
copyMode = EDITOR_COPY_MODE_LINES;
copy = Text_create();
for (i = 0; i < repeat; i++) {
Text_addLine(copy, Text_size(copy), Text_removeLine(this->text, this->view->cursorLine));
size = Text_size(this->text);
if (size > 0 && this->view->cursorLine >= size) {
this->view->cursorLine = size - 1;
}
}
this->view->cursorCharacter = 0;
Editor_paint(this);
Editor_updateCursorPosition(this);
} break;
case 'J': { /* join lines */
Line line;
Line nextLine;
if (this->view->cursorLine + 1 > Text_size(this->text) - 1) {
break;
}
line = Text_getLine(this->text, this->view->cursorLine);
this->view->cursorCharacter = Line_size(line);
Line_addCharacter(line, Line_size(line), ' ');
nextLine = Text_getLine(this->text, this->view->cursorLine + 1);
Line_addLine(line, Line_size(line), nextLine);
Line_destroy(Text_removeLine(this->text, this->view->cursorLine + 1));
Editor_paint(this);
Editor_updateCursorPosition(this);
} break;
case 'y': { /* copy */
int repeat;
int i;
repeat = this->keyCommand->count1;
if (repeat == 0) {
repeat = 1;
}
if (repeat > Text_size(this->text) - this->view->cursorLine) {
repeat = Text_size(this->text) - this->view->cursorLine;
}
if (repeat < 1) {
break;
}
Text_destroy(copy);
copyMode = EDITOR_COPY_MODE_LINES;
copy = Text_create();
for (i = 0; i < repeat; i++) {
Text_addLine(copy, Text_size(copy), Line_clone(Text_getLine(this->text, this->view->cursorLine + i)));
}
} break;
case 'p': { /* paste */
int i;
int size;
int lastLine;
if (copyMode != EDITOR_COPY_MODE_LINES) {
break;
}
for (i = 0; i < Text_size(copy); i++) {
if (Text_size(this->text) < 1) {
Text_addLine(this->text, 0, Line_clone(Text_getLine(copy, i)));
} else {
Text_addLine(this->text, this->view->cursorLine + 1, Line_clone(Text_getLine(copy, i)));
this->view->cursorLine++;
}
}
size = Line_size(Text_getLine(this->text, this->view->cursorLine));
if (size < 1) {
this->view->cursorCharacter = 0;
} else if (this->view->cursorCharacter >= size) {
this->view->cursorCharacter = size - 1;
}
lastLine = View_lastLineIndex(this->view);
if (this->view->cursorLine > lastLine) {
this->view->origin += this->view->cursorLine - lastLine;
}
Editor_paint(this);
Editor_updateCursorPosition(this);
} break;
case 'P': { /* paste above */
int i;
int size;
if (copyMode != EDITOR_COPY_MODE_LINES) {
break;
}
for (i = 0; i < Text_size(copy); i++) {
Text_addLine(this->text, this->view->cursorLine, Line_clone(Text_getLine(copy, i)));
}
size = Line_size(Text_getLine(this->text, this->view->cursorLine));
if (size < 1) {
this->view->cursorCharacter = 0;
} else if (this->view->cursorCharacter >= size) {
this->view->cursorCharacter = size - 1;
}
if (this->view->cursorLine < this->view->origin) {
this->view->origin = this->view->cursorLine;
}
Editor_paint(this);
Editor_updateCursorPosition(this);
} break;
case 'Z':
if (this->keyCommand->motion == 'Z') {
Editor_save(this);
exit(EXIT_SUCCESS);
}
break;
}
} else if (this->keyCommand->motion != 0) {
switch (this->keyCommand->motion) {
default:
assert(0);
case '0': /* move to head of line */
View_moveToHead(this->view);
break;
case '$': /* move to tail of line */
View_moveToTail(this->view);
break;
case 'G': { /* move to line */
int index;
index = this->keyCommand->count1 - 1;
if (index == -1) {
index = Text_size(this->text) - 1;
}
if (index >= Text_size(this->text)) {
index = Text_size(this->text) - 1;
}
if (index < 0) {
index = 0;
}
View_moveToLine(this->view, index);
} break;
case 'h': { /* move left */
int repeat;
repeat = this->keyCommand->count1;
if (repeat == 0) {
repeat = 1;
}
View_moveLeft(this->view, repeat);
} break;
case 'j': { /* move down */
int repeat;
repeat = this->keyCommand->count1;
if (repeat == 0) {
repeat = 1;
}
View_moveDown(this->view, repeat);
} break;
case 'k': { /* move up */
int repeat;
repeat = this->keyCommand->count1;
if (repeat == 0) {
repeat = 1;
}
View_moveUp(this->view, repeat);
} break;
case 'l': { /* move right */
int repeat;
repeat = this->keyCommand->count1;
if (repeat == 0) {
repeat = 1;
}
View_moveRight(this->view, repeat);
} break;
}
} else {
assert(0);
}
}
#ifdef DEBUG
static void showKeyCommand(Editor this)
{
char edit;
char motion;
if (this->keyCommand->edit == 0) {
edit = '-';
} else {
edit = this->keyCommand->edit;
}
if (this->keyCommand->motion == 0) {
motion = '-';
} else {
motion = this->keyCommand->motion;
}
Window_setCursorPosition(this->input->window, 0, 0);
printf("[%d,%c,%d,%c]", this->keyCommand->count1, edit, this->keyCommand->count2, motion);
Editor_updateCursorPosition(this);
}
#endif
void Editor_keyTyped(Editor this, int keyChar)
{
switch (this->mode) {
default:
assert(0);
case EDITOR_MODE_COMMAND:
switch (KeyCommand_read(this->keyCommand, keyChar)) {
default:
assert(0);
case KEY_COMMAND_SWALLOWED:
return;
case KEY_COMMAND_FINISHED:
#ifdef DEBUG
showKeyCommand(this);
#endif
runKeyCommand(this);
KeyCommand_reset(this->keyCommand);
return;
case KEY_COMMAND_CANCELED:
KeyCommand_reset(this->keyCommand);
return;
case KEY_COMMAND_ERROR:
KeyCommand_reset(this->keyCommand);
return;
}
case EDITOR_MODE_FIELD:
if (keyChar == 0x1b) {
this->mode = EDITOR_MODE_COMMAND;
Input_clear(this->input);
Input_paint(this->input);
Editor_updateCursorPosition(this);
} else if (keyChar == '\n') {
runInput(this);
this->mode = EDITOR_MODE_COMMAND;
Input_clear(this->input);
Input_paint(this->input);
Editor_updateCursorPosition(this);
} else {
Input_keyTyped(this->input, keyChar);
Input_paint(this->input);
Input_updateCursorPosition(this->input);
}
break;
case EDITOR_MODE_INSERT:
if (Text_size(this->text) <= this->view->cursorLine) {
Text_addLine(this->text, this->view->cursorLine, Line_create());
}
if (keyChar == 0x1b) {
this->mode = EDITOR_MODE_COMMAND;
if (this->view->cursorCharacter > 0) {
this->view->cursorCharacter--;
}
Editor_updateCursorPosition(this);
} else if (keyChar == '\n') {
Line line;
Line subLine;
int lastLine;
line = Text_getLine(this->text, this->view->cursorLine);
subLine = Line_removeRange(line, this->view->cursorCharacter, Line_size(line) - this->view->cursorCharacter);
this->view->cursorLine++;
this->view->cursorCharacter = 0;
Text_addLine(this->text, this->view->cursorLine, subLine);
lastLine = View_lastLineIndex(this->view);
if (this->view->cursorLine > lastLine) {
this->view->origin += this->view->cursorLine - lastLine;
Editor_paint(this);
}
Editor_paint(this);
Editor_updateCursorPosition(this);
} else if (keyChar == 0x08 || keyChar == 0x7f) {
Line line;
int size;
line = Text_getLine(this->text, this->view->cursorLine);
size = Line_size(line);
if (size > 0) {
Line_removeCharacter(line, size - 1);
this->view->cursorCharacter--;
Editor_paint(this);
Editor_updateCursorPosition(this);
}
} else {
Line line;
int lastLine;
line = Text_getLine(this->text, this->view->cursorLine);
Line_addCharacter(line, this->view->cursorCharacter, keyChar);
this->view->cursorCharacter++;
lastLine = View_lastLineIndex(this->view);
if (this->view->cursorLine > lastLine) {
this->view->origin += this->view->cursorLine - lastLine;
}
Editor_paint(this);
Editor_updateCursorPosition(this);
}
break;
}
}
void Editor_setFilename(Editor this, char *filename)
{
free(this->filename);
this->filename = malloc(sizeof(char) * (strlen(filename) + 1));
if (this->filename == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(this->filename, filename);
}
void Editor_load(Editor this)
{
if (this->filename == NULL) {
return;
}
Text_load(this->text, this->filename);
Editor_paint(this);
Editor_updateCursorPosition(this);
}
void Editor_save(Editor this)
{
if (this->filename == NULL) {
return;
}
Text_save(this->text, this->filename);
}