add support for reloading the current file
This commit is contained in:
5
Makefile
5
Makefile
@@ -26,3 +26,8 @@ clean:
|
|||||||
.PHONY: test.txt
|
.PHONY: test.txt
|
||||||
test.txt:
|
test.txt:
|
||||||
cp test.txt.bak $@
|
cp test.txt.bak $@
|
||||||
|
|
||||||
|
.PHONY: gdb
|
||||||
|
gdb:
|
||||||
|
@test -f $(TARGET).pid || (echo "error: $(TARGET).pid not found" >&2; exit 1)
|
||||||
|
@gdb -p $$(cat $(TARGET).pid | tr -d ' \t\n\r') ./$(TARGET)
|
||||||
|
|||||||
9
ke.1
9
ke.1
@@ -40,12 +40,19 @@ Edit a new file. Also C-k C-e.
|
|||||||
Incremental find.
|
Incremental find.
|
||||||
.It C-k g
|
.It C-k g
|
||||||
Go to a specific line.
|
Go to a specific line.
|
||||||
|
.It C-k j
|
||||||
|
Jump to the mark.
|
||||||
.It C-k l
|
.It C-k l
|
||||||
List the number of lines of code in a saved file.
|
List the number of lines of code in a saved file.
|
||||||
.It C-k m
|
.It C-k m
|
||||||
Run make(1).
|
Run make(1).
|
||||||
.It C-k q
|
.It C-k q
|
||||||
exit the editor. Also C-k C-q.
|
Exit the editor. If the file has unsaved changes,
|
||||||
|
a warning will be printed; a second C-k q will exit.
|
||||||
|
.It C-k C-q
|
||||||
|
Immediately exit the editor.
|
||||||
|
.It C-k C-r
|
||||||
|
Reload the current buffer from disk.
|
||||||
.It C-k s
|
.It C-k s
|
||||||
save the file, prompting for a filename if needed. Also C-k C-s.
|
save the file, prompting for a filename if needed. Also C-k C-s.
|
||||||
.It C-k x
|
.It C-k x
|
||||||
|
|||||||
373
main.c
373
main.c
@@ -1,8 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* kyle's editor
|
* ke - kyle's editor
|
||||||
*
|
*
|
||||||
* first version is a run-through of the kilo editor walkthrough as a
|
* ke started off following along with the kilo walkthrough at
|
||||||
* set of guiderails. I've made a lot of changes.
|
* https://viewsourcecode.org/snaptoken/kilo/
|
||||||
|
*
|
||||||
|
* It is inspired heavily by mg(1) and VDE. This is a single file and
|
||||||
|
* can be built with
|
||||||
|
* $(CC) -D_DEFAULT_SOURCE -D_XOPEN_SOURCE -Wall -Wextra -pedantic \
|
||||||
|
* -Wshadow -Werror -std=c99 -g -o ke main.c
|
||||||
|
*
|
||||||
|
* It builds and runs on Linux and Darwin. I can't confirm BSD compatibility.
|
||||||
|
*
|
||||||
|
* commit 59d3fa1dab68e8683d5f5a9341f5f42ef3308876
|
||||||
|
* Author: Kyle Isom <kyle@imap.cc>
|
||||||
|
* Date: Fri Feb 7 20:46:43 2020 -0800
|
||||||
|
*
|
||||||
|
* Initial import, starting with kyle's editor.
|
||||||
*/
|
*/
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
@@ -10,17 +23,18 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <locale.h>
|
|
||||||
#include <wchar.h>
|
|
||||||
#include <wctype.h>
|
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <wctype.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -57,10 +71,8 @@
|
|||||||
#define KILLRING_FLUSH 4 /* clear the killring */
|
#define KILLRING_FLUSH 4 /* clear the killring */
|
||||||
|
|
||||||
|
|
||||||
|
static FILE* debug_log = NULL;
|
||||||
|
|
||||||
/*
|
|
||||||
* Function and struct declarations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* append buffer */
|
/* append buffer */
|
||||||
struct abuf {
|
struct abuf {
|
||||||
@@ -132,6 +144,7 @@ struct editor_t {
|
|||||||
|
|
||||||
int next_power_of_2(int n);
|
int next_power_of_2(int n);
|
||||||
int cap_growth(int cap, int sz);
|
int cap_growth(int cap, int sz);
|
||||||
|
size_t kstrnlen(const char *buf, const size_t max);
|
||||||
void init_editor(void);
|
void init_editor(void);
|
||||||
void reset_editor(void);
|
void reset_editor(void);
|
||||||
void ab_append(struct abuf* buf, const char* s, int len);
|
void ab_append(struct abuf* buf, const char* s, int len);
|
||||||
@@ -198,7 +211,38 @@ void scroll(void);
|
|||||||
void display_refresh(void);
|
void display_refresh(void);
|
||||||
void editor_set_status(const char* fmt, ...);
|
void editor_set_status(const char* fmt, ...);
|
||||||
void loop(void);
|
void loop(void);
|
||||||
void process_normal(int16_t c);
|
void enable_debugging(const char* logfile);
|
||||||
|
void deathknell(void);
|
||||||
|
static void signal_handler(int sig);
|
||||||
|
static void install_signal_handlers(void);
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef strnstr
|
||||||
|
/*
|
||||||
|
* Find the first occurrence of find in s, where the search is limited to the
|
||||||
|
* first slen characters of s.
|
||||||
|
*/
|
||||||
|
char*
|
||||||
|
strnstr(const char* s, const char* find, size_t slen)
|
||||||
|
{
|
||||||
|
char c, sc;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if ((c = *find++) != '\0') {
|
||||||
|
len = strlen(find);
|
||||||
|
do {
|
||||||
|
do {
|
||||||
|
if (slen-- < 1 || (sc = *s++) == '\0')
|
||||||
|
return (NULL);
|
||||||
|
} while (sc != c);
|
||||||
|
if (len > slen)
|
||||||
|
return (NULL);
|
||||||
|
} while (strncmp(s, find, len) != 0);
|
||||||
|
s--;
|
||||||
|
}
|
||||||
|
return ((char*)s);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -250,6 +294,17 @@ enum KeyPress {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
kstrnlen(const char *buf, const size_t max)
|
||||||
|
{
|
||||||
|
if (buf == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strnlen(buf, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* init_editor should set up the global editor struct.
|
* init_editor should set up the global editor struct.
|
||||||
*/
|
*/
|
||||||
@@ -271,7 +326,12 @@ init_editor(void)
|
|||||||
editor.nrows = 0;
|
editor.nrows = 0;
|
||||||
editor.rowoffs = editor.coloffs = 0;
|
editor.rowoffs = editor.coloffs = 0;
|
||||||
editor.row = NULL;
|
editor.row = NULL;
|
||||||
editor.killring = NULL;
|
|
||||||
|
/* don't clear out the kill ring:
|
||||||
|
* killing / yanking across files is helpful, and killring
|
||||||
|
* is initialized to NULL at program start.
|
||||||
|
*/
|
||||||
|
/* editor.killring = NULL; */
|
||||||
editor.kill = 0;
|
editor.kill = 0;
|
||||||
editor.no_kill = 0;
|
editor.no_kill = 0;
|
||||||
|
|
||||||
@@ -300,11 +360,15 @@ reset_editor(void)
|
|||||||
editor.filename = NULL;
|
editor.filename = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* commenting this out, it's useful to be able
|
||||||
|
* yank across files. */
|
||||||
|
/*
|
||||||
if (editor.killring != NULL) {
|
if (editor.killring != NULL) {
|
||||||
erow_free(editor.killring);
|
erow_free(editor.killring);
|
||||||
free(editor.killring);
|
free(editor.killring);
|
||||||
editor.killring = NULL;
|
editor.killring = NULL;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
init_editor();
|
init_editor();
|
||||||
}
|
}
|
||||||
@@ -861,7 +925,7 @@ delete_region(void)
|
|||||||
jump_to_position(markx, marky);
|
jump_to_position(markx, marky);
|
||||||
|
|
||||||
while (killed < count) {
|
while (killed < count) {
|
||||||
move_cursor(ARROW_RIGHT);
|
// move_cursor(ARROW_RIGHT);
|
||||||
deletech(KILLRING_NO_OP);
|
deletech(KILLRING_NO_OP);
|
||||||
killed++;
|
killed++;
|
||||||
}
|
}
|
||||||
@@ -925,14 +989,29 @@ get_winsz(int *rows, int *cols)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
jump_to_position(const int x, const int y)
|
jump_to_position(int col, int row)
|
||||||
{
|
{
|
||||||
editor.curx = x;
|
/* clamp position */
|
||||||
editor.cury = y;
|
if (row < 0) {
|
||||||
|
row = 0;
|
||||||
editor.rowoffs = editor.cury - (editor.rows / 2);
|
} else if (row > editor.nrows) {
|
||||||
|
row = editor.nrows - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (col < 0) {
|
||||||
|
col = 0;
|
||||||
|
} else if (col > editor.row[row].size) {
|
||||||
|
col = editor.row[row].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.curx = col;
|
||||||
|
editor.cury = row;
|
||||||
|
|
||||||
|
scroll();
|
||||||
|
display_refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
goto_line(void)
|
goto_line(void)
|
||||||
{
|
{
|
||||||
@@ -1047,6 +1126,7 @@ find_prev_word(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
delete_prev_word(void)
|
delete_prev_word(void)
|
||||||
{
|
{
|
||||||
@@ -1077,6 +1157,7 @@ delete_prev_word(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
delete_row(int at)
|
delete_row(int at)
|
||||||
{
|
{
|
||||||
@@ -1216,6 +1297,12 @@ deletech(uint8_t op)
|
|||||||
|
|
||||||
row = &editor.row[editor.cury];
|
row = &editor.row[editor.cury];
|
||||||
|
|
||||||
|
if (cursor_at_eol()) {
|
||||||
|
if (editor.cury >= editor.nrows - 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* determine which character is being deleted for killring purposes */
|
/* determine which character is being deleted for killring purposes */
|
||||||
if (editor.curx > 0) {
|
if (editor.curx > 0) {
|
||||||
dch = (unsigned char)row->line[editor.curx - 1];
|
dch = (unsigned char)row->line[editor.curx - 1];
|
||||||
@@ -1279,6 +1366,10 @@ open_file(const char *filename)
|
|||||||
|
|
||||||
reset_editor();
|
reset_editor();
|
||||||
|
|
||||||
|
if (filename == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
editor.filename = strdup(filename);
|
editor.filename = strdup(filename);
|
||||||
assert(editor.filename != NULL);
|
assert(editor.filename != NULL);
|
||||||
|
|
||||||
@@ -1560,6 +1651,7 @@ editor_prompt(char *prompt, void (*cb)(char *, int16_t))
|
|||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1569,7 +1661,7 @@ editor_find_callback(char *query, int16_t c)
|
|||||||
static int lmatch = -1;
|
static int lmatch = -1;
|
||||||
static int dir = -1;
|
static int dir = -1;
|
||||||
int i, current, traversed = 0;
|
int i, current, traversed = 0;
|
||||||
int qlen = strnlen(query, 128);
|
int qlen = kstrnlen(query, 128);
|
||||||
char* match;
|
char* match;
|
||||||
struct erow* row;
|
struct erow* row;
|
||||||
|
|
||||||
@@ -1589,6 +1681,7 @@ editor_find_callback(char *query, int16_t c)
|
|||||||
|
|
||||||
if (lmatch == -1) {
|
if (lmatch == -1) {
|
||||||
dir = 1;
|
dir = 1;
|
||||||
|
current = editor.cury;
|
||||||
}
|
}
|
||||||
current = lmatch;
|
current = lmatch;
|
||||||
|
|
||||||
@@ -1599,9 +1692,9 @@ editor_find_callback(char *query, int16_t c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
current += dir;
|
current += dir;
|
||||||
if (current == -1) {
|
if (current < 0) {
|
||||||
current = editor.nrows - 1;
|
current = editor.nrows - 1;
|
||||||
} else if (current == editor.nrows) {
|
} else if (current >= editor.nrows) {
|
||||||
current = 0;
|
current = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1635,6 +1728,7 @@ editor_find_callback(char *query, int16_t c)
|
|||||||
void
|
void
|
||||||
editor_find(void)
|
editor_find(void)
|
||||||
{
|
{
|
||||||
|
/* TODO(kyle): consider making this an abuf */
|
||||||
char* query;
|
char* query;
|
||||||
int scx = editor.curx;
|
int scx = editor.curx;
|
||||||
int scy = editor.cury;
|
int scy = editor.cury;
|
||||||
@@ -1645,6 +1739,7 @@ editor_find(void)
|
|||||||
editor_find_callback);
|
editor_find_callback);
|
||||||
if (query) {
|
if (query) {
|
||||||
free(query);
|
free(query);
|
||||||
|
query = NULL;
|
||||||
} else {
|
} else {
|
||||||
editor.curx = scx;
|
editor.curx = scx;
|
||||||
editor.cury = scy;
|
editor.cury = scy;
|
||||||
@@ -1727,7 +1822,7 @@ move_cursor(int16_t c)
|
|||||||
break;
|
break;
|
||||||
case ARROW_DOWN:
|
case ARROW_DOWN:
|
||||||
case CTRL_KEY('n'):
|
case CTRL_KEY('n'):
|
||||||
if (editor.cury < editor.nrows) {
|
if (editor.cury < editor.nrows - 1) {
|
||||||
editor.cury++;
|
editor.cury++;
|
||||||
row = (editor.cury >= editor.nrows)
|
row = (editor.cury >= editor.nrows)
|
||||||
? NULL
|
? NULL
|
||||||
@@ -1740,12 +1835,12 @@ move_cursor(int16_t c)
|
|||||||
if (row && editor.curx < row->size) {
|
if (row && editor.curx < row->size) {
|
||||||
editor.curx++;
|
editor.curx++;
|
||||||
/* skip over UTF-8 continuation bytes */
|
/* skip over UTF-8 continuation bytes */
|
||||||
while (row && editor.curx < row->size &&
|
while (editor.curx < row->size &&
|
||||||
((unsigned char)row->line[editor.curx] &
|
((unsigned char)row->line[editor.curx] &
|
||||||
0xC0) == 0x80) {
|
0xC0) == 0x80) {
|
||||||
editor.curx++;
|
editor.curx++;
|
||||||
}
|
}
|
||||||
} else if (row && editor.curx == row->size) {
|
} else if (row && editor.curx == row->size && editor.cury < editor.nrows - 1) {
|
||||||
editor.cury++;
|
editor.cury++;
|
||||||
row = (editor.cury >= editor.nrows)
|
row = (editor.cury >= editor.nrows)
|
||||||
? NULL
|
? NULL
|
||||||
@@ -1857,7 +1952,7 @@ get_cloc_code_lines(const char* filename)
|
|||||||
if (editor.filename == NULL) {
|
if (editor.filename == NULL) {
|
||||||
snprintf(command, sizeof(command),
|
snprintf(command, sizeof(command),
|
||||||
"buffer has no associated file.");
|
"buffer has no associated file.");
|
||||||
result = malloc((strnlen(command, sizeof(command))) + 1);
|
result = malloc((kstrnlen(command, sizeof(command))) + 1);
|
||||||
assert(result != NULL);
|
assert(result != NULL);
|
||||||
strcpy(result, command);
|
strcpy(result, command);
|
||||||
return result;
|
return result;
|
||||||
@@ -1866,7 +1961,7 @@ get_cloc_code_lines(const char* filename)
|
|||||||
if (editor.dirty) {
|
if (editor.dirty) {
|
||||||
snprintf(command, sizeof(command),
|
snprintf(command, sizeof(command),
|
||||||
"buffer must be saved first.");
|
"buffer must be saved first.");
|
||||||
result = malloc((strnlen(command, sizeof(command))) + 1);
|
result = malloc((kstrnlen(command, sizeof(command))) + 1);
|
||||||
assert(result != NULL);
|
assert(result != NULL);
|
||||||
strcpy(result, command);
|
strcpy(result, command);
|
||||||
return result;
|
return result;
|
||||||
@@ -1909,11 +2004,30 @@ get_cloc_code_lines(const char* filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
dump_pidfile(void)
|
||||||
|
{
|
||||||
|
FILE* pid_file = NULL;
|
||||||
|
|
||||||
|
if ((pid_file = fopen("ke.pid", "w")) == NULL) {
|
||||||
|
editor_set_status("Failed to dump PID file: %s", strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(pid_file, "%ld", (long)getpid());
|
||||||
|
fclose(pid_file);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
process_kcommand(int16_t c)
|
process_kcommand(int16_t c)
|
||||||
{
|
{
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
int jumpx = 0;
|
||||||
|
int jumpy = 0;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case BACKSPACE:
|
case BACKSPACE:
|
||||||
@@ -1921,13 +2035,39 @@ process_kcommand(int16_t c)
|
|||||||
process_normal(BACKSPACE);
|
process_normal(BACKSPACE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TAB_KEY:
|
||||||
|
if (editor.mark_set) {
|
||||||
|
indent_region();
|
||||||
|
} else {
|
||||||
|
editor_set_status("Mark not set.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CTRL_KEY('\\'):
|
case CTRL_KEY('\\'):
|
||||||
/* sometimes it's nice to dump core */
|
/* sometimes it's nice to dump core */
|
||||||
disable_termraw();
|
disable_termraw();
|
||||||
abort();
|
abort();
|
||||||
|
case '@':
|
||||||
|
if (!dump_pidfile()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FALLTHRU */
|
||||||
|
case '!':
|
||||||
|
/* useful for debugging */
|
||||||
|
editor_set_status("PID: %ld", (long)getpid());
|
||||||
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
toggle_markset();
|
toggle_markset();
|
||||||
break;
|
break;
|
||||||
|
case CTRL_KEY(' '):
|
||||||
|
jumpx = editor.mark_curx;
|
||||||
|
jumpy = editor.mark_cury;
|
||||||
|
editor.mark_curx = editor.curx;
|
||||||
|
editor.mark_cury = editor.cury;
|
||||||
|
|
||||||
|
jump_to_position(jumpx, jumpy);
|
||||||
|
editor_set_status("Jumped to mark");
|
||||||
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
len = editor.killring->size;
|
len = editor.killring->size;
|
||||||
killring_flush();
|
killring_flush();
|
||||||
@@ -1965,6 +2105,20 @@ process_kcommand(int16_t c)
|
|||||||
case 'g':
|
case 'g':
|
||||||
goto_line();
|
goto_line();
|
||||||
break;
|
break;
|
||||||
|
case 'j':
|
||||||
|
if (!editor.mark_set) {
|
||||||
|
editor_set_status("Mark not set.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
jumpx = editor.mark_curx;
|
||||||
|
jumpy = editor.mark_cury;
|
||||||
|
editor.mark_curx = editor.curx;
|
||||||
|
editor.mark_cury = editor.cury;
|
||||||
|
|
||||||
|
jump_to_position(jumpx, jumpy);
|
||||||
|
editor_set_status("Jumped to mark; mark is now the previous location.");
|
||||||
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
buf = get_cloc_code_lines(editor.filename);
|
buf = get_cloc_code_lines(editor.filename);
|
||||||
|
|
||||||
@@ -1976,13 +2130,11 @@ process_kcommand(int16_t c)
|
|||||||
editor_set_status(
|
editor_set_status(
|
||||||
"process failed: %s",
|
"process failed: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
editor_set_status("make: ok");
|
editor_set_status("make: ok");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
case CTRL_KEY('q'):
|
|
||||||
if (editor.dirty && editor.dirtyex) {
|
if (editor.dirty && editor.dirtyex) {
|
||||||
editor_set_status(
|
editor_set_status(
|
||||||
"File not saved - C-k q again to quit.");
|
"File not saved - C-k q again to quit.");
|
||||||
@@ -1990,6 +2142,25 @@ process_kcommand(int16_t c)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
|
case CTRL_KEY('q'):
|
||||||
|
exit(0);
|
||||||
|
case CTRL_KEY('r'):
|
||||||
|
if (editor.dirty && editor.dirtyex) {
|
||||||
|
editor_set_status("File not saved - C-k C-r again to reload.");
|
||||||
|
editor.dirtyex = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jumpx = editor.curx;
|
||||||
|
jumpy = editor.cury;
|
||||||
|
buf = strdup(editor.filename);
|
||||||
|
|
||||||
|
reset_editor();
|
||||||
|
open_file(buf);
|
||||||
|
display_refresh();
|
||||||
|
|
||||||
|
jump_to_position(jumpx, jumpy);
|
||||||
|
break;
|
||||||
case CTRL_KEY('s'):
|
case CTRL_KEY('s'):
|
||||||
case 's':
|
case 's':
|
||||||
save_file();
|
save_file();
|
||||||
@@ -2069,11 +2240,7 @@ process_normal(int16_t c)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (c == TAB_KEY) {
|
if (c == TAB_KEY) {
|
||||||
if (editor.mark_set) {
|
|
||||||
indent_region();
|
|
||||||
} else {
|
|
||||||
insertch(c);
|
insertch(c);
|
||||||
}
|
|
||||||
} else if (c >= 0x20 && c != 0x7f) {
|
} else if (c >= 0x20 && c != 0x7f) {
|
||||||
insertch(c);
|
insertch(c);
|
||||||
}
|
}
|
||||||
@@ -2244,19 +2411,20 @@ draw_rows(struct abuf *ab)
|
|||||||
{
|
{
|
||||||
assert(editor.cols >= 0);
|
assert(editor.cols >= 0);
|
||||||
|
|
||||||
|
struct erow *row;
|
||||||
char buf[editor.cols];
|
char buf[editor.cols];
|
||||||
int buflen, filerow, padding;
|
int len, filerow, padding;
|
||||||
int y;
|
int y;
|
||||||
|
|
||||||
for (y = 0; y < editor.rows; y++) {
|
for (y = 0; y < editor.rows; y++) {
|
||||||
filerow = y + editor.rowoffs;
|
filerow = y + editor.rowoffs;
|
||||||
if (filerow >= editor.nrows) {
|
if (filerow >= editor.nrows) {
|
||||||
if ((editor.nrows == 0) && (y == editor.rows / 3)) {
|
if ((editor.nrows == 0) && (y == editor.rows / 3)) {
|
||||||
buflen = snprintf(buf,
|
len = snprintf(buf,
|
||||||
sizeof(buf),
|
sizeof(buf),
|
||||||
"%s",
|
"%s",
|
||||||
KE_VERSION);
|
KE_VERSION);
|
||||||
padding = (editor.rows - buflen) / 2;
|
padding = (editor.rows - len) / 2;
|
||||||
|
|
||||||
if (padding) {
|
if (padding) {
|
||||||
ab_append(ab, "|", 1);
|
ab_append(ab, "|", 1);
|
||||||
@@ -2265,23 +2433,24 @@ draw_rows(struct abuf *ab)
|
|||||||
|
|
||||||
while (padding--)
|
while (padding--)
|
||||||
ab_append(ab, " ", 1);
|
ab_append(ab, " ", 1);
|
||||||
ab_append(ab, buf, buflen);
|
ab_append(ab, buf, len);
|
||||||
} else {
|
} else {
|
||||||
ab_append(ab, "|", 1);
|
ab_append(ab, "|", 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
erow_update(&editor.row[filerow]);
|
row = &editor.row[filerow];
|
||||||
buflen = editor.row[filerow].rsize - editor.coloffs;
|
erow_update(row);
|
||||||
if (buflen < 0) {
|
len = row->rsize - editor.coloffs;
|
||||||
buflen = 0;
|
if (len < 0) {
|
||||||
|
len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buflen > editor.cols) {
|
if (len > editor.cols) {
|
||||||
buflen = editor.cols;
|
len = editor.cols;
|
||||||
}
|
}
|
||||||
ab_append(ab,
|
ab_append(ab,
|
||||||
editor.row[filerow].render + editor.coloffs,
|
editor.row[filerow].render + editor.coloffs,
|
||||||
buflen);
|
len);
|
||||||
}
|
}
|
||||||
ab_append(ab, ESCSEQ "K", 3);
|
ab_append(ab, ESCSEQ "K", 3);
|
||||||
ab_append(ab, "\r\n", 2);
|
ab_append(ab, "\r\n", 2);
|
||||||
@@ -2419,7 +2588,7 @@ display_refresh(void)
|
|||||||
ESCSEQ "%d;%dH",
|
ESCSEQ "%d;%dH",
|
||||||
(editor.cury - editor.rowoffs) + 1,
|
(editor.cury - editor.rowoffs) + 1,
|
||||||
(editor.rx - editor.coloffs) + 1);
|
(editor.rx - editor.coloffs) + 1);
|
||||||
ab_append(&ab, buf, strnlen(buf, 32));
|
ab_append(&ab, buf, kstrnlen(buf, 32));
|
||||||
/* ab_append(&ab, ESCSEQ "1;2H", 7); */
|
/* ab_append(&ab, ESCSEQ "1;2H", 7); */
|
||||||
ab_append(&ab, ESCSEQ "?25h", 6);
|
ab_append(&ab, ESCSEQ "?25h", 6);
|
||||||
|
|
||||||
@@ -2463,16 +2632,128 @@ loop(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
enable_debugging(const char* logfile)
|
||||||
|
{
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
if (debug_log != NULL) {
|
||||||
|
fclose(debug_log);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((debug_log = fopen(logfile, "w")) == NULL) {
|
||||||
|
fprintf(stderr, "Failed to open error log!\n");
|
||||||
|
fprintf(stderr, "\t%s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_pidfile();
|
||||||
|
stderr = debug_log;
|
||||||
|
|
||||||
|
now = time(&now);
|
||||||
|
printf("time: %s\n", ctime(&now));
|
||||||
|
fprintf(stderr, "Debug log started %s\n", ctime(&now));
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
deathknell(void)
|
||||||
|
{
|
||||||
|
if (debug_log != NULL) {
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
fclose(debug_log);
|
||||||
|
debug_log = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editor.killring != NULL) {
|
||||||
|
erow_free(editor.killring);
|
||||||
|
free(editor.killring);
|
||||||
|
editor.killring = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_editor();
|
||||||
|
disable_termraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
signal_handler(int sig)
|
||||||
|
{
|
||||||
|
signal(sig, SIG_DFL);
|
||||||
|
|
||||||
|
fprintf(stderr, "caught signal %d\n", sig);
|
||||||
|
|
||||||
|
deathknell();
|
||||||
|
|
||||||
|
raise(sig);
|
||||||
|
_exit(127 + sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
install_signal_handlers(void)
|
||||||
|
{
|
||||||
|
/* Block all these signals while inside any of them */
|
||||||
|
const int fatal_signals[] = {
|
||||||
|
SIGABRT, SIGFPE, SIGILL, SIGSEGV,
|
||||||
|
#ifdef SIGBUS
|
||||||
|
SIGBUS,
|
||||||
|
#endif
|
||||||
|
#ifdef SIGQUIT
|
||||||
|
SIGQUIT,
|
||||||
|
#endif
|
||||||
|
#ifdef SIGSYS
|
||||||
|
SIGSYS,
|
||||||
|
#endif
|
||||||
|
-1 /* sentinel */
|
||||||
|
};
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; fatal_signals[i] != -1; i++) {
|
||||||
|
signal(fatal_signals[i], signal_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
atexit(deathknell);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char* argv[])
|
main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
|
char* logfile = "debug-ke.log";
|
||||||
|
int opt;
|
||||||
|
int debug = 0;
|
||||||
|
|
||||||
|
install_signal_handlers();
|
||||||
|
|
||||||
|
while ((opt = getopt(argc, argv, "df:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'd':
|
||||||
|
debug = 1;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
logfile = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Usage: ke [-d] [-f logfile] [path]\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
|
if (debug) {
|
||||||
|
enable_debugging(logfile);
|
||||||
|
}
|
||||||
|
|
||||||
setup_terminal();
|
setup_terminal();
|
||||||
init_editor();
|
init_editor();
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 0) {
|
||||||
open_file(argv[1]);
|
open_file(argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
editor_set_status("C-k q to exit / C-k d to dump core");
|
editor_set_status("C-k q to exit / C-k d to dump core");
|
||||||
|
|||||||
Reference in New Issue
Block a user