diff --git a/Makefile b/Makefile index 80f3963..727f1ed 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,34 @@ -BINARY := csedit +BINARY := hermes PREFIX := /usr/local EXEC_PREFIX := ${PREFIX} BINDIR := ${PREFIX}/bin MANDIR := ${PREFIX}/man MAN1DIR := ${MANDIR}/man1 -csedit: csedit.c config.h - $(CC) csedit.c -o csedit -Wall -Wextra -pedantic -std=c99 +csedit: hermes.c config.h + $(CC) hermes.c -o hermes -Wall -Wextra -pedantic -std=c99 .PHONY: install install: install-bin install-man .PHONY: install-bin -install-bin: csedit +install-bin: hermes install -d ${BINDIR} install -m 0755 ./${BINARY} ${BINDIR} .PHONY: install-man -install-man: - @echo "Coming soon..." - +install-man: hermes.1 + gzip -k ./hermes.1 + install -d ${BINDIR} + install -m 0644 ${MAN1DIR} .PHONY: clean clean: rm -f ./${BINARY} + rm -f ./hermes.1.gz + +.PHONY: uninstall +uninstall: clean + rm -f ${MAN1DIR}/hermes.1.gz + rm -f ${BINDIR}/${BINARY} + diff --git a/hermes b/hermes new file mode 100755 index 0000000..c5ffdc5 Binary files /dev/null and b/hermes differ diff --git a/hermes.1 b/hermes.1 new file mode 100644 index 0000000..cef2e3e --- /dev/null +++ b/hermes.1 @@ -0,0 +1,123 @@ +.TH "hermes" 1 "01 JAN 2020" "" "General Operation Manual" +.SH NAME +\fBhermes\fP +.SH SYNOPSIS +.nf +.fam C +\fBhermes\fP [\fBfilepath\fP] +.fam T +.fi +.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 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. +.TP +.B +a +Go from command mode to input mode after the current character. +.TP +.B + +Save as. Like save, but will query for a new filename. +.TP +.B +b +Move to the beginning of the previous word. +.TP +.B +d +Delete. Used as a leader key that is followed by another command (ex. dw to delete until the next word). When used twice in a row, deletes the current line. +.TP +.B + or +Move down one visual page worth of rows. +.TP +.B +e +Move cursor to the end of the current word, or the next word if cursor is currently on a whitespace character. +.TP +.B + +If there is a numerical value in the command buffer then pressing enter will move the cursor to the row represented by that value (ex. 15 would move the cursor to row 15). +.TP +.B + +Go from input mode to command mode. +.TP +.B +g +Move cursor to the top left of the document. +.TP +.B +G +Move cursor to the bottom right of the document. +.TP +.B +h or left arrow +Move one character to the left. +.TP +.B +i +Enter input mode. While in input mode all keys are taken literally and entered into the document. Ctrl key commands still work as normal. Press escape to go back to command mode. +.TP +.B +j or +Move cursor one row down. +.TP +.B +k or< up arrow> +Move cursor one row up. +.TP +.B +l or +Move cursor one character to the right. +.TP +.B +o +Add a row below the current row and enter input mode with the cursor on the new row. +.TP +.B +O +Add a row above the current row and enter input mode with the cursor on the new row. +.TP +.B + +Quit \fBhermes\fP. +.TP +.B + +Save the current document. Will query for filename if there is no current filename. +.TP +.B + or +Move up one visual page worth of rows. +.TP +.B +w +Move cursor to the beginning of the next word. +.TP +.B +x +Delete the character at the current cursor location. +.TP +.B +$ or end +Move cursor toathe end of the current row. +.TP +.B +^ or home +Move cusror to the beginning of the current row. +.SH BUGS +There are very likely bugs. +.SH LINKS +\fBhermes\fP maintains a presence in the following locations: +.TP +.B +Source Code Repository +https://tildegit.org/sloum/hermes +.TP +.B +Gopher Homepage +gopher://colorfield.space/1/hermes/ +.SH AUTHORS +\fBhermes\fP is based on \fBkilo\fP by Salvatore Sanfilippo (aka antirez) and acquired via a code walkthrough by Pailey Quilts. The bits not by either of those authors are by sloum. diff --git a/csedit.c b/hermes.c similarity index 95% rename from csedit.c rename to hermes.c index 39197bc..a49ced4 100644 --- a/csedit.c +++ b/hermes.c @@ -22,7 +22,7 @@ // // definitions // ----------- -#define CSEDIT_VERSION "0.0.1" +#define HERMES_VERSION "0.5" #define CTRL_KEY(k) ((k) & 0x1f) #define HL_HIGHLIGHT_NUMBERS (1<<0) #define HL_HIGHLIGHT_STRINGS (1<<1) @@ -725,7 +725,7 @@ void editorDrawRows(struct abuf *ab) { if (filerow >= E.numRows) { if (E.numRows == 0 && y == E.screenRows / 3) { char welcome[80]; - int welcomelen = snprintf(welcome, sizeof(welcome), "[ cs edit ] - version %s", CSEDIT_VERSION); + int welcomelen = snprintf(welcome, sizeof(welcome), "[ hermes ] - version %s", HERMES_VERSION); if (welcomelen > E.screenCols) welcomelen = E.screenCols; int padding = (E.screenCols - welcomelen) / 2; if (padding) { @@ -921,6 +921,18 @@ void editorEndOfWord() { int y = E.cy; erow *row = (y >= E.numRows) ? NULL : &E.row[y]; + while (x + 1 >= row->size) { + if (y + 1 < E.numRows) { + x = 0; + y++; + row = &E.row[y]; + } + } + + if (row->chars[x + 1] == ' ' || row->chars[x + 1] == '\t') { + x++; + } + while (1) { if (row->chars[x] != ' ' && row->chars[x] != '\t' && (x + 1 >= row->size || (row->chars[x + 1] == ' ' || row->chars[x + 1] == '\t'))) { E.cx = x; @@ -1063,6 +1075,7 @@ void editorCommandKp(int c) { static int deleting = 0; static int counter = 1; static int place = 1; + static int counting = 0; switch (c) { case 'j': case 'k': @@ -1075,6 +1088,7 @@ void editorCommandKp(int c) { break; case 'g': E.cy = 0; + E.cx = 0; break; case 'G': if (E.numRows > E.screenRows) { @@ -1083,6 +1097,20 @@ void editorCommandKp(int c) { } else { E.cy = E.numRows - 1; } + E.cx = E.row[E.cy].size - 1; + if (E.cx < 0) E.cx = 0; + break; + case '\r': + if (counting) { + counter--; + if (counter > E.numRows - 1) { + E.cy = E.numRows - 1; + } else if (counter < 0) { + E.cy = 0; + } else { + E.cy = counter; + } + } break; case 'o': editorCommandKp('$'); @@ -1103,7 +1131,6 @@ void editorCommandKp(int c) { E.mode = CommandMode; editorDeleteChar(); if (E.cx == E.row[E.cy].size) editorMoveCursor(ARROW_LEFT); - counter--; } break; @@ -1145,30 +1172,32 @@ void editorCommandKp(int c) { break; case 'w': while (counter > 0) { - counter--; if (deleting) { - int orig = E.cx; + int start_x = E.cx; + int start_y = E.cy; editorNextWord(); - int diff = E.cx - orig; - if (diff < 0) { - editorPrevWord(); - editorEndOfWord(); - editorMoveCursor(ARROW_RIGHT); - diff = E.cx - orig; - } - while (diff > 0) { + while (E.cy != start_y || E.cx != start_x) { editorDeleteChar(); - diff--; } } else { editorNextWord(); } + counter--; } break; case 'b': while (counter > 0) { if (deleting) { - // TODO + int start_x = E.cx; + int start_y = E.cy; + editorPrevWord(); + int end_x = E.cx; + int end_y = E.cy; + E.cx = start_x; + E.cy = start_y; + while (E.cy != end_y || E.cx != end_x) { + editorDeleteChar(); + } } else { editorPrevWord(); } @@ -1178,7 +1207,17 @@ void editorCommandKp(int c) { case 'e': while (counter > 0) { if (deleting) { - // TODO + int start_x = E.cx; + int start_y = E.cy; + editorEndOfWord(); + while (E.cy != start_y || E.cx != start_x) { + editorDeleteChar(); + } + E.mode = InputMode; + editorMoveCursor(ARROW_RIGHT); + E.mode = CommandMode; + editorDeleteChar(); + if (E.cx == E.row[E.cy].size) editorMoveCursor(ARROW_LEFT); } else { editorEndOfWord(); } @@ -1195,17 +1234,6 @@ void editorCommandKp(int c) { } break; case '0': - if (counter == 1) { - if (deleting) { - while (E.cx > 0) { - editorDeleteChar(); - } - } else { - E.cx = 0; - } - break; - } - /* fall through */ case '1': case '2': case '3': @@ -1218,14 +1246,20 @@ void editorCommandKp(int c) { { if (counter <= 1 && place == 1) counter--; int num = c - 48; - counter += num * place; + if (counting && num == 0) { + counter *= place; + } else { + counter += num * place; + } place *= 10; + counting++; } return; } deleting = 0; place = 1; counter = 1; + counting = 0; } void editorProcessKeypress() {