add utf8_char_t struct

This commit is contained in:
Arthur Barraux
2025-11-19 10:37:41 +01:00
parent c06c820dfb
commit eae85c32ca
18 changed files with 770 additions and 339 deletions
+121 -34
View File
@@ -7,6 +7,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
extern char *strdup(const char *);
extern ssize_t getline(char **restrict lineptr, size_t *restrict n,
@@ -14,37 +15,56 @@ extern ssize_t getline(char **restrict lineptr, size_t *restrict n,
extern int ftruncate(int fd, off_t length);
extern struct editorConfig E;
// Convert utf_8_char_t array to byte string
char *editorRowsToString(int *buffer_len) {
int tot_len = 0;
int j;
int j, i;
char *buf;
char *p;
// Calculate total byte length (not character count)
for (j = 0; j < E.numrows; ++j) {
tot_len += E.row[j].size + 1;
// Count actual bytes in each character
for (i = 0; i < E.row[j].size; i++) {
tot_len += E.row[j].chars[i].len;
}
tot_len++; // For newline
}
*buffer_len = tot_len;
buf = malloc(tot_len);
if (!buf) return NULL;
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++;
// Copy each character's bytes
for (i = 0; i < E.row[j].size; i++) {
for (int k = 0; k < E.row[j].chars[i].len; k++) {
*p++ = E.row[j].chars[i].c[k];
}
}
*p++ = '\n';
}
return buf;
}
void editorCloseFile(void) {
// Free all rows
for (int i = 0; i < E.numrows; i++) {
editorFreeRow(&E.row[i]);
}
E.cursor_x = 0;
E.cursor_y = 0;
E.rx = 0;
E.row_offset = 0;
E.col_offset = 0;
E.numrows = 0;
free(E.row);
E.row = NULL;
E.dirty = 0;
free(E.filename);
E.filename = NULL;
E.status_msg[0] = '\0';
E.status_msg_time = 0;
@@ -56,25 +76,29 @@ void editorOpen(char *filename) {
// Test if a file is already open
if (E.filename != NULL) {
editorCloseFile();
E.state = READ_AND_WRITE;
}
E.state = READ_AND_WRITE;
free(E.filename);
E.filename = strdup(filename);
fp = fopen(filename, "a+");
if (!fp)
die("fopen");
fp = fopen(filename, "r");
if (!fp) {
// File doesn't exist - that's okay, we'll create it on save
E.dirty = 0;
return;
}
char *line = NULL;
size_t line_cap = 0;
ssize_t line_len;
while ((line_len = getline(&line, &line_cap, fp)) != -1) {
// Strip newline characters
while (line_len > 0 &&
(line[line_len - 1] == '\n' || line[line_len - 1] == '\r')) {
--line_len;
}
// editorInsertRow will convert bytes to utf_8_char_t
editorInsertRow(E.numrows, line, line_len);
}
free(line);
@@ -86,6 +110,7 @@ void editorSave() {
int len;
char *buf;
int fd;
if (E.filename == NULL) {
E.filename = editorPrompt("Save as: %s (ESC to cancel)", "", 1);
if (E.filename == NULL) {
@@ -93,38 +118,100 @@ void editorSave() {
return;
}
}
buf = editorRowsToString(&len);
fd = open(E.filename, O_RDWR | O_CREAT, 0644);
if (!buf) {
editorSetStatusMessage("Can't save! Memory error");
return;
}
fd = open(E.filename, O_RDWR | O_CREAT | O_TRUNC, 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;
}
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));
}
void editorFind() {
char *query = editorPrompt("Search: %s (ESC to cancel)", "", 0);
if (query == NULL) return;
int i;
for (i = E.cursor_y + 1; i < E.numrows; i++) {
erow *row = &E.row[i];
char *match = strstr(row->render, query);
if (match) {
E.cursor_y = i;
E.cursor_x = editorRowRxToCx(row, match - row->render);
E.row_offset = E.numrows;
break;
// Helper to convert utf_8_char_t array to byte string for searching
static char *row_to_string(erow *row) {
// Calculate byte length
int byte_len = 0;
for (int i = 0; i < row->rsize; i++) {
byte_len += row->render[i].len;
}
}
free(query);
char *str = malloc(byte_len + 1);
if (!str) return NULL;
// Convert to bytes
int pos = 0;
for (int i = 0; i < row->rsize; i++) {
for (int j = 0; j < row->render[i].len; j++) {
str[pos++] = row->render[i].c[j];
}
}
str[pos] = '\0';
return str;
}
void editorFind() {
char *query = editorPrompt("Search: %s (ESC to cancel)", "", 0);
if (query == NULL) return;
int saved_cursor_x = E.cursor_x;
int saved_cursor_y = E.cursor_y;
int saved_row_offset = E.row_offset;
int saved_col_offset = E.col_offset;
// Search from current position forward
for (int i = E.cursor_y; i < E.numrows; i++) {
erow *row = &E.row[i];
// Convert row to byte string for searching
char *render_str = row_to_string(row);
if (!render_str) continue;
char *match = strstr(render_str, query);
if (match) {
E.cursor_y = i;
// Find the character index from byte position
int byte_pos = match - render_str;
int char_idx = 0;
int current_byte = 0;
for (char_idx = 0; char_idx < row->rsize; char_idx++) {
if (current_byte >= byte_pos) break;
current_byte += row->render[char_idx].len;
}
E.cursor_x = editorRowRxToCx(row, char_idx);
E.row_offset = E.numrows; // Force scroll
free(render_str);
free(query);
return;
}
free(render_str);
}
// Not found - restore cursor position
E.cursor_x = saved_cursor_x;
E.cursor_y = saved_cursor_y;
E.row_offset = saved_row_offset;
E.col_offset = saved_col_offset;
editorSetStatusMessage("Not found: %s", query);
free(query);
}