Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c9977b0fc0 | |||
| dd2c888766 | |||
| 2967998893 | |||
| a400cdf5ad | |||
| c8a43fb328 | |||
| 3ea7c31cba | |||
| 115091e517 | |||
| 1b9b618e3a | |||
| 527759de09 | |||
| 8a724cfc87 | |||
| c03d184a05 |
37
.github/workflows/release.yml
vendored
Normal file
37
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
homebrew:
|
||||||
|
name: Bump Homebrew formula
|
||||||
|
# Skip this job in case of git pushes to prerelease tags
|
||||||
|
if: ${{ github.event_name != 'push' || !contains(github.ref, '-') }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- name: Extract version
|
||||||
|
id: extract-version
|
||||||
|
run: |
|
||||||
|
echo "tag-name=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- uses: mislav/bump-homebrew-formula-action@v3
|
||||||
|
with:
|
||||||
|
formula-name: ke
|
||||||
|
formula-path: Formula/ke.rb
|
||||||
|
homebrew-tap: kisom/homebrew-tap
|
||||||
|
base-branch: master
|
||||||
|
commit-message: |
|
||||||
|
{{formulaName}} {{version}}
|
||||||
|
|
||||||
|
Created by https://github.com/mislav/bump-homebrew-formula-action
|
||||||
|
env:
|
||||||
|
COMMITTER_TOKEN: ${{ secrets.GH_CPAT }}
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.log
|
||||||
|
build
|
||||||
@@ -2,13 +2,18 @@ cmake_minimum_required(VERSION 3.15)
|
|||||||
project(ke C) # Specify C language explicitly
|
project(ke C) # Specify C language explicitly
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(KE_VERSION "1.0.0")
|
set(KE_VERSION "1.0.4")
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS "-Wall -Wextra -pedantic -Wshadow -Werror -std=c99 -g")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DEFAULT_SOURCE -D_XOPEN_SOURCE")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
|
|
||||||
|
|
||||||
# Add executable
|
# Add executable
|
||||||
add_executable(ke main.c)
|
add_executable(ke main.c)
|
||||||
|
|
||||||
# Define KE_VERSION for use in C code (e.g., #define KE_VERSION)
|
# Define KE_VERSION for use in C code (e.g., #define KE_VERSION)
|
||||||
target_compile_definitions(ke PRIVATE KE_VERSION="${KE_VERSION}")
|
target_compile_definitions(ke PRIVATE KE_VERSION="ke version ${KE_VERSION}")
|
||||||
|
|
||||||
# Set output properties
|
# Set output properties
|
||||||
set_target_properties(ke PROPERTIES
|
set_target_properties(ke PROPERTIES
|
||||||
|
|||||||
@@ -6,4 +6,9 @@ used fairly often.
|
|||||||
|
|
||||||
See the man page for more info.
|
See the man page for more info.
|
||||||
|
|
||||||
|
It should be available via homebrew, even:
|
||||||
|
|
||||||
|
brew tap kisom/homebrew-tap
|
||||||
|
brew install ke
|
||||||
|
|
||||||
Released under an ISC license.
|
Released under an ISC license.
|
||||||
2
ke.1
2
ke.1
@@ -24,8 +24,6 @@ saving a file can be done with either C-k s or C-k C-s.
|
|||||||
.Bl -tag -width xxxxxxxxxxxx -offset indent
|
.Bl -tag -width xxxxxxxxxxxx -offset indent
|
||||||
.It C-k BACKSPACE
|
.It C-k BACKSPACE
|
||||||
Delete from the cursor to the beginning of the line.
|
Delete from the cursor to the beginning of the line.
|
||||||
.It C-k C-d
|
|
||||||
Delete the current row.
|
|
||||||
.It C-k d
|
.It C-k d
|
||||||
Delete from the cursor to the end of the line.
|
Delete from the cursor to the end of the line.
|
||||||
.It C-k e
|
.It C-k e
|
||||||
|
|||||||
121
main.c
121
main.c
@@ -30,6 +30,14 @@
|
|||||||
#define TAB_STOP 8
|
#define TAB_STOP 8
|
||||||
#define MSG_TIMEO 3
|
#define MSG_TIMEO 3
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Provide a sensiblerdefault version string if not supplied by the
|
||||||
|
* build system
|
||||||
|
*/
|
||||||
|
#ifndef KE_VERSION
|
||||||
|
#define KE_VERSION "ke devel"
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* define the keyboard input modes
|
* define the keyboard input modes
|
||||||
* normal: no special mode
|
* normal: no special mode
|
||||||
@@ -44,6 +52,44 @@
|
|||||||
#define TAB_STOP 8
|
#define TAB_STOP 8
|
||||||
|
|
||||||
|
|
||||||
|
#define INITIAL_BUFSIZE 64
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
next_power_of_2(int n)
|
||||||
|
{
|
||||||
|
if (n < 2) {
|
||||||
|
n = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
n--;
|
||||||
|
n |= n >> 1;
|
||||||
|
n |= n >> 2;
|
||||||
|
n |= n >> 4;
|
||||||
|
n |= n >> 8;
|
||||||
|
n |= n >> 16;
|
||||||
|
|
||||||
|
return n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cap_growth is a generalized strategy to growing buffers.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
cap_growth(int cap, int sz)
|
||||||
|
{
|
||||||
|
if (cap == 0) {
|
||||||
|
cap = INITIAL_BUFSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cap <= sz) {
|
||||||
|
cap = next_power_of_2(cap + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function and struct declarations.
|
* Function and struct declarations.
|
||||||
*/
|
*/
|
||||||
@@ -67,6 +113,8 @@ struct erow {
|
|||||||
|
|
||||||
int size;
|
int size;
|
||||||
int rsize;
|
int rsize;
|
||||||
|
|
||||||
|
int cap;
|
||||||
};
|
};
|
||||||
|
|
||||||
char nibble_to_hex(char c);
|
char nibble_to_hex(char c);
|
||||||
@@ -181,7 +229,7 @@ init_editor(void)
|
|||||||
editor.rows = 0;
|
editor.rows = 0;
|
||||||
|
|
||||||
if (get_winsz(&editor.rows, &editor.cols) == -1) {
|
if (get_winsz(&editor.rows, &editor.cols) == -1) {
|
||||||
die("can't get window size - is this an interactive terminal?");
|
// die("can't get window size - is this an interactive terminal?");
|
||||||
}
|
}
|
||||||
editor.rows--; /* status bar */
|
editor.rows--; /* status bar */
|
||||||
editor.rows--; /* message line */
|
editor.rows--; /* message line */
|
||||||
@@ -229,17 +277,21 @@ ab_append(struct abuf *buf, const char *s, int len)
|
|||||||
char *nc = buf->b;
|
char *nc = buf->b;
|
||||||
int sz;
|
int sz;
|
||||||
|
|
||||||
assert((delta <= 0 && buf->len < INT_MAX - delta));
|
assert((delta >= 0 && buf->len < INT_MAX - delta));
|
||||||
sz = buf->len + delta;
|
sz = buf->len + delta;
|
||||||
|
|
||||||
if (sz >= buf->cap) {
|
if (sz > buf->cap) {
|
||||||
if (buf->cap == 0) {
|
if (buf->cap == 0) {
|
||||||
buf->cap = 1;
|
buf->cap = 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* grow until capacity is at least the required
|
||||||
|
* size
|
||||||
|
*/
|
||||||
while (sz > buf->cap) {
|
while (sz > buf->cap) {
|
||||||
if (buf->cap < INT_MAX/2) {
|
if (buf->cap > INT_MAX/2) {
|
||||||
buf->cap *= INT_MAX;
|
buf->cap = INT_MAX;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
buf->cap *= 2;
|
buf->cap *= 2;
|
||||||
@@ -332,9 +384,10 @@ erow_update(struct erow *row)
|
|||||||
* TODO(kyle): I'm not thrilled with this double-render.
|
* TODO(kyle): I'm not thrilled with this double-render.
|
||||||
*/
|
*/
|
||||||
for (j = 0; j < row->size; j++) {
|
for (j = 0; j < row->size; j++) {
|
||||||
if (row->line[j] == '\t') {
|
unsigned char ch = (unsigned char)row->line[j];
|
||||||
|
if (ch == '\t') {
|
||||||
tabs++;
|
tabs++;
|
||||||
} else if (!isprint(row->line[j])) {
|
} else if (!isprint(ch)) {
|
||||||
ctrl++;
|
ctrl++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,16 +401,17 @@ erow_update(struct erow *row)
|
|||||||
assert(row->render != NULL);
|
assert(row->render != NULL);
|
||||||
|
|
||||||
for (j = 0; j < row->size; j++) {
|
for (j = 0; j < row->size; j++) {
|
||||||
if (row->line[j] == '\t') {
|
unsigned char ch = (unsigned char)row->line[j];
|
||||||
|
if (ch == '\t') {
|
||||||
do {
|
do {
|
||||||
row->render[i++] = ' ';
|
row->render[i++] = ' ';
|
||||||
} while ((i % TAB_STOP) != 0);
|
} while ((i % TAB_STOP) != 0);
|
||||||
} else if (!isprint(row->line[j])) {
|
} else if (!isprint(ch)) {
|
||||||
row->render[i++] = '\\';
|
row->render[i++] = '\\';
|
||||||
row->render[i++] = nibble_to_hex(row->line[j] >> 4);
|
row->render[i++] = nibble_to_hex((char)(ch >> 4));
|
||||||
row->render[i++] = nibble_to_hex(row->line[j] & 0x0f);
|
row->render[i++] = nibble_to_hex((char)(ch & 0x0f));
|
||||||
} else {
|
} else {
|
||||||
row->render[i++] = row->line[j];
|
row->render[i++] = (char)ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,8 +427,9 @@ erow_init(struct erow *row, int len)
|
|||||||
row->rsize = 0;
|
row->rsize = 0;
|
||||||
row->render = NULL;
|
row->render = NULL;
|
||||||
row->line = NULL;
|
row->line = NULL;
|
||||||
|
row->cap = cap_growth(0, len);
|
||||||
|
|
||||||
row->line = malloc(len+1);
|
row->line = malloc(row->cap);
|
||||||
assert(row->line != NULL);
|
assert(row->line != NULL);
|
||||||
if (row->line == NULL) {
|
if (row->line == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -504,6 +559,8 @@ row_append_row(struct erow *row, char *s, int len)
|
|||||||
assert(row->line != NULL);
|
assert(row->line != NULL);
|
||||||
memcpy(&row->line[row->size], s, len);
|
memcpy(&row->line[row->size], s, len);
|
||||||
row->size += len;
|
row->size += len;
|
||||||
|
|
||||||
|
row->cap = row->size + 1;
|
||||||
row->line[row->size] = '\0';
|
row->line[row->size] = '\0';
|
||||||
erow_update(row);
|
erow_update(row);
|
||||||
editor.dirty++;
|
editor.dirty++;
|
||||||
@@ -513,6 +570,9 @@ row_append_row(struct erow *row, char *s, int len)
|
|||||||
void
|
void
|
||||||
row_insert_ch(struct erow *row, int at, int16_t c)
|
row_insert_ch(struct erow *row, int at, int16_t c)
|
||||||
{
|
{
|
||||||
|
int ncap = 0;
|
||||||
|
char *nline = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* row_insert_ch just concerns itself with how to update a row.
|
* row_insert_ch just concerns itself with how to update a row.
|
||||||
*/
|
*/
|
||||||
@@ -521,8 +581,22 @@ row_insert_ch(struct erow *row, int at, int16_t c)
|
|||||||
}
|
}
|
||||||
assert(c > 0);
|
assert(c > 0);
|
||||||
|
|
||||||
row->line = realloc(row->line, row->size+2);
|
/* We will move existing bytes including the current NUL, so we need
|
||||||
assert(row->line != NULL);
|
* at least row->size + 2 bytes of storage (new char + NUL). Ensure
|
||||||
|
* capacity exceeds index row->size + 1. */
|
||||||
|
if (row->size + 1 >= row->cap) {
|
||||||
|
ncap = cap_growth(row->cap, row->size + 1);
|
||||||
|
nline = realloc(row->line, ncap);
|
||||||
|
|
||||||
|
assert(nline != NULL);
|
||||||
|
if (nline == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
row->cap = ncap;
|
||||||
|
row->line = nline;
|
||||||
|
}
|
||||||
|
|
||||||
memmove(&row->line[at+1], &row->line[at], row->size - at + 1);
|
memmove(&row->line[at+1], &row->line[at], row->size - at + 1);
|
||||||
row->size++;
|
row->size++;
|
||||||
row->line[at] = c & 0xff;
|
row->line[at] = c & 0xff;
|
||||||
@@ -1089,6 +1163,7 @@ process_kcommand(int16_t c)
|
|||||||
case 'x':
|
case 'x':
|
||||||
exit(save_file());
|
exit(save_file());
|
||||||
case CTRL_KEY('d'):
|
case CTRL_KEY('d'):
|
||||||
|
case CTRL_KEY('y'):
|
||||||
delete_row(editor.cury);
|
delete_row(editor.cury);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
@@ -1368,7 +1443,6 @@ draw_rows(struct abuf *ab)
|
|||||||
ab_append(ab, "|", 1);
|
ab_append(ab, "|", 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
erow_update(&editor.row[filerow]);
|
|
||||||
buflen = editor.row[filerow].rsize - editor.coloffs;
|
buflen = editor.row[filerow].rsize - editor.coloffs;
|
||||||
if (buflen < 0) {
|
if (buflen < 0) {
|
||||||
buflen = 0;
|
buflen = 0;
|
||||||
@@ -1377,6 +1451,7 @@ draw_rows(struct abuf *ab)
|
|||||||
if (buflen > editor.cols) {
|
if (buflen > editor.cols) {
|
||||||
buflen = editor.cols;
|
buflen = editor.cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
ab_append(ab, editor.row[filerow].render+editor.coloffs,
|
ab_append(ab, editor.row[filerow].render+editor.coloffs,
|
||||||
buflen);
|
buflen);
|
||||||
}
|
}
|
||||||
@@ -1519,10 +1594,10 @@ editor_set_status(const char *fmt, ...)
|
|||||||
void
|
void
|
||||||
loop(void)
|
loop(void)
|
||||||
{
|
{
|
||||||
int up = 1; /* update on the first runthrough */
|
display_refresh();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (up) display_refresh();
|
int update = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ke should only refresh the display if it has received keyboard
|
* ke should only refresh the display if it has received keyboard
|
||||||
@@ -1530,8 +1605,12 @@ loop(void)
|
|||||||
* handling pastes without massive screen flicker.
|
* handling pastes without massive screen flicker.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
if ((up = process_keypress()) != 0) {
|
while (process_keypress()) {
|
||||||
while (process_keypress()) ;
|
update = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
display_refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user