temp commit

This commit is contained in:
2026-05-22 13:40:03 +02:00
parent bc66e673fa
commit edb5384f0e
23 changed files with 848 additions and 621 deletions
-1
View File
@@ -80,7 +80,6 @@
(map-key "PAGE-DOWN" move-cursor-page-down "no-prefix") (map-key "PAGE-DOWN" move-cursor-page-down "no-prefix")
(map-key "f" editor-open-file "user") (map-key "f" editor-open-file "user")
(map-key "TAB" editor-insert-tab "no-prefix") (map-key "TAB" editor-insert-tab "no-prefix")
(map-key "CTRL-k" editor-del-row "no-prefix")
(map-key "CTRL-s" buffer-find "no-prefix") (map-key "CTRL-s" buffer-find "no-prefix")
(map-key "CTRL-r" editor-move-to-end-of-word "no-prefix") (map-key "CTRL-r" editor-move-to-end-of-word "no-prefix")
(map-key "ARROW-RIGHT" editor-switch-next-buffer "user") (map-key "ARROW-RIGHT" editor-switch-next-buffer "user")
+2
View File
@@ -55,4 +55,6 @@ int bufferSave(void);
*/ */
int bufferSaveAll(void); int bufferSaveAll(void);
void bufferFind(struct buffer_t *buf);
#endif #endif
-1
View File
@@ -17,7 +17,6 @@ Lisp l_editorInsertNewLine(Lisp args, LispError* e, LispContext ctx);
Lisp l_editorInserTab(Lisp args, LispError *e, LispContext ctx); Lisp l_editorInserTab(Lisp args, LispError *e, LispContext ctx);
Lisp deletePreviousChar(Lisp args, LispError *e, LispContext ctx); Lisp deletePreviousChar(Lisp args, LispError *e, LispContext ctx);
Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx); Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx);
Lisp editorDelRow_L(Lisp args, LispError *e, LispContext ctx);
Lisp editorReadChar_L(Lisp args, LispError *e, LispContext ctx); Lisp editorReadChar_L(Lisp args, LispError *e, LispContext ctx);
// Editor // Editor
+9 -17
View File
@@ -33,15 +33,12 @@ typedef enum {
*/ */
typedef struct { typedef struct {
int buffer_id; // Which buffer this pane displays int buffer_id; // Which buffer this pane displays
int start_row; // Starting row on screen
int start_col; // Starting column on screen
int height; // Height of this pane int height; // Height of this pane
int width; // Width of this pane int width; // Width of this pane
int origin_x, origin_y;
int cursor_x; // Local cursor x in this pane int cursor_x; // Local cursor x in this pane
int cursor_y; // Local cursor y in this pane int cursor_y; // Local cursor y in this pane
int rx, ry; int x_offset, y_offset;
int row_offset; // Scroll offset for rows
int col_offset; // Scroll offset for columns
int is_active; // Is this pane currently active int is_active; // Is this pane currently active
} EditorPane; } EditorPane;
@@ -95,15 +92,12 @@ enum buffer_type { FILE_BUFF, TERMINAL_BUFF };
struct buffer_t { struct buffer_t {
enum buffer_type type; enum buffer_type type;
int buffer_id; int buffer_id;
int width, height; int x, y; /**< Position in the file */
int x, y; /**< Position in the buffer (cursor) */ row_t *row;
frow *row;
int numrows; int numrows;
char *filename; char *filename;
enum bufferStatus_e state; enum bufferStatus_e state;
int dirty; /**< Has this buffer been modified since last save */ int dirty; /**< Has this buffer been modified since last save */
int row_offset; /**< Scroll offset for rows in this buffer */
int col_offset; /**< Scroll offset for columns in this buffer */
}; };
/** /**
@@ -112,19 +106,16 @@ struct buffer_t {
*/ */
struct editorConfig { struct editorConfig {
int cursor_x, cursor_y; /**< Cursor position */ int cursor_x, cursor_y; /**< Cursor position */
int rx; /**< Position in the render*/
int row_offset; /**< Position scroll of lines */
int col_offset; /**< Position scroll of colomns*/
int screenrows; /**< Terminal height*/ int screenrows; /**< Terminal height*/
int screencols; /**< Terminal width*/ int screencols; /**< Terminal width*/
ScreenLayout layout; ScreenLayout layout;
int numrows; /**< Number of rows contained */ row_t *rows; /**< Store all the rows printed */
row_t *rows; /**< Store all the rows printed */
int dirty; int dirty;
int prefix_state;
char status_msg[80]; char *status_msg;
time_t status_msg_time; time_t status_msg_time;
struct termios orig_termios; /**< Terminal communication interface */ struct termios orig_termios; /**< Terminal communication interface */
@@ -143,6 +134,7 @@ struct editorConfig {
struct prefix_t *prefix; struct prefix_t *prefix;
int number_of_prefix; int number_of_prefix;
int prefix_state;
struct buffer_t buffers[64]; struct buffer_t buffers[64];
int number_of_buffer; int number_of_buffer;
+2 -1
View File
@@ -8,8 +8,9 @@
#define HIDE_CURSOR "\x1b[?25l" #define HIDE_CURSOR "\x1b[?25l"
#define SHOW_CURSOR "\x1b[?25h" #define SHOW_CURSOR "\x1b[?25h"
#define ERASE_END_LINE "\x1b[K" #define ERASE_END_LINE "\x1b[K"
#define TAB "\x09" #define TAB "\x9"
#define SPACE "\x20" #define SPACE "\x20"
#define APP_DEBUG
enum editorKey_e { enum editorKey_e {
BACKSPACE = 127, BACKSPACE = 127,
+3 -2
View File
@@ -2,10 +2,11 @@
#define EDITOR_OP_H_ #define EDITOR_OP_H_
#include "data.h" #include "data.h"
void bufferInsertChar(int c);
void bufferInsertNewLine(); void bufferInsertNewLine();
void bufferInsertBytes(char *src, int n);
void editorSetStatusMessage(const char *fmt, ...); void editorSetStatusMessage(const char *fmt, ...);
void bufferDelBytes();
#endif // EDITOR_OP_H_ #endif // EDITOR_OP_H_
-5
View File
@@ -8,15 +8,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h> #include <sys/types.h>
char *bufferRowsToString(struct buffer_t *buf,int *buffer_len);
void editorCloseFile(void); void editorCloseFile(void);
void editorOpen(struct buffer_t *buffer); void editorOpen(struct buffer_t *buffer);
void editorSave(); void editorSave();
void bufferFind(struct buffer_t *buf);
#endif // FILE_IO_H_ #endif // FILE_IO_H_
+1 -1
View File
@@ -22,7 +22,7 @@
char *editorPrompt(char *prompt, char * PlaceHolder, char bPathMode); char *editorPrompt(char *prompt, char * PlaceHolder, char bPathMode);
char *key_to_string(int key); const char *file_completion(const char *path);
int editorMoveCursor(int key); int editorMoveCursor(int key);
-2
View File
@@ -9,8 +9,6 @@
* \brief Draws left rows of the editor. * \brief Draws left rows of the editor.
*/ */
void editorDrawRows(struct abuf *ab);
void editorRefreshScreen(); void editorRefreshScreen();
void editorScroll(); void editorScroll();
+4 -12
View File
@@ -10,17 +10,9 @@
void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len); void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len);
int editorRowCxToByte(const row_t *row, int cursor_x); int editorRowCxToByte(const row_t *row, int cursor_x);
void bufferFreeRow(row_t *row);
int editorRowCharCount(row_t *row); int editorRowCharCount(row_t *row, int x);
void bufferRowInsertBytes(struct buffer_t *buffer, row_t *row, int at, char *src, int n);
void bufferDelRow(struct buffer_t *buffer, int at); void bufferRowDelByte(struct buffer_t *buffer, row_t *row, int at, int n);
void editorRowInsertBytes(row_t *row, int at, const char *src, int len);
void editorRowDelByte(row_t *row, int at, int n);
void bufferRowInsertChar(struct buffer_t *buffer, frow *row, int at, int c);
void bufferRowAppendString(struct buffer_t *buffer, frow *row, char *s, size_t len);
void bufferRowDelchar(struct buffer_t *buffer, frow *row, int at);
#endif // ROW_OP_H_ #endif // ROW_OP_H_
+2
View File
@@ -33,4 +33,6 @@ int getWindowSize(int *rows, int *cols);
char *key_to_string(int key); char *key_to_string(int key);
void appDebug(const char *fmt, ...);
#endif #endif
+8 -7
View File
@@ -5,6 +5,10 @@
* interactions. \version 0.1 \date 21 septembre 2024 * interactions. \version 0.1 \date 21 septembre 2024
*/ */
#define _DEFAULT_SOURCE
#define _BSD_SOURCE
#define _GNU_SOURCE
#include "include/buffer.h" #include "include/buffer.h"
#include "include/split_screen.h" #include "include/split_screen.h"
#include <stdio.h> #include <stdio.h>
@@ -12,10 +16,6 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#define _DEFAULT_SOURCE
#define _BSD_SOURCE
#define _GNU_SOURCE
#include "include/data.h" #include "include/data.h"
#include "include/file_io.h" #include "include/file_io.h"
#include "include/init.h" #include "include/init.h"
@@ -28,7 +28,7 @@ struct editorConfig E;
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
char * splash_screen = (char *) calloc(256, sizeof(char)); char * splash_screen = (char *) calloc(256, sizeof(char));
enableRawMode(); enableRawMode();
initEditor(); initEditor();
if (argc >= 2) { if (argc >= 2) {
@@ -37,11 +37,12 @@ int main(int argc, char *argv[]) {
} else { } else {
strcat(splash_screen, getenv("HOME")); strcat(splash_screen, getenv("HOME"));
strcat(splash_screen, "/.beluga/assets/beluga.txt"); strcat(splash_screen, "/.beluga/assets/beluga.txt");
fprintf(stderr, "%s\n", splash_screen);
appDebug("splash : %s\n", splash_screen);
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
active->buffer_id = bufferCreate(splash_screen); active->buffer_id = bufferCreate(splash_screen);
} }
//free(splash_screen); free(splash_screen);
editorSetStatusMessage("HELP: Ctrl-x Ctrl-s = save | Ctrl-x Ctrl-c = quit"); editorSetStatusMessage("HELP: Ctrl-x Ctrl-s = save | Ctrl-x Ctrl-c = quit");
+136 -69
View File
@@ -12,6 +12,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "include/input.h"
extern struct editorConfig E; extern struct editorConfig E;
/** /**
@@ -19,10 +21,13 @@ extern struct editorConfig E;
* @param filename The filename to search for * @param filename The filename to search for
* @return Buffer ID if found, -1 if not found * @return Buffer ID if found, -1 if not found
*/ */
static int bufferFindByFilename(const char *filename) { static int bufferFindByFilename(const char* filename)
for (int i = 0; i < E.number_of_buffer; i++) { {
if (E.buffers[i].filename != NULL && for (int i = 0; i < E.number_of_buffer; i++)
strcmp(E.buffers[i].filename, filename) == 0) { {
if (E.buffers[i].filename != NULL &&
strcmp(E.buffers[i].filename, filename) == 0)
{
return E.buffers[i].buffer_id; return E.buffers[i].buffer_id;
} }
} }
@@ -34,9 +39,12 @@ static int bufferFindByFilename(const char *filename) {
* @param buffer_id The buffer ID to find * @param buffer_id The buffer ID to find
* @return Pointer to buffer, NULL if not found * @return Pointer to buffer, NULL if not found
*/ */
struct buffer_t *bufferFindById(int buffer_id) { struct buffer_t* bufferFindById(int buffer_id)
for (int i = 0; i < E.number_of_buffer; i++) { {
if (E.buffers[i].buffer_id == buffer_id) { for (int i = 0; i < E.number_of_buffer; i++)
{
if (E.buffers[i].buffer_id == buffer_id)
{
return &E.buffers[i]; return &E.buffers[i];
} }
} }
@@ -50,36 +58,37 @@ struct buffer_t *bufferFindById(int buffer_id) {
* @param filename Path to the file * @param filename Path to the file
* @return Buffer ID on success, -1 on failure * @return Buffer ID on success, -1 on failure
*/ */
int bufferCreate(const char *filename) { int bufferCreate(const char* filename)
{
// Check if file is already open // Check if file is already open
int existing_id = bufferFindByFilename(filename); const int existing_id = bufferFindByFilename(filename);
if (existing_id != -1) { if (existing_id != -1)
{
return bufferSwitch(existing_id); return bufferSwitch(existing_id);
} }
// Check if we have space for more buffers // Check if we have space for more buffers
if (E.number_of_buffer >= 64) { if (E.number_of_buffer >= 64)
{
editorSetStatusMessage("Error: maximum buffers reached (64)"); editorSetStatusMessage("Error: maximum buffers reached (64)");
return -1; return -1;
} }
// Initialize new buffer // Initialize new buffer
struct buffer_t *new_buf = &E.buffers[E.number_of_buffer]; struct buffer_t* new_buf = &E.buffers[E.number_of_buffer];
new_buf->buffer_id = E.number_of_buffer; new_buf->buffer_id = E.number_of_buffer;
new_buf->filename = strdup(filename); new_buf->filename = strdup(filename);
new_buf->type = FILE_BUFF; new_buf->type = FILE_BUFF;
new_buf->state = READ_AND_WRITE; new_buf->state = READ_AND_WRITE;
new_buf->x = 0; new_buf->x = 0;
new_buf->y = 0; new_buf->y = 0;
new_buf->row_offset = 0; new_buf->dirty = 0; // New file starts clean
new_buf->col_offset = 0;
new_buf->dirty = 0; // New file starts clean
// Load file content using existing editorOpen // Load file content using existing editorOpen
editorOpen(new_buf); editorOpen(new_buf);
E.number_of_buffer++; E.number_of_buffer++;
editorSetStatusMessage("Opened: %s (buffer %d)", filename, new_buf->buffer_id); editorSetStatusMessage("Opened: %s (buffer %d)", filename, new_buf->buffer_id);
return new_buf->buffer_id; return new_buf->buffer_id;
} }
@@ -90,17 +99,19 @@ int bufferCreate(const char *filename) {
* @param buffer_id The buffer ID to switch to * @param buffer_id The buffer ID to switch to
* @return 0 on success, -1 on failure * @return 0 on success, -1 on failure
*/ */
int bufferSwitch(int buffer_id) { int bufferSwitch(int buffer_id)
struct buffer_t *target = bufferFindById(buffer_id); {
if (target == NULL) { struct buffer_t* target = bufferFindById(buffer_id);
E.layout.panes[E.layout.active_pane].buffer_id = buffer_id; if (target == NULL)
{
E.layout.panes[E.layout.active_pane].buffer_id = buffer_id;
editorSetStatusMessage("Error: buffer not found"); editorSetStatusMessage("Error: buffer not found");
return -1; return -1;
} }
editorSetStatusMessage("Switched to: %s (buffer %d)", editorSetStatusMessage("Switched to: %s (buffer %d)",
target->filename, buffer_id); target->filename, buffer_id);
return 0; return 0;
} }
@@ -112,51 +123,62 @@ int bufferSwitch(int buffer_id) {
* @param buffer_id The buffer ID to close * @param buffer_id The buffer ID to close
* @return 0 on success, -1 on failure * @return 0 on success, -1 on failure
*/ */
int bufferClose(int buffer_id) { int bufferClose(int buffer_id)
struct buffer_t *buf = bufferFindById(buffer_id); {
if (buf == NULL) { struct buffer_t* buf = bufferFindById(buffer_id);
if (buf == NULL)
{
editorSetStatusMessage("Error: buffer not found"); editorSetStatusMessage("Error: buffer not found");
return -1; return -1;
} }
EditorPane * active = splitScreenGetActivePane(); EditorPane* active = splitScreenGetActivePane();
// If this is the current buffer, find next buffer to switch to // If this is the current buffer, find next buffer to switch to
if (active->buffer_id == buffer_id) { if (active->buffer_id == buffer_id)
{
int next_id = -1; int next_id = -1;
// Try to switch to next buffer // Try to switch to next buffer
for (int i = 0; i < E.number_of_buffer; i++) { for (int i = 0; i < E.number_of_buffer; i++)
if (E.buffers[i].buffer_id != buffer_id) { {
if (E.buffers[i].buffer_id != buffer_id)
{
next_id = E.buffers[i].buffer_id; next_id = E.buffers[i].buffer_id;
break; break;
} }
} }
if (next_id != -1) { if (next_id != -1)
{
bufferSwitch(next_id); bufferSwitch(next_id);
} else { }
else
{
// No other buffers, clear editor // No other buffers, clear editor
editorCloseFile(); editorCloseFile();
} }
} }
// Free buffer resources // Free buffer resources
free(buf->filename); free(buf->filename);
buf->filename = NULL; buf->filename = NULL;
buf->buffer_id = -1; buf->buffer_id = -1;
// Remove from buffer list by shifting // Remove from buffer list by shifting
for (int i = 0; i < E.number_of_buffer; i++) { for (int i = 0; i < E.number_of_buffer; i++)
if (E.buffers[i].buffer_id == buffer_id) { {
for (int j = i; j < E.number_of_buffer - 1; j++) { if (E.buffers[i].buffer_id == buffer_id)
{
for (int j = i; j < E.number_of_buffer - 1; j++)
{
E.buffers[j] = E.buffers[j + 1]; E.buffers[j] = E.buffers[j + 1];
} }
E.number_of_buffer--; E.number_of_buffer--;
break; break;
} }
} }
editorSetStatusMessage("Closed buffer %d", buffer_id); editorSetStatusMessage("Closed buffer %d", buffer_id);
return 0; return 0;
} }
@@ -165,8 +187,9 @@ int bufferClose(int buffer_id) {
* @brief Gets the current active buffer * @brief Gets the current active buffer
* @return Pointer to current buffer_t, NULL if none * @return Pointer to current buffer_t, NULL if none
*/ */
struct buffer_t *bufferGetCurrent(void) { struct buffer_t* bufferGetCurrent(void)
EditorPane * active = splitScreenGetActivePane(); {
EditorPane* active = splitScreenGetActivePane();
return bufferFindById(active->buffer_id); return bufferFindById(active->buffer_id);
} }
@@ -175,24 +198,27 @@ struct buffer_t *bufferGetCurrent(void) {
* @details Prints buffer information to status message * @details Prints buffer information to status message
* @return Number of open buffers * @return Number of open buffers
*/ */
int bufferListAll(void) { int bufferListAll(void)
if (E.number_of_buffer == 0) { {
if (E.number_of_buffer == 0)
{
editorSetStatusMessage("No buffers open"); editorSetStatusMessage("No buffers open");
return 0; return 0;
} }
char buf[256] = ""; char buf[256] = "";
int offset = 0; int offset = 0;
EditorPane * active = splitScreenGetActivePane(); EditorPane* active = splitScreenGetActivePane();
for (int i = 0; i < E.number_of_buffer; i++) { for (int i = 0; i < E.number_of_buffer; i++)
struct buffer_t *b = &E.buffers[i]; {
struct buffer_t* b = &E.buffers[i];
char marker = (b->buffer_id == active->buffer_id) ? '*' : ' '; char marker = (b->buffer_id == active->buffer_id) ? '*' : ' ';
offset += snprintf(&buf[offset], sizeof(buf) - offset, offset += snprintf(&buf[offset], sizeof(buf) - offset,
"%c%d:%s ", marker, b->buffer_id, "%c%d:%s ", marker, b->buffer_id,
b->filename ? b->filename : "[No Name]"); b->filename ? b->filename : "[No Name]");
} }
editorSetStatusMessage("Buffers: %s", buf); editorSetStatusMessage("Buffers: %s", buf);
return E.number_of_buffer; return E.number_of_buffer;
} }
@@ -201,13 +227,15 @@ int bufferListAll(void) {
* @brief Saves current buffer to disk * @brief Saves current buffer to disk
* @return 0 on success, -1 on failure * @return 0 on success, -1 on failure
*/ */
int bufferSave(void) { int bufferSave(void)
EditorPane * active = splitScreenGetActivePane(); {
if (active->buffer_id == -1) { EditorPane* active = splitScreenGetActivePane();
if (active->buffer_id == -1)
{
editorSetStatusMessage("Error: no buffer active"); editorSetStatusMessage("Error: no buffer active");
return -1; return -1;
} }
editorSave(); editorSave();
return 0; return 0;
} }
@@ -217,20 +245,59 @@ int bufferSave(void) {
* @details Iterates through all buffers, saves each one * @details Iterates through all buffers, saves each one
* @return 0 on success, -1 on failure * @return 0 on success, -1 on failure
*/ */
int bufferSaveAll(void) { int bufferSaveAll(void)
{
int saved = 0; int saved = 0;
int failed = 0; int failed = 0;
for (int i = 0; i < E.number_of_buffer; i++) { for (int i = 0; i < E.number_of_buffer; i++)
if (bufferSwitch(E.buffers[i].buffer_id) == 0) { {
if (E.dirty && bufferSave() == 0) { if (bufferSwitch(E.buffers[i].buffer_id) == 0)
{
if (E.dirty && bufferSave() == 0)
{
saved++; saved++;
} }
} else { }
else
{
failed++; failed++;
} }
} }
editorSetStatusMessage("Saved %d buffers (%d failed)", saved, failed); editorSetStatusMessage("Saved %d buffers (%d failed)", saved, failed);
return (failed == 0) ? 0 : -1; return (failed == 0) ? 0 : -1;
} }
/**
* @brief Searches for a string in the document
* @details Prompts user for a search query, then searches forward from current
* cursor position. Updates cursor position to the first match found.
* @note Updates global editor state E (cursor position, row_offset)
* @note Search is case-sensitive and operates on rendered line content
* @note Searches begin from the line after current cursor position
* @see editorPrompt()
* @see editorRowRxToCx()
*/
void bufferFind(struct buffer_t* buf)
{
appDebug("searching\n");
char* query = editorPrompt("Search: %s (ESC to cancel)", "", 0);
EditorPane* active = splitScreenGetActivePane();
if (query == NULL)
return;
int i;
for (i = active->cursor_y + 1; i < buf->numrows; i++)
{
row_t* row = &buf->row[i];
char* match = strstr(row->chars, query);
if (match)
{
active->cursor_y = i;
buf->y = buf->numrows;
break;
}
}
free(query);
}
+46 -60
View File
@@ -2,17 +2,18 @@
* @file builtins.c * @file builtins.c
* @brief Built-in Lisp functions for editor operations * @brief Built-in Lisp functions for editor operations
* @details Provides Lisp bindings for core editor functionality including * @details Provides Lisp bindings for core editor functionality including
* cursor movement, file operations, keybinding management, and text manipulation * cursor movement, file operations, keybinding management, and text
* manipulation
*/ */
#include "../include/builtins.h" #include "../include/builtins.h"
#include "../include/buffer.h"
#include "../include/data.h" #include "../include/data.h"
#include "../include/define.h" #include "../include/define.h"
#include "../include/editor_op.h" #include "../include/editor_op.h"
#include "../include/file_io.h" #include "../include/file_io.h"
#include "../include/input.h" #include "../include/input.h"
#include "../include/row_op.h" #include "../include/row_op.h"
#include "../include/buffer.h"
#include "../include/split_screen.h" #include "../include/split_screen.h"
#include <stdio.h> #include <stdio.h>
@@ -57,7 +58,7 @@ Lisp mapKey(Lisp args, LispError *e, LispContext ctx) {
const char *key_sequence = lisp_string(lisp_car(args)); const char *key_sequence = lisp_string(lisp_car(args));
args = lisp_cdr(args); args = lisp_cdr(args);
// second argument // second argument
Lisp func = lisp_car(args); const Lisp func = lisp_car(args);
E.key_binds = (struct keyBind_t *)realloc( E.key_binds = (struct keyBind_t *)realloc(
E.key_binds, ++E.number_of_keybinds * sizeof(struct keyBind_t)); E.key_binds, ++E.number_of_keybinds * sizeof(struct keyBind_t));
@@ -74,13 +75,14 @@ Lisp mapKey(Lisp args, LispError *e, LispContext ctx) {
struct prefix_t prefix = find_prefix(prefix_name); struct prefix_t prefix = find_prefix(prefix_name);
E.key_binds[E.number_of_keybinds - 1].prefix_id = prefix.prefix_id; E.key_binds[E.number_of_keybinds - 1].prefix_id = prefix.prefix_id;
return lisp_null(); return lisp_null();
} }
/** /**
* @brief Lisp function to move cursor in a specified direction * @brief Lisp function to move cursor in a specified direction
* @details Moves the editor cursor up, down, left, or right based on direction string. * @details Moves the editor cursor up, down, left, or right based on direction
* string.
* @param args Lisp list with one argument: direction string * @param args Lisp list with one argument: direction string
* - "u": up, "d": down, "r": right, "l": left * - "u": up, "d": down, "r": right, "l": left
* @param e Error pointer for Lisp error handling * @param e Error pointer for Lisp error handling
@@ -106,7 +108,7 @@ Lisp moveCursor(Lisp args, LispError *e, LispContext ctx) {
is_in = editorMoveCursor(ARROW_LEFT); is_in = editorMoveCursor(ARROW_LEFT);
break; break;
} }
fprintf(stderr, "move lisp %d\n", is_in); appDebug("move lisp %d\n", is_in);
return lisp_make_bool(is_in); return lisp_make_bool(is_in);
} }
@@ -130,21 +132,20 @@ void free_structs(void) {
for (i = 0; i < E.number_of_buffer; ++i) { for (i = 0; i < E.number_of_buffer; ++i) {
free(E.buffers[i].filename); free(E.buffers[i].filename);
for (j = 0; j < E.buffers[i].numrows; ++j) { for (j = 0; j < E.buffers[i].numrows; ++j) {
free(E.buffers[i].row[j].render);
free(E.buffers[i].row[j].chars); free(E.buffers[i].row[j].chars);
} }
free(E.buffers[i].row); free(E.buffers[i].row);
} }
free(E.init_file_path); free(E.init_file_path);
fclose(E.fd_init_file); fclose(E.fd_init_file);
} }
/** /**
* @brief Lisp function to quit the editor * @brief Lisp function to quit the editor
* @details Closes editor with unsaved changes protection. Prompts user to confirm * @details Closes editor with unsaved changes protection. Prompts user to
* quit after multiple attempts if file is dirty. Cleans up resources and restores terminal. * confirm quit after multiple attempts if file is dirty. Cleans up resources
* and restores terminal.
* @param args Lisp arguments (unused) * @param args Lisp arguments (unused)
* @param e Error pointer for Lisp error handling * @param e Error pointer for Lisp error handling
* @param ctx Lisp context * @param ctx Lisp context
@@ -182,10 +183,10 @@ Lisp editorQuit(Lisp args, LispError *e, LispContext ctx) {
Lisp l_editorSplitScreenVertical(Lisp args, LispError *e, LispContext ctx) { Lisp l_editorSplitScreenVertical(Lisp args, LispError *e, LispContext ctx) {
if (E.number_of_buffer >= 2) { if (E.number_of_buffer >= 2) {
splitScreenVertical(E.buffers[0].buffer_id, E.buffers[1].buffer_id); splitScreenVertical(E.buffers[0].buffer_id, E.buffers[1].buffer_id);
} else { } else {
editorSetStatusMessage("Need at least 2 buffers open"); editorSetStatusMessage("Need at least 2 buffers open");
} }
return lisp_null(); return lisp_null();
} }
@@ -222,9 +223,10 @@ Lisp l_editorInsertNewLine(Lisp args, LispError *e, LispContext ctx) {
* @note Uses E.constantes.TAB_LENGTH for indentation width * @note Uses E.constantes.TAB_LENGTH for indentation width
*/ */
Lisp l_editorInserTab(Lisp args, LispError *e, LispContext ctx) { Lisp l_editorInserTab(Lisp args, LispError *e, LispContext ctx) {
EditorPane *active = splitScreenGetActivePane();
for (int i = 0; i<E.constantes.TAB_LENGTH; ++i) { struct buffer_t *buf = bufferFindById(active->buffer_id);
bufferInsertChar(' '); for (int i = 0; i < E.constantes.TAB_LENGTH; ++i) {
bufferInsertBytes(" ", 1);
} }
return lisp_null(); return lisp_null();
@@ -240,7 +242,9 @@ Lisp l_editorInserTab(Lisp args, LispError *e, LispContext ctx) {
* @note Updates global editor state E * @note Updates global editor state E
*/ */
Lisp moveCursorBeginLine(Lisp args, LispError *e, LispContext ctx) { Lisp moveCursorBeginLine(Lisp args, LispError *e, LispContext ctx) {
E.layout.panes[E.layout.active_pane].cursor_x = 0; EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buf = bufferFindById(active->buffer_id);
buf->x = 0;
return lisp_null(); return lisp_null();
} }
@@ -256,9 +260,7 @@ Lisp moveCursorBeginLine(Lisp args, LispError *e, LispContext ctx) {
Lisp moveCursorEndLine(Lisp args, LispError *e, LispContext ctx) { Lisp moveCursorEndLine(Lisp args, LispError *e, LispContext ctx) {
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buf = bufferFindById(active->buffer_id); struct buffer_t *buf = bufferFindById(active->buffer_id);
if (active->cursor_y < buf->numrows) { buf->x = buf->row[buf->y].size;
active->cursor_x = buf->row[active->cursor_y].size;
}
return lisp_null(); return lisp_null();
} }
@@ -272,13 +274,14 @@ Lisp moveCursorEndLine(Lisp args, LispError *e, LispContext ctx) {
* @see editorDelChar() * @see editorDelChar()
*/ */
Lisp deletePreviousChar(Lisp args, LispError *e, LispContext ctx) { Lisp deletePreviousChar(Lisp args, LispError *e, LispContext ctx) {
bufferDelChar(); bufferDelBytes();
return lisp_null(); return lisp_null();
} }
/** /**
* @brief Lisp function to move cursor up by one screen * @brief Lisp function to move cursor up by one screen
* @details Scrolls up one full screen height, moving cursor to top of visible area. * @details Scrolls up one full screen height, moving cursor to top of visible
* area.
* @param args Lisp arguments (unused) * @param args Lisp arguments (unused)
* @param e Error pointer for Lisp error handling * @param e Error pointer for Lisp error handling
* @param ctx Lisp context * @param ctx Lisp context
@@ -288,7 +291,7 @@ Lisp deletePreviousChar(Lisp args, LispError *e, LispContext ctx) {
*/ */
Lisp editorMoveCursorPageUp(Lisp args, LispError *e, LispContext ctx) { Lisp editorMoveCursorPageUp(Lisp args, LispError *e, LispContext ctx) {
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
active->cursor_y = active->row_offset; active->cursor_y = active->y_offset;
int times = E.screenrows; int times = E.screenrows;
while (--times) { while (--times) {
editorMoveCursor(ARROW_UP); editorMoveCursor(ARROW_UP);
@@ -298,7 +301,8 @@ Lisp editorMoveCursorPageUp(Lisp args, LispError *e, LispContext ctx) {
/** /**
* @brief Lisp function to move cursor down by one screen * @brief Lisp function to move cursor down by one screen
* @details Scrolls down one full screen height, moving cursor to bottom of visible area. * @details Scrolls down one full screen height, moving cursor to bottom of
* visible area.
* @param args Lisp arguments (unused) * @param args Lisp arguments (unused)
* @param e Error pointer for Lisp error handling * @param e Error pointer for Lisp error handling
* @param ctx Lisp context * @param ctx Lisp context
@@ -309,7 +313,7 @@ Lisp editorMoveCursorPageUp(Lisp args, LispError *e, LispContext ctx) {
Lisp editorMoveCursorPageDown(Lisp args, LispError *e, LispContext ctx) { Lisp editorMoveCursorPageDown(Lisp args, LispError *e, LispContext ctx) {
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buffer = bufferFindById(active->buffer_id); struct buffer_t *buffer = bufferFindById(active->buffer_id);
active->cursor_y = active->row_offset + E.screenrows - 1; active->cursor_y = active->y_offset + E.screenrows - 1;
if (active->cursor_y > buffer->numrows) { if (active->cursor_y > buffer->numrows) {
active->cursor_y = buffer->numrows; active->cursor_y = buffer->numrows;
} }
@@ -334,20 +338,20 @@ Lisp editorMoveCursorPageDown(Lisp args, LispError *e, LispContext ctx) {
*/ */
Lisp editorOpenFile(Lisp args, LispError *e, LispContext ctx) { Lisp editorOpenFile(Lisp args, LispError *e, LispContext ctx) {
char *filename = editorPrompt("Open : %s", getenv("PWD"), 1); char *filename = editorPrompt("Open : %s", getenv("PWD"), 1);
if (filename){ if (filename) {
// editorOpen(filename); // editorOpen(filename);
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
active->buffer_id = bufferCreate(filename); active->buffer_id = bufferCreate(filename);
} }
free(filename); free(filename);
return lisp_null(); return lisp_null();
} }
/** /**
* @brief Lisp function to insert a character * @brief Lisp function to insert a character
* @details Extracts a character from Lisp string argument and inserts it at cursor. * @details Extracts a character from Lisp string argument and inserts it at
* cursor.
* @param args Lisp list with one string argument * @param args Lisp list with one string argument
* @param e Error pointer for Lisp error handling * @param e Error pointer for Lisp error handling
* @param ctx Lisp context * @param ctx Lisp context
@@ -355,8 +359,8 @@ Lisp editorOpenFile(Lisp args, LispError *e, LispContext ctx) {
* @note Uses first character of the string argument * @note Uses first character of the string argument
*/ */
Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx) { Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx) {
char c = lisp_string(lisp_car(args))[0]; char *src = lisp_string(lisp_car(args));
bufferInsertChar(c); bufferInsertBytes(src, strlen(src));
return lisp_null(); return lisp_null();
} }
@@ -373,14 +377,14 @@ Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx) {
*/ */
Lisp addPackage(Lisp args, LispError *e, LispContext ctx) { Lisp addPackage(Lisp args, LispError *e, LispContext ctx) {
const char *package_name = lisp_string(lisp_car(args)); const char *package_name = lisp_string(lisp_car(args));
fprintf(stderr, "%s\n", package_name); appDebug("%s\n", package_name);
char *package_dir = (char *)calloc(256, sizeof(char)); char *package_dir = (char *)calloc(256, sizeof(char));
FILE *fd_package = NULL; FILE *fd_package = NULL;
strcat(package_dir, getenv("HOME")); strcat(package_dir, getenv("HOME"));
strcat(package_dir, "/.beluga/packages/"); strcat(package_dir, "/.beluga/packages/");
strcat(package_dir, package_name); strcat(package_dir, package_name);
strcat(package_dir, "/init.lisp"); strcat(package_dir, "/init.lisp");
fprintf(stderr, "%s\n", package_dir); appDebug("%s\n", package_dir);
fd_package = fopen(package_dir, "r"); fd_package = fopen(package_dir, "r");
lisp_eval(lisp_read_file(fd_package, &E.ctx_error, E.ctx), &E.ctx_error, lisp_eval(lisp_read_file(fd_package, &E.ctx_error, E.ctx), &E.ctx_error,
E.ctx); E.ctx);
@@ -390,30 +394,13 @@ Lisp addPackage(Lisp args, LispError *e, LispContext ctx) {
return lisp_null(); return lisp_null();
} }
/**
* @brief Lisp function to delete the current row
* @details Removes the line at the current cursor position.
* @param args Lisp arguments (unused)
* @param e Error pointer for Lisp error handling
* @param ctx Lisp context
* @return lisp_null()
* @note Updates global editor state E
* @see editorDelRow()
*/
Lisp editorDelRow_L(Lisp args, LispError *e, LispContext ctx) {
EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buffer = bufferFindById(active->buffer_id);
bufferDelRow(buffer, active->cursor_y);
return lisp_null();
}
Lisp editorSwitchNextBuffer(Lisp args, LispError *e, LispContext ctx) { Lisp editorSwitchNextBuffer(Lisp args, LispError *e, LispContext ctx) {
fprintf(stderr, "switch buffer\n"); appDebug("switch buffer\n");
if (E.number_of_buffer > 0) { if (E.number_of_buffer > 0) {
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
int next_idx = (active->buffer_id + 1) % E.number_of_buffer; int next_idx = (active->buffer_id + 1) % E.number_of_buffer;
active->buffer_id = next_idx; active->buffer_id = next_idx;
} }
return lisp_null(); return lisp_null();
} }
@@ -440,7 +427,7 @@ Lisp editorUnifiedPanes(Lisp args, LispError *e, LispContext ctx) {
* @see editorFind() * @see editorFind()
*/ */
Lisp bufferFind_L(Lisp args, LispError *e, LispContext ctx) { Lisp bufferFind_L(Lisp args, LispError *e, LispContext ctx) {
fprintf(stderr, "LispFind\n"); appDebug("LispFind\n");
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buffer = bufferFindById(active->buffer_id); struct buffer_t *buffer = bufferFindById(active->buffer_id);
bufferFind(buffer); bufferFind(buffer);
@@ -449,8 +436,8 @@ Lisp bufferFind_L(Lisp args, LispError *e, LispContext ctx) {
/** /**
* @brief Lisp function to read character at cursor * @brief Lisp function to read character at cursor
* @details Returns the character at the current cursor position as a Lisp character. * @details Returns the character at the current cursor position as a Lisp
* Returns 'a' if at end of line. * character. Returns 'a' if at end of line.
* @param args Lisp arguments (unused) * @param args Lisp arguments (unused)
* @param e Error pointer for Lisp error handling * @param e Error pointer for Lisp error handling
* @param ctx Lisp context * @param ctx Lisp context
@@ -460,11 +447,10 @@ Lisp editorReadChar_L(Lisp args, LispError *e, LispContext ctx) {
Lisp returned_char; Lisp returned_char;
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buffer = bufferFindById(active->buffer_id); struct buffer_t *buffer = bufferFindById(active->buffer_id);
if (buffer->row[active->cursor_y].render[active->cursor_x] == 0) { if (buffer->row[buffer->y].chars[buffer->x] == 0) {
returned_char = lisp_make_char('a'); returned_char = lisp_make_char('a');
} else { } else {
returned_char = lisp_make_char(buffer->row[buffer->y].chars[buffer->x]);
returned_char = lisp_make_char(buffer->row[active->cursor_y].render[active->cursor_x]);
} }
return returned_char; return returned_char;
} }
@@ -488,7 +474,7 @@ Lisp editorSetPrefix(Lisp args, LispError *e, LispContext ctx) {
struct prefix_t prefix = find_prefix(prefix_name); struct prefix_t prefix = find_prefix(prefix_name);
E.prefix_state = prefix.prefix_id; E.prefix_state = prefix.prefix_id;
editorSetStatusMessage("prefix %s", prefix.prefix_name); editorSetStatusMessage("prefix %s", prefix.prefix_name);
fprintf(stderr, "%s set\n", prefix_name); appDebug("%s set\n", prefix_name);
return lisp_null(); return lisp_null();
} }
+96 -38
View File
@@ -1,8 +1,13 @@
#include "../include/editor_op.h" #include "../include/editor_op.h"
#include <stdarg.h>
#include "../include/row_op.h" #include "../include/row_op.h"
#include "include/buffer.h" #include "../include/buffer.h"
#include "include/data.h" #include "../include/data.h"
#include "include/split_screen.h" #include "../include/split_screen.h"
#include "../include/terminal.h"
#include "../include/utf8.h"
extern struct editorConfig E; extern struct editorConfig E;
@@ -17,46 +22,99 @@ extern struct editorConfig E;
* @note Updates global editor state E (status_msg, status_msg_time) * @note Updates global editor state E (status_msg, status_msg_time)
* @see editorDrawMessageBar() * @see editorDrawMessageBar()
*/ */
void editorSetStatusMessage(const char *fmt, ...) { void editorSetStatusMessage(const char* fmt, ...)
va_list ap; {
va_start(ap, fmt); va_list ap;
vsnprintf(E.status_msg, sizeof(E.status_msg), fmt, ap); va_start(ap, fmt);
va_end(ap); vsnprintf(E.status_msg, E.screencols, fmt, ap);
E.status_msg_time = time(NULL); va_end(ap);
E.status_msg_time = time(NULL);
} }
void bufferInsertChar(int c) { void bufferInsertBytes(char* src, int n)
EditorPane *active = splitScreenGetActivePane(); {
struct buffer_t *buf = bufferFindById(active->buffer_id); appDebug("bufferInsertBytes \r\n");
if (active->cursor_y == buf->numrows) { EditorPane* active = splitScreenGetActivePane();
bufferInsertRow(buf, buf->numrows, "", 0); struct buffer_t* buf = bufferFindById(active->buffer_id);
if (buf->y == buf->numrows)
{
bufferInsertRow(buf, buf->numrows, "", 0);
} }
bufferRowInsertChar(buf, &buf->row[active->cursor_y], active->cursor_x, c); bufferRowInsertBytes(buf, &buf->row[buf->y], buf->x, src, n);
active->cursor_x++; buf->x += n;
} }
void bufferInsertNewLine() { void bufferDelBytes(void)
/* {
* Add new line and place the cursor at the beginning of it EditorPane* active = splitScreenGetActivePane();
*/ struct buffer_t* buf = bufferFindById(active->buffer_id);
fprintf(stderr, "Inserting new line\n");
/* Nothing to delete */
if (buf->numrows == 0) return;
if (buf->x == 0 && buf->y == 0) return;
/* Use row_offset, not col_offset, for row indexing */
row_t* r = &buf->row[buf->y];
if (buf->x > 0)
{
int byte_end = editorRowCxToByte(r, buf->x);
int byte_start = editorRowCxToByte(r, buf->x - 1);
int char_width = byte_end - byte_start; /* byte width of the character */
bufferRowDelByte(buf, r, byte_start, char_width);
E.dirty = 1;
}
else
{
/* Merge current row into the previous one */
row_t* prev = &buf->row[buf->y - 1]; // FIX: was buf->y (same as r)
int prev_char_count = editorRowCharCount(prev, prev->size);
bufferRowInsertBytes(buf, prev, prev->size, r->chars, r->size);
free(r->chars);
r->chars = NULL;
memmove(&buf->row[buf->y],
&buf->row[buf->y + 1],
sizeof(row_t) * (buf->numrows - buf->y - 1));
buf->numrows--;
active->cursor_x = prev_char_count;
buf->x = prev_char_count;
active->cursor_y--;
buf->y--;
E.dirty = 1;
}
}
void bufferInsertNewLine(void) {
appDebug("Inserting new line\n");
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buf = bufferFindById(active->buffer_id); struct buffer_t *buf = bufferFindById(active->buffer_id);
frow *row;
if (!active->cursor_x) {
bufferInsertRow(buf, active->cursor_y, "", 0);
} else {
row = &buf->row[active->cursor_y];
bufferInsertRow(buf, active->cursor_y + 1, &row->chars[active->cursor_x],
row->size - active->cursor_x);
row = &buf->row[active->cursor_y];
row->size = active->cursor_x;
row->chars[row->size] = '\0';
bufferUpdatfrow(row);
}
++active->cursor_y;
active->cursor_x = 0;
fprintf(stderr, "Insert new line done\n");
}
appDebug("buf x %d\n", buf->x);
if (buf->y >= buf->numrows) {
/* Cursor is past the last row: just append a blank line */
bufferInsertRow(buf, buf->numrows, "", 0);
} else {
row_t *row = &buf->row[buf->y];
/* Insert the tail (from cursor to end) as a new row below */
bufferInsertRow(buf, buf->y + 1, &row->chars[buf->x], row->size - buf->x);
/* Re-fetch: realloc inside bufferInsertRow may have moved the array */
row = &buf->row[buf->y];
/* Truncate the current row at the cursor */
row->size = buf->x;
row->chars[row->size] = '\0';
/* Do NOT touch row->cap — the allocation is still valid */
}
buf->y++;
buf->x = 0;
appDebug("Insert new line done\n");
}
+14 -45
View File
@@ -33,12 +33,10 @@ void editorCloseFile(void) {
struct buffer_t *buf = bufferFindById(active->buffer_id); struct buffer_t *buf = bufferFindById(active->buffer_id);
active->cursor_x = 0; active->cursor_x = 0;
active->cursor_y = 0; active->cursor_y = 0;
active->rx = 0; active->x_offset = 0;
active->row_offset = 0; active->y_offset = 0;
active->col_offset = 0;
for (int i = 0; i < buf->numrows; ++i) { for (int i = 0; i < buf->numrows; ++i) {
free(buf->row[i].chars); free(buf->row[i].chars);
free(buf->row[i].render);
} }
buf->numrows = 0; buf->numrows = 0;
free(buf->row); free(buf->row);
@@ -69,14 +67,17 @@ void editorOpen(struct buffer_t* buffer) {
die("fopen"); die("fopen");
char *line = NULL; char *line = NULL;
size_t line_cap = 0; size_t line_cap;
ssize_t line_len; ssize_t line_len;
rewind(fp);
while ((line_len = getline(&line, &line_cap, fp)) != -1) { while ((line_len = getline(&line, &line_cap, fp)) != -1) {
while (line_len > 0 && while (line_len > 0 &&
(line[line_len - 1] == '\n' || line[line_len - 1] == '\r')) { (line[line_len - 1] == '\n' || line[line_len - 1] == '\r')) {
--line_len; --line_len;
} }
appDebug("line %s\n", line);
bufferInsertRow(buffer, buffer->numrows, line, line_len); bufferInsertRow(buffer, buffer->numrows, line, line_len);
free(line); free(line);
line = NULL; line = NULL;
@@ -100,7 +101,6 @@ void editorSave() {
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buffer = bufferFindById(active->buffer_id); struct buffer_t *buffer = bufferFindById(active->buffer_id);
int len; int len;
char *buf;
int fd; int fd;
if (buffer->filename == NULL) { if (buffer->filename == NULL) {
buffer->filename = editorPrompt("Save as: %s (ESC to cancel)", "", 1); buffer->filename = editorPrompt("Save as: %s (ESC to cancel)", "", 1);
@@ -109,52 +109,21 @@ void editorSave() {
return; return;
} }
} }
buf = bufferRowsToString(buffer, &len);
fd = open(buffer->filename, O_RDWR | O_CREAT, 0644); fd = open(buffer->filename, O_RDWR | O_CREAT, 0644);
if (fd != -1) { if (fd != -1) {
if (ftruncate(fd, len) != -1) { for (int i = 0; i < buffer->numrows; ++i)
if (write(fd, buf, len) == len) { {
len = strlen(buffer->row[i].chars);
if (write(fd, buffer->row[i].chars, len) != len) {
close(fd); close(fd);
free(buf);
E.dirty = 0; E.dirty = 0;
editorSetStatusMessage("%d bytes written to disk", len); editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
return; return;
} }
write(fd, "\n", 1);
} }
close(fd); close(fd);
} }
free(buf); editorSetStatusMessage("File saved");
editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
} }
/**
* @brief Searches for a string in the document
* @details Prompts user for a search query, then searches forward from current
* cursor position. Updates cursor position to the first match found.
* @note Updates global editor state E (cursor position, row_offset)
* @note Search is case-sensitive and operates on rendered line content
* @note Searches begin from the line after current cursor position
* @see editorPrompt()
* @see editorRowRxToCx()
*/
void bufferFind(struct buffer_t *buf) {
fprintf(stderr, "searching\n");
char *query = editorPrompt("Search: %s (ESC to cancel)", "", 0);
EditorPane *active = splitScreenGetActivePane();
if (query == NULL)
return;
int i;
for (i = active->cursor_y + 1; i < buf->numrows; i++) {
frow *row = &buf->row[i];
char *match = strstr(row->render, query);
if (match) {
active->cursor_y = i;
active->cursor_x = bufferRowRxToCx(row, match - row->render);
buf->row_offset = buf->numrows;
break;
}
}
free(query);
}
+13 -5
View File
@@ -17,7 +17,7 @@ struct editorConfig;
void registerBuiltin(char *key_sequence, LispCFunc f) { void registerBuiltin(char *key_sequence, LispCFunc f) {
lisp_env_define(E.ctx.p->env, lisp_make_symbol(key_sequence, E.ctx), lisp_env_define(E.ctx.p->env, lisp_make_symbol(key_sequence, E.ctx),
lisp_make_func(f), E.ctx); lisp_make_func(f), E.ctx);
} }
void initBuiltins() { void initBuiltins() {
@@ -35,7 +35,6 @@ void initBuiltins() {
registerBuiltin("editor-open-file", editorOpenFile); registerBuiltin("editor-open-file", editorOpenFile);
registerBuiltin("editor-insert-char", editorPrintC); registerBuiltin("editor-insert-char", editorPrintC);
registerBuiltin("add-package", addPackage); registerBuiltin("add-package", addPackage);
registerBuiltin("editor-del-row", editorDelRow_L);
registerBuiltin("buffer-find", bufferFind_L); registerBuiltin("buffer-find", bufferFind_L);
registerBuiltin("editor-read-char", editorReadChar_L); registerBuiltin("editor-read-char", editorReadChar_L);
registerBuiltin("add-prefix", editorPrefix); registerBuiltin("add-prefix", editorPrefix);
@@ -50,6 +49,7 @@ void initBuiltins() {
void initConfig() { void initConfig() {
E.ctx = lisp_init(); E.ctx = lisp_init();
E.ctx.p->err_port = fopen("log.err", "w");
E.env = lisp_env(E.ctx); E.env = lisp_env(E.ctx);
lisp_lib_load(E.ctx); lisp_lib_load(E.ctx);
// Init builtins lisp functions // Init builtins lisp functions
@@ -90,23 +90,31 @@ void initEditor() {
if (getWindowSize(&E.screenrows, &E.screencols) == -1) { if (getWindowSize(&E.screenrows, &E.screencols) == -1) {
die("getWindowSize"); die("getWindowSize");
} }
appDebug("%d %d\n", E.screenrows, E.screencols);
E.screenrows -= 2; E.screenrows -= 2;
// Init graphics variables // Init graphics variables
splitScreenInit(); splitScreenInit();
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
E.cursor_x = 0;
E.cursor_y = 0;
active->cursor_x = 0; active->cursor_x = 0;
active->cursor_y = 0; active->cursor_y = 0;
active->rx = 0; active->origin_x = 0;
active->row_offset = 0; active->origin_y = 0;
active->col_offset = 0; active->width = E.screencols;
active->height = E.screenrows;
E.init_file_path = (char *)calloc(256, sizeof(char)); E.init_file_path = (char *)calloc(256, sizeof(char));
strcat(E.init_file_path, getenv("HOME")); strcat(E.init_file_path, getenv("HOME"));
strcat(E.init_file_path, "/.beluga/config/init.lisp"); strcat(E.init_file_path, "/.beluga/config/init.lisp");
appDebug("%s\n", E.init_file_path);
E.fd_init_file = fopen(E.init_file_path, "r"); E.fd_init_file = fopen(E.init_file_path, "r");
// Status bar // Status bar
E.status_msg = (char *)calloc(E.screencols, sizeof(char));
E.status_msg[0] = '\0'; E.status_msg[0] = '\0';
E.status_msg_time = 0; E.status_msg_time = 0;
+50 -33
View File
@@ -5,6 +5,7 @@
#include "include/data.h" #include "include/data.h"
#include "include/buffer.h" #include "include/buffer.h"
#include "include/data.h" #include "include/data.h"
#include "include/row_op.h"
#include "include/split_screen.h" #include "include/split_screen.h"
#include <ctype.h> #include <ctype.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -16,6 +17,9 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include "include/terminal.h"
#include "include/utf8.h"
extern struct editorConfig E; extern struct editorConfig E;
/** /**
@@ -40,7 +44,7 @@ extern struct editorConfig E;
const char *file_completion(const char *path) { const char *file_completion(const char *path) {
DIR *dir; DIR *dir;
struct dirent *entry; struct dirent *entry;
char directory[128]; char directory[256];
char predict[128]; char predict[128];
const char *last_slash; const char *last_slash;
int predict_len = 0; int predict_len = 0;
@@ -48,8 +52,8 @@ const char *file_completion(const char *path) {
// path is a directory // path is a directory
if (path[strlen(path) - 1] == '/') { if (path[strlen(path) - 1] == '/') {
fprintf(stderr, "[FILE COMP] is dir\n"); appDebug("[FILE COMP] is dir\n");
strncpy(directory, path, 128); strncpy(directory, path, 256);
} }
// Find dir name // Find dir name
@@ -61,9 +65,9 @@ const char *file_completion(const char *path) {
strncpy(predict, last_slash + 1, predict_len); strncpy(predict, last_slash + 1, predict_len);
directory[dir_len] = '\0'; directory[dir_len] = '\0';
predict[predict_len] = '\0'; predict[predict_len] = '\0';
fprintf(stderr, "%s %s\n", directory, predict); appDebug("%s %s\n", directory, predict);
} else { } else {
fprintf(stderr, "[FILE COMP] dir not found\n"); appDebug("[FILE COMP] dir not found\n");
return strdup(path); return strdup(path);
} }
@@ -73,7 +77,7 @@ const char *file_completion(const char *path) {
while ((entry = readdir(dir)) != NULL) { while ((entry = readdir(dir)) != NULL) {
if (strncmp(entry->d_name, predict, predict_len) == 0) { if (strncmp(entry->d_name, predict, predict_len) == 0) {
static char full_path[512]; static char full_path[1024];
snprintf(full_path, sizeof(full_path), "%s%s", directory, entry->d_name); snprintf(full_path, sizeof(full_path), "%s%s", directory, entry->d_name);
struct stat st; struct stat st;
@@ -90,7 +94,7 @@ const char *file_completion(const char *path) {
closedir(dir); closedir(dir);
dir = NULL; dir = NULL;
free(entry); free(entry);
fprintf(stderr, "[FILE COMP] no entries\n"); appDebug("[FILE COMP] no entries\n");
return strdup(path); return strdup(path);
} }
@@ -109,7 +113,8 @@ const char *file_completion(const char *path) {
* @note Uses editorReadKey() for input and editorRefreshScreen() for display * @note Uses editorReadKey() for input and editorRefreshScreen() for display
*/ */
char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) { char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) {
size_t buf_size = 128; size_t buf_size = 256;
appDebug("[FILE COMP] %s %d\n", placeHolder, strlen(placeHolder));
char *buf = malloc(buf_size); char *buf = malloc(buf_size);
size_t buf_len = 0; size_t buf_len = 0;
int c = 0; int c = 0;
@@ -135,18 +140,18 @@ char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) {
return buf; return buf;
} }
} else if (bPathMode && c == '\t') { } else if (bPathMode && c == '\t') {
char path[128]; char path[256];
char *pwd; char *pwd;
if (buf[0] != '/') { if (buf[0] != '/') {
pwd = getenv("PWD"); pwd = getenv("PWD");
fprintf(stderr, "%s\n", pwd); appDebug("%s\n", pwd);
memcpy(path, pwd, strlen(pwd)); memcpy(path, pwd, strlen(pwd));
path[strlen(pwd)] = '/'; path[strlen(pwd)] = '/';
strncat(path, buf, buf_len); strncat(path, buf, buf_len);
} else { } else {
strcpy(path, buf); strcpy(path, buf);
} }
memset(buf, 0, 128); memset(buf, 0, 256);
buf_len = 0; buf_len = 0;
char * buf_complete = (char *) file_completion(path); char * buf_complete = (char *) file_completion(path);
strcpy(buf, buf_complete); strcpy(buf, buf_complete);
@@ -154,7 +159,7 @@ char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) {
buf_len = strlen(buf); buf_len = strlen(buf);
buf[buf_len] = '\0'; buf[buf_len] = '\0';
} else if (!iscntrl(c) && c < 128) { } else if (!iscntrl(c) && c < 256) {
if (buf_len == buf_size - 1) { if (buf_len == buf_size - 1) {
buf_size *= 2; buf_size *= 2;
buf = realloc(buf, buf_size); buf = realloc(buf, buf_size);
@@ -177,40 +182,49 @@ char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) {
int editorMoveCursor(int key) { int editorMoveCursor(int key) {
EditorPane *active = splitScreenGetActivePane(); EditorPane *active = splitScreenGetActivePane();
struct buffer_t *buf = bufferFindById(active->buffer_id); struct buffer_t *buf = bufferFindById(active->buffer_id);
frow *row = (active->cursor_y + active->row_offset >= buf->numrows) ? NULL : &buf->row[active->cursor_y + active->row_offset]; row_t *row = &buf->row[buf->y];
int row_len;
int x = active->cursor_x + active->col_offset;
int y = active->cursor_y + active->row_offset;
switch (key) { switch (key) {
case ARROW_RIGHT: case ARROW_RIGHT:
if (row && x < row->size) { if (row && buf->x < row->size) {
active->cursor_x++; int len = utf8Seqlen(row->chars[buf->x]);
buf->x += len;
} else if (row && y == row->size) { } else if (row && buf->y < buf->numrows) {
active->cursor_y++; buf->y++;
active->cursor_x = 0; buf->x = 0;
} }
break; break;
case ARROW_DOWN: case ARROW_DOWN:
if (y < buf->numrows) { if (buf->y < buf->numrows) {
active->cursor_y++; buf->y++;
} }
break; break;
case ARROW_UP: case ARROW_UP:
if (y != 0) { if (buf->y != 0) {
--active->cursor_y; --buf->y;
} }
break; break;
case ARROW_LEFT: case ARROW_LEFT:
if (x != 0) { if (buf->x != 0) {
--active->cursor_x; --buf->x;
} else if (y > 0) { } else if (buf->y > 0) {
--active->cursor_y; --buf->y;
active->cursor_x = buf->row[y].size; buf->x = buf->row[buf->y].size;
} }
break; break;
} }
/*
fprintf(stderr, "acx: %d acy %d aox %d aoy %d bx %d by %d ah %d aw %d\n",
active->cursor_x,
active->cursor_y,
active->x_offset,
active->y_offset,
buf->x,
buf->y,
active->height,
active->width
);
*/
return 1; return 1;
@@ -228,7 +242,7 @@ int editorMoveCursor(int key) {
int executeKeyBind(char *key_sequence) { int executeKeyBind(char *key_sequence) {
int i; int i;
int previous_state = 0; int previous_state = 0;
fprintf(stderr, "pressed %s\n", key_sequence); appDebug("pressed %s\n", key_sequence);
for (i = 0; i < E.number_of_keybinds; ++i) { for (i = 0; i < E.number_of_keybinds; ++i) {
if (!strcmp(key_sequence, E.key_binds[i].key_sequence)) { if (!strcmp(key_sequence, E.key_binds[i].key_sequence)) {
if (E.prefix_state != E.key_binds[i].prefix_id) { if (E.prefix_state != E.key_binds[i].prefix_id) {
@@ -256,10 +270,13 @@ int executeKeyBind(char *key_sequence) {
*/ */
void editorProcessKeypress() { void editorProcessKeypress() {
int c = editorReadKey(); int c = editorReadKey();
char key_sequence[8];
if (executeKeyBind(key_to_string(c))) { if (executeKeyBind(key_to_string(c))) {
return; return;
} }
bufferInsertChar(c); int seq_len = utf8Encode(c, key_sequence);
appDebug("key seq : %s\n", key_sequence);
bufferInsertBytes(key_sequence, seq_len);
E.quit_times_buffer = E.constantes.QUIT_TIMES; E.quit_times_buffer = E.constantes.QUIT_TIMES;
} }
+282 -205
View File
@@ -13,6 +13,7 @@
#include "../include/row_op.h" #include "../include/row_op.h"
#include "../include/split_screen.h" #include "../include/split_screen.h"
#include "../include/syntax_highlighter.h" #include "../include/syntax_highlighter.h"
#include "../include/terminal.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -23,127 +24,135 @@ extern struct editorConfig E;
/** /**
* @brief Renders a single pane with its buffer content * @brief Renders a single pane with its buffer content
*/ */
static void editorDrawPane(struct abuf *ab, EditorPane *pane) { static void editorDrawPane(struct abuf* ab, EditorPane* pane)
if (pane == NULL || pane->buffer_id < 0) {
return; int file_row;
struct buffer_t *buf = bufferFindById(pane->buffer_id);
if (buf == NULL)
return;
// Draw content for this pane
for (int y = 0; y < pane->height; y++) {
int file_row = y + pane->row_offset;
// Position cursor at start of pane row
char pos_buf[32]; char pos_buf[32];
int pos_len = snprintf(pos_buf, sizeof(pos_buf), "\x1b[%d;%dH", int pos_len;
pane->start_row + y + 1, pane->start_col + 1); int chars_printed;
abAppend(ab, pos_buf, pos_len); int start_offset;
int byte_len_to_print;
int bytes_to_print;
char* highlighted;
char welcome[80];
int welcome_len;
int padding;
// Apply background color (6 bytes for RGB format) if (pane == NULL || pane->buffer_id < 0)
abAppend(ab, E.theme.BACKGROUND_COLOR, strlen(E.theme.BACKGROUND_COLOR)); return;
int chars_printed = 0; const struct buffer_t* buf = bufferFindById(pane->buffer_id);
if (buf == NULL)
return;
if (file_row >= buf->numrows) { // Draw all pane
// Empty line - show tilde for (int y = 0; y < pane->height; y++)
if (buf->numrows == 0 && y == pane->height / 3) { {
char welcome[80]; file_row = y + pane->y_offset;
int welcome_len =
snprintf(welcome, sizeof(welcome), "Buffer %d", pane->buffer_id);
if (welcome_len > pane->width)
welcome_len = pane->width;
int padding = (pane->width - welcome_len) / 2; // Set cursor at start of pane row
if (padding) { pos_len = snprintf(pos_buf, sizeof(pos_buf), "\x1b[%d;%dH",
abAppend(ab, "~", 1); pane->origin_y + y + 1, pane->origin_x + 1);
chars_printed++; abAppend(ab, pos_buf, pos_len);
padding--;
// Apply background color (6 bytes for RGB format)
abAppend(ab, E.theme.BACKGROUND_COLOR, strlen(E.theme.BACKGROUND_COLOR));
chars_printed = 0;
// pane line is out of buffer
if (file_row >= buf->numrows)
{
// Empty line - show tilde
abAppend(ab, "~", 1);
for (int i = 0;
i < pane->width - 1;
++i)
{
abAppend(ab, " ", 1);
}
} }
while (padding-- && chars_printed < pane->width) { else
abAppend(ab, " ", 1); {
chars_printed++; start_offset = pane->x_offset;
if (buf->filename[strlen(buf->filename) - 1] == 'c')
{
// Render line with syntax highlighting, constrain to pane width
highlighted = highlight_line(
&buf->row[file_row].chars[pane->x_offset], &byte_len_to_print);
// Print only up to pane width
abAppend(ab, highlighted, byte_len_to_print);
free(highlighted);
}
else
{
// Render basic line
bytes_to_print =
buf->row[file_row].size - pane->x_offset < pane->width
? buf->row[file_row].size - pane->x_offset
: pane->width;
abAppend(ab, &buf->row[file_row].chars[pane->x_offset], bytes_to_print);
}
// Fill remaining space with background color to pane width
for (int i = 0;
i < pane->width - editorRowCharCount(&buf->row[file_row], pane->width) + pane->x_offset;
++i)
{
abAppend(ab, " ", 1);
}
} }
abAppend(ab, welcome, welcome_len);
chars_printed += welcome_len;
} else {
abAppend(ab, "~", 1);
chars_printed++;
}
} else {
// Render line with syntax highlighting, constrain to pane width
int start_offset = pane->col_offset;
int visible_len = buf->row[file_row].rsize - start_offset;
if (visible_len < 0)
visible_len = 0;
if (visible_len > pane->width)
visible_len = pane->width;
if (buf->filename[strlen(buf->filename) - 1] == 'c') {
int byte_len_to_print;
char *highlighted = highlight_line(
&buf->row[file_row].render[start_offset], &byte_len_to_print);
// Print only up to pane width
abAppend(ab, highlighted, byte_len_to_print);
free(highlighted);
} else {
abAppend(ab, &buf->row[file_row].render[start_offset], buf->row[file_row].rsize);
}
chars_printed = visible_len;
} }
// Fill remaining space with background color to pane width
abAppend(ab, E.theme.BACKGROUND_COLOR, strlen(E.theme.BACKGROUND_COLOR));
while (chars_printed < pane->width) {
abAppend(ab, " ", 1);
chars_printed++;
}
// Restore background color at end of line
}
} }
/** /**
* @brief Renders all panes based on current split configuration * @brief Renders all panes based on current split configuration
*/ */
static void editorDrawAllPanes(struct abuf *ab) { static void editorDrawAllPanes(struct abuf* ab)
ScreenLayout *layout = splitScreenGetLayout(); {
const ScreenLayout* layout = splitScreenGetLayout();
if (layout->num_panes == 1) { if (layout->num_panes == 1)
// Single pane fullscreen {
editorDrawPane(ab, &layout->panes[0]); // Single pane fullscreen
} else if (layout->num_panes == 2) { editorDrawPane(ab, &layout->panes[0]);
// Draw both panes }
for (int i = 0; i < 2; i++) { else if (layout->num_panes == 2)
editorDrawPane(ab, &layout->panes[i]); {
// Draw both panes
// Draw pane border/divider if not the last pane for (int i = 0; i < 2; i++)
if (layout->mode == SPLIT_VERTICAL && i == 0) { {
// Draw vertical divider editorDrawPane(ab, &layout->panes[i]);
int divider_col = layout->panes[0].width;
for (int y = 0; y < layout->panes[0].height; y++) { // Draw pane border/divider if not the last pane
char pos_buf[32]; if (layout->mode == SPLIT_VERTICAL && i == 0)
snprintf(pos_buf, sizeof(pos_buf), "\x1b[%d;%dH", y + 1, divider_col); {
abAppend(ab, pos_buf, strlen(pos_buf)); // Draw vertical divider
abAppend(ab, "\x1b[1m|\x1b[0m", 9); // Bold pipe divider int divider_col = layout->panes[0].width;
} for (int y = 0; y < layout->panes[0].height; y++)
} else if (layout->mode == SPLIT_HORIZONTAL && i == 0) { {
// Draw horizontal divider char pos_buf[32];
int divider_row = layout->panes[0].height; snprintf(pos_buf, sizeof(pos_buf), "\x1b[%d;%dH", y + 1, divider_col);
char pos_buf[32]; abAppend(ab, pos_buf, strlen(pos_buf));
snprintf(pos_buf, sizeof(pos_buf), "\x1b[%d;%dH", divider_row + 1, 1); abAppend(ab, "\x1b[1m|\x1b[0m", 9); // Bold pipe divider
abAppend(ab, pos_buf, strlen(pos_buf)); }
for (int x = 0; x < E.screencols; x++) { }
abAppend(ab, "\x1b[1m-\x1b[0m", 9); // Bold dash divider else if (layout->mode == SPLIT_HORIZONTAL && i == 0)
} {
} // Draw horizontal divider
int divider_row = layout->panes[0].height;
char pos_buf[32];
snprintf(pos_buf, sizeof(pos_buf), "\x1b[%d;%dH", divider_row + 1, 1);
abAppend(ab, pos_buf, strlen(pos_buf));
for (int x = 0; x < E.screencols; x++)
{
abAppend(ab, "\x1b[1m-\x1b[0m", 9); // Bold dash divider
}
}
}
} }
}
} }
/** /**
@@ -153,35 +162,89 @@ static void editorDrawAllPanes(struct abuf *ab) {
* @note Updates global editor state E * @note Updates global editor state E
* @see editorRowCxToRx() * @see editorRowCxToRx()
*/ */
void editorScroll() { void editorScroll()
EditorPane *active = splitScreenGetActivePane(); {
struct buffer_t *buf = bufferFindById(active->buffer_id); EditorPane* active = splitScreenGetActivePane();
active->rx = active->cursor_x; struct buffer_t* buf = bufferFindById(active->buffer_id);
int rel_x, rel_y;
fprintf(stderr, "%d %d / %d %d\n", active->cursor_x, active->col_offset, // compute relative coordinates
active->cursor_y, active->row_offset); rel_x = editorRowCharCount(&buf->row[buf->y], buf->x);
appDebug("counting %d\n", rel_x);
rel_y = buf->y;
if (active->cursor_x < 0) { appDebug("%d %d / %d %d\n", active->cursor_x, active->x_offset,
active->cursor_x = 0; active->cursor_y, active->y_offset);
active->col_offset = active->col_offset == 0 ? 0 : --active->col_offset;
}
if (active->cursor_y < 0) { while (rel_x != active->cursor_x + active->x_offset ||
active->cursor_y = 0; rel_y != active->cursor_y + active->y_offset)
active->row_offset = active->row_offset == 0 ? 0 : --active->row_offset; {
} if (rel_x < active->cursor_x + active->x_offset)
{
// LEFT
if (active->cursor_x == 0 && active->x_offset)
{
active->x_offset--;
} else
{
active->cursor_x--;
}
} else
{
// RIGHT
if (rel_x > active->cursor_x + active->x_offset)
{
if (active->cursor_x == active->width - 1)
{
active->x_offset++;
} else
{
active->cursor_x++;
}
}
}
if (active->cursor_x == active->width) { if (rel_y < active->cursor_y + active->y_offset)
{
if (active->cursor_y == 0 && active->y_offset)
{
active->y_offset--;
} else
{
active->cursor_y--;
}
}
active->cursor_x--; if (rel_y > active->cursor_y + active->y_offset)
active->col_offset++; {
} if (active->cursor_y == active->height - 1)
{
active->y_offset++;
} else
{
active->cursor_y++;
}
}
if (active->cursor_y == active->height) { }
}
active->cursor_y--; char * basename(char *path)
active->row_offset++; {
} int len = strlen(path);
int flag=0;
for(int i=len-1; i>0; i--)
{
if(path[i]=='/' )
{
flag=1;
path = path+i+1;
break;
}
}
return path;
} }
/** /**
@@ -192,55 +255,63 @@ void editorScroll() {
* @param ab Pointer to append buffer structure for accumulating output * @param ab Pointer to append buffer structure for accumulating output
* @note Uses ANSI escape codes for color inversion * @note Uses ANSI escape codes for color inversion
*/ */
void editorDrawStatusBar(struct abuf *ab) { void editorDrawStatusBar(struct abuf* ab)
int len, render_len; {
char status[80], render_status[80]; // TO MODIFY
EditorPane *active = splitScreenGetActivePane(); int len, render_len;
struct buffer_t *buf = bufferFindById(active->buffer_id); char status[E.screencols], render_status[E.screencols * 4];
EditorPane* active = splitScreenGetActivePane();
struct buffer_t* buf = bufferFindById(active->buffer_id);
abAppend(ab, "\x1b[7m", 4); // inverting colors abAppend(ab, "\x1b[7m", 4); // inverting colors
const char *mode_str = ""; const char* mode_str = "";
ScreenLayout *layout = splitScreenGetLayout(); ScreenLayout* layout = splitScreenGetLayout();
if (layout->mode == SPLIT_VERTICAL) if (layout->mode == SPLIT_VERTICAL)
mode_str = " [V-SPLIT]"; mode_str = " [V-SPLIT]";
else if (layout->mode == SPLIT_HORIZONTAL) else if (layout->mode == SPLIT_HORIZONTAL)
mode_str = " [H-SPLIT]"; mode_str = " [H-SPLIT]";
// Build buffer status showing all buffers with dirty indicators // Build buffer status showing all buffers with dirty indicators
char buf_status[200] = ""; char buf_status[1024] = "";
int offset = 0; int offset = 0;
for (int i = 0; i < E.number_of_buffer; i++) { for (int i = 0; i < E.number_of_buffer; i++)
struct buffer_t *b = &E.buffers[i]; {
char marker = (b->buffer_id == active->buffer_id) ? '>' : ' '; struct buffer_t* b = &E.buffers[i];
char dirty_marker = b->dirty ? '*' : ' '; char marker = (b->buffer_id == active->buffer_id) ? '>' : ' ';
offset += snprintf(&buf_status[offset], sizeof(buf_status) - offset, char dirty_marker = b->dirty ? '*' : ' ';
"%c%d:%s%c ", marker, b->buffer_id, offset += snprintf(&buf_status[offset], sizeof(buf_status) - offset,
b->filename ? b->filename : "[No Name]", dirty_marker); "%c%d:%s%c ", marker, b->buffer_id,
} b->filename ? basename(b->filename) : "[No Name]", dirty_marker);
len = snprintf(status, sizeof(status), "%s%s", buf_status, mode_str);
render_len = snprintf(render_status, sizeof(render_status), "%d/%d",
active->cursor_y + 1, buf->numrows);
if (len > E.screencols) {
len = E.screencols;
}
abAppend(ab, status, len);
while (len < E.screencols) {
if (E.screencols - len == render_len) {
abAppend(ab, render_status, render_len);
break;
} else {
abAppend(ab, " ", 1);
++len;
} }
}
abAppend(ab, "\x1b[m", 3); // normal text mode len = snprintf(status, sizeof(status), "%s%s", buf_status, mode_str);
abAppend(ab, "\r\n", 2);
render_len = snprintf(render_status, sizeof(render_status), "%d/%d",
active->cursor_y + 1, buf->numrows);
if (len > E.screencols)
{
len = E.screencols;
}
abAppend(ab, status, len);
while (len < E.screencols)
{
if (E.screencols - len == render_len + 1)
{
abAppend(ab, render_status, render_len);
break;
}
else
{
abAppend(ab, " ", 1);
++len;
}
}
abAppend(ab, "\x1b[m", 3); // normal text mode
abAppend(ab, "\r\n", 2);
} }
/** /**
@@ -250,15 +321,18 @@ void editorDrawStatusBar(struct abuf *ab) {
* @param ab Pointer to append buffer structure for accumulating output * @param ab Pointer to append buffer structure for accumulating output
* @note Messages are set by editorSetStatusMessage() * @note Messages are set by editorSetStatusMessage()
*/ */
void editorDrawMessageBar(struct abuf *ab) { void editorDrawMessageBar(struct abuf* ab)
int msg_len = strlen(E.status_msg); {
abAppend(ab, ERASE_END_LINE, 3); int msg_len = strlen(E.status_msg);
if (msg_len > E.screencols) { abAppend(ab, ERASE_END_LINE, 3);
msg_len = E.screencols; if (msg_len > E.screencols)
} {
if (msg_len && time(NULL) - E.status_msg_time < 5) { msg_len = E.screencols;
abAppend(ab, E.status_msg, msg_len); }
} if (msg_len && time(NULL) - E.status_msg_time < 5)
{
abAppend(ab, E.status_msg, msg_len);
}
} }
/** /**
@@ -272,33 +346,36 @@ void editorDrawMessageBar(struct abuf *ab) {
* @see editorDrawMessageBar() * @see editorDrawMessageBar()
*/ */
void editorRefreshScreen() { void editorRefreshScreen()
struct abuf ab = ABUF_INIT; {
char buf[32]; struct abuf ab = ABUF_INIT;
char buf[32];
abAppend(&ab, HIDE_CURSOR, 6); abAppend(&ab, HIDE_CURSOR, 6);
abAppend(&ab, CURSOR_TOP_LEFT, 3); abAppend(&ab, CURSOR_TOP_LEFT, 3);
abAppend(&ab, E.theme.BACKGROUND_COLOR, abAppend(&ab, E.theme.BACKGROUND_COLOR,
strlen(E.theme.BACKGROUND_COLOR)); // RGB background is 12 bytes strlen(E.theme.BACKGROUND_COLOR)); // RGB background is 12 bytes
// Draw all panes // Draw all panes
editorScroll(); editorScroll();
editorDrawAllPanes(&ab); editorDrawAllPanes(&ab);
// Draw status bar and message bar // Draw status bar and message bar
editorDrawStatusBar(&ab); editorDrawStatusBar(&ab);
editorDrawMessageBar(&ab); editorDrawMessageBar(&ab);
// Position cursor in active pane // Position cursor in active pane
EditorPane *active = splitScreenGetActivePane(); EditorPane* active = splitScreenGetActivePane();
if (active != NULL) { struct buffer_t* buffer = bufferGetCurrent();
snprintf(buf, sizeof(buf), "\x1b[%d;%dH", if (active != NULL)
active->cursor_y + active->start_row + 1, {
active->cursor_x + active->start_col + 1); snprintf(buf, sizeof(buf), "\x1b[%d;%dH",
abAppend(&ab, buf, strlen(buf)); active->cursor_y + active->origin_y + 1,
} active->cursor_x + active->origin_x + 1);
abAppend(&ab, buf, strlen(buf));
}
abAppend(&ab, SHOW_CURSOR, 6); abAppend(&ab, SHOW_CURSOR, 6);
write(STDOUT_FILENO, ab.b, ab.len); write(STDOUT_FILENO, ab.b, ab.len);
abFree(&ab); abFree(&ab);
} }
+39 -40
View File
@@ -6,44 +6,46 @@
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include "include/terminal.h"
#include "include/utf8.h" #include "include/utf8.h"
extern struct editorConfig E; extern struct editorConfig E;
void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len) { void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len) {
if (at < 0 || at > buffer->numrows)
return;
if (at < 0 || at > buffer->numrows) { row_t *tmp = realloc(buffer->row, sizeof(row_t) * (buffer->numrows + 1));
if (!tmp)
return; return;
}
row_t *tmp = (row_t *)realloc(buffer->row, sizeof(row_t) * (buffer->numrows + 1));
if (!tmp) {
return;
}
buffer->row = tmp; buffer->row = tmp;
memmove(&buffer->row[at + 1], &buffer->row[at], sizeof(row_t) * (buffer->numrows - at));
buffer->row[at].size = len; /* Shift existing rows to make room at 'at' — no at++ */
buffer->row[at].cap = len + 1; if (at < buffer->numrows) {
memmove(&buffer->row[at + 1], &buffer->row[at],
sizeof(row_t) * (buffer->numrows - at)); /* not -at+1 */
}
buffer->row[at].size = len;
buffer->row[at].cap = len + 1;
buffer->row[at].chars = malloc(len + 1); buffer->row[at].chars = malloc(len + 1);
if (!buffer->row[at].chars)
return;
memcpy(buffer->row[at].chars, s, len); memcpy(buffer->row[at].chars, s, len);
buffer->row[at].chars[len] = '\n'; buffer->row[at].chars[len] = '\0'; /* always NUL-terminate */
buffer->numrows++;
++buffer->numrows; buffer->dirty++;
++buffer->dirty;
} }
void bufferFreeRow(row_t *row) { void bufferFreeRow(row_t *row) { free(row->chars); }
free(row->chars);
}
int editorRowCxToByte(const row_t *row, int cursor_x) { int editorRowCxToByte(const row_t *row, int cursor_x) {
int i = 0, col = 0; int i = 0, col = 0;
while (col < cursor_x && i < row->size) { while (col < cursor_x && i < row->size) {
int sl = utf8Seqlen((unsigned char)row->chars[i]); int sl = utf8Seqlen((unsigned char)row->chars[i]);
if (sl < 1) sl = 1; if (sl < 1)
sl = 1;
col++; col++;
i += sl; i += sl;
} }
@@ -54,7 +56,8 @@ int editorRowCxToByte(const row_t *row, int cursor_x) {
* \fn editorRowInsertChar(erow *row, int at, int c) * \fn editorRowInsertChar(erow *row, int at, int c)
* \param at Index of where we want to insert the char */ * \param at Index of where we want to insert the char */
void bufferRowInsertBytes(struct buffer_t *buffer, row_t *row, int at, char *src, int n) { void bufferRowInsertBytes(struct buffer_t *buffer, row_t *row, int at,
char *src, int n) {
if (buffer->state == READ_ONLY) if (buffer->state == READ_ONLY)
return; return;
if (row->size + n + 1 > row->cap) { if (row->size + n + 1 > row->cap) {
@@ -65,35 +68,31 @@ void bufferRowInsertBytes(struct buffer_t *buffer, row_t *row, int at, char *src
memcpy(row->chars + at, src, n); memcpy(row->chars + at, src, n);
row->size += n; row->size += n;
row->chars = realloc(row->chars, row->size + 2); row->chars = realloc(row->chars, row->size + 2);
memmove(&row->chars[at + 1], &row->chars[at], row->size - at + 1);
++row->size;
++buffer->dirty; ++buffer->dirty;
} }
/** /**
* \fn bufferRowDelChar(struct bufferConfig *E, frow *frow, int at) * \fn bufferRowDelChar(struct bufferConfig *E, frow *frow, int at)
* \brief Delete the a char at the chosen position on the given row * \brief Delete the a char at the chosen position on the given row
* \param at Index of the char to delete * \param at Index of the char to delete
* \param row Row on operation is made */ * \param row Row on operation is made */
void bufferRowDelByte(struct buffer_t *buffer, row_t *row, int at, int n) void bufferRowDelByte(struct buffer_t *buffer, row_t *row, int at, int n) {
{ if (at < 0 || at >= row->size)
if (at < 0 || at >= row->size) {
return; return;
memmove(row->chars + at, row->chars + at + n, row->size - at - n); memmove(row->chars + at, row->chars + at + n, row->size - at - n);
row->size -= n; row->size -= n;
row->chars[row->size] = '\0'; row->chars[row->size] = '\0';
} buffer->x -= n;
++buffer->dirty; ++buffer->dirty;
} }
int editorRowCharCount(row_t *row) int editorRowCharCount(row_t *row, int x) {
{ int n = 0, i = 0;
int n = 0, i = 0; while (i < x && i < row->size) {
while (i < row->size) { int sl = utf8Seqlen((unsigned char)row->chars[i]);
int sl = utf8Seqlen((unsigned char)row->chars[i]); if (sl < 1)
if (sl < 1) sl = 1; sl = 1;
n++; i += sl; n++;
} i += sl;
return n;
} }
return n;
}
+48 -48
View File
@@ -18,19 +18,19 @@ void splitScreenInit(void) {
E.layout.mode = SPLIT_NONE; E.layout.mode = SPLIT_NONE;
E.layout.num_panes = 1; E.layout.num_panes = 1;
E.layout.active_pane = 0; E.layout.active_pane = 0;
E.layout.panes = malloc(sizeof(EditorPane) * 2); E.layout.panes = malloc(sizeof(EditorPane) * 2);
// Initialize single fullscreen pane // Initialize single fullscreen pane
E.layout.panes[0].buffer_id = -1; // No buffer for now E.layout.panes[0].buffer_id = -1; // No buffer for now
E.layout.panes[0].start_row = 0; E.layout.panes[0].origin_y = 0;
E.layout.panes[0].start_col = 0; E.layout.panes[0].origin_x = 0;
E.layout.panes[0].height = E.screenrows - 2; // Leave room for status bar E.layout.panes[0].height = E.screenrows - 2; // Leave room for status bar
E.layout.panes[0].width = E.screencols; E.layout.panes[0].width = E.screencols;
E.layout.panes[0].cursor_x = 0; E.layout.panes[0].cursor_x = 0;
E.layout.panes[0].cursor_y = 0; E.layout.panes[0].cursor_y = 0;
E.layout.panes[0].row_offset = 0; E.layout.panes[0].y_offset = 0;
E.layout.panes[0].col_offset = 0; E.layout.panes[0].x_offset = 0;
E.layout.panes[0].is_active = 1; E.layout.panes[0].is_active = 1;
} }
@@ -47,40 +47,40 @@ int splitScreenVertical(int buffer_id_left, int buffer_id_right) {
editorSetStatusMessage("Error: invalid buffer IDs"); editorSetStatusMessage("Error: invalid buffer IDs");
return -1; return -1;
} }
// Reallocate panes array // Reallocate panes array
E.layout.panes = realloc(E.layout.panes, sizeof(EditorPane) * 2); E.layout.panes = realloc(E.layout.panes, sizeof(EditorPane) * 2);
E.layout.mode = SPLIT_VERTICAL; E.layout.mode = SPLIT_VERTICAL;
E.layout.num_panes = 2; E.layout.num_panes = 2;
E.layout.active_pane = 0; E.layout.active_pane = 0;
int half_width = E.screencols / 2; int half_width = E.screencols / 2;
int pane_height = E.screenrows - 2; // Leave room for status bar int pane_height = E.screenrows; // Leave room for status bar
// Left pane // Left pane
E.layout.panes[0].buffer_id = buffer_id_left; E.layout.panes[0].buffer_id = buffer_id_left;
E.layout.panes[0].start_row = 0; E.layout.panes[0].origin_y = 0;
E.layout.panes[0].start_col = 0; E.layout.panes[0].origin_x = 0;
E.layout.panes[0].height = pane_height; E.layout.panes[0].height = pane_height;
E.layout.panes[0].width = half_width; E.layout.panes[0].width = half_width;
E.layout.panes[0].cursor_x = 0; E.layout.panes[0].cursor_x = 0;
E.layout.panes[0].cursor_y = 0; E.layout.panes[0].cursor_y = 0;
E.layout.panes[0].row_offset = 0; E.layout.panes[0].y_offset = 0;
E.layout.panes[0].col_offset = 0; E.layout.panes[0].x_offset = 0;
E.layout.panes[0].is_active = 1; E.layout.panes[0].is_active = 1;
// Right pane // Right pane
E.layout.panes[1].buffer_id = buffer_id_right; E.layout.panes[1].buffer_id = buffer_id_right;
E.layout.panes[1].start_row = 0; E.layout.panes[1].origin_y = 0;
E.layout.panes[1].start_col = half_width; E.layout.panes[1].origin_x = half_width;
E.layout.panes[1].height = pane_height; E.layout.panes[1].height = pane_height;
E.layout.panes[1].width = E.screencols - half_width; E.layout.panes[1].width = E.screencols - half_width;
E.layout.panes[1].cursor_x = 0; E.layout.panes[1].cursor_x = 0;
E.layout.panes[1].cursor_y = 0; E.layout.panes[1].cursor_y = 0;
E.layout.panes[1].row_offset = 0; E.layout.panes[1].y_offset = 0;
E.layout.panes[1].col_offset = 0; E.layout.panes[1].x_offset = 0;
E.layout.panes[1].is_active = 0; E.layout.panes[1].is_active = 0;
editorSetStatusMessage("Vertical split: %d | %d", buffer_id_left, buffer_id_right); editorSetStatusMessage("Vertical split: %d | %d", buffer_id_left, buffer_id_right);
return 0; return 0;
} }
@@ -98,39 +98,39 @@ int splitScreenHorizontal(int buffer_id_top, int buffer_id_bottom) {
editorSetStatusMessage("Error: invalid buffer IDs"); editorSetStatusMessage("Error: invalid buffer IDs");
return -1; return -1;
} }
// Reallocate panes array // Reallocate panes array
E.layout.panes = realloc(E.layout.panes, sizeof(EditorPane) * 2); E.layout.panes = realloc(E.layout.panes, sizeof(EditorPane) * 2);
E.layout.mode = SPLIT_HORIZONTAL; E.layout.mode = SPLIT_HORIZONTAL;
E.layout.num_panes = 2; E.layout.num_panes = 2;
E.layout.active_pane = 0; E.layout.active_pane = 0;
int half_height = (E.screenrows - 2) / 2; // Account for status bar int half_height = (E.screenrows - 2) / 2; // Account for status bar
// Top pane // Top pane
E.layout.panes[0].buffer_id = buffer_id_top; E.layout.panes[0].buffer_id = buffer_id_top;
E.layout.panes[0].start_row = 0; E.layout.panes[0].origin_y = 0;
E.layout.panes[0].start_col = 0; E.layout.panes[0].origin_x = 0;
E.layout.panes[0].height = half_height; E.layout.panes[0].height = half_height;
E.layout.panes[0].width = E.screencols; E.layout.panes[0].width = E.screencols;
E.layout.panes[0].cursor_x = 0; E.layout.panes[0].cursor_x = 0;
E.layout.panes[0].cursor_y = 0; E.layout.panes[0].cursor_y = 0;
E.layout.panes[0].row_offset = 0; E.layout.panes[0].y_offset = 0;
E.layout.panes[0].col_offset = 0; E.layout.panes[0].x_offset = 0;
E.layout.panes[0].is_active = 1; E.layout.panes[0].is_active = 1;
// Bottom pane // Bottom pane
E.layout.panes[1].buffer_id = buffer_id_bottom; E.layout.panes[1].buffer_id = buffer_id_bottom;
E.layout.panes[1].start_row = half_height; E.layout.panes[1].origin_y = half_height;
E.layout.panes[1].start_col = 0; E.layout.panes[1].origin_x = 0;
E.layout.panes[1].height = E.screenrows - 2 - half_height; E.layout.panes[1].height = E.screenrows - 2 - half_height;
E.layout.panes[1].width = E.screencols; E.layout.panes[1].width = E.screencols;
E.layout.panes[1].cursor_x = 0; E.layout.panes[1].cursor_x = 0;
E.layout.panes[1].cursor_y = 0; E.layout.panes[1].cursor_y = 0;
E.layout.panes[1].row_offset = 0; E.layout.panes[1].x_offset = 0;
E.layout.panes[1].col_offset = 0; E.layout.panes[1].y_offset = 0;
E.layout.panes[1].is_active = 0; E.layout.panes[1].is_active = 0;
editorSetStatusMessage("Horizontal split: %d / %d", buffer_id_top, buffer_id_bottom); editorSetStatusMessage("Horizontal split: %d / %d", buffer_id_top, buffer_id_bottom);
return 0; return 0;
} }
@@ -142,13 +142,13 @@ void splitScreenUnify(void) {
E.layout.mode = SPLIT_NONE; E.layout.mode = SPLIT_NONE;
E.layout.num_panes = 1; E.layout.num_panes = 1;
E.layout.active_pane = 0; E.layout.active_pane = 0;
E.layout.panes[0].start_row = 0; E.layout.panes[0].origin_x = 0;
E.layout.panes[0].start_col = 0; E.layout.panes[0].origin_y = 0;
E.layout.panes[0].height = E.screenrows - 2; E.layout.panes[0].height = E.screenrows;
E.layout.panes[0].width = E.screencols; E.layout.panes[0].width = E.screencols;
E.layout.panes[0].is_active = 1; E.layout.panes[0].is_active = 1;
editorSetStatusMessage("Unified view"); editorSetStatusMessage("Unified view");
} }
@@ -161,17 +161,17 @@ int splitScreenSwitchPane(void) {
editorSetStatusMessage("No split to switch"); editorSetStatusMessage("No split to switch");
return -1; return -1;
} }
// Deactivate current pane // Deactivate current pane
E.layout.panes[E.layout.active_pane].is_active = 0; E.layout.panes[E.layout.active_pane].is_active = 0;
// Move to next pane // Move to next pane
E.layout.active_pane = (E.layout.active_pane + 1) % E.layout.num_panes; E.layout.active_pane = (E.layout.active_pane + 1) % E.layout.num_panes;
// Activate new pane // Activate new pane
E.layout.panes[E.layout.active_pane].is_active = 1; E.layout.panes[E.layout.active_pane].is_active = 1;
editorSetStatusMessage("Switched to pane %d (buffer %d)", editorSetStatusMessage("Switched to pane %d (buffer %d)",
E.layout.active_pane, E.layout.active_pane,
E.layout.panes[E.layout.active_pane].buffer_id); E.layout.panes[E.layout.active_pane].buffer_id);
return 0; return 0;
@@ -187,15 +187,15 @@ int splitScreenSetPaneBuffer(int buffer_id) {
editorSetStatusMessage("Error: invalid buffer ID"); editorSetStatusMessage("Error: invalid buffer ID");
return -1; return -1;
} }
EditorPane *active = &E.layout.panes[E.layout.active_pane]; EditorPane *active = &E.layout.panes[E.layout.active_pane];
active->buffer_id = buffer_id; active->buffer_id = buffer_id;
active->cursor_x = 0; active->cursor_x = 0;
active->cursor_y = 0; active->cursor_y = 0;
active->row_offset = 0; active->origin_x = 0;
active->col_offset = 0; active->origin_y = 0;
editorSetStatusMessage("Pane %d now showing buffer %d", editorSetStatusMessage("Pane %d now showing buffer %d",
E.layout.active_pane, buffer_id); E.layout.active_pane, buffer_id);
return 0; return 0;
} }
+80 -29
View File
@@ -1,5 +1,6 @@
#include "../include/syntax_highlighter.h" #include "../include/syntax_highlighter.h"
#include "../include/data.h" #include "../include/data.h"
#include "../include/utf8.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -18,10 +19,52 @@ const char *c_types[] = {"int", "char", "float", "double",
"void", "long", "short", "unsigned", "void", "long", "short", "unsigned",
"signed", "bool", NULL}; "signed", "bool", NULL};
// Returns the byte length of the UTF-8 character starting at s.
// Never returns 0 for a non-NUL byte, so callers won't infinite-loop.
static int utf8_char_len(const char *s)
{
unsigned char c = (unsigned char)*s;
if (c == 0) return 0;
if (c < 0x80) return 1;
if ((c & 0xE0) == 0xC0) return 2;
if ((c & 0xF0) == 0xE0) return 3;
if ((c & 0xF8) == 0xF0) return 4;
return 1; // continuation byte or invalid — advance 1 to avoid infinite loop
}
// Copy one full UTF-8 character from src+i into dst+pos, advance both indices.
static void copy_utf8_char(char *dst, int *dst_pos, const char *src, int *src_pos)
{
int len = utf8_char_len(&src[*src_pos]);
for (int b = 0; b < len; b++)
dst[(*dst_pos)++] = src[(*src_pos)++];
}
// Check if character is alphanumeric or underscore // Check if character is alphanumeric or underscore
int is_word_char(char c) { int is_word_char(const char *s)
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || {
(c >= '0' && c <= '9') || c == '_' || c == '#'; uint32_t cp = utf8Decode(&s);
if ((cp >= 'a' && cp <= 'z') || (cp >= 'A' && cp <= 'Z') ||
(cp >= '0' && cp <= '9') || cp == '_' || cp == '#')
return 1;
if (cp == 0xFFFD) return 0;
if (cp >= 0x00C0 && cp <= 0x017F) return 1;
if (cp >= 0x0370 && cp <= 0x03FF) return 1;
if (cp >= 0x0400 && cp <= 0x04FF) return 1;
if (cp >= 0x0600 && cp <= 0x06FF) return 1;
if (cp >= 0x05D0 && cp <= 0x05EA) return 1;
if (cp >= 0x0900 && cp <= 0x097F) return 1;
if (cp >= 0x4E00 && cp <= 0x9FFF) return 1;
if ((cp >= 0x3040 && cp <= 0x309F) ||
(cp >= 0x30A0 && cp <= 0x30FF)) return 1;
if (cp >= 0xAC00 && cp <= 0xD7A3) return 1;
if ((cp >= 0x0660 && cp <= 0x0669) ||
(cp >= 0x06F0 && cp <= 0x06F9)) return 1;
return 0;
} }
// Check if string is a keyword // Check if string is a keyword
@@ -65,26 +108,29 @@ int comment_section = 0;
// Highlight a line of C code and return the highlighted string // Highlight a line of C code and return the highlighted string
// Returns a newly allocated string that must be freed by the caller // Returns a newly allocated string that must be freed by the caller
char *highlight_line(const char *line, int *length) { char *highlight_line(const char *line, int *length) {
char *result = malloc(1024); // Allocate space for result // Each byte can expand to at most (color_prefix + 4 bytes + color_reset).
// Allocate generously based on line length to avoid overflow.
int line_len = strlen(line);
int buf_size = line_len * 32 + 256;
char *result = malloc(buf_size);
int result_pos = 0; int result_pos = 0;
int i = 0; int i = 0;
while (line[i] != '\0' && line[i] != '\n') { while (line[i] != '\0' && line[i] != '\n') {
// Skip whitespace // Skip whitespace — copy full UTF-8 char (whitespace is always ASCII,
// but using copy_utf8_char keeps the pattern consistent)
if (line[i] == ' ' || line[i] == '\t') { if (line[i] == ' ' || line[i] == '\t') {
result[result_pos++] = line[i++]; copy_utf8_char(result, &result_pos, line, &i);
continue; continue;
} }
if (comment_section) { if (comment_section) {
result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT); result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT);
while (line[i] != '\0' && line[i] != '\n') { while (line[i] != '\0' && line[i] != '\n') {
if (line[i] == '*' && line[i + 1] == '/') {
if (line[i] == '*' && line[i + 1] == '/') { comment_section = 0;
comment_section = 0; }
} copy_utf8_char(result, &result_pos, line, &i);
result[result_pos++] = line[i++];
} }
result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET);
continue; continue;
@@ -94,14 +140,14 @@ char *highlight_line(const char *line, int *length) {
if (line[i] == '/' && line[i + 1] == '/') { if (line[i] == '/' && line[i + 1] == '/') {
result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT); result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT);
while (line[i] != '\0' && line[i] != '\n') { while (line[i] != '\0' && line[i] != '\n') {
result[result_pos++] = line[i++]; copy_utf8_char(result, &result_pos, line, &i);
} }
result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET);
continue; continue;
} }
// Handle block comments // Handle block comments
if ((line[i] == '/' && line[i + 1] == '*')) { if (line[i] == '/' && line[i + 1] == '*') {
comment_section = 1; comment_section = 1;
result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT); result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_COMMENT);
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
@@ -110,9 +156,10 @@ char *highlight_line(const char *line, int *length) {
if (line[i] == '*' && line[i + 1] == '/') { if (line[i] == '*' && line[i + 1] == '/') {
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
comment_section = 0;
break; break;
} }
result[result_pos++] = line[i++]; copy_utf8_char(result, &result_pos, line, &i);
} }
result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET);
continue; continue;
@@ -125,9 +172,9 @@ char *highlight_line(const char *line, int *length) {
while (line[i] != '\0' && line[i] != '"') { while (line[i] != '\0' && line[i] != '"') {
if (line[i] == '\\') { if (line[i] == '\\') {
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
result[result_pos++] = line[i++]; copy_utf8_char(result, &result_pos, line, &i);
} else { } else {
result[result_pos++] = line[i++]; copy_utf8_char(result, &result_pos, line, &i);
} }
} }
if (line[i] == '"') if (line[i] == '"')
@@ -143,9 +190,9 @@ char *highlight_line(const char *line, int *length) {
while (line[i] != '\0' && line[i] != '\'') { while (line[i] != '\0' && line[i] != '\'') {
if (line[i] == '\\') { if (line[i] == '\\') {
result[result_pos++] = line[i++]; result[result_pos++] = line[i++];
result[result_pos++] = line[i++]; copy_utf8_char(result, &result_pos, line, &i);
} else { } else {
result[result_pos++] = line[i++]; copy_utf8_char(result, &result_pos, line, &i);
} }
} }
if (line[i] == '\'') if (line[i] == '\'')
@@ -157,22 +204,26 @@ char *highlight_line(const char *line, int *length) {
// Handle numbers // Handle numbers
if (line[i] >= '0' && line[i] <= '9') { if (line[i] >= '0' && line[i] <= '9') {
result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_NUMBER); result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_NUMBER);
while (is_word_char(line[i]) || line[i] == '.') { while (is_word_char(&line[i]) || line[i] == '.') {
result[result_pos++] = line[i++]; copy_utf8_char(result, &result_pos, line, &i);
} }
result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET);
continue; continue;
} }
// Handle identifiers and keywords // Handle identifiers and keywords
if (is_word_char(line[i])) { if (is_word_char(&line[i])) {
int start = i; int start = i;
while (is_word_char(line[i])) // Advance by full UTF-8 character widths, not single bytes
i++; while (line[i] != '\0' && is_word_char(&line[i]))
i += utf8_char_len(&line[i]);
char word[256]; char word[256];
strncpy(word, &line[start], i - start); int word_len = i - start;
word[i - start] = '\0'; if (word_len >= (int)sizeof(word))
word_len = (int)sizeof(word) - 1;
strncpy(word, &line[start], word_len);
word[word_len] = '\0';
TokenType type = TOKEN_DEFAULT; TokenType type = TOKEN_DEFAULT;
if (is_keyword(word)) if (is_keyword(word))
@@ -185,9 +236,9 @@ char *highlight_line(const char *line, int *length) {
continue; continue;
} }
// Handle operators and other characters // Handle operators and other characters (including non-ASCII multi-byte)
result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_DEFAULT); result_pos += sprintf(&result[result_pos], "%s", E.theme.COLOR_DEFAULT);
result[result_pos++] = line[i++]; copy_utf8_char(result, &result_pos, line, &i);
result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET); result_pos += sprintf(&result[result_pos], "%s", COLOR_RESET);
} }
+13
View File
@@ -5,6 +5,7 @@
#include "../include/data.h" #include "../include/data.h"
#include "../include/define.h" #include "../include/define.h"
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
@@ -85,6 +86,7 @@ int editorReadKey() {
char c; char c;
/* read first byte — may be start of UTF-8 or escape */ /* read first byte — may be start of UTF-8 or escape */
while (read(STDIN_FILENO, &c, 1) != 1); while (read(STDIN_FILENO, &c, 1) != 1);
appDebug("f : %X\r\n", c);
if (c == '\x1b') { if (c == '\x1b') {
char seq[6]; char seq[6];
@@ -179,3 +181,14 @@ int getWindowSize(int *rows, int *cols) {
return 0; return 0;
} }
} }
void appDebug(const char *fmt, ...) {
#ifdef APP_DEBUG
va_list ap;
char message[256];
va_start(ap, fmt);
vsnprintf(message, 256, fmt, ap);
va_end(ap);
fprintf(stderr, "%s\n", message);
#endif
}