Saving and backspacing
This commit is contained in:
parent
061ddbc5b5
commit
e14432eae4
126
kilo.c
126
kilo.c
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -19,7 +20,8 @@
|
|||||||
/*** defines ***/
|
/*** defines ***/
|
||||||
|
|
||||||
#define KILO_VERSION "0.0.1"
|
#define KILO_VERSION "0.0.1"
|
||||||
#define KILO_TAB_STOP 8
|
#define KILO_TAB_STOP 4
|
||||||
|
#define KILO_QUIT_TIMES 3
|
||||||
|
|
||||||
#define CTRL_KEY(k) ((k) & 0x1f)
|
#define CTRL_KEY(k) ((k) & 0x1f)
|
||||||
|
|
||||||
@ -54,6 +56,7 @@ struct editorConfig {
|
|||||||
int screencols;
|
int screencols;
|
||||||
int numrows;
|
int numrows;
|
||||||
erow *row;
|
erow *row;
|
||||||
|
int dirty;
|
||||||
char *filename;
|
char *filename;
|
||||||
char statusmsg[80];
|
char statusmsg[80];
|
||||||
time_t statusmsg_time;
|
time_t statusmsg_time;
|
||||||
@ -62,6 +65,10 @@ struct editorConfig {
|
|||||||
|
|
||||||
struct editorConfig E;
|
struct editorConfig E;
|
||||||
|
|
||||||
|
/*** prototypes ***/
|
||||||
|
|
||||||
|
void editorSetStatusMessage(const char *fmt, ...);
|
||||||
|
|
||||||
/*** terminal ***/
|
/*** terminal ***/
|
||||||
|
|
||||||
void die(const char *s)
|
void die(const char *s)
|
||||||
@ -311,6 +318,7 @@ void editorAppendRow(char *s, size_t len)
|
|||||||
editorUpdateRow(&E.row[at]);
|
editorUpdateRow(&E.row[at]);
|
||||||
|
|
||||||
E.numrows++;
|
E.numrows++;
|
||||||
|
E.dirty++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void editorRowInsertChar(erow *row, int at, int c)
|
void editorRowInsertChar(erow *row, int at, int c)
|
||||||
@ -325,6 +333,20 @@ void editorRowInsertChar(erow *row, int at, int c)
|
|||||||
row->size++;
|
row->size++;
|
||||||
row->chars[at] = c;
|
row->chars[at] = c;
|
||||||
editorUpdateRow(row);
|
editorUpdateRow(row);
|
||||||
|
E.dirty++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void editorRowDelChar(erow *row, int at)
|
||||||
|
{
|
||||||
|
if (at < 0 || at >= row->size)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(&row->chars[at], &row->chars[at + 1], row->size - at);
|
||||||
|
row->size--;
|
||||||
|
editorUpdateRow(row);
|
||||||
|
E.dirty++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** editor operations ***/
|
/*** editor operations ***/
|
||||||
@ -339,7 +361,46 @@ void editorInsertChar(int c)
|
|||||||
E.cx++;
|
E.cx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void editorDelChar()
|
||||||
|
{
|
||||||
|
if (E.cy == E.numrows)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
erow *row = &E.row[E.cy];
|
||||||
|
if (E.cx > 0)
|
||||||
|
{
|
||||||
|
editorRowDelChar(row, E.cx - 1);
|
||||||
|
E.cx--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*** file i/o ***/
|
/*** file i/o ***/
|
||||||
|
|
||||||
|
char *editorRowsToString(int *buflen)
|
||||||
|
{
|
||||||
|
int totlen = 0;
|
||||||
|
int j;
|
||||||
|
for (j = 0; j < E.numrows; j++)
|
||||||
|
{
|
||||||
|
totlen += E.row[j].size + 1;
|
||||||
|
}
|
||||||
|
*buflen = totlen;
|
||||||
|
|
||||||
|
char *buf = malloc(totlen);
|
||||||
|
char *p = buf;
|
||||||
|
for (j = 0; j < E.numrows; j++)
|
||||||
|
{
|
||||||
|
memcpy(p, E.row[j].chars, E.row[j].size);
|
||||||
|
p += E.row[j].size;
|
||||||
|
*p = '\n';
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
void editorOpen(char *filename)
|
void editorOpen(char *filename)
|
||||||
{
|
{
|
||||||
free(E.filename);
|
free(E.filename);
|
||||||
@ -367,6 +428,37 @@ void editorOpen(char *filename)
|
|||||||
|
|
||||||
free(line);
|
free(line);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
E.dirty = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void editorSave()
|
||||||
|
{
|
||||||
|
if (E.filename == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len;
|
||||||
|
char *buf = editorRowsToString(&len);
|
||||||
|
|
||||||
|
int fd = open(E.filename, O_RDWR | O_CREAT, 0644);
|
||||||
|
if (fd != -1)
|
||||||
|
{
|
||||||
|
if (ftruncate(fd, len) != -1)
|
||||||
|
{
|
||||||
|
if (write(fd, buf, len) == len)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
free(buf);
|
||||||
|
E.dirty = 0;
|
||||||
|
editorSetStatusMessage("%d bytes written to disk", len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** append buffer ***/
|
/*** append buffer ***/
|
||||||
@ -491,8 +583,9 @@ void editorDrawStatusBar(struct abuf *ab)
|
|||||||
{
|
{
|
||||||
abAppend(ab, "\x1b[7m", 4);
|
abAppend(ab, "\x1b[7m", 4);
|
||||||
char status[80], rstatus[80];
|
char status[80], rstatus[80];
|
||||||
int len = snprintf(status, sizeof(status), "%.20s - %d lines",
|
int len = snprintf(status, sizeof(status), "%.20s - %d lines %s",
|
||||||
E.filename ? E.filename : "[No Name]", E.numrows);
|
E.filename ? E.filename : "[No Name]", E.numrows,
|
||||||
|
E.dirty ? "(modified)" : "");
|
||||||
int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d",
|
int rlen = snprintf(rstatus, sizeof(rstatus), "%d/%d",
|
||||||
E.cy + 1, E.numrows);
|
E.cy + 1, E.numrows);
|
||||||
|
|
||||||
@ -626,6 +719,8 @@ void editorMoveCursor(int key)
|
|||||||
|
|
||||||
void editorProcessKeypress()
|
void editorProcessKeypress()
|
||||||
{
|
{
|
||||||
|
static int quit_times = KILO_QUIT_TIMES;
|
||||||
|
|
||||||
int c = editorReadKey();
|
int c = editorReadKey();
|
||||||
|
|
||||||
switch (c)
|
switch (c)
|
||||||
@ -635,11 +730,22 @@ void editorProcessKeypress()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CTRL_KEY('q'):
|
case CTRL_KEY('q'):
|
||||||
|
if (E.dirty && quit_times > 0)
|
||||||
|
{
|
||||||
|
editorSetStatusMessage("WARNING!!! File has unsaved changes ."
|
||||||
|
"Press Ctrl-Q %d more time(s) to quit.", quit_times);
|
||||||
|
quit_times--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
write(STDOUT_FILENO, "\x1b[2J", 4);
|
write(STDOUT_FILENO, "\x1b[2J", 4);
|
||||||
write(STDOUT_FILENO, "\x1b[H", 3);
|
write(STDOUT_FILENO, "\x1b[H", 3);
|
||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CTRL_KEY('s'):
|
||||||
|
editorSave();
|
||||||
|
break;
|
||||||
|
|
||||||
case HOME_KEY:
|
case HOME_KEY:
|
||||||
E.cx = 0;
|
E.cx = 0;
|
||||||
break;
|
break;
|
||||||
@ -654,11 +760,16 @@ void editorProcessKeypress()
|
|||||||
case BACKSPACE:
|
case BACKSPACE:
|
||||||
case CTRL_KEY('h'):
|
case CTRL_KEY('h'):
|
||||||
case DEL_KEY:
|
case DEL_KEY:
|
||||||
/* TODO */
|
if (c == DEL_KEY)
|
||||||
|
{
|
||||||
|
editorMoveCursor(ARROW_RIGHT);
|
||||||
|
}
|
||||||
|
editorDelChar();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PAGE_UP:
|
case PAGE_UP:
|
||||||
case PAGE_DOWN: {
|
case PAGE_DOWN:
|
||||||
|
{
|
||||||
if (c == PAGE_UP)
|
if (c == PAGE_UP)
|
||||||
{
|
{
|
||||||
E.cy = E.rowoff;
|
E.cy = E.rowoff;
|
||||||
@ -695,6 +806,8 @@ void editorProcessKeypress()
|
|||||||
editorInsertChar(c);
|
editorInsertChar(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quit_times = KILO_QUIT_TIMES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** init ***/
|
/*** init ***/
|
||||||
@ -708,6 +821,7 @@ void initEditor()
|
|||||||
E.coloff = 0;
|
E.coloff = 0;
|
||||||
E.numrows = 0;
|
E.numrows = 0;
|
||||||
E.row = NULL;
|
E.row = NULL;
|
||||||
|
E.dirty = 0;
|
||||||
E.filename = NULL;
|
E.filename = NULL;
|
||||||
E.statusmsg[0] = '\0';
|
E.statusmsg[0] = '\0';
|
||||||
E.statusmsg_time = 0;
|
E.statusmsg_time = 0;
|
||||||
@ -729,7 +843,7 @@ int main(int argc, char *argv[])
|
|||||||
editorOpen(argv[1]);
|
editorOpen(argv[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
editorSetStatusMessage("HELP: Ctrl-Q = quit");
|
editorSetStatusMessage("HELP: Ctrl-S = save | Ctrl-Q = quit");
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user