editor/text.c
2021-12-21 21:15:08 +10:00

486 lines
9.4 KiB
C

#include "text.h"
#include "text.xpm"
/**
* Word Processing Program
* Features:
* -Real time editing
* -Saving
* -Loading
**/
int winx, winy;
int y_offset = 0; // TODO: move to local scope
int tab_offset = 0;
extern void convert_xpm(char **xpm, unsigned char **buffer);
extern unsigned char *QUINN_Icon;
WINDOW *menu;
WINDOW *editor;
WINDOW *linenos;
short curs_color(int fg)
{
switch (7 & fg) { /* RGB */
case 0: /* 000 */
return (COLOR_BLACK);
case 1: /* 001 */
return (COLOR_BLUE);
case 2: /* 010 */
return (COLOR_GREEN);
case 3: /* 011 */
return (COLOR_CYAN);
case 4: /* 100 */
return (COLOR_RED);
case 5: /* 101 */
return (COLOR_MAGENTA);
case 6: /* 110 */
return (COLOR_YELLOW);
case 7: /* 111 */
return (COLOR_WHITE);
}
}
void init_colorpairs(void)
{
int fg, bg;
int colorpair;
for (bg = 0; bg <= 7; bg++) {
for (fg = 0; fg <= 7; fg++) {
colorpair = colornum(fg, bg);
init_pair(colorpair, curs_color(fg), curs_color(bg));
}
}
}
int colornum(int fg, int bg)
{
int B, bbb, ffff;
B = 1 << 7;
bbb = (7 & bg) << 4;
ffff = 7 & fg;
return (B | bbb | ffff);
}
void setcolor(int fg, int bg)
{
/* set the color pair (colornum) and bold/bright (A_BOLD) */
attron(COLOR_PAIR(colornum(fg, bg)));
if (is_bold(fg)) {
attron(A_BOLD);
}
}
void unsetcolor(int fg, int bg)
{
/* unset the color pair (colornum) and
bold/bright (A_BOLD) */
attroff(COLOR_PAIR(colornum(fg, bg)));
if (is_bold(fg)) {
attroff(A_BOLD);
}
}
int is_bold(int fg)
{
/* return the intensity bit */
int i;
i = 1 << 3;
return (i & fg);
}
void print_loc(int x, int y)
{
int oldx, oldy;
getyx(stdscr, oldy, oldx);
wmove(menu, 0, COLS - 30);
wprintw(menu, "X: %d Y: %d Offset: %d", x + 1, y + 1, y_offset);
wclrtoeol(menu);
move(oldy, oldx);
}
int main(int argc, char *argv[])
{
PAGE page;
convert_xpm(text_xpm, &QUINN_Icon);
if(argc > 1)
{
if(file_exists(argv[1]))
{
load_file(&page, argv[1]);
}
else
{
init_page(&page, argv[1], PAGE_SIZE);
page.numlines = 1;
}
}
else // initialize
{
init_page(&page, "untitled.txt", PAGE_SIZE);
page.numlines = 1;
}
/* curses interface */
initscr();
noecho();
keypad(stdscr, 1);
start_color();
init_colorpairs();
winx = 0;
winy = 0;
menu = subwin(stdscr, 2, 80, 23, 0);
wbkgd(menu, COLOR_PAIR(colornum(COLOR_BLACK, COLOR_CYAN)));
editor = subwin(stdscr, 23, 75, 0, 5);
wbkgd(editor, COLOR_PAIR(colornum(COLOR_WHITE, COLOR_BLUE)));
linenos = subwin(stdscr, 23, 5, 0, 0);
wbkgd(linenos, COLOR_PAIR(colornum(COLOR_BLUE, COLOR_WHITE)));
int beg = 0;
int i;
update_status(&page, "");
print_page(editor, linenos, &page, beg);
wmove(editor, winy, winx);
while(1)
{
beg = y_offset;
int ch = wgetch(editor);
update_status(&page, ""); // default text
switch(ch)
{
case KEY_F(4):
if(prompt_yesno("Are you sure you want to quit?"))
goto endnc;
print_page(editor, linenos, &page, beg);
break;
case KEY_F(5):
save_file(&page);
update_status(&page, "Saved!");
break;
case KEY_F(6):
prompt_string("Save As:", page.filename, NAME_LIMIT);
save_file(&page);
print_page(editor, linenos, &page, beg);
update_status(&page, "Saved!");
break;
case KEY_UP:
move_up(&page);
break;
case KEY_DOWN:
move_down(&page);
break;
case KEY_LEFT:
move_left(&page);
break;
case KEY_RIGHT:
move_right(&page);
break;
case KEY_END:
move_to_eol(&page);
case KEY_DC:
case 127: // backspace key...
case KEY_BACKSPACE:
case '\b':
if(strlen(page.text[page.y].line) == 0)
{ // can only delete blank lines for now
remove_line(&page, page.y);
move_up(&page);
}
else if( page.x > 0 )
{
remove_char(&page.text[page.y], page.x - 1); // delete
move_left(&page); // char behind cursor
}
print_page(editor, linenos, &page, beg);
wmove(editor, winy, winx);
page.saved = 0;
break;
case '\t':
for(i = 0; i < TAB_WIDTH; i++)
{
insert_char(&page.text[page.y], ' ', page.x);
print_page(editor, linenos, &page, beg);
move_right(&page);
}
page.saved = 0;
break;
case '\n': // newline
insert_line(&page, page.y + 1);
print_page(editor, linenos, &page, beg);
move_down(&page);
break;
default: // all other chars
if( isprint(ch) )
{
insert_char(&page.text[page.y], ch, page.x);
print_page(editor, linenos, &page, beg);
move_right(&page);
page.saved = 0;
}
}
print_loc(page.x, page.y);
wrefresh(menu);
wrefresh(editor);
}
endnc:
/* end curses */
endwin();
dest_page(&page);
return EXIT_SUCCESS;
} // main
// prints a message at the bottom of the window
void update_status(PAGE *p, char *info)
{
char title[61];
snprintf(title, 60, "Text: %s%c", p->filename, p->saved == 1 ? ' ' : '*');
PDC_set_title(title);
wmove(menu, 0, 0);
wprintw(menu, "%s", info);
wmove(menu, 1, 0);
wprintw(menu, "F4: Quit F5: Save F6: Save As ");
wrefresh(menu);
} // update_status
/* movement */
void move_to_eol(PAGE *p)
{
while (p->x <= strlen(p->text[p->y].line)) {
move_right(p);
}
}
void move_left(PAGE *p)
{
if(p->x - 1 > 0) {
p->x--;
winx--;
winy = 0;
if (p->x > 75) {
winx = p->x % 75;
winy = p->x / 75;
} else {
winx = p->x;
}
for (int j = y_offset; j < p->y; j++) {
winy += p->text[j].lines_in_screen;
}
wmove(editor, winy, winx);
} else if (p->x - 1 == 0){
p->x = 0;
winx = 0;
}
}
void move_right(PAGE *p)
{
if(p->x <= strlen(p->text[p->y].line))
{
p->x++;
winy = 0;
if (p->x > 75) {
winx = p->x % 75;
winy = p->x / 75;
} else {
winx++;
}
for (int j = y_offset; j < p->y; j++) {
if (strlen(p->text[j].line) > 75) {
winy += p->text[j].lines_in_screen;
} else {
winy++;
}
}
wmove(editor, winy, winx);
}
}
void move_up(PAGE *p)
{
if (p->y == y_offset && y_offset > 0) {
p->y--;
y_offset--;
if( p->x > strlen(p->text[p->y].line) ) { // cursor adjusts
p->x = strlen(p->text[p->y].line); // to smaller lines
int oldy = p->x / 75;
p->x = strlen(p->text[p->y].line);
winx = p->x % 75;
winy = winy - (oldy - p->x / 75);
}
print_page(editor, linenos, p, y_offset);
wmove(editor, winy, winx);
} else if (p->y > 0) {
p->y--;
winy -= p->text[p->y].lines_in_screen;
if( p->x > strlen(p->text[p->y].line) ) { // cursor adjusts
int oldy = p->x / 75;
p->x = strlen(p->text[p->y].line);
winx = p->x % 75;
winy = winy - (oldy - p->x / 75);
}
wmove(editor, winy, winx);
}
}
void move_down(PAGE *p)
{
if (p->y < p->numlines - 1) {
winy += p->text[p->y].lines_in_screen;
p->y++;
int new_y_offset = y_offset;
while (1) {
int count = 0;
for (int i = new_y_offset; i <= p->y; i++) {
count += p->text[i].lines_in_screen;
}
if (count > EDITOR_SIZE) {
new_y_offset++;
} else {
break;
}
}
if (new_y_offset != y_offset) {
winy = 0;
for (int i = new_y_offset;i < p->y; i++) {
winy += p->text[i].lines_in_screen;
}
y_offset = new_y_offset;
print_page(editor, linenos, p, y_offset);
}
if( p->x > strlen(p->text[p->y].line)) {
int oldy = p->x / 75;
p->x = strlen(p->text[p->y].line);
winx = p->x % 75;
winy = winy - (oldy - p->x / 75);
}
wmove(editor, winy, winx);
}
}
/* movement */
int count_lines(FILE *fp)
{
char ch = '\0';
int count = 0;
while((ch = fgetc(fp)) != EOF)
if( ch == '\n' )
count++;
fseek(fp, 0, SEEK_SET); // go to beginning of file
return count;
} // count_lines
/* saving and loading */
void load_file(PAGE *p, char *filename)
{
FILE *fp = fopen(filename, "r");
int size = count_lines(fp) * 2;
char ch = '\0';
int line;
if(size < PAGE_SIZE)
size = PAGE_SIZE;
init_page(p, filename, size);
if(fp == NULL) // file doesn't exist yet. don't bother reading
{
p->numlines = 1;
return;
}
for(line = 0; line < size && ch != EOF; line++)
{
ch = fgetc(fp);
while(ch != '\n' && ch != EOF)
{
LINE *currline = &(p->text[line]);
if(ch != '\t')
{
add_char(currline, ch);
}
else // tab. add 4 spaces instead
{
int i;
for(i = 0; i < TAB_WIDTH; i++)
{
add_char(currline, ' ');
}
}
ch = fgetc(fp);
}
p->numlines++;
}
fclose(fp);
} // load_file
void save_file(PAGE *p)
{
FILE *fp = fopen(p->filename, "w");
int line, col;
for(line = 0; line < p->numlines; line++)
{
col = 0;
while(p->text[line].line[col] != '\0')
{
fputc(p->text[line].line[col], fp);
col++;
}
fputc('\n', fp);
}
fclose(fp);
p->saved = 1;
} // save_file
int file_exists(char *filename)
{
FILE *fp = fopen(filename, "r");
if(fp != NULL) {
fclose(fp);
return 1;
}
return 0;
}
/* saving and loading */