Got most of a paste buffer working
This commit is contained in:
parent
8ad3f71a1c
commit
3915c8ab68
|
@ -0,0 +1,27 @@
|
|||
This software (c) 2020, Brian Evans <sloum at colorfield dot space>
|
||||
based on/extending "kilo" by Salvatore Sanfilippo:
|
||||
|
||||
Copyright (c) 2016, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
6
hermes.1
6
hermes.1
|
@ -10,7 +10,7 @@
|
|||
.SH DESCRIPTION
|
||||
\fBhermes\fP is a minimalist modal text editor with support for some vi-like key commands. \fBhermes\fP supports basic syntax highlighting and filetype detection.
|
||||
.SH USAGE
|
||||
Most of the key bindings that follow are only available in command mode (the exceptions being any Ctrl based key combinations, the arrow keys, home,a nd end). In addition to the listed keys, while in command mode you may enter numbers that will modify the following action keys in some way. For example 10w would move the cursor forward 10 words. 10<enter> would move the cursor to the 10th row of the file. The d key is also special, as it does not do anything on its own, but modifies a key that follows it. For example 10dw would delete the next ten words.
|
||||
Most of the key bindings that follow are only available in command mode (the exceptions being any Ctrl based key combinations, the arrow keys, home, and end). In addition to the listed keys, while in command mode you may enter numbers that will modify the following action keys in some way. For example 10w would move the cursor forward 10 words. 10<enter> would move the cursor to the 10th row of the file. The d key is also special, as it modifies a key that follows it. For example 10dw would delete the next ten words.
|
||||
.TP
|
||||
.B
|
||||
a
|
||||
|
@ -46,11 +46,11 @@ Go from input mode to command mode.
|
|||
.TP
|
||||
.B
|
||||
g
|
||||
Move cursor to the top left of the document.
|
||||
Move cursor to the beginning of the document.
|
||||
.TP
|
||||
.B
|
||||
G
|
||||
Move cursor to the bottom right of the document.
|
||||
Move cursor to the end of the document.
|
||||
.TP
|
||||
.B
|
||||
h or left arrow
|
||||
|
|
203
hermes.c
203
hermes.c
|
@ -24,8 +24,6 @@
|
|||
// -----------
|
||||
#define HERMES_VERSION "0.5"
|
||||
#define CTRL_KEY(k) ((k) & 0x1f)
|
||||
#define HL_HIGHLIGHT_NUMBERS (1<<0)
|
||||
#define HL_HIGHLIGHT_STRINGS (1<<1)
|
||||
|
||||
//
|
||||
// definitions for config file
|
||||
|
@ -56,10 +54,13 @@ enum editorKey {
|
|||
END_KEY
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// data
|
||||
// ----
|
||||
|
||||
#include "syntaxhl.h"
|
||||
|
||||
typedef struct erow {
|
||||
int idx;
|
||||
int size;
|
||||
|
@ -79,7 +80,9 @@ struct editorConfig {
|
|||
int screenCols;
|
||||
int numRows;
|
||||
int unsaved;
|
||||
int pastelen;
|
||||
erow *row;
|
||||
char *paste;
|
||||
char *filename;
|
||||
char statusmsg[80];
|
||||
time_t statusmsg_time;
|
||||
|
@ -87,82 +90,10 @@ struct editorConfig {
|
|||
struct editorSyntax *syntax;
|
||||
};
|
||||
|
||||
struct editorSyntax {
|
||||
char *filetype;
|
||||
char **filematch;
|
||||
char *singleline_comment_start;
|
||||
char *multiline_comment_start;
|
||||
char *multiline_comment_end;
|
||||
char **keywords;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct editorConfig E;
|
||||
|
||||
|
||||
//
|
||||
// filetypes
|
||||
// ---------
|
||||
char *C_HL_extensions[] = {".c", ".h", ".cpp", NULL};
|
||||
char *C_HL_keywords[] = {
|
||||
"switch", "if", "while", "for", "break", "return", "else", "continue",
|
||||
"struct|", "union", "typedef", "static", "enum|", "class", "case|",
|
||||
"int|", "long|", "double|", "float|", "char|", "unsigned|", "signed|",
|
||||
"void|", "NULL", NULL
|
||||
};
|
||||
|
||||
char *PY_HL_extensions[] = {".py", ".pyc", NULL};
|
||||
char *PY_HL_keywords[] = {
|
||||
"if", "elif", "for", "break", "return", "else",
|
||||
"def", "", "static", "enum", "class", "with", "assert",
|
||||
"except", "continue", "while", "finally", "try", "global",
|
||||
"False|", "True|", "None|", "not|", "and|", "as|", "yield|",
|
||||
"void|", "or|", "import|", "is|", "in|", "lambda|", "pass|",
|
||||
"raise|", "del|", NULL
|
||||
};
|
||||
|
||||
char *GO_HL_extensions[] = {".go", NULL};
|
||||
char *GO_HL_keywords[] = {
|
||||
"break", "switch", "continue", "func", "interface", "select",
|
||||
"case", "defer", "go", "map", "struct", "chan", "else", "goto",
|
||||
"package", "const", "fallthrough|", "if", "range|", "type",
|
||||
"for", "import", "return", "var", "uint8|", "uint16|", "uint32|",
|
||||
"uint64", "int|", "uint|", "int8|", "int16|", "int32|", "int64|",
|
||||
"float32|", "float", "float64|", "complex64|", "complex128|",
|
||||
"byte|", "rune|", "uintptr|", "string|", "bool|", NULL
|
||||
};
|
||||
|
||||
struct editorSyntax HLDB[] = {
|
||||
{
|
||||
"c",
|
||||
C_HL_extensions,
|
||||
"//",
|
||||
"/*",
|
||||
"*/",
|
||||
C_HL_keywords,
|
||||
HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
|
||||
},
|
||||
{
|
||||
"python",
|
||||
PY_HL_extensions,
|
||||
"#",
|
||||
"'''",
|
||||
"'''",
|
||||
PY_HL_keywords,
|
||||
HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
|
||||
},
|
||||
{
|
||||
"go",
|
||||
GO_HL_extensions,
|
||||
"//",
|
||||
"/*",
|
||||
"*/",
|
||||
GO_HL_keywords,
|
||||
HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
|
||||
}
|
||||
};
|
||||
|
||||
#define HLDB_ENTRIES (sizeof(HLDB) / sizeof(HLDB[0]))
|
||||
|
||||
//
|
||||
// prototypes
|
||||
|
@ -594,6 +525,12 @@ void editorInsertNewline() {
|
|||
E.cx = 0;
|
||||
}
|
||||
|
||||
void editorUpdatePaste(char *str, int len) {
|
||||
E.paste = realloc(E.paste, len);
|
||||
memcpy(E.paste, str, len);
|
||||
E.pastelen = len;
|
||||
}
|
||||
|
||||
//
|
||||
// file io
|
||||
// -------
|
||||
|
@ -1053,7 +990,7 @@ void editorInputKp(int c) {
|
|||
switch (c) {
|
||||
case '\033':
|
||||
case CTRL_KEY('l'):
|
||||
if (E.cx == E.row[E.cy].size) editorMoveCursor(ARROW_LEFT);
|
||||
editorMoveCursor(ARROW_LEFT);
|
||||
E.mode = CommandMode;
|
||||
break;
|
||||
case '\r':
|
||||
|
@ -1087,18 +1024,66 @@ void editorCommandKp(int c) {
|
|||
}
|
||||
break;
|
||||
case 'g':
|
||||
E.cy = 0;
|
||||
E.cx = 0;
|
||||
if (deleting) {
|
||||
int totlen = 0;
|
||||
int j;
|
||||
for (j = 0; j <= E.cy; j++)
|
||||
totlen += E.row[j].size + 1;
|
||||
|
||||
char *buf = malloc(totlen);
|
||||
char *p = buf;
|
||||
|
||||
int count = E.cy;
|
||||
E.cy = 0;
|
||||
while (count >= 0) {
|
||||
memcpy(p, E.row[E.cy].chars, E.row[E.cy].size);
|
||||
p += E.row[E.cy].size;
|
||||
*p = '\r';
|
||||
p++;
|
||||
|
||||
deleting = 1;
|
||||
editorCommandKp('d');
|
||||
count--;
|
||||
}
|
||||
editorUpdatePaste(buf, totlen);
|
||||
} else {
|
||||
E.cy = 0;
|
||||
E.cx = 0;
|
||||
}
|
||||
break;
|
||||
case 'G':
|
||||
if (E.numRows > E.screenRows) {
|
||||
E.cy = E.numRows - 1;
|
||||
E.rowoff = E.numRows - E.screenRows - 1;
|
||||
if (deleting) {
|
||||
int totlen = 0;
|
||||
int j;
|
||||
for (j = E.cy; j <= E.numRows; j++)
|
||||
totlen += E.row[j].size + 1;
|
||||
|
||||
char *buf = malloc(totlen);
|
||||
char *p = buf;
|
||||
|
||||
int count = E.numRows - E.cy - 1;
|
||||
if (count < 0) count = 0;
|
||||
while (count >= 0) {
|
||||
memcpy(p, E.row[E.cy].chars, E.row[E.cy].size);
|
||||
p += E.row[E.cy].size;
|
||||
*p = '\r';
|
||||
p++;
|
||||
|
||||
deleting = 1;
|
||||
editorCommandKp('d');
|
||||
count--;
|
||||
}
|
||||
editorUpdatePaste(buf, totlen);
|
||||
} else {
|
||||
E.cy = E.numRows - 1;
|
||||
if (E.numRows > E.screenRows) {
|
||||
E.cy = E.numRows - 1;
|
||||
E.rowoff = E.numRows - E.screenRows - 1;
|
||||
} else {
|
||||
E.cy = E.numRows - 1;
|
||||
}
|
||||
E.cx = E.row[E.cy].size - 1;
|
||||
if (E.cx < 0) E.cx = 0;
|
||||
}
|
||||
E.cx = E.row[E.cy].size - 1;
|
||||
if (E.cx < 0) E.cx = 0;
|
||||
break;
|
||||
case '\r':
|
||||
if (counting) {
|
||||
|
@ -1113,23 +1098,25 @@ void editorCommandKp(int c) {
|
|||
}
|
||||
break;
|
||||
case 'o':
|
||||
editorCommandKp('$');
|
||||
editorCommandKp('i');
|
||||
deleting = 0;
|
||||
E.cx = E.row[E.cy].size;
|
||||
E.mode = InputMode;
|
||||
editorMoveCursor(ARROW_RIGHT);
|
||||
editorInsertNewline();
|
||||
break;
|
||||
case 'O':
|
||||
editorCommandKp('^');
|
||||
E.cx = 0;
|
||||
editorInsertNewline();
|
||||
editorMoveCursor(ARROW_UP);
|
||||
editorCommandKp('i');
|
||||
E.mode = InputMode;
|
||||
break;
|
||||
case 'x':
|
||||
while (counter > 0) {
|
||||
editorUpdatePaste(&E.row[E.cy].chars[E.cx], 1);
|
||||
E.mode = InputMode;
|
||||
editorMoveCursor(ARROW_RIGHT);
|
||||
E.mode = CommandMode;
|
||||
editorDeleteChar();
|
||||
E.mode = CommandMode;
|
||||
if (E.cx == E.row[E.cy].size) editorMoveCursor(ARROW_LEFT);
|
||||
counter--;
|
||||
}
|
||||
|
@ -1144,6 +1131,12 @@ void editorCommandKp(int c) {
|
|||
deleting++;
|
||||
return;
|
||||
} else {
|
||||
// TODO fix this. There are issues.... :(
|
||||
char *buf = malloc(E.row[E.cy].size + 1);
|
||||
int len = snprintf(buf, E.row[E.cy].size, "%s", E.row[E.cy].chars);
|
||||
buf[len] = '\r';
|
||||
editorUpdatePaste(buf, len);
|
||||
free(buf);
|
||||
while (counter > 0) {
|
||||
editorDelRow(E.cy);
|
||||
if (E.cy == E.numRows) E.cy--;
|
||||
|
@ -1155,13 +1148,14 @@ void editorCommandKp(int c) {
|
|||
case '$':
|
||||
if (deleting) {
|
||||
int diff = E.row[E.cy].size - E.cx;
|
||||
editorUpdatePaste(&E.row[E.cy].chars[E.cx], diff);
|
||||
E.cx = E.row[E.cy].size - 1;
|
||||
if (E.cx < 0) E.cx = 0;
|
||||
while (diff > 0) {
|
||||
E.mode = InputMode;
|
||||
editorMoveCursor(ARROW_RIGHT);
|
||||
E.mode = CommandMode;
|
||||
editorDeleteChar();
|
||||
E.mode = CommandMode;
|
||||
if (E.cx == E.row[E.cy].size) editorMoveCursor(ARROW_LEFT);
|
||||
diff--;
|
||||
}
|
||||
|
@ -1176,6 +1170,7 @@ void editorCommandKp(int c) {
|
|||
int start_x = E.cx;
|
||||
int start_y = E.cy;
|
||||
editorNextWord();
|
||||
editorUpdatePaste(&E.row[E.cy].chars[start_x], E.cx - start_x);
|
||||
while (E.cy != start_y || E.cx != start_x) {
|
||||
editorDeleteChar();
|
||||
}
|
||||
|
@ -1185,6 +1180,30 @@ void editorCommandKp(int c) {
|
|||
counter--;
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
case 'p':
|
||||
{
|
||||
char open = c == 'p' ? 'o' : 'O';
|
||||
int startx = E.cx;
|
||||
int multiline = 0;
|
||||
if (E.paste && E.paste[E.pastelen-1] == '\r') multiline = 1;
|
||||
if (multiline) {
|
||||
editorCommandKp(open);
|
||||
} else {
|
||||
E.mode = InputMode;
|
||||
if (open == 'o') editorMoveCursor(ARROW_RIGHT);
|
||||
}
|
||||
|
||||
for (int i = 0; i < E.pastelen; i++) {
|
||||
editorInputKp(E.paste[i]);
|
||||
}
|
||||
if (multiline) {
|
||||
editorInputKp(DEL_KEY);
|
||||
E.cx = startx <= E.row[E.cy].size ? startx : E.row[E.cy].size;
|
||||
}
|
||||
E.mode = CommandMode;
|
||||
break;
|
||||
}
|
||||
case 'b':
|
||||
while (counter > 0) {
|
||||
if (deleting) {
|
||||
|
@ -1195,6 +1214,7 @@ void editorCommandKp(int c) {
|
|||
int end_y = E.cy;
|
||||
E.cx = start_x;
|
||||
E.cy = start_y;
|
||||
editorUpdatePaste(&E.row[E.cy].chars[end_x], start_x - end_x);
|
||||
while (E.cy != end_y || E.cx != end_x) {
|
||||
editorDeleteChar();
|
||||
}
|
||||
|
@ -1210,13 +1230,14 @@ void editorCommandKp(int c) {
|
|||
int start_x = E.cx;
|
||||
int start_y = E.cy;
|
||||
editorEndOfWord();
|
||||
editorUpdatePaste(&E.row[E.cy].chars[start_x], E.cx - start_x);
|
||||
while (E.cy != start_y || E.cx != start_x) {
|
||||
editorDeleteChar();
|
||||
}
|
||||
E.mode = InputMode;
|
||||
editorMoveCursor(ARROW_RIGHT);
|
||||
E.mode = CommandMode;
|
||||
editorDeleteChar();
|
||||
E.mode = CommandMode;
|
||||
if (E.cx == E.row[E.cy].size) editorMoveCursor(ARROW_LEFT);
|
||||
} else {
|
||||
editorEndOfWord();
|
||||
|
@ -1226,6 +1247,7 @@ void editorCommandKp(int c) {
|
|||
break;
|
||||
case '^':
|
||||
if (deleting) {
|
||||
editorUpdatePaste(&E.row[E.cy].chars[0], E.cx);
|
||||
while (E.cx > 0) {
|
||||
editorDeleteChar();
|
||||
}
|
||||
|
@ -1327,6 +1349,7 @@ void initEditor() {
|
|||
E.cx = 0;
|
||||
E.cy = 0;
|
||||
E.rx = 0;
|
||||
E.paste = NULL;
|
||||
E.row = NULL;
|
||||
E.filename = NULL;
|
||||
E.syntax = NULL;
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#define HL_HIGHLIGHT_NUMBERS (1<<0)
|
||||
#define HL_HIGHLIGHT_STRINGS (1<<1)
|
||||
|
||||
struct editorSyntax {
|
||||
char *filetype;
|
||||
char **filematch;
|
||||
char *singleline_comment_start;
|
||||
char *multiline_comment_start;
|
||||
char *multiline_comment_end;
|
||||
char **keywords;
|
||||
int flags;
|
||||
};
|
||||
|
||||
//
|
||||
// filetypes
|
||||
// ---------
|
||||
char *C_HL_extensions[] = {".c", ".h", ".cpp", NULL};
|
||||
char *C_HL_keywords[] = {
|
||||
"switch", "if", "while", "for", "break", "return", "else", "continue",
|
||||
"struct|", "union", "typedef", "static", "enum|", "class", "case|",
|
||||
"int|", "long|", "double|", "float|", "char|", "unsigned|", "signed|",
|
||||
"void|", "NULL", NULL
|
||||
};
|
||||
|
||||
char *PY_HL_extensions[] = {".py", ".pyc", NULL};
|
||||
char *PY_HL_keywords[] = {
|
||||
"if", "elif", "for", "break", "return", "else",
|
||||
"def", "", "static", "enum", "class", "with", "assert",
|
||||
"except", "continue", "while", "finally", "try", "global",
|
||||
"False|", "True|", "None|", "not|", "and|", "as|", "yield|",
|
||||
"void|", "or|", "import|", "is|", "in|", "lambda|", "pass|",
|
||||
"raise|", "del|", NULL
|
||||
};
|
||||
|
||||
char *GO_HL_extensions[] = {".go", NULL};
|
||||
char *GO_HL_keywords[] = {
|
||||
"break", "switch", "continue", "func", "interface", "select",
|
||||
"case", "defer", "go", "map", "struct", "chan", "else", "goto",
|
||||
"package", "const", "fallthrough|", "if", "range|", "type",
|
||||
"for", "import", "return", "var", "uint8|", "uint16|", "uint32|",
|
||||
"uint64", "int|", "uint|", "int8|", "int16|", "int32|", "int64|",
|
||||
"float32|", "float", "float64|", "complex64|", "complex128|",
|
||||
"byte|", "rune|", "uintptr|", "string|", "bool|", NULL
|
||||
};
|
||||
|
||||
static struct editorSyntax HLDB[] = {
|
||||
{
|
||||
"c",
|
||||
C_HL_extensions,
|
||||
"//",
|
||||
"/*",
|
||||
"*/",
|
||||
C_HL_keywords,
|
||||
HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
|
||||
},
|
||||
{
|
||||
"python",
|
||||
PY_HL_extensions,
|
||||
"#",
|
||||
"'''",
|
||||
"'''",
|
||||
PY_HL_keywords,
|
||||
HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
|
||||
},
|
||||
{
|
||||
"go",
|
||||
GO_HL_extensions,
|
||||
"//",
|
||||
"/*",
|
||||
"*/",
|
||||
GO_HL_keywords,
|
||||
HL_HIGHLIGHT_NUMBERS | HL_HIGHLIGHT_STRINGS
|
||||
}
|
||||
};
|
||||
|
||||
#define HLDB_ENTRIES (sizeof(HLDB) / sizeof(HLDB[0]))
|
Loading…
Reference in New Issue