Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b6b3d1766 | |||
| 3d49a0e2eb |
@@ -86,3 +86,7 @@
|
||||
(map-key "\"" editor-split-screen-vertical "user")
|
||||
(map-key "o" editor-switch-next-pane "user")
|
||||
(map-key "*" editor-unify-panes "user")
|
||||
(map-key "CTRL-y" editor-paste "no-prefix")
|
||||
(map-key "CTRL-k" editor-cut-end-line "no-prefix")
|
||||
(map-key "a" editor-move-cursor-beg-buffer "user")
|
||||
(map-key "z" editor-move-cursor-end-buffer "user")
|
||||
|
||||
+7
-1
@@ -57,7 +57,13 @@ int bufferSaveAll(void);
|
||||
|
||||
void bufferFind(struct buffer_t *buf);
|
||||
void bufferFindReverse(struct buffer_t* buf);
|
||||
|
||||
void bufferInsertNewLine();
|
||||
void bufferInsertBytes(const char *src, int n);
|
||||
void bufferDelBytes();
|
||||
void bufferRowInsertBytes(struct buffer_t *buffer, row_t *row, int at, const char *src, int n);
|
||||
void bufferRowDelByte(struct buffer_t *buffer, row_t *row, int at, int n);
|
||||
void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len);
|
||||
void bufferFreeRow(row_t *row);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+6
-2
@@ -45,12 +45,16 @@ Lisp editorSwitchNextPane(Lisp args, LispError *e, LispContext ctx);
|
||||
Lisp editorUnifiedPanes(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
|
||||
Lisp editorPaste(Lisp args, LispError *e, LispContext ctx);
|
||||
Lisp editorCutEndLine(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
|
||||
|
||||
Lisp editorMoveBegBuffer(Lisp args, LispError *e, LispContext ctx);
|
||||
Lisp editorMoveEndBuffer(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
// Other
|
||||
|
||||
|
||||
|
||||
void free_structs(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,13 @@ typedef struct row {
|
||||
char *chars; /**< Characters of the line */
|
||||
} row_t;
|
||||
|
||||
typedef struct context_buffer_t
|
||||
{
|
||||
int editor_x, editor_y;
|
||||
int width, height;
|
||||
row_t *rows;
|
||||
} ContextBuffer;
|
||||
|
||||
/**
|
||||
* @brief Split modes for screen layout
|
||||
*/
|
||||
@@ -113,6 +120,8 @@ struct editorConfig {
|
||||
|
||||
row_t *rows; /**< Store all the rows printed */
|
||||
|
||||
ContextBuffer* context_buffers;
|
||||
|
||||
int dirty;
|
||||
|
||||
char *status_msg;
|
||||
|
||||
+12
-2
@@ -2,15 +2,17 @@
|
||||
#define DEFINE_H_
|
||||
|
||||
#define CTRL_KEY(k) ((k) & 0x1f)
|
||||
#define ALT(k) ((k) | 0x200) // set bit 9 to mark as Option combo
|
||||
|
||||
|
||||
#define ESCAPE '\x1b'
|
||||
#define CURSOR_TOP_LEFT "\x1b[H"
|
||||
#define HIDE_CURSOR "\x1b[?25l"
|
||||
#define SHOW_CURSOR "\x1b[?25h"
|
||||
#define ERASE_END_LINE "\x1b[K"
|
||||
#define TAB "\x9"
|
||||
#define TAB "\t"
|
||||
#define SPACE "\x20"
|
||||
// #define APP_DEBUG
|
||||
#define APP_DEBUG
|
||||
|
||||
enum editorKey_e {
|
||||
BACKSPACE = 127,
|
||||
@@ -29,4 +31,12 @@ enum editorKey_e {
|
||||
|
||||
#define BELUGA_VERSION "2.4"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define CLIPBOARD_COPY_CMD "pbcopy"
|
||||
#define CLIPBOARD_PASTE_CMD "pbpaste"
|
||||
#else
|
||||
#define CLIPBOARD_COPY_CMD "xclip -selection clipboard"
|
||||
#define CLIPBOARD_PASTE_CMD "xclip -selection clipboard -o"
|
||||
#endif
|
||||
|
||||
#endif // DEFINE_H_
|
||||
|
||||
+4
-3
@@ -3,10 +3,11 @@
|
||||
|
||||
#include "data.h"
|
||||
|
||||
void bufferInsertNewLine();
|
||||
void bufferInsertBytes(char *src, int n);
|
||||
void editorSetStatusMessage(const char *fmt, ...);
|
||||
void bufferDelBytes();
|
||||
int editorRowCharCount(row_t *row, int x);
|
||||
int editorRowCxToByte(const row_t *row, int cursor_x);
|
||||
char *editorGetClipboard(void);
|
||||
void editorSetClipboard(const char *text, int len);
|
||||
|
||||
|
||||
#endif // EDITOR_OP_H_
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#define FILE_IO_H_
|
||||
|
||||
#include "data.h"
|
||||
#include "row_op.h"
|
||||
#include "terminal.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
|
||||
char *editorPrompt(char *prompt, char * PlaceHolder, char bPathMode);
|
||||
|
||||
const char *file_completion(const char *path);
|
||||
const char *fileCompletion(const char *path);
|
||||
|
||||
int editorMoveCursor(int key);
|
||||
|
||||
|
||||
+3
-6
@@ -8,11 +8,8 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len);
|
||||
int editorRowCxToByte(const row_t *row, int cursor_x);
|
||||
void bufferFreeRow(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 bufferRowDelByte(struct buffer_t *buffer, row_t *row, int at, int n);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // ROW_OP_H_
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef SYNTAX_HIGHLIGHTER_H_
|
||||
#define SYNTAX_HIGHLIGHTER_H_
|
||||
|
||||
#include "color.h"
|
||||
|
||||
// Color codes that only affect foreground, preserving your background color
|
||||
#define COLOR_RESET "\x1b[39m" // Reset all (4 bytes)
|
||||
@@ -20,4 +19,3 @@ typedef enum {
|
||||
char *highlight_line(const char * line, int *length);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+1
-3
@@ -4,8 +4,6 @@
|
||||
|
||||
/* includes */
|
||||
|
||||
#include "data.h"
|
||||
#include "define.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -31,7 +29,7 @@ int getCursorPosition(int *rows, int *cols);
|
||||
|
||||
int getWindowSize(int *rows, int *cols);
|
||||
|
||||
char *key_to_string(int key);
|
||||
char *keyToString(int key);
|
||||
|
||||
void appDebug(const char *fmt, ...);
|
||||
|
||||
|
||||
@@ -11,13 +11,10 @@
|
||||
|
||||
#include "include/buffer.h"
|
||||
#include "include/split_screen.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "include/data.h"
|
||||
#include "include/file_io.h"
|
||||
#include "include/init.h"
|
||||
#include "include/input.h"
|
||||
#include "include/editor_op.h"
|
||||
|
||||
@@ -30,4 +30,6 @@ src_files = files(
|
||||
executable('beluga',
|
||||
src_files,
|
||||
dependencies: [m]
|
||||
)
|
||||
dependencies: [m]
|
||||
)
|
||||
|
||||
+153
-3
@@ -15,7 +15,6 @@
|
||||
|
||||
#include "include/input.h"
|
||||
|
||||
extern struct editorConfig E;
|
||||
|
||||
/**
|
||||
* @brief Finds a buffer by filename
|
||||
@@ -284,7 +283,6 @@ 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;
|
||||
@@ -306,7 +304,6 @@ void bufferFindReverse(struct buffer_t* buf)
|
||||
{
|
||||
appDebug("searching\n");
|
||||
char* query = editorPrompt("Reverse search: %s (ESC to cancel)", "", 0);
|
||||
EditorPane* active = splitScreenGetActivePane();
|
||||
|
||||
if (query == NULL)
|
||||
return;
|
||||
@@ -325,3 +322,156 @@ void bufferFindReverse(struct buffer_t* buf)
|
||||
}
|
||||
free(query);
|
||||
}
|
||||
|
||||
void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len) {
|
||||
if (at < 0 || at > buffer->numrows)
|
||||
return;
|
||||
|
||||
row_t *tmp = realloc(buffer->row, sizeof(row_t) * (buffer->numrows + 1));
|
||||
if (!tmp)
|
||||
return;
|
||||
buffer->row = tmp;
|
||||
|
||||
/* Shift existing rows to make room at 'at' — no at++ */
|
||||
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);
|
||||
if (!buffer->row[at].chars)
|
||||
return;
|
||||
memcpy(buffer->row[at].chars, s, len);
|
||||
buffer->row[at].chars[len] = '\0'; /* always NUL-terminate */
|
||||
|
||||
buffer->numrows++;
|
||||
buffer->dirty++;
|
||||
}
|
||||
|
||||
void bufferFreeRow(row_t *row) { free(row->chars); }
|
||||
|
||||
/**
|
||||
* \fn editorRowInsertChar(erow *row, int at, int c)
|
||||
* \param at Index of where we want to insert the char */
|
||||
|
||||
void bufferRowInsertBytes(struct buffer_t *buffer, row_t *row, int at,
|
||||
const char *src, int n) {
|
||||
if (buffer->state == READ_ONLY)
|
||||
return;
|
||||
if (row->size + n + 1 > row->cap) {
|
||||
row->cap = (row->size + n + 1) * 2;
|
||||
row->chars = realloc(row->chars, row->cap);
|
||||
}
|
||||
memmove(row->chars + at + n, row->chars + at, row->size - at);
|
||||
memcpy(row->chars + at, src, n);
|
||||
row->size += n;
|
||||
row->chars = realloc(row->chars, row->size + 2);
|
||||
++buffer->dirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn bufferRowDelChar(struct bufferConfig *E, frow *frow, int at)
|
||||
* \brief Delete the a char at the chosen position on the given row
|
||||
* \param at Index of the char to delete
|
||||
* \param row Row on operation is made */
|
||||
void bufferRowDelByte(struct buffer_t *buffer, row_t *row, int at, int n) {
|
||||
if (buffer->state == READ_ONLY)
|
||||
return;
|
||||
if (at < 0 || at >= row->size)
|
||||
return;
|
||||
memmove(row->chars + at, row->chars + at + n, row->size - at - n);
|
||||
row->size -= n;
|
||||
row->chars[row->size] = '\0';
|
||||
buffer->x -= n;
|
||||
++buffer->dirty;
|
||||
}
|
||||
|
||||
|
||||
void bufferInsertBytes(const char* src, int n)
|
||||
{
|
||||
appDebug("bufferInsertBytes \r\n");
|
||||
EditorPane* active = splitScreenGetActivePane();
|
||||
struct buffer_t* buf = bufferFindById(active->buffer_id);
|
||||
if (buf->y == buf->numrows)
|
||||
{
|
||||
bufferInsertRow(buf, buf->numrows, "", 0);
|
||||
}
|
||||
bufferRowInsertBytes(buf, &buf->row[buf->y], buf->x, src, n);
|
||||
buf->x += n;
|
||||
}
|
||||
|
||||
void bufferDelBytes(void)
|
||||
{
|
||||
EditorPane* active = splitScreenGetActivePane();
|
||||
struct buffer_t* buf = bufferFindById(active->buffer_id);
|
||||
|
||||
/* 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();
|
||||
struct buffer_t *buf = bufferFindById(active->buffer_id);
|
||||
|
||||
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");
|
||||
}
|
||||
+49
-4
@@ -13,8 +13,9 @@
|
||||
#include "../include/editor_op.h"
|
||||
#include "../include/file_io.h"
|
||||
#include "../include/input.h"
|
||||
#include "../include/row_op.h"
|
||||
#include "../include/terminal.h"
|
||||
#include "../include/split_screen.h"
|
||||
#include "../include/completion.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -223,8 +224,6 @@ Lisp l_editorInsertNewLine(Lisp args, LispError *e, LispContext ctx) {
|
||||
* @note Uses E.constantes.TAB_LENGTH for indentation width
|
||||
*/
|
||||
Lisp l_editorInserTab(Lisp args, LispError *e, LispContext ctx) {
|
||||
EditorPane *active = splitScreenGetActivePane();
|
||||
struct buffer_t *buf = bufferFindById(active->buffer_id);
|
||||
for (int i = 0; i < E.constantes.TAB_LENGTH; ++i) {
|
||||
bufferInsertBytes(" ", 1);
|
||||
}
|
||||
@@ -359,7 +358,7 @@ Lisp editorOpenFile(Lisp args, LispError *e, LispContext ctx) {
|
||||
* @note Uses first character of the string argument
|
||||
*/
|
||||
Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx) {
|
||||
char *src = lisp_string(lisp_car(args));
|
||||
const char *src = lisp_string(lisp_car(args));
|
||||
bufferInsertBytes(src, strlen(src));
|
||||
return lisp_null();
|
||||
}
|
||||
@@ -514,3 +513,49 @@ Lisp editorPrefix(Lisp args, LispError *e, LispContext ctx) {
|
||||
64);
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp editorPaste(Lisp args, LispError *e, LispContext ctx)
|
||||
{
|
||||
const char *char_to_paste = editorGetClipboard();
|
||||
appDebug("editor-paste, %s\n", char_to_paste);
|
||||
bufferInsertBytes(char_to_paste, (int) strlen(char_to_paste));
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp editorCutEndLine(Lisp args, LispError *e, LispContext ctx)
|
||||
{
|
||||
EditorPane *active = splitScreenGetActivePane();
|
||||
struct buffer_t *buffer = bufferFindById(active->buffer_id);
|
||||
int bytes_to_delete = buffer->row[buffer->y].size - buffer->x;
|
||||
editorSetClipboard(&buffer->row[buffer->y].chars[buffer->x], bytes_to_delete);
|
||||
buffer->x = buffer->row[buffer->y].size;
|
||||
while (bytes_to_delete--)
|
||||
{
|
||||
bufferDelBytes();
|
||||
}
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp editorMoveBegBuffer(Lisp args, LispError *e, LispContext ctx)
|
||||
{
|
||||
EditorPane *active = splitScreenGetActivePane();
|
||||
struct buffer_t *buffer = bufferFindById(active->buffer_id);
|
||||
buffer->x = 0;
|
||||
buffer->y = 0;
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp editorMoveEndBuffer(Lisp args, LispError *e, LispContext ctx)
|
||||
{
|
||||
EditorPane *active = splitScreenGetActivePane();
|
||||
struct buffer_t *buffer = bufferFindById(active->buffer_id);
|
||||
buffer->x = buffer->row[buffer->numrows-1].size;
|
||||
buffer->y = buffer->numrows-1;
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp editorAutoComplete(Lisp args, LispError *e, LispContext ctx)
|
||||
{
|
||||
createContextBuffer(E.cursor_x - 2, E.cursor_y + 1, "hello");
|
||||
return lisp_null();
|
||||
}
|
||||
+91
-81
@@ -31,90 +31,100 @@ void editorSetStatusMessage(const char* fmt, ...)
|
||||
E.status_msg_time = time(NULL);
|
||||
}
|
||||
|
||||
|
||||
void bufferInsertBytes(char* src, int n)
|
||||
{
|
||||
appDebug("bufferInsertBytes \r\n");
|
||||
EditorPane* active = splitScreenGetActivePane();
|
||||
struct buffer_t* buf = bufferFindById(active->buffer_id);
|
||||
if (buf->y == buf->numrows)
|
||||
{
|
||||
bufferInsertRow(buf, buf->numrows, "", 0);
|
||||
}
|
||||
bufferRowInsertBytes(buf, &buf->row[buf->y], buf->x, src, n);
|
||||
buf->x += n;
|
||||
}
|
||||
|
||||
void bufferDelBytes(void)
|
||||
{
|
||||
EditorPane* active = splitScreenGetActivePane();
|
||||
struct buffer_t* buf = bufferFindById(active->buffer_id);
|
||||
|
||||
/* 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");
|
||||
/**
|
||||
* @brief Moves the cursor based on arrow key input
|
||||
* @details Updates cursor position (E.cursor_x, E.cursor_y) based on the given
|
||||
* key direction. Handles line wrapping and boundary conditions. Prevents cursor
|
||||
* from exceeding line lengths.
|
||||
* @param key The arrow key code (ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT)
|
||||
* @return 1 if cursor movement was valid, 0 if cursor was constrained to line boundary
|
||||
* @note Updates global editor state E
|
||||
*/
|
||||
int editorMoveCursor(int key) {
|
||||
EditorPane *active = splitScreenGetActivePane();
|
||||
struct buffer_t *buf = bufferFindById(active->buffer_id);
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case ARROW_RIGHT:
|
||||
if (row && buf->x < row->size) {
|
||||
int len = utf8Seqlen(row->chars[buf->x]);
|
||||
buf->x += len;
|
||||
} else if (row && buf->y < buf->numrows) {
|
||||
buf->y++;
|
||||
buf->x = 0;
|
||||
appDebug("Insert new line done\n");
|
||||
}
|
||||
break;
|
||||
case ARROW_DOWN:
|
||||
if (buf->y < buf->numrows) {
|
||||
|
||||
buf->y++;
|
||||
}
|
||||
break;
|
||||
case ARROW_UP:
|
||||
if (buf->y != 0) {
|
||||
--buf->y;
|
||||
}
|
||||
break;
|
||||
case ARROW_LEFT:
|
||||
if (buf->x != 0) {
|
||||
--buf->x;
|
||||
} else if (buf->y > 0) {
|
||||
--buf->y;
|
||||
buf->x = buf->row[buf->y].size;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *editorGetClipboard(void) {
|
||||
FILE *pipe = popen(CLIPBOARD_PASTE_CMD, "r");
|
||||
if (!pipe) return NULL;
|
||||
|
||||
size_t cap = 4096;
|
||||
size_t len = 0;
|
||||
char *buf = malloc(cap);
|
||||
|
||||
int c;
|
||||
while ((c = fgetc(pipe)) != EOF) {
|
||||
if (len + 1 >= cap) {
|
||||
cap *= 2;
|
||||
buf = realloc(buf, cap);
|
||||
}
|
||||
buf[len++] = (char)c;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
pclose(pipe);
|
||||
return buf; // caller must free
|
||||
}
|
||||
|
||||
void editorSetClipboard(const char *text, int len) {
|
||||
FILE *pipe = popen(CLIPBOARD_COPY_CMD, "w");
|
||||
if (!pipe) return;
|
||||
fwrite(text, 1, len, pipe);
|
||||
pclose(pipe);
|
||||
}
|
||||
|
||||
int editorRowCxToByte(const row_t *row, int cursor_x) {
|
||||
int i = 0, col = 0;
|
||||
while (col < cursor_x && i < row->size) {
|
||||
int sl = utf8Seqlen((unsigned char)row->chars[i]);
|
||||
if (sl < 1)
|
||||
sl = 1;
|
||||
col++;
|
||||
i += sl;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int editorRowCharCount(row_t *row, int x) {
|
||||
int n = 0, i = 0;
|
||||
while (i < x && i < row->size) {
|
||||
int sl = utf8Seqlen((unsigned char)row->chars[i]);
|
||||
if (sl < 1)
|
||||
sl = 1;
|
||||
n++;
|
||||
i += sl;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "../include/buffer.h"
|
||||
#include "../include/data.h"
|
||||
#include "../include/split_screen.h"
|
||||
#include "../include/row_op.h"
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
+6
-2
@@ -45,6 +45,10 @@ void initBuiltins() {
|
||||
registerBuiltin("editor-split-screen-vertical", l_editorSplitScreenVertical);
|
||||
registerBuiltin("editor-switch-next-pane", editorSwitchNextPane);
|
||||
registerBuiltin("editor-unify-panes", editorUnifiedPanes);
|
||||
registerBuiltin("editor-paste", editorPaste);
|
||||
registerBuiltin("editor-cut-end-line", editorCutEndLine);
|
||||
registerBuiltin("editor-move-cursor-beg-buffer", editorMoveBegBuffer);
|
||||
registerBuiltin("editor-move-cursor-end-buffer", editorMoveEndBuffer);
|
||||
}
|
||||
|
||||
void initConfig() {
|
||||
@@ -64,7 +68,7 @@ void initConfig() {
|
||||
lisp_eval(E.ctx_data, &E.ctx_error, E.ctx);
|
||||
}
|
||||
|
||||
void init_theme() {
|
||||
void initTheme() {
|
||||
E.constantes.THEME = (char *)lisp_string(
|
||||
lisp_eval(lisp_read("THEME", &E.ctx_error, E.ctx), &E.ctx_error, E.ctx));
|
||||
if (strcmp(E.constantes.THEME, "dark") == 0) {
|
||||
@@ -130,7 +134,7 @@ void initEditor() {
|
||||
|
||||
initConfig();
|
||||
|
||||
init_theme();
|
||||
initTheme();
|
||||
|
||||
// To modify
|
||||
|
||||
|
||||
+3
-62
@@ -5,7 +5,6 @@
|
||||
#include "include/data.h"
|
||||
#include "include/buffer.h"
|
||||
#include "include/data.h"
|
||||
#include "include/row_op.h"
|
||||
#include "include/split_screen.h"
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -41,7 +40,7 @@ extern struct editorConfig E;
|
||||
* @note Caller is responsible for freeing the returned string
|
||||
* @note Uses static buffer internally; may return stale pointers across calls
|
||||
*/
|
||||
const char *file_completion(const char *path) {
|
||||
const char *fileCompletion(const char *path) {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
char directory[256];
|
||||
@@ -153,7 +152,7 @@ char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) {
|
||||
}
|
||||
memset(buf, 0, 256);
|
||||
buf_len = 0;
|
||||
char * buf_complete = (char *) file_completion(path);
|
||||
char * buf_complete = (char *) fileCompletion(path);
|
||||
strcpy(buf, buf_complete);
|
||||
free(buf_complete);
|
||||
buf_len = strlen(buf);
|
||||
@@ -170,65 +169,7 @@ char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Moves the cursor based on arrow key input
|
||||
* @details Updates cursor position (E.cursor_x, E.cursor_y) based on the given
|
||||
* key direction. Handles line wrapping and boundary conditions. Prevents cursor
|
||||
* from exceeding line lengths.
|
||||
* @param key The arrow key code (ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT)
|
||||
* @return 1 if cursor movement was valid, 0 if cursor was constrained to line boundary
|
||||
* @note Updates global editor state E
|
||||
*/
|
||||
int editorMoveCursor(int key) {
|
||||
EditorPane *active = splitScreenGetActivePane();
|
||||
struct buffer_t *buf = bufferFindById(active->buffer_id);
|
||||
row_t *row = &buf->row[buf->y];
|
||||
switch (key) {
|
||||
case ARROW_RIGHT:
|
||||
if (row && buf->x < row->size) {
|
||||
int len = utf8Seqlen(row->chars[buf->x]);
|
||||
buf->x += len;
|
||||
} else if (row && buf->y < buf->numrows) {
|
||||
buf->y++;
|
||||
buf->x = 0;
|
||||
}
|
||||
break;
|
||||
case ARROW_DOWN:
|
||||
if (buf->y < buf->numrows) {
|
||||
|
||||
buf->y++;
|
||||
}
|
||||
break;
|
||||
case ARROW_UP:
|
||||
if (buf->y != 0) {
|
||||
--buf->y;
|
||||
}
|
||||
break;
|
||||
case ARROW_LEFT:
|
||||
if (buf->x != 0) {
|
||||
--buf->x;
|
||||
} else if (buf->y > 0) {
|
||||
--buf->y;
|
||||
buf->x = buf->row[buf->y].size;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Executes the command bound to a key sequence
|
||||
@@ -272,7 +213,7 @@ void editorProcessKeypress() {
|
||||
int c = editorReadKey();
|
||||
char key_sequence[8];
|
||||
|
||||
if (executeKeyBind(key_to_string(c))) {
|
||||
if (executeKeyBind(keyToString(c))) {
|
||||
return;
|
||||
}
|
||||
int seq_len = utf8Encode(c, key_sequence);
|
||||
|
||||
+11
-17
@@ -8,6 +8,7 @@
|
||||
#include "../include/output.h"
|
||||
#include "../include/append_buffer.h"
|
||||
#include "../include/buffer.h"
|
||||
#include "../include/editor_op.h"
|
||||
#include "../include/data.h"
|
||||
#include "../include/define.h"
|
||||
#include "../include/row_op.h"
|
||||
@@ -29,14 +30,9 @@ static void editorDrawPane(struct abuf* ab, EditorPane* pane)
|
||||
int file_row;
|
||||
char pos_buf[32];
|
||||
int pos_len;
|
||||
int chars_printed;
|
||||
int start_offset;
|
||||
int byte_len_to_print;
|
||||
int bytes_to_print;
|
||||
char* highlighted;
|
||||
char welcome[80];
|
||||
int welcome_len;
|
||||
int padding;
|
||||
|
||||
if (pane == NULL || pane->buffer_id < 0)
|
||||
return;
|
||||
@@ -56,9 +52,8 @@ static void editorDrawPane(struct abuf* ab, EditorPane* pane)
|
||||
abAppend(ab, pos_buf, pos_len);
|
||||
|
||||
// Apply background color (6 bytes for RGB format)
|
||||
abAppend(ab, E.theme.BACKGROUND_COLOR, strlen(E.theme.BACKGROUND_COLOR));
|
||||
abAppend(ab, E.theme.BACKGROUND_COLOR, (int) strlen(E.theme.BACKGROUND_COLOR));
|
||||
|
||||
chars_printed = 0;
|
||||
|
||||
// pane line is out of buffer
|
||||
if (file_row >= buf->numrows)
|
||||
@@ -75,7 +70,7 @@ static void editorDrawPane(struct abuf* ab, EditorPane* pane)
|
||||
}
|
||||
else
|
||||
{
|
||||
start_offset = pane->x_offset;
|
||||
|
||||
|
||||
if (buf->filename[strlen(buf->filename) - 1] == 'c' || buf->filename[strlen(buf->filename) - 1] == 'h')
|
||||
{
|
||||
@@ -135,7 +130,7 @@ static void editorDrawAllPanes(struct abuf* ab)
|
||||
{
|
||||
char pos_buf[32];
|
||||
snprintf(pos_buf, sizeof(pos_buf), "\x1b[%d;%dH", y + 1, divider_col);
|
||||
abAppend(ab, pos_buf, strlen(pos_buf));
|
||||
abAppend(ab, pos_buf, (int) strlen(pos_buf));
|
||||
abAppend(ab, "\x1b[1m|\x1b[0m", 9); // Bold pipe divider
|
||||
}
|
||||
}
|
||||
@@ -145,7 +140,7 @@ static void editorDrawAllPanes(struct abuf* ab)
|
||||
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));
|
||||
abAppend(ab, pos_buf, (int) strlen(pos_buf));
|
||||
for (int x = 0; x < E.screencols; x++)
|
||||
{
|
||||
abAppend(ab, "\x1b[1m-\x1b[0m", 9); // Bold dash divider
|
||||
@@ -231,15 +226,13 @@ void editorScroll()
|
||||
|
||||
char * basename(char *path)
|
||||
{
|
||||
int len = strlen(path);
|
||||
int flag=0;
|
||||
int len = (int) strlen(path);
|
||||
|
||||
|
||||
for(int i=len-1; i>0; i--)
|
||||
{
|
||||
if(path[i]=='/' )
|
||||
{
|
||||
flag=1;
|
||||
path = path+i+1;
|
||||
break;
|
||||
}
|
||||
@@ -323,7 +316,7 @@ void editorDrawStatusBar(struct abuf* ab)
|
||||
*/
|
||||
void editorDrawMessageBar(struct abuf* ab)
|
||||
{
|
||||
int msg_len = strlen(E.status_msg);
|
||||
int msg_len = (int) strlen(E.status_msg);
|
||||
abAppend(ab, ERASE_END_LINE, 3);
|
||||
if (msg_len > E.screencols)
|
||||
{
|
||||
@@ -335,6 +328,7 @@ void editorDrawMessageBar(struct abuf* ab)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Performs complete screen refresh and buffer synchronization
|
||||
* @details Clears screen, redraws all visible content (rows, status bar,
|
||||
@@ -354,7 +348,7 @@ void editorRefreshScreen()
|
||||
abAppend(&ab, HIDE_CURSOR, 6);
|
||||
abAppend(&ab, CURSOR_TOP_LEFT, 3);
|
||||
abAppend(&ab, E.theme.BACKGROUND_COLOR,
|
||||
strlen(E.theme.BACKGROUND_COLOR)); // RGB background is 12 bytes
|
||||
(int) strlen(E.theme.BACKGROUND_COLOR)); // RGB background is 12 bytes
|
||||
|
||||
// Draw all panes
|
||||
editorScroll();
|
||||
@@ -363,16 +357,16 @@ void editorRefreshScreen()
|
||||
// Draw status bar and message bar
|
||||
editorDrawStatusBar(&ab);
|
||||
editorDrawMessageBar(&ab);
|
||||
// editorDrawContextBuffer(&ab);
|
||||
|
||||
// Position cursor in active pane
|
||||
EditorPane* active = splitScreenGetActivePane();
|
||||
struct buffer_t* buffer = bufferGetCurrent();
|
||||
if (active != NULL)
|
||||
{
|
||||
snprintf(buf, sizeof(buf), "\x1b[%d;%dH",
|
||||
active->cursor_y + active->origin_y + 1,
|
||||
active->cursor_x + active->origin_x + 1);
|
||||
abAppend(&ab, buf, strlen(buf));
|
||||
abAppend(&ab, buf, (int) strlen(buf));
|
||||
}
|
||||
|
||||
abAppend(&ab, SHOW_CURSOR, 6);
|
||||
|
||||
+1
-89
@@ -1,100 +1,12 @@
|
||||
#include "../include/row_op.h"
|
||||
#include "../include/data.h"
|
||||
#include "../include/define.h"
|
||||
#include "../include/utf8.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "include/terminal.h"
|
||||
#include "include/utf8.h"
|
||||
|
||||
extern struct editorConfig E;
|
||||
|
||||
void bufferInsertRow(struct buffer_t *buffer, int at, char *s, size_t len) {
|
||||
if (at < 0 || at > buffer->numrows)
|
||||
return;
|
||||
|
||||
row_t *tmp = realloc(buffer->row, sizeof(row_t) * (buffer->numrows + 1));
|
||||
if (!tmp)
|
||||
return;
|
||||
buffer->row = tmp;
|
||||
|
||||
/* Shift existing rows to make room at 'at' — no at++ */
|
||||
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);
|
||||
if (!buffer->row[at].chars)
|
||||
return;
|
||||
memcpy(buffer->row[at].chars, s, len);
|
||||
buffer->row[at].chars[len] = '\0'; /* always NUL-terminate */
|
||||
|
||||
buffer->numrows++;
|
||||
buffer->dirty++;
|
||||
}
|
||||
|
||||
void bufferFreeRow(row_t *row) { free(row->chars); }
|
||||
|
||||
int editorRowCxToByte(const row_t *row, int cursor_x) {
|
||||
int i = 0, col = 0;
|
||||
while (col < cursor_x && i < row->size) {
|
||||
int sl = utf8Seqlen((unsigned char)row->chars[i]);
|
||||
if (sl < 1)
|
||||
sl = 1;
|
||||
col++;
|
||||
i += sl;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn editorRowInsertChar(erow *row, int at, int c)
|
||||
* \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) {
|
||||
if (buffer->state == READ_ONLY)
|
||||
return;
|
||||
if (row->size + n + 1 > row->cap) {
|
||||
row->cap = (row->size + n + 1) * 2;
|
||||
row->chars = realloc(row->chars, row->cap);
|
||||
}
|
||||
memmove(row->chars + at + n, row->chars + at, row->size - at);
|
||||
memcpy(row->chars + at, src, n);
|
||||
row->size += n;
|
||||
row->chars = realloc(row->chars, row->size + 2);
|
||||
++buffer->dirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn bufferRowDelChar(struct bufferConfig *E, frow *frow, int at)
|
||||
* \brief Delete the a char at the chosen position on the given row
|
||||
* \param at Index of the char to delete
|
||||
* \param row Row on operation is made */
|
||||
void bufferRowDelByte(struct buffer_t *buffer, row_t *row, int at, int n) {
|
||||
if (buffer->state == READ_ONLY)
|
||||
return;
|
||||
if (at < 0 || at >= row->size)
|
||||
return;
|
||||
memmove(row->chars + at, row->chars + at + n, row->size - at - n);
|
||||
row->size -= n;
|
||||
row->chars[row->size] = '\0';
|
||||
buffer->x -= n;
|
||||
++buffer->dirty;
|
||||
}
|
||||
int editorRowCharCount(row_t *row, int x) {
|
||||
int n = 0, i = 0;
|
||||
while (i < x && i < row->size) {
|
||||
int sl = utf8Seqlen((unsigned char)row->chars[i]);
|
||||
if (sl < 1)
|
||||
sl = 1;
|
||||
n++;
|
||||
i += sl;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
+4
-2
@@ -46,7 +46,7 @@ void enableRawMode() {
|
||||
|
||||
#include <ctype.h> /* isprint */
|
||||
|
||||
char *key_to_string(int key) {
|
||||
char *keyToString(int key) {
|
||||
static char key_str[32];
|
||||
|
||||
if (key == '\r') {
|
||||
@@ -111,7 +111,7 @@ int editorReadKey() {
|
||||
/* read first byte — may be start of UTF-8 or escape */
|
||||
while (read(STDIN_FILENO, &c, 1) != 1)
|
||||
;
|
||||
appDebug("f : %X\r\n", c);
|
||||
appDebug("f : %hhu %ld\r\n", c, 0x200);
|
||||
|
||||
if (c == '\x1b') {
|
||||
char seq[6];
|
||||
@@ -120,6 +120,8 @@ int editorReadKey() {
|
||||
return '\x1b';
|
||||
if (read(STDIN_FILENO, &seq[1], 1) != 1)
|
||||
return '\x1b';
|
||||
appDebug("f2 : %s\r\n", seq);
|
||||
|
||||
if (seq[0] == '[') {
|
||||
if (seq[1] >= '0' && seq[1] <= '9') {
|
||||
if (read(STDIN_FILENO, &seq[2], 1) != 1)
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
#include "../include/utf8.h"
|
||||
#include "../include/data.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
Reference in New Issue
Block a user