18 Commits

Author SHA1 Message Date
arthur 39e07902f4 Update README.md
Build project / build (push) Successful in 24s
2026-01-09 15:03:08 +01:00
Arthur Barraux 815114923d Add prefix feature
Build project / build (push) Successful in 56s
2026-01-09 14:54:07 +01:00
arthur 410f382592 Add go to end of word function
Build project / build (push) Successful in 1m22s
2025-12-24 14:50:14 +01:00
arthur 80c0bf73e0 Update README.md
Build project / build (push) Successful in 1m1s
2025-12-08 00:25:05 +01:00
arthur d4ee0d86c2 Update .gitea/workflows/build.yml
Build project / build (push) Failing after 2m18s
2025-12-04 01:34:33 +01:00
arthur c06c820dfb Patch path complete and read char lisp function
Build project / build (push) Has been cancelled
2025-11-07 16:23:56 +01:00
arthur 5588b0a8d7 add path autocomplete
Build project / build (push) Has been cancelled
2025-11-05 15:49:01 +01:00
arthur 419e924650 Add search function
Build project / build (push) Has been cancelled
2025-11-03 16:45:23 +01:00
arthur 6a201b3ebc delete line macro
Build project / build (push) Has been cancelled
2025-11-03 16:05:25 +01:00
arthur 1d253e51ef Update README.md
Build project / build (push) Failing after 3m27s
2025-11-01 13:22:10 +01:00
Arthur Barraux 42f82e2e0d add packages
Build project / build (push) Has been cancelled
2025-11-01 13:03:07 +01:00
arthur fa32f4b177 Update src/init.c
Build project / build (push) Has been cancelled
2025-10-31 09:10:57 +01:00
arthur 65f997e964 Update install.sh
Build project / build (push) Has been cancelled
2025-10-31 09:09:20 +01:00
Arthur Barraux 7eaf6913cb Merge remote-tracking branch 'gitea/main'
Build project / build (push) Has been cancelled
2025-10-30 18:18:12 +01:00
Arthur Barraux 8f7dcf3534 Adding installer script 2025-10-30 18:17:19 +01:00
arthur d8c6b9ace3 Update README.md
Build project / build (push) Has been cancelled
2025-10-28 09:16:36 +01:00
arthur d0173d7308 Update README.md
Build project / build (push) Has been cancelled
2025-10-28 09:02:29 +01:00
arthur 40fc234eeb Update .gitea/workflows/build.yml
Build project / build (push) Failing after 39s
2025-10-18 15:35:57 +02:00
18 changed files with 679 additions and 314 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ on:
jobs: jobs:
build: build:
runs-on: home-1 runs-on: giorgio-runner
steps: steps:
- name: Checkout code - name: Checkout code
+16 -10
View File
@@ -1,26 +1,32 @@
# Beluga # Beluga
Beluga is a project of CLI text editor that will fit perfectly with your azerty keyboard. Beluga is a project of CLI text editor that uses lisp as configuration language.
## Requirements ## Requirements
You will only need **cmake** and **clang** to compile the editor. You will only need **meson** and a **C compiler** to compile the editor.
## Installation ## Installation
### From source
Here is the installation line for development version: Here is the installation line for development version:
```git clone --recurse-submodules https://github.com/le-cocotier/beluga.git ~/.beluga && cd ~/.beluga && mkdir build && cd build && cmake ../ && make beluga``` ```git clone https://git.giorgio-nas.fr/arthur/beluga.git && cd beluga && meson setup build && meson compile -C build```
The executable file will be in `bin/beluga`. Feel free to add it to your path. The executable file will be `build/beluga`. Feel free to add it to your path.
You can either run `make all` or `make doc_doxygen` if you're interested by the doxygen documentation. ### From installation script ( prefered )
Just clone the repo and execute the script `install.sh`. It will automatically add beluga to your path.
## Getting start ## Getting start
To open an existing file just type : To open an existing file just type :
```beluga path_to_my_file``` ```./build/beluga path_to_my_file```
The only keybinds that you will need will be : Here is some few command that you will need :
- Ctrl-Q : leave the editor
- Ctrl-S : Save a file | keybind | command |
|---------------|------------------|
| Ctrl-x Ctrl-c | leave the editor |
| Ctrl-x Ctrl-s | Save a file |
| Ctrl-x f | open file |
+65 -15
View File
@@ -3,6 +3,11 @@
(define TAB-LENGTH 4) (define TAB-LENGTH 4)
(define QUIT-TIMES 1) (define QUIT-TIMES 1)
;; PACKAGES
;; First git clone it
;; (add-package "smart_delimiters")
;; FUNCTIONS ;; FUNCTIONS
(define editor-delete-next-char (lambda () ( (define editor-delete-next-char (lambda () (
@@ -13,22 +18,67 @@
) )
;; KEY MAPPING (define (char-between ch lo hi)
(if (char>=? ch lo)
(char<=? ch hi)
#f))
(map-key "CTRL-q" editor-quit) (define (alphanumericp ch)
(map-key "CTRL-s" editor-save) (if ch
(map-key "ARROW-UP" '(move-cursor "up")) (if (char-between ch #\a #\z)
(map-key "ARROW-DOWN" '(move-cursor "down")) #t
(map-key "ARROW-RIGHT" '(move-cursor "right")) (if (char-between ch #\A #\Z)
(map-key "ARROW-LEFT" '(move-cursor "left")) #t
(map-key "ENTER" editor-insert-new-line) (if (char-between ch #\0 #\9)
(map-key "CTRL-a" move-cursor-beg-line) #t
(map-key "CTRL-e" move-cursor-end-line) #f)))
(map-key "BACKSPACE" editor-delete-previous-char) #f))
(map-key "DEL" editor-delete-next-char)
(map-key "PAGE-UP" move-cursor-page-up)
(map-key "PAGE-DOWN" move-cursor-page-down) (define (word-char-p ch)
(map-key "CTRL-o" editor-open-file) (if (alphanumericp ch)
#t
#f))
(define editor-move-to-end-of-word (lambda () (
(if (word-char-p (editor-read-char))
((move-cursor "right")
(editor-move-to-end-of-word))
))
))
(define enter-and-tab
(lambda ()
(editor-insert-new-line)
(let ((is-in (move-cursor "up")))
(do ((ch (editor-read-char) (editor-read-char)))
((and (not (char=? ch #\space)) is-in) #f)
(move-cursor "down")
(editor-insert-char " ")
(set! is-in (move-cursor "up")))
(move-cursor "down"))))
(add-prefix "user")
(map-key "CTRL-x" '(editor-set-prefix "user") "no-prefix")
(map-key "CTRL-g" '(editor-set-prefix "no-prefix") "user")
(map-key "CTRL-c" editor-quit "user")
(map-key "CTRL-s" editor-save "user")
(map-key "ARROW-UP" '(move-cursor "up") "no-prefix")
(map-key "ARROW-DOWN" '(move-cursor "down") "no-prefix")
(map-key "ARROW-RIGHT" '(move-cursor "right") "no-prefix")
(map-key "ARROW-LEFT" '(move-cursor "left") "no-prefix")
(map-key "ENTER" enter-and-tab "no-prefix")
(map-key "CTRL-a" move-cursor-beg-line "no-prefix")
(map-key "CTRL-e" move-cursor-end-line "no-prefix")
(map-key "BACKSPACE" editor-delete-previous-char "no-prefix")
(map-key "DEL" editor-delete-next-char "no-prefix")
(map-key "PAGE-UP" move-cursor-page-up "no-prefix")
(map-key "PAGE-DOWN" move-cursor-page-down "no-prefix")
(map-key "f" editor-open-file "user")
(map-key "TAB" editor-insert-tab "no-prefix")
(map-key "CTRL-k" editor-del-row "no-prefix")
(map-key "CTRL-s" editor-find "no-prefix")
(map-key "CTRL-r" editor-move-to-end-of-word "no-prefix")
+16
View File
@@ -19,6 +19,8 @@ Lisp moveCursorBeginLine(Lisp args, LispError *e, LispContext ctx);
Lisp moveCursorEndLine(Lisp args, LispError *e, LispContext ctx); Lisp moveCursorEndLine(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 editorMoveCursorPageUp(Lisp args, LispError* e, LispContext ctx); Lisp editorMoveCursorPageUp(Lisp args, LispError* e, LispContext ctx);
@@ -29,4 +31,18 @@ Lisp editorOpenFile(Lisp args, LispError *e, LispContext ctx);
Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx); Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx);
Lisp addPackage(Lisp args, LispError *e, LispContext ctx);
Lisp editorDelRow_L(Lisp args, LispError *e, LispContext ctx);
Lisp editorFind_L(Lisp args, LispError *e, LispContext ctx);
Lisp editorReadChar_L(Lisp args, LispError *e, LispContext ctx);
Lisp editorSetPrefix(Lisp args, LispError *e, LispContext ctx);
Lisp editorPrefix(Lisp args, LispError *e, LispContext ctx);
void free_structs(void);
#endif #endif
+10
View File
@@ -31,8 +31,14 @@ struct const_t {
int QUIT_TIMES; int QUIT_TIMES;
}; };
struct prefix_t {
char prefix_name[64];
int prefix_id;
};
struct keyBind_t { struct keyBind_t {
char *key_sequence; char *key_sequence;
int prefix_id;
Lisp command; Lisp command;
}; };
@@ -53,6 +59,7 @@ struct editorConfig {
int dirty; int dirty;
char *filename; char *filename;
enum editorStatus_e state; enum editorStatus_e state;
int prefix_state;
char status_msg[80]; char status_msg[80];
time_t status_msg_time; time_t status_msg_time;
struct termios orig_termios; /**< Terminal communication interface */ struct termios orig_termios; /**< Terminal communication interface */
@@ -69,6 +76,9 @@ struct editorConfig {
struct keyBind_t* key_binds; struct keyBind_t* key_binds;
int number_of_keybinds; int number_of_keybinds;
struct prefix_t* prefix;
int number_of_prefix;
}; };
/** /**
+2
View File
@@ -17,4 +17,6 @@ void editorOpen(char *filename);
void editorSave(); void editorSave();
void editorFind();
#endif // FILE_IO_H_ #endif // FILE_IO_H_
+2 -2
View File
@@ -20,11 +20,11 @@
// END \x1b[4~ || <esc>[8~ || <esc>[F || <esc>OF // END \x1b[4~ || <esc>[8~ || <esc>[F || <esc>OF
// DELETE \x1b[3~ // DELETE \x1b[3~
char *editorPrompt(char *prompt); char *editorPrompt(char *prompt, char * PlaceHolder, char bPathMode);
char *key_to_string(int key); char *key_to_string(int key);
void editorMoveCursor(int key); int editorMoveCursor(int key);
int executeKeyBind(char *key_sequence); int executeKeyBind(char *key_sequence);
+12 -12
View File
@@ -1861,8 +1861,8 @@ static Lisp parse_symbol_(Lexer* lex, LispContext ctx)
char scratch[LISP_IDENTIFIER_MAX]; char scratch[LISP_IDENTIFIER_MAX];
size_t length = lexer_copy_token(lex, 0, LISP_IDENTIFIER_MAX, scratch); size_t length = lexer_copy_token(lex, 0, LISP_IDENTIFIER_MAX, scratch);
// always convert symbols to uppercase // always convert symbols to uppercase
for (int i = 0; i < length; ++i) // for (int i = 0; i < length; ++i)
scratch[i] = toupper(scratch[i]); // scratch[i] = toupper(scratch[i]);
return symbol_intern_(ctx.p->symbols, scratch, length, ctx); return symbol_intern_(ctx.p->symbols, scratch, length, ctx);
} }
@@ -3183,17 +3183,17 @@ LispContext lisp_init(void)
ctx.p->macros = lisp_make_table(ctx); ctx.p->macros = lisp_make_table(ctx);
Lisp* c = ctx.p->symbol_cache; Lisp* c = ctx.p->symbol_cache;
c[SYM_IF] = lisp_make_symbol("IF", ctx); c[SYM_IF] = lisp_make_symbol("if", ctx);
c[SYM_BEGIN] = lisp_make_symbol("BEGIN", ctx); c[SYM_BEGIN] = lisp_make_symbol("begin", ctx);
c[SYM_QUOTE] = lisp_make_symbol("QUOTE", ctx); c[SYM_QUOTE] = lisp_make_symbol("quote", ctx);
c[SYM_QUASI_QUOTE] = lisp_make_symbol("QUASIQUOTE", ctx); c[SYM_QUASI_QUOTE] = lisp_make_symbol("quasiquote", ctx);
c[SYM_UNQUOTE] = lisp_make_symbol("UNQUOTE", ctx); c[SYM_UNQUOTE] = lisp_make_symbol("unquote", ctx);
c[SYM_UNQUOTE_SPLICE] = lisp_make_symbol("UNQUOTESPLICE", ctx); c[SYM_UNQUOTE_SPLICE] = lisp_make_symbol("unquotesplice", ctx);
c[SYM_DEFINE] = lisp_make_symbol("_DEF", ctx); c[SYM_DEFINE] = lisp_make_symbol("_def", ctx);
c[SYM_DEFINE_MACRO] = lisp_make_symbol("DEFINE-MACRO", ctx); c[SYM_DEFINE_MACRO] = lisp_make_symbol("define-macro", ctx);
c[SYM_SET] = lisp_make_symbol("_SET!", ctx); c[SYM_SET] = lisp_make_symbol("_set!", ctx);
c[SYM_LAMBDA] = lisp_make_symbol("/\\_", ctx); c[SYM_LAMBDA] = lisp_make_symbol("/\\_", ctx);
c[SYM_CONS] = lisp_make_symbol("CONS", ctx); c[SYM_CONS] = lisp_make_symbol("cons", ctx);
return ctx; return ctx;
} }
+194 -197
View File
@@ -36,7 +36,7 @@ static const char* lib_0_sequences_src_ =
(if (pair? args) \n\ (if (pair? args) \n\
(if (pair? (cdr args)) \n\ (if (pair? (cdr args)) \n\
(if (pair? (cdr (cdr args))) \n\ (if (pair? (cdr (cdr args))) \n\
`(/\\_ ,(car args) ,(cons 'BEGIN (cdr args))) \n\ `(/\\_ ,(car args) ,(cons 'begin (cdr args))) \n\
`(/\\_ ,(car args) ,(car (cdr args)))) \n\ `(/\\_ ,(car args) ,(car (cdr args)))) \n\
(syntax-error \"lambda missing body expressions: (lambda (args) body)\")) \n\ (syntax-error \"lambda missing body expressions: (lambda (args) body)\")) \n\
(syntax-error \"lambda missing argument: (lambda (args) body)\")))) \n\ (syntax-error \"lambda missing argument: (lambda (args) body)\")))) \n\
@@ -44,18 +44,18 @@ static const char* lib_0_sequences_src_ =
(define-macro set! (lambda (var x) \n\ (define-macro set! (lambda (var x) \n\
(begin \n\ (begin \n\
(if (not (symbol? var)) (syntax-error \"set! not a variable\")) \n\ (if (not (symbol? var)) (syntax-error \"set! not a variable\")) \n\
`(_SET! ,var ,x)))) \n\ `(_set! ,var ,x)))) \n\
\n\ \n\
(define-macro define \n\ (define-macro define \n\
(lambda (var . exprs) \n\ (lambda (var . exprs) \n\
(if (symbol? var) \n\ (if (symbol? var) \n\
(if (pair? (cdr exprs)) \n\ (if (pair? (cdr exprs)) \n\
(syntax-error \"define: (define var x)\") \n\ (syntax-error \"define: (define var x)\") \n\
`(_DEF ,var ,(car exprs))) \n\ `(_def ,var ,(car exprs))) \n\
(if (pair? var) \n\ (if (pair? var) \n\
`(_DEF ,(car var) \n\ `(_def ,(car var) \n\
(LAMBDA ,(cdr var) \n\ (lambda ,(cdr var) \n\
,(if (null? (cdr exprs)) (car exprs) (cons 'BEGIN exprs)))) \n\ ,(if (null? (cdr exprs)) (car exprs) (cons 'begin exprs)))) \n\
(syntax-error \"define: not a symbol\") )))) \n\ (syntax-error \"define: not a symbol\") )))) \n\
\n\ \n\
(define (first x) (car x)) \n\ (define (first x) (car x)) \n\
@@ -98,13 +98,13 @@ static const char* lib_0_sequences_src_ =
(define (_expand-shorthand-body path) \n\ (define (_expand-shorthand-body path) \n\
(if (null? path) (cons 'pair '()) \n\ (if (null? path) (cons 'pair '()) \n\
(list (if (char=? (car path) #\\A) \n\ (list (if (char=? (car path) #\\A) \n\
(cons 'CAR (_expand-shorthand-body (cdr path))))))) \n\ (cons 'car (_expand-shorthand-body (cdr path))))))) \n\
\n\ \n\
(define (_expand-shorthand text) \n\ (define (_expand-shorthand text) \n\
(cons 'DEFINE (cons (list (string->symbol (string-append \"C\" text \"R\")) 'pair) \n\ (cons 'define (cons (list (string->symbol (string-append \"C\" text \"R\")) 'pair) \n\
(_expand-shorthand-body (string->list text))))) \n\ (_expand-shorthand-body (string->list text))))) \n\
\n\ \n\
(define-macro _shorthand-accessors (lambda args (cons 'BEGIN (map1 _expand-shorthand args)))) \n\ (define-macro _shorthand-accessors (lambda args (cons 'begin (map1 _expand-shorthand args)))) \n\
\n\ \n\
(define (vector . args) (list->vector args)) \n\ (define (vector . args) (list->vector args)) \n\
\n\ \n\
@@ -124,14 +124,14 @@ static const char* lib_0_sequences_src_ =
static const char* lib_1_forms_src_ = static const char* lib_1_forms_src_ =
"(define (_make-lambda args body) \n\ "(define (_make-lambda args body) \n\
(list 'LAMBDA args (if (null? (cdr body)) (car body) (cons 'BEGIN body)))) \n\ (list 'lambda args (if (null? (cdr body)) (car body) (cons 'begin body)))) \n\
\n\ \n\
\n\ \n\
; (LET <name> ((<var0> <expr0>) ... (<varN> <expr1>)) <body0> ... <bodyN>) \n\ ; (let <name> ((<var0> <expr0>) ... (<varN> <expr1>)) <body0> ... <bodyN>) \n\
; => ((LAMBDA (<var0> ... <varN>) (BEGIN <body0> ... <bodyN>)) <expr0> ... <expr1>) \n\ ; => ((lambda (<var0> ... <varN>) (begin <body0> ... <bodyN>)) <expr0> ... <expr1>) \n\
; => named \n\ ; => named \n\
; ((lambda () \n\ ; ((lambda () \n\
; (define <name> (LAMBDA (<var0> ... <varN>) (BEGIN <body0> ... <bodyN>))) \n\ ; (define <name> (lambda (<var0> ... <varN>) (begin <body0> ... <bodyN>))) \n\
; (<name> <expr0> ... <exprN>))) \n\ ; (<name> <expr0> ... <exprN>))) \n\
\n\ \n\
(define (_check-binding-list bindings) \n\ (define (_check-binding-list bindings) \n\
@@ -145,7 +145,7 @@ static const char* lib_1_forms_src_ =
(define initial-args (map1 (lambda (entry) (second entry)) bindings)) \n\ (define initial-args (map1 (lambda (entry) (second entry)) bindings)) \n\
(if (null? var) \n\ (if (null? var) \n\
(cons body-func initial-args) \n\ (cons body-func initial-args) \n\
(list (_make-lambda '() (list (list 'DEFINE var body-func) (cons var initial-args)))))) \n\ (list (_make-lambda '() (list (list 'define var body-func) (cons var initial-args)))))) \n\
\n\ \n\
(define-macro let (lambda args \n\ (define-macro let (lambda args \n\
(if (pair? (first args)) \n\ (if (pair? (first args)) \n\
@@ -153,8 +153,8 @@ static const char* lib_1_forms_src_ =
(_let->combination (first args) (second args) (cdr (cdr args)))))) \n\ (_let->combination (first args) (second args) (cdr (cdr args)))))) \n\
\n\ \n\
(define (_let*-helper bindings body) \n\ (define (_let*-helper bindings body) \n\
(if (null? bindings) (if (null? (cdr body)) (car body) (cons 'BEGIN body)) \n\ (if (null? bindings) (if (null? (cdr body)) (car body) (cons 'begin body)) \n\
(list 'LET (list (car bindings)) (_let*-helper (cdr bindings) body)))) \n\ (list 'let (list (car bindings)) (_let*-helper (cdr bindings) body)))) \n\
\n\ \n\
(define-macro let* (lambda (bindings . body) \n\ (define-macro let* (lambda (bindings . body) \n\
(_check-binding-list bindings) \n\ (_check-binding-list bindings) \n\
@@ -163,17 +163,17 @@ static const char* lib_1_forms_src_ =
(define-macro letrec (lambda (bindings . body) \n\ (define-macro letrec (lambda (bindings . body) \n\
(_check-binding-list bindings) \n\ (_check-binding-list bindings) \n\
(cons (_make-lambda (map1 (lambda (entry) (first entry)) bindings) \n\ (cons (_make-lambda (map1 (lambda (entry) (first entry)) bindings) \n\
(append (map1 (lambda (entry) (list 'SET! (first entry) (second entry))) \n\ (append (map1 (lambda (entry) (list 'set! (first entry) (second entry))) \n\
bindings) body)) \n\ bindings) body)) \n\
(map1 (lambda (entry) '()) bindings)))) \n\ (map1 (lambda (entry) '()) bindings)))) \n\
\n\ \n\
\n\ \n\
; (COND (<pred0> <expr0>) \n\ ; (cond (<pred0> <expr0>) \n\
; (<pred1> <expr1>) \n\ ; (<pred1> <expr1>) \n\
; ... \n\ ; ... \n\
; (else <expr-1>)) \n\ ; (else <expr-1>)) \n\
; => \n\ ; => \n\
; (IF <pred0> <expr0> \n\ ; (if <pred0> <expr0> \n\
; (if <pred1> <expr1> \n\ ; (if <pred1> <expr1> \n\
; .... \n\ ; .... \n\
; (if <predN> <exprN> <expr-1>)) ... ) \n\ ; (if <predN> <exprN> <expr-1>)) ... ) \n\
@@ -187,11 +187,11 @@ static const char* lib_1_forms_src_ =
\n\ \n\
(define (_cond-helper clauses) \n\ (define (_cond-helper clauses) \n\
(if (null? clauses) '() \n\ (if (null? clauses) '() \n\
(if (eq? (car (car clauses)) 'ELSE) \n\ (if (eq? (car (car clauses)) 'else) \n\
(cons 'BEGIN (cdr (car clauses))) \n\ (cons 'begin (cdr (car clauses))) \n\
(list 'IF \n\ (list 'if \n\
(car (car clauses)) \n\ (car (car clauses)) \n\
(cons 'BEGIN (cdr (car clauses))) \n\ (cons 'begin (cdr (car clauses))) \n\
(_cond-helper (cdr clauses)))))) \n\ (_cond-helper (cdr clauses)))))) \n\
\n\ \n\
(define-macro cond (lambda clauses \n\ (define-macro cond (lambda clauses \n\
@@ -206,26 +206,26 @@ static const char* lib_2_forms_src_ =
(cond ((null? preds) #t) \n\ (cond ((null? preds) #t) \n\
((null? (cdr preds)) (car preds)) \n\ ((null? (cdr preds)) (car preds)) \n\
(else \n\ (else \n\
`(IF ,(car preds) ,(_and-helper (cdr preds)) #f)))) \n\ `(if ,(car preds) ,(_and-helper (cdr preds)) #f)))) \n\
(define-macro and (lambda preds (_and-helper preds))) \n\ (define-macro and (lambda preds (_and-helper preds))) \n\
\n\ \n\
(define (_or-helper preds var) \n\ (define (_or-helper preds var) \n\
(cond ((null? preds) #f) \n\ (cond ((null? preds) #f) \n\
((null? (cdr preds)) (car preds)) \n\ ((null? (cdr preds)) (car preds)) \n\
(else \n\ (else \n\
`(BEGIN (SET! ,var ,(car preds)) \n\ `(begin (set! ,var ,(car preds)) \n\
(IF ,var ,var ,(_or-helper (cdr preds) var)))))) \n\ (if ,var ,var ,(_or-helper (cdr preds) var)))))) \n\
\n\ \n\
(define-macro or (lambda preds \n\ (define-macro or (lambda preds \n\
(let ((var (gensym))) \n\ (let ((var (gensym))) \n\
`(LET ((,var '())) ,(_or-helper preds var))))) \n\ `(let ((,var '())) ,(_or-helper preds var))))) \n\
\n\ \n\
(define-macro case (lambda (key . clauses) \n\ (define-macro case (lambda (key . clauses) \n\
(let ((expr (gensym))) \n\ (let ((expr (gensym))) \n\
`(LET ((,expr ,key)) \n\ `(let ((,expr ,key)) \n\
,(cons 'COND (map1 (lambda (entry) \n\ ,(cons 'cond (map1 (lambda (entry) \n\
(cons (if (pair? (car entry)) \n\ (cons (if (pair? (car entry)) \n\
`(MEMV ,expr (quote ,(car entry))) \n\ `(memv ,expr (quote ,(car entry))) \n\
(car entry)) \n\ (car entry)) \n\
(cdr entry))) clauses)))))) \n\ (cdr entry))) clauses)))))) \n\
\n\ \n\
@@ -234,20 +234,21 @@ static const char* lib_2_forms_src_ =
`(begin (set! ,l (cons ,v ,l)) ,l))) \n\ `(begin (set! ,l (cons ,v ,l)) ,l))) \n\
\n\ \n\
; (DO ((<var0> <init0> <step0>) ...) (<test> <result>) <body>) \n\ ; (DO ((<var0> <init0> <step0>) ...) (<test> <result>) <body>) \n\
\n\
(define-macro do \n\ (define-macro do \n\
(lambda (vars loop-check . loops) \n\ (lambda (vars loop-check . loops) \n\
(let ( (names '()) (inits '()) (steps '()) (f (gensym)) ) \n\ (let ( (names '()) (inits '()) (steps '()) (f (gensym)) ) \n\
(for-each1 (lambda (var) \n\ (for-each1 (lambda (var-spec) \n\
(push (car var) names) \n\ (push (car var-spec) names) \n\
(set! var (cdr var)) \n\ (push (car (cdr var-spec)) inits) \n\
(push (car var) inits) \n\ (if (pair? (cdr (cdr var-spec))) \n\
(set! var (cdr var)) \n\ (push (car (cdr (cdr var-spec))) steps) \n\
(push (car var) steps)) vars) \n\ (push (car var-spec) steps))) vars) \n\
`((LAMBDA () \n\ `((lambda () \n\
(DEFINE ,f (LAMBDA ,names \n\ (define ,f (lambda ,names \n\
(IF ,(car loop-check) \n\ (if ,(car loop-check) \n\
,(if (pair? (cdr loop-check)) (car (cdr loop-check)) '()) \n\ ,(if (pair? (cdr loop-check)) (car (cdr loop-check)) '()) \n\
,(cons 'BEGIN (append loops (list (cons f steps)))) ))) \n\ ,(cons 'begin (append loops (list (cons f steps)))) ))) \n\
,(cons f inits) \n\ ,(cons f inits) \n\
)) ))) \n\ )) ))) \n\
\n\ \n\
@@ -262,18 +263,18 @@ static const char* lib_2_forms_src_ =
(define-macro swap! \n\ (define-macro swap! \n\
(lambda (x y) \n\ (lambda (x y) \n\
(let ((temp (gensym))) \n\ (let ((temp (gensym))) \n\
`(LET ((,temp ,x)) \n\ `(let ((,temp ,x)) \n\
(SET! ,temp ,x) \n\ (set! ,temp ,x) \n\
(SET! ,x ,y) \n\ (set! ,x ,y) \n\
(SET! ,y ,temp))))) \n\ (set! ,y ,temp))))) \n\
\n\ \n\
(define-macro inc! ; CL incf \n\ (define-macro inc! ; CL incf \n\
(lambda (x) \n\ (lambda (x) \n\
`(SET! ,x (+ ,x 1)))) \n\ `(set! ,x (+ ,x 1)))) \n\
\n\ \n\
(define-macro dec! ; CL decf \n\ (define-macro dec! ; CL decf \n\
(lambda (x) \n\ (lambda (x) \n\
`(SET! ,x (- ,x 1))))"; `(set! ,x (- ,x 1))))";
static const char* lib_3_math_src_ = static const char* lib_3_math_src_ =
"(define (number? x) (real? x)) \n\ "(define (number? x) (real? x)) \n\
@@ -445,7 +446,7 @@ static const char* lib_4_sequences_src_ =
static const char* lib_5_streams_src_ = static const char* lib_5_streams_src_ =
"(define-macro delay (lambda (expr) \n\ "(define-macro delay (lambda (expr) \n\
`(make-promise ,(cons 'LAMBDA \n\ `(make-promise ,(cons 'lambda \n\
(cons '() \n\ (cons '() \n\
(cons expr '())))))) \n\ (cons expr '())))))) \n\
\n\ \n\
@@ -1926,182 +1927,178 @@ static Lisp sch_is_cont(Lisp args, LispError* e, LispContext ctx)
static const LispFuncDef lib_cfunc_defs[] = { static const LispFuncDef lib_cfunc_defs[] = {
{ "ERROR", sch_error }, { "error", sch_error },
{ "SYNTAX-ERROR", sch_syntax_error }, { "syntax-error", sch_syntax_error },
// Output Procedures https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Output-Procedures.html // Output Procedures
{ "_WRITE", sch_write }, { "_write", sch_write },
{ "_DISPLAY", sch_display }, { "_display", sch_display },
{ "_WRITE-CHAR", sch_write_char }, { "_write-char", sch_write_char },
{ "_FLUSH-OUTPUT-PORT", sch_flush }, { "_flush-output-port", sch_flush },
{ "_READ", sch_read }, { "_read", sch_read },
{ "INPUT-PORT?", sch_is_port_in }, { "input-port?", sch_is_port_in },
{ "OUTPUT-PORT?", sch_is_port_out }, { "output-port?", sch_is_port_out },
{ "OPEN-INPUT-FILE", sch_open_input }, { "open-input-file", sch_open_input },
{ "OPEN-OUTPUT-FILE", sch_open_output }, { "open-output-file", sch_open_output },
{ "CLOSE-INPUT-PORT", sch_port_close }, { "close-input-port", sch_port_close },
{ "CLOSE-OUTPUT-PORT", sch_port_close }, { "close-output-port", sch_port_close },
{ "EOF-OBJECT?", sch_is_eof }, { "eof-object?", sch_is_eof },
// Universal Time https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Universal-Time.html // Universal Time
{ "GET-UNIVERSAL-TIME", sch_univeral_time }, { "get-universal-time", sch_univeral_time },
{ "PRINT-GC-STATISTICS", sch_print_gc_stats }, { "print-gc-statistics", sch_print_gc_stats },
{ "MACROEXPAND", sch_macroexpand }, { "macroexpand", sch_macroexpand },
// Equivalence Predicates https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Equivalence-Predicates.html // Equivalence Predicates
{ "EQ?", sch_exact_eq }, { "eq?", sch_exact_eq },
{ "EQV?", sch_equal }, { "eqv?", sch_equal },
{ "EQUAL?", sch_equal_r }, { "equal?", sch_equal_r },
// Booleans https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Booleans.html // Booleans
{ "BOOLEAN?", sch_is_boolean }, { "boolean?", sch_is_boolean },
{ "NOT", sch_not }, { "not", sch_not },
// PAIRS // PAIRS
{ "CONS", sch_cons }, { "cons", sch_cons },
{ "CAR", sch_car }, { "car", sch_car },
{ "CDR", sch_cdr }, { "cdr", sch_cdr },
{ "SET-CAR!", sch_set_car }, { "set-car!", sch_set_car },
{ "SET-CDR!", sch_set_cdr }, { "set-cdr!", sch_set_cdr },
{ "NULL?", sch_is_null }, { "null?", sch_is_null },
{ "PAIR?", sch_is_pair }, { "pair?", sch_is_pair },
// Lists https://groups.csail.mit.edu/mac/ftpdir/scheme-7.4/doc-html/scheme_8.html // Lists
{ "LIST", sch_list }, { "list", sch_list },
{ "LIST?", sch_is_list }, { "list?", sch_is_list },
{ "MAKE-LIST", sch_make_list }, { "make-list", sch_make_list },
{ "LIST-COPY", sch_list_copy }, { "list-copy", sch_list_copy },
{ "LENGTH", sch_length }, { "length", sch_length },
{ "APPEND", sch_append }, { "append", sch_append },
{ "APPEND-REVERSE!", sch_append_reverse }, { "append-reverse!", sch_append_reverse },
{ "LIST-REF", sch_list_ref }, { "list-ref", sch_list_ref },
{ "NTHCDR", sch_list_advance }, { "nthcdr", sch_list_advance },
// Vectors https://groups.csail.mit.edu/mac/ftpdir/scheme-7.4/doc-html/scheme_9.html#SEC82 // Vectors
{ "VECTOR?", sch_is_vector }, { "vector?", sch_is_vector },
{ "MAKE-VECTOR", sch_make_vector }, { "make-vector", sch_make_vector },
{ "VECTOR-GROW", sch_vector_grow }, { "vector-grow", sch_vector_grow },
{ "VECTOR-LENGTH", sch_vector_length }, { "vector-length", sch_vector_length },
{ "VECTOR-SET!", sch_vector_set }, { "vector-set!", sch_vector_set },
{ "VECTOR-SWAP!", sch_vector_swap }, { "vector-swap!", sch_vector_swap },
{ "VECTOR-REF", sch_vector_ref }, { "vector-ref", sch_vector_ref },
{ "VECTOR-FILL!", sch_vector_fill }, { "vector-fill!", sch_vector_fill },
{ "VECTOR-ASSQ", sch_vector_assq }, { "vector-assq", sch_vector_assq },
{ "SUBVECTOR", sch_subvector }, { "subvector", sch_subvector },
{ "LIST->VECTOR", sch_list_to_vector }, { "list->vector", sch_list_to_vector },
{ "VECTOR->LIST", sch_vector_to_list }, { "vector->list", sch_vector_to_list },
// Strings https://groups.csail.mit.edu/mac/ftpdir/scheme-7.4/doc-html/scheme_7.html#SEC61 // Strings
{ "STRING?", sch_is_string }, { "string?", sch_is_string },
{ "MAKE-STRING", sch_make_string }, { "make-string", sch_make_string },
{ "STRING=?", sch_equal_r }, { "string=?", sch_equal_r },
{ "STRING<?", sch_string_less }, { "string<?", sch_string_less },
{ "SUBSTRING", sch_substring }, { "substring", sch_substring },
{ "STRING-NULL?", sch_string_is_null }, { "string-null?", sch_string_is_null },
{ "STRING-LENGTH", sch_string_length }, { "string-length", sch_string_length },
{ "STRING-REF", sch_string_ref }, { "string-ref", sch_string_ref },
{ "STRING-SET!", sch_string_set }, { "string-set!", sch_string_set },
{ "STRING-UPCASE", sch_string_upcase }, { "string-upcase", sch_string_upcase },
{ "STRING-DOWNCASE", sch_string_downcase }, { "string-downcase", sch_string_downcase },
{ "STRING-APPEND", sch_string_append }, { "string-append", sch_string_append },
{ "STRING->LIST", sch_string_to_list }, { "string->list", sch_string_to_list },
{ "LIST->STRING", sch_list_to_string }, { "list->string", sch_list_to_string },
{ "STRING->NUMBER", sch_string_to_number }, { "string->number", sch_string_to_number },
{ "NUMBER->STRING", sch_number_to_string }, { "number->string", sch_number_to_string },
// Characters https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Characters.html#Characters // Characters
{ "CHAR?", sch_is_char }, { "char?", sch_is_char },
{ "CHAR=?", sch_equals }, { "char=?", sch_equals },
{ "CHAR<?", sch_char_less }, { "char<?", sch_char_less },
{ "CHAR-UPCASE", sch_char_upcase }, { "char-upcase", sch_char_upcase },
{ "CHAR-DOWNCASE", sch_char_downcase }, { "char-downcase", sch_char_downcase },
{ "CHAR-WHITESPACE?", sch_char_is_white }, { "char-whitespace?", sch_char_is_white },
{ "CHAR-ALPHANUMERIC?", sch_char_is_alphanum }, { "char-alphanumeric?", sch_char_is_alphanum },
{ "CHAR-ALPHABETIC?", sch_char_is_alpha }, { "char-alphabetic?", sch_char_is_alpha },
{ "CHAR-NUMERIC?", sch_char_is_number }, { "char-numeric?", sch_char_is_number },
{ "CHAR->INTEGER", sch_char_to_int }, { "char->integer", sch_char_to_int },
// Association Lists https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Association-Lists.html // Numerical operations
// Numerical operations https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Numerical-operations.html
{ "=", sch_equals }, { "=", sch_equals },
{ "+", sch_add }, { "+", sch_add },
{ "-", sch_sub }, { "-", sch_sub },
{ "*", sch_mult }, { "*", sch_mult },
{ "/", sch_divide }, { "/", sch_divide },
{ "<", sch_less }, { "<", sch_less },
{ "INTEGER?", sch_is_int }, { "integer?", sch_is_int },
{ "EVEN?", sch_is_even }, { "even?", sch_is_even },
{ "REAL?", sch_is_real }, { "real?", sch_is_real },
{ "EXP", sch_exp }, { "exp", sch_exp },
{ "EXPT", sch_power }, { "expt", sch_power },
{ "LOG", sch_log }, { "log", sch_log },
{ "SIN", sch_sin }, { "sin", sch_sin },
{ "COS", sch_cos }, { "cos", sch_cos },
{ "TAN", sch_tan }, { "tan", sch_tan },
{ "ATAN", sch_atan }, { "atan", sch_atan },
{ "SQRT", sch_sqrt }, { "sqrt", sch_sqrt },
{ "ROUND", sch_round }, { "round", sch_round },
{ "FLOOR", sch_floor }, { "floor", sch_floor },
{ "CEILING", sch_ceiling }, { "ceiling", sch_ceiling },
{ "QUOTIENT", sch_quotient }, { "quotient", sch_quotient },
{ "REMAINDER", sch_remainder }, { "remainder", sch_remainder },
{ "MODULO", sch_modulo }, { "modulo", sch_modulo },
{ "ABS", sch_abs }, { "abs", sch_abs },
{ "MAGNITUDE", sch_abs }, { "magnitude", sch_abs },
{ "EXACT?", sch_is_int }, { "exact?", sch_is_int },
{ "EXACT->INEXACT", sch_to_inexact }, { "exact->inexact", sch_to_inexact },
{ "INEXACT->EXACT", sch_to_exact }, { "inexact->exact", sch_to_exact },
// Symbols https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Symbols.html // Symbols
{ "SYMBOL?", sch_is_symbol }, { "symbol?", sch_is_symbol },
{ "SYMBOL<?", sch_symbol_less }, { "symbol<?", sch_symbol_less },
{ "STRING->SYMBOL", sch_string_to_symbol }, { "string->symbol", sch_string_to_symbol },
{ "SYMBOL->STRING", sch_symbol_to_string }, { "symbol->string", sch_symbol_to_string },
{ "GENERATE-UNINTERNED-SYMBOL", sch_gensym }, { "generate-uninterned-symbol", sch_gensym },
{ "GENSYM", sch_gensym }, { "gensym", sch_gensym },
// Environments https://groups.csail.mit.edu/mac/ftpdir/scheme-7.4/doc-html/scheme_14.html // Environments
{ "EVAL", sch_eval }, { "eval", sch_eval },
{ "SCHEME-REPORT-ENVIRONMENT", sch_system_env }, { "scheme-report-environment", sch_system_env },
{ "INTERACTION-ENVIRONMENT", sch_user_env }, { "interaction-environment", sch_user_env },
// { "THE-ENVIRONMENT", sch_current_env },
// Hash Tables https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Basic-Hash-Table-Operations.html#Basic-Hash-Table-Operations // Hash Tables
{ "HASH-TABLE?", sch_is_table }, { "hash-table?", sch_is_table },
{ "MAKE-HASH-TABLE", sch_table_make }, { "make-hash-table", sch_table_make },
{ "HASH-TABLE-SET!", sch_table_set }, { "hash-table-set!", sch_table_set },
{ "HASH-TABLE-REF", sch_table_get }, { "hash-table-ref", sch_table_get },
{ "HASH-TABLE-SIZE", sch_table_size }, { "hash-table-size", sch_table_size },
{ "HASH-TABLE->ALIST", sch_table_to_alist }, { "hash-table->alist", sch_table_to_alist },
{ "PROMISE?", sch_is_promise }, { "promise?", sch_is_promise },
{ "MAKE-PROMISE", sch_make_promise }, { "make-promise", sch_make_promise },
{ "_PROMISE-PROCEDURE", sch_promise_proc }, { "_promise-procedure", sch_promise_proc },
{ "_PROMISE-STORE!", sch_promise_store }, { "_promise-store!", sch_promise_store },
{ "PROMISE-VALUE", sch_promise_val }, { "promise-value", sch_promise_val },
{ "PROMISE-FORCED?", sch_promise_forced }, { "promise-forced?", sch_promise_forced },
// Procedures https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Procedure-Operations.html#Procedure-Operations // Procedures
{ "APPLY", sch_apply }, { "apply", sch_apply },
{ "COMPILED-PROCEDURE?", sch_is_func }, { "compiled-procedure?", sch_is_func },
{ "COMPOUND-PROCEDURE?", sch_is_lambda }, { "compound-procedure?", sch_is_lambda },
{ "PROCEDURE-ENVIRONMENT", sch_lambda_env }, { "procedure-environment", sch_lambda_env },
// TOOD: Almost standard { "procedure-body", sch_lambda_body },
{ "PROCEDURE-BODY", sch_lambda_body }, { "call/cc", sch_call_cc },
{ "CALL/CC", sch_call_cc }, { "continuation?", sch_is_cont },
{ "CONTINUATION?", sch_is_cont },
// Random Numbers https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-ref/Random-Numbers.html // Random Numbers
{ "RANDOM", sch_pseudo_rand }, { "random", sch_pseudo_rand },
{ "RANDOM-SEED!", sch_pseudo_seed }, { "random-seed!", sch_pseudo_seed },
// Garbage Collection https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-user/Garbage-Collection.html // Garbage Collection
{ "GC-FLIP", sch_gc_flip }, { "gc-flip", sch_gc_flip },
{ NULL, NULL } { NULL, NULL }
}; };
void lisp_lib_load(LispContext ctx) void lisp_lib_load(LispContext ctx)
@@ -2111,14 +2108,14 @@ void lisp_lib_load(LispContext ctx)
lisp_table_set( lisp_table_set(
table, table,
lisp_make_symbol("_CURRENT-OUTPUT-PORT", ctx), lisp_make_symbol("_current-output-port", ctx),
lisp_make_port(stdout, 0), lisp_make_port(stdout, 0),
ctx ctx
); );
lisp_table_set( lisp_table_set(
table, table,
lisp_make_symbol("_CURRENT-INPUT-PORT", ctx), lisp_make_symbol("_current-input-port", ctx),
lisp_make_port(stdin, 1), lisp_make_port(stdin, 1),
ctx ctx
); );
+2
View File
@@ -10,6 +10,8 @@
int editorRowCxToRx(erow *row, int cursor_x); int editorRowCxToRx(erow *row, int cursor_x);
int editorRowRxToCx(erow *row, int rx);
void editorUpdateRow(erow *row); void editorUpdateRow(erow *row);
void editorInsertRow(int at, char *s, size_t len); void editorInsertRow(int at, char *s, size_t len);
Executable
+42
View File
@@ -0,0 +1,42 @@
#!/bin/bash
echo "--- Welcome to Beluga installer ---"
read -p "Do you want to start the installation ? (Y/n)" confirm && [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]] || exit 1
# Check dependencies
if ! command -v "meson" &>/dev/null; then
echo "❌ Error: meson not found. Please install it first."
exit 1
fi
# Create config files
echo "Create config files ..."
mkdir -pv ~/.beluga/
cp -rv ./assets/ ~/.beluga/
mkdir -pv ~/.beluga/packages/
read -p "Do you want to replace your config file or keep it (init.lisp.bak) / (init.lisp.new) ? (Y/n)" confirm
if [[ "$confirm" =~ ^[Yy]$ ]]; then
mv ~/.beluga/config/init.lisp ~/.beluga/config/init.lisp.bak
cp -rv ./config/init.lisp ~/.beluga/config/
else
cp -rv ./config/init.lisp ~/.beluga/config/init.lisp.new
fi
# Compile the project
echo "Start compilation ..."
meson setup build/
meson compile -C build/
# Add to path
echo "Adding beluga to the path"
sudo cp -f ./build/beluga /usr/local/bin/
echo "Installation finish"
echo "Check ~/.beluga/config/init.lisp for customization"
+10 -1
View File
@@ -5,6 +5,9 @@
* interactions. \version 0.1 \date 21 septembre 2024 * interactions. \version 0.1 \date 21 septembre 2024
*/ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#define _DEFAULT_SOURCE #define _DEFAULT_SOURCE
@@ -22,14 +25,20 @@ struct editorConfig E;
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
char * splash_screen = (char *) calloc(256, sizeof(char));
enableRawMode(); enableRawMode();
initEditor(); initEditor();
if (argc >= 2) { if (argc >= 2) {
E.state = READ_AND_WRITE; E.state = READ_AND_WRITE;
editorOpen(argv[1]); editorOpen(argv[1]);
} else { } else {
editorOpen("assets/beluga.txt"); strcat(splash_screen, getenv("HOME"));
strcat(splash_screen, "/.beluga/assets/beluga.txt");
fprintf(stderr, "%s\n", splash_screen);
editorOpen(splash_screen);
} }
free(splash_screen);
editorSetStatusMessage("HELP: Ctrl-S = save | Ctrl-Q = quit"); editorSetStatusMessage("HELP: Ctrl-S = save | Ctrl-Q = quit");
+125 -23
View File
@@ -1,51 +1,87 @@
#include "../include/builtins.h" #include "../include/builtins.h"
#include "../include/define.h"
#include "../include/input.h"
#include "../include/file_io.h"
#include "../include/editor_op.h"
#include "../include/data.h" #include "../include/data.h"
#include "../include/define.h"
#include "../include/editor_op.h"
#include "../include/file_io.h"
#include "../include/input.h"
#include "../include/row_op.h"
#include "include/output.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
struct prefix_t find_prefix(const char prefix_name[64]) {
int i = E.number_of_prefix + 1;
while (i--) {
if (!strcmp(prefix_name, E.prefix[i].prefix_name)) {
return E.prefix[i];
}
}
return E.prefix[0];
}
Lisp mapKey(Lisp args, LispError *e, LispContext ctx) { Lisp mapKey(Lisp args, LispError *e, LispContext ctx) {
/*
* 3 arguments keybind command prefix
*/
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); Lisp func = lisp_car(args);
E.key_binds = E.key_binds = (struct keyBind_t *)realloc(
(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));
E.key_binds[E.number_of_keybinds - 1].key_sequence = (char *) malloc(50 * sizeof(char)); E.key_binds[E.number_of_keybinds - 1].key_sequence =
(char *)malloc(50 * sizeof(char));
strncpy(E.key_binds[E.number_of_keybinds - 1].key_sequence, key_sequence, 50); strncpy(E.key_binds[E.number_of_keybinds - 1].key_sequence, key_sequence, 50);
E.key_binds[E.number_of_keybinds - 1].command = func; E.key_binds[E.number_of_keybinds - 1].command = func;
// Third argument
args = lisp_cdr(args);
const char *prefix_name = lisp_string(lisp_car(args));
struct prefix_t prefix = find_prefix(prefix_name);
E.key_binds[E.number_of_keybinds - 1].prefix_id = prefix.prefix_id;
return lisp_null(); return lisp_null();
} }
Lisp moveCursor(Lisp args, LispError *e, LispContext ctx) { Lisp moveCursor(Lisp args, LispError *e, LispContext ctx) {
fprintf(stderr, "Cursor is moving\n");
const char *direction = lisp_string(lisp_car(args)); const char *direction = lisp_string(lisp_car(args));
int is_in = 0;
switch (direction[0]) { switch (direction[0]) {
case 'u': case 'u':
editorMoveCursor(ARROW_UP); is_in = editorMoveCursor(ARROW_UP);
break; break;
case 'd': case 'd':
editorMoveCursor(ARROW_DOWN); is_in = editorMoveCursor(ARROW_DOWN);
break; break;
case 'r': case 'r':
editorMoveCursor(ARROW_RIGHT); is_in = editorMoveCursor(ARROW_RIGHT);
break; break;
case 'l': case 'l':
editorMoveCursor(ARROW_LEFT); is_in = editorMoveCursor(ARROW_LEFT);
break; break;
} }
fprintf(stderr, "move lisp %d\n", is_in);
return lisp_make_bool(is_in);
}
void free_structs(void) {
int i;
free(E.prefix);
for (i = 0; i < E.number_of_keybinds; ++i) {
free(E.key_binds[i].key_sequence);
}
free(E.key_binds);
free(E.filename);
free(E.row->chars);
free(E.row->render);
free(E.row);
return lisp_null();
} }
Lisp editorQuit(Lisp args, LispError *e, LispContext ctx) { Lisp editorQuit(Lisp args, LispError *e, LispContext ctx) {
@@ -55,24 +91,21 @@ Lisp editorQuit(Lisp args, LispError* e, LispContext ctx) {
--E.quit_times_buffer; --E.quit_times_buffer;
return lisp_null(); return lisp_null();
} }
free_structs();
write(STDOUT_FILENO, "\x1b[2J", 4); write(STDOUT_FILENO, "\x1b[2J", 4);
write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3); write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3);
disableRawMode(); disableRawMode();
lisp_shutdown(E.ctx);
exit(0); exit(0);
return lisp_null(); return lisp_null();
} }
Lisp l_editorSave(Lisp args, LispError *e, LispContext ctx) { Lisp l_editorSave(Lisp args, LispError *e, LispContext ctx) {
editorSave(); editorSave();
return lisp_null(); return lisp_null();
} }
Lisp l_editorInsertNewLine(Lisp args, LispError *e, LispContext ctx) { Lisp l_editorInsertNewLine(Lisp args, LispError *e, LispContext ctx) {
@@ -80,8 +113,15 @@ Lisp l_editorInsertNewLine(Lisp args, LispError* e, LispContext ctx) {
editorInsertNewLine(); editorInsertNewLine();
return lisp_null(); return lisp_null();
}
Lisp l_editorInserTab(Lisp args, LispError *e, LispContext ctx) {
for (int i = 0; i<E.constantes.TAB_LENGTH; ++i) {
editorInsertChar(' ');
}
return lisp_null();
} }
Lisp moveCursorBeginLine(Lisp args, LispError *e, LispContext ctx) { Lisp moveCursorBeginLine(Lisp args, LispError *e, LispContext ctx) {
@@ -96,7 +136,6 @@ Lisp moveCursorEndLine(Lisp args, LispError* e, LispContext ctx) {
return lisp_null(); return lisp_null();
} }
Lisp deletePreviousChar(Lisp args, LispError *e, LispContext ctx) { Lisp deletePreviousChar(Lisp args, LispError *e, LispContext ctx) {
editorDelChar(); editorDelChar();
return lisp_null(); return lisp_null();
@@ -125,17 +164,80 @@ 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("Path : %s"); char *filename = editorPrompt("Open : %s", getenv("PWD"), 1);
if (filename) if (filename){
editorOpen(filename); editorOpen(filename);
}
free(filename);
return lisp_null(); return lisp_null();
} }
Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx) { Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx) {
char c = lisp_char(lisp_car(args)); char c = lisp_string(lisp_car(args))[0];
editorInsertChar(c); editorInsertChar(c);
return lisp_null(); return lisp_null();
} }
Lisp addPackage(Lisp args, LispError *e, LispContext ctx) {
const char *package_name = lisp_string(lisp_car(args));
fprintf(stderr, "%s\n", package_name);
char *package_dir = (char *)calloc(256, sizeof(char));
FILE *fd_package = NULL;
strcat(package_dir, getenv("HOME"));
strcat(package_dir, "/.beluga/packages/");
strcat(package_dir, package_name);
strcat(package_dir, "/init.lisp");
fprintf(stderr, "%s\n", package_dir);
fd_package = fopen(package_dir, "r");
lisp_eval(lisp_read_file(fd_package, &E.ctx_error, E.ctx), &E.ctx_error,
E.ctx);
fclose(fd_package);
free(package_dir);
return lisp_null();
}
Lisp editorDelRow_L(Lisp args, LispError *e, LispContext ctx) {
editorDelRow(E.cursor_y);
return lisp_null();
}
Lisp editorFind_L(Lisp args, LispError *e, LispContext ctx) {
editorFind();
return lisp_null();
}
Lisp editorReadChar_L(Lisp args, LispError *e, LispContext ctx) {
Lisp returned_char;
if (E.row[E.cursor_y].render[E.cursor_x] == 0) {
returned_char = lisp_make_char('a');
} else {
returned_char = lisp_make_char(E.row[E.cursor_y].render[E.cursor_x]);
}
return returned_char;
}
Lisp editorSetPrefix(Lisp args, LispError *e, LispContext ctx) {
/*
* Set the prefix state of editor to the prefix in argument
*/
const char *prefix_name = lisp_string(lisp_car(args));
struct prefix_t prefix = find_prefix(prefix_name);
E.prefix_state = prefix.prefix_id;
editorSetStatusMessage("prefix %s", prefix.prefix_name);
fprintf(stderr, "%s set\n", prefix_name);
return lisp_null();
}
Lisp editorPrefix(Lisp args, LispError *e, LispContext ctx) {
E.prefix = (struct prefix_t *)realloc(E.prefix, (++(E.number_of_prefix) + 1) *
sizeof(struct prefix_t));
E.prefix[E.number_of_prefix].prefix_id = E.number_of_prefix;
strncpy(E.prefix[E.number_of_prefix].prefix_name, lisp_string(lisp_car(args)),
64);
return lisp_null();
}
+5
View File
@@ -13,6 +13,10 @@ void editorInsertChar(int c) {
} }
void editorInsertNewLine() { void editorInsertNewLine() {
/*
* Add new line and place the cursor at the beginning of it
*/
fprintf(stderr, "Inserting new line\n");
erow *row; erow *row;
if (!E.cursor_x) { if (!E.cursor_x) {
editorInsertRow(E.cursor_y, "", 0); editorInsertRow(E.cursor_y, "", 0);
@@ -27,6 +31,7 @@ void editorInsertNewLine() {
} }
++E.cursor_y; ++E.cursor_y;
E.cursor_x = 0; E.cursor_x = 0;
fprintf(stderr, "Insert new line done\n");
} }
void editorDelChar() { void editorDelChar() {
+19 -1
View File
@@ -87,7 +87,7 @@ void editorSave() {
char *buf; char *buf;
int fd; int fd;
if (E.filename == NULL) { if (E.filename == NULL) {
E.filename = editorPrompt("Save as: %s (ESC to cancel)"); E.filename = editorPrompt("Save as: %s (ESC to cancel)", "", 1);
if (E.filename == NULL) { if (E.filename == NULL) {
editorSetStatusMessage("Save aborted"); editorSetStatusMessage("Save aborted");
return; return;
@@ -110,3 +110,21 @@ void editorSave() {
free(buf); free(buf);
editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno)); editorSetStatusMessage("Can't save! I/O error: %s", strerror(errno));
} }
void editorFind() {
char *query = editorPrompt("Search: %s (ESC to cancel)", "", 0);
if (query == NULL) return;
int i;
for (i = E.cursor_y + 1; i < E.numrows; i++) {
erow *row = &E.row[i];
char *match = strstr(row->render, query);
if (match) {
E.cursor_y = i;
E.cursor_x = editorRowRxToCx(row, match - row->render);
E.row_offset = E.numrows;
break;
}
}
free(query);
}
+33 -16
View File
@@ -1,8 +1,9 @@
#include "../include/init.h" #include "../include/init.h"
#include "../include/builtins.h"
#include "../include/data.h" #include "../include/data.h"
#include "../include/terminal.h" #include "../include/terminal.h"
#include "../include/builtins.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#define LISP_IMPLEMENTATION #define LISP_IMPLEMENTATION
#include "../include/lisp.h" #include "../include/lisp.h"
@@ -10,30 +11,36 @@
extern struct editorConfig; extern 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() {
// move cursor // move cursor
registerBuiltin("MOVE-CURSOR", moveCursor); registerBuiltin("move-cursor", moveCursor);
registerBuiltin("MAP-KEY", mapKey); registerBuiltin("map-key", mapKey);
registerBuiltin("EDITOR-QUIT", editorQuit); registerBuiltin("editor-quit", editorQuit);
registerBuiltin("EDITOR-SAVE", l_editorSave); registerBuiltin("editor-save", l_editorSave);
registerBuiltin("EDITOR-INSERT-NEW-LINE", l_editorInsertNewLine); registerBuiltin("editor-insert-new-line", l_editorInsertNewLine);
registerBuiltin("MOVE-CURSOR-BEG-LINE", moveCursorBeginLine); registerBuiltin("move-cursor-beg-line", moveCursorBeginLine);
registerBuiltin("MOVE-CURSOR-END-LINE", moveCursorEndLine); registerBuiltin("move-cursor-end-line", moveCursorEndLine);
registerBuiltin("EDITOR-DELETE-PREVIOUS-CHAR", deletePreviousChar); registerBuiltin("editor-delete-previous-char", deletePreviousChar);
registerBuiltin("MOVE-CURSOR-PAGE-UP", editorMoveCursorPageUp); registerBuiltin("move-cursor-page-up", editorMoveCursorPageUp);
registerBuiltin("MOVE-CURSOR-PAGE-DOWN", editorMoveCursorPageDown); registerBuiltin("move-cursor-page-down", editorMoveCursorPageDown);
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("editor-del-row", editorDelRow_L);
registerBuiltin("editor-find", editorFind_L);
registerBuiltin("editor-read-char", editorReadChar_L);
registerBuiltin("add-prefix", editorPrefix);
registerBuiltin("editor-set-prefix", editorSetPrefix);
registerBuiltin("editor-insert-tab", l_editorInserTab);
} }
void initEditor() { void initEditor() {
char *init_file_path = (char *)calloc(256, sizeof(char));
E.cursor_x = 0; E.cursor_x = 0;
E.cursor_y = 0; E.cursor_y = 0;
E.rx = 0; E.rx = 0;
@@ -52,9 +59,18 @@ void initEditor() {
E.screenrows -= 2; E.screenrows -= 2;
E.number_of_keybinds = 0; E.number_of_keybinds = 0;
E.number_of_prefix = 0;
// General prefix is 0 (no prefix)
E.prefix = (struct prefix_t *)malloc(sizeof(struct prefix_t));
E.prefix[0].prefix_id = 0;
strncpy(E.prefix[0].prefix_name, "no-prefix", 64);
E.prefix_state = 0;
E.fd_init_file = fopen("config/init.lisp", "r"); strcat(init_file_path, getenv("HOME"));
strcat(init_file_path, "/.beluga/config/init.lisp");
printf("%s\n", init_file_path);
E.fd_init_file = fopen(init_file_path, "r");
E.ctx = lisp_init(); E.ctx = lisp_init();
E.env = lisp_env(E.ctx); E.env = lisp_env(E.ctx);
lisp_lib_load(E.ctx); lisp_lib_load(E.ctx);
@@ -63,6 +79,7 @@ void initEditor() {
// Read config file // Read config file
E.ctx_data = lisp_read_file(E.fd_init_file, &E.ctx_error, E.ctx); E.ctx_data = lisp_read_file(E.fd_init_file, &E.ctx_error, E.ctx);
free(init_file_path);
if (E.ctx_error != LISP_ERROR_NONE) { if (E.ctx_error != LISP_ERROR_NONE) {
die("init failed"); die("init failed");
} }
+87 -10
View File
@@ -1,26 +1,79 @@
#include "../include/input.h" #include "../include/input.h"
#include "../include/define.h"
#include "../include/editor_op.h" #include "../include/editor_op.h"
#include "../include/output.h" #include "../include/output.h"
#include "../include/define.h"
#include <ctype.h> #include <ctype.h>
#include <dirent.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
extern struct editorConfig E; extern struct editorConfig E;
char *file_completion(const char *path) {
DIR *dir;
struct dirent *entry;
char directory[128];
char predict[128];
int predict_len = 0;
if (path[strlen(path) - 1] == '/') {
return path;
}
// Find dir name
char *last_slash = strrchr(path, '/');
if (last_slash) {
size_t dir_len = last_slash - path + 1; // length of dir_path
strncpy(directory, path, dir_len);
predict_len = strlen(path) - dir_len - 1;
strncpy(predict, last_slash + 1, predict_len);
directory[dir_len] = '\0';
predict[predict_len] = '\0';
fprintf(stderr, "%s %s\n", directory, predict);
} else {
return NULL;
}
dir = opendir(directory);
if (!dir)
return NULL;
while ((entry = readdir(dir)) != NULL) {
if (strncmp(entry->d_name, predict, predict_len) == 0) {
static char full_path[128];
snprintf(full_path, sizeof(full_path), "%s%s", directory, entry->d_name);
struct stat st;
if (stat(full_path, &st) == 0 && S_ISDIR(st.st_mode)) {
strcat(full_path, "/"); // add slash for directories
}
return strdup(full_path);
}
}
// Cleanup when no more entries
closedir(dir);
dir = NULL;
return NULL;
}
/** /**
* \fn char * editorPrompt(struct editorConfig *E, char *prompt) * \fn char * editorPrompt(struct editorConfig *E, char *prompt, char bPathMode)
* \brief Return user input in a prompt when enter is hit. */ * \brief Return user input in a prompt when enter is hit. */
char *editorPrompt(char *prompt) { char *editorPrompt(char *prompt, char *placeHolder, char bPathMode) {
size_t buf_size = 128; size_t buf_size = 128;
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;
buf[0] = '\0'; buf[0] = '\0';
strcpy(buf, placeHolder);
buf_len = strlen(placeHolder);
while (1) { while (1) {
editorSetStatusMessage(prompt, buf); editorSetStatusMessage(prompt, buf);
@@ -39,6 +92,24 @@ char *editorPrompt(char *prompt) {
editorSetStatusMessage(""); editorSetStatusMessage("");
return buf; return buf;
} }
} else if (bPathMode && c == '\t') {
char path[128];
char *pwd;
if (buf[0] != '/') {
pwd = getenv("PWD");
fprintf(stderr, "%s\n", pwd);
memcpy(path, pwd, strlen(pwd));
path[strlen(pwd)] = '/';
strncat(path, buf, buf_len);
} else {
strcpy(path, buf);
}
memset(buf, 0, 128);
buf_len = 0;
strcpy(buf, file_completion(path));
buf_len = strlen(buf);
buf[buf_len] = '\0';
} else if (!iscntrl(c) && c < 128) { } else if (!iscntrl(c) && c < 128) {
if (buf_len == buf_size - 1) { if (buf_len == buf_size - 1) {
buf_size *= 2; buf_size *= 2;
@@ -56,11 +127,12 @@ char *key_to_string(int key) {
char tmp[10]; char tmp[10];
sprintf(tmp, "%d", key); sprintf(tmp, "%d", key);
// First test enter key // First test enter key
if (key == '\r') { if (key == '\r') {
strcpy(key_str, "ENTER"); strcpy(key_str, "ENTER");
} else if (key == '\t') {
strcpy(key_str, "TAB");
} else if (key >= 1 && key <= 26) { // CTRL keys } else if (key >= 1 && key <= 26) { // CTRL keys
snprintf(key_str, sizeof(key_str), "CTRL-%c", 'a' + key - 1); snprintf(key_str, sizeof(key_str), "CTRL-%c", 'a' + key - 1);
} else { } else {
@@ -85,7 +157,6 @@ char *key_to_string(int key) {
strcpy(key_str, "PAGE-DOWN"); strcpy(key_str, "PAGE-DOWN");
break; break;
case DEL_KEY: case DEL_KEY:
fprintf(stderr, "delete key\n");
strcpy(key_str, "DEL"); strcpy(key_str, "DEL");
break; break;
@@ -116,8 +187,7 @@ char *key_to_string(int key) {
return key_str; return key_str;
} }
int editorMoveCursor(int key) {
void editorMoveCursor(int key) {
erow *row = (E.cursor_y >= E.numrows) ? NULL : &E.row[E.cursor_y]; erow *row = (E.cursor_y >= E.numrows) ? NULL : &E.row[E.cursor_y];
int row_len; int row_len;
switch (key) { switch (key) {
@@ -153,18 +223,26 @@ void editorMoveCursor(int key) {
row_len = row ? row->size : 0; row_len = row ? row->size : 0;
if (E.cursor_x > row_len) { if (E.cursor_x > row_len) {
E.cursor_x = row_len; E.cursor_x = row_len;
return 0;
} }
return 1;
} }
int executeKeyBind(char *key_sequence) { int executeKeyBind(char *key_sequence) {
int i; int i;
int previous_state = 0;
fprintf(stderr, "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) {
fprintf(stderr, "lisp function %s\n", key_sequence); return 0;
}
previous_state = E.prefix_state;
// It's a symbol, create a function call // It's a symbol, create a function call
lisp_eval(lisp_cons(E.key_binds[i].command, lisp_null(), E.ctx), lisp_eval(lisp_cons(E.key_binds[i].command, lisp_null(), E.ctx),
&E.ctx_error, E.ctx); &E.ctx_error, E.ctx);
if (E.prefix_state == previous_state)
E.prefix_state = 0;
return 1; return 1;
} }
} }
@@ -179,5 +257,4 @@ void editorProcessKeypress() {
} }
editorInsertChar(c); editorInsertChar(c);
E.quit_times_buffer = E.constantes.QUIT_TIMES; E.quit_times_buffer = E.constantes.QUIT_TIMES;
} }
+12
View File
@@ -18,6 +18,18 @@ int editorRowCxToRx(erow *row, int cursor_x) {
return render_x; return render_x;
} }
int editorRowRxToCx(erow *row, int rx) {
int cur_rx = 0;
int cx;
for (cx = 0; cx < row->size; cx++) {
if (row->chars[cx] == '\t')
cur_rx += (E.constantes.TAB_LENGTH - 1) - (cur_rx % E.constantes.TAB_LENGTH);
cur_rx++;
if (cur_rx > rx) return cx;
}
return cx;
}
/** /**
* \fn editorUpdateRow(erow *row) * \fn editorUpdateRow(erow *row)
* \brief Copy content of \p row in \p row->render. * \brief Copy content of \p row in \p row->render.