Compare commits
38 Commits
8ce621dfde
..
V2.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d253e51ef | |||
| 42f82e2e0d | |||
| fa32f4b177 | |||
| 65f997e964 | |||
| 7eaf6913cb | |||
| 8f7dcf3534 | |||
| d8c6b9ace3 | |||
| d0173d7308 | |||
| 40fc234eeb | |||
| 756deba83e | |||
| 85e8067e41 | |||
| 09d78f48e9 | |||
| ce94e9fb87 | |||
| 29a92ce904 | |||
| 9348ae668a | |||
| 9157b94398 | |||
| 3b6c60a49e | |||
| 53d6572c8c | |||
| d083948dfe | |||
| 09ef5c0f3b | |||
| e4691669b8 | |||
| 27ae0a684f | |||
| 3505084527 | |||
| 02d7f27ec3 | |||
| 7dded62db9 | |||
| 6cd79b5c76 | |||
| d9aab06c1c | |||
| 8844d2f064 | |||
| d8fc7d2d67 | |||
| ab482df604 | |||
| be31e83fb9 | |||
| 54db6321ad | |||
| ec0eba849a | |||
| 2ca64fae41 | |||
| 72178adebb | |||
| 7a98f89531 | |||
| 3e562c1071 | |||
| bff3f84ecd |
@@ -0,0 +1,35 @@
|
||||
name: Build project
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
tokens: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y meson ninja-build gcc
|
||||
|
||||
- name: Configure Meson
|
||||
run: meson setup build
|
||||
|
||||
- name: Build project
|
||||
run: meson compile -C build
|
||||
|
||||
- name: Run tests
|
||||
run: ctest --test-dir build || true
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: beluga
|
||||
path: build/beluga
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
tmp/*
|
||||
bin/*
|
||||
build/*
|
||||
doc/*
|
||||
beluga.wiki/*
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "lisp-interpreter"]
|
||||
path = lisp-interpreter
|
||||
url = https://github.com/justinmeiners/lisp-interpreter.git
|
||||
@@ -1,26 +1,33 @@
|
||||
# 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.
|
||||
It's abviously only working for **Linux**.
|
||||
|
||||
## Requirements
|
||||
|
||||
You will only need **make** or **gcc** to compile the editor.
|
||||
You will only need **meson** and a **C compiler** to compile the editor.
|
||||
|
||||
## Installation
|
||||
### From source
|
||||
Here is the installation line for development version:
|
||||
|
||||
Here is the installation line :
|
||||
```git clone https://homelinuxserver.ddns.net/git/arthur/beluga.git ~/.beluga && cd ~/.beluga && meson setup build && meson compile -C build```
|
||||
|
||||
```git clone --branch V1.0 --single-branch https://github.com/le-cocotier/beluga.git ~/.beluga && cd ~/.beluga && make build```
|
||||
The executable file will be `build/beluga`. Feel free to add it to your path.
|
||||
|
||||
The executable file will be in `bin/beluga`. Feel free to add it to your path.
|
||||
### From installation script ( prefered )
|
||||
|
||||
You can either run `make all` if you're interested by the doxygen documentation.
|
||||
Just clone the repo and execute the script `install.sh`. It will automatically add beluga to your path.
|
||||
|
||||
## Getting start
|
||||
|
||||
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 :
|
||||
- Ctrl-Q : leave the editor
|
||||
- Ctrl-S : Save a file
|
||||
Here is some few command that you will need :
|
||||
|
||||
| keybind| command |
|
||||
|--------|------------------|
|
||||
| Ctrl-Q | leave the editor |
|
||||
| Ctrl-S | Save a file |
|
||||
| Ctrl-O | open file |
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
**#%#*****###%**
|
||||
*##+--------------------=##*
|
||||
#*=----------------------------=*#*
|
||||
#*------------------------------------*#
|
||||
%+----------------------------------------=#*
|
||||
#+---------------------------------------------##
|
||||
*#-------------------------------------------------=##
|
||||
*#----------------------------------------------------:-##
|
||||
#----------------------------------------------------------##
|
||||
#=--------------------------------------------------------------##
|
||||
+--------------------------+@#-%*-----------------------------------#*
|
||||
+--------------------------%@@@@#-------------------------------------** BELUGA - VERSION 1.1
|
||||
*-=-------------------------#@@*---------------------------------------=%
|
||||
%*#==--------------------------------------------------------------------+# ----- KEY-BINDS -----
|
||||
*%%=-=--------------------------------------------------------------------=# CTRL-q leave
|
||||
%=--------------------------------------------------------------------------#* CTRL-s save
|
||||
%-----------------------------------------------------------------------------** CTRL-o open-file
|
||||
*+--=---===----=---------------=*-----------------------------------------------**
|
||||
#--=## *#%#*+==----==+**+----------------------= ***=---------------------%
|
||||
*%**=-----------==== ==---------------------------------=+#+-----------------=#
|
||||
*%=----------------------------------------------------------=#*---------------#
|
||||
##=----------------------------------=------------------------+%=------------+#
|
||||
#%+---------------------------------=*------------------------+%------------#
|
||||
*#%*=-------------=-----------------#-------------------------#+----------#
|
||||
**#%#*******+=======-------------#=------------------------#----------#
|
||||
#===#*=======------------------#*----=-----------=--=##*-----------#
|
||||
-====##=------------------------*%+------------=*#+=====----------#
|
||||
--=====+#*=----------------------=-=+*#####***+=======-----------=*
|
||||
%------=====*%*=-------------------------========-----------------+*
|
||||
*-=--------====%%###+=--------------------------=-----------------#
|
||||
#-----------=% +*##%%%%%%@@%%%%####*==---------------------**
|
||||
%=-------#* #%*=-----------------+#
|
||||
*%+--=## ##=-----------------=#*
|
||||
** #+----=-------------------#*
|
||||
%+----------------------------#*
|
||||
*%-------------==----------------+#
|
||||
##--------------==------------------#
|
||||
*#--------------===%-----------------=%
|
||||
##---------------=-##*-----------------+#
|
||||
*#---------------==#+=#%-----------------%
|
||||
*%---------------+# %*---------------#*
|
||||
*#------------=+#* #%*=-----------#*
|
||||
#****##****** *#%%##+=----%
|
||||
@@ -0,0 +1,34 @@
|
||||
;; MACROS
|
||||
|
||||
(define TAB-LENGTH 4)
|
||||
(define QUIT-TIMES 1)
|
||||
|
||||
;; FUNCTIONS
|
||||
|
||||
(define editor-delete-next-char (lambda () (
|
||||
(move-cursor "right")
|
||||
(editor-delete-previous-char)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
;; KEY MAPPING
|
||||
|
||||
(map-key "CTRL-q" editor-quit)
|
||||
(map-key "CTRL-s" editor-save)
|
||||
(map-key "ARROW-UP" '(move-cursor "up"))
|
||||
(map-key "ARROW-DOWN" '(move-cursor "down"))
|
||||
(map-key "ARROW-RIGHT" '(move-cursor "right"))
|
||||
(map-key "ARROW-LEFT" '(move-cursor "left"))
|
||||
(map-key "ENTER" editor-insert-new-line)
|
||||
(map-key "CTRL-a" move-cursor-beg-line)
|
||||
(map-key "CTRL-e" move-cursor-end-line)
|
||||
(map-key "BACKSPACE" editor-delete-previous-char)
|
||||
(map-key "DEL" editor-delete-next-char)
|
||||
(map-key "PAGE-UP" move-cursor-page-up)
|
||||
(map-key "PAGE-DOWN" move-cursor-page-down)
|
||||
(map-key "CTRL-o" editor-open-file)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef BUILTINS_H_
|
||||
#define BUILTINS_H_
|
||||
|
||||
#include "lisp.h"
|
||||
|
||||
Lisp moveCursor(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
Lisp mapKey(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
void registerBuiltin(char * key_sequence, LispCFunc f);
|
||||
|
||||
Lisp editorQuit(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
Lisp l_editorSave(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
Lisp l_editorInsertNewLine(Lisp args, LispError* e, LispContext ctx);
|
||||
|
||||
Lisp moveCursorBeginLine(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
Lisp moveCursorEndLine(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
Lisp deletePreviousChar(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
Lisp editorMoveCursorPageUp(Lisp args, LispError* e, LispContext ctx);
|
||||
|
||||
Lisp editorMoveCursorPageDown(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
Lisp editorOpenFile(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
Lisp addPackage(Lisp args, LispError *e, LispContext ctx);
|
||||
|
||||
#endif
|
||||
+32
-1
@@ -1,10 +1,12 @@
|
||||
#ifndef DATA_H_
|
||||
#define DATA_H_
|
||||
|
||||
#include "../lisp-interpreter/dist/lisp.h"
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "lisp.h"
|
||||
|
||||
/**
|
||||
* \struct erow
|
||||
* \brief Store one editor row
|
||||
@@ -18,6 +20,23 @@ typedef struct erow {
|
||||
char *render; /**< The actual line we will print */
|
||||
} erow;
|
||||
|
||||
enum editorStatus_e {
|
||||
IDLE,
|
||||
READ_ONLY,
|
||||
READ_AND_WRITE,
|
||||
};
|
||||
|
||||
struct const_t {
|
||||
int TAB_LENGTH;
|
||||
int QUIT_TIMES;
|
||||
};
|
||||
|
||||
struct keyBind_t {
|
||||
char *key_sequence;
|
||||
Lisp command;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct editorConfig
|
||||
* \brief Containing our editor state.
|
||||
@@ -33,12 +52,23 @@ struct editorConfig {
|
||||
erow *row; /**< Store all the rows printed */
|
||||
int dirty;
|
||||
char *filename;
|
||||
enum editorStatus_e state;
|
||||
char status_msg[80];
|
||||
time_t status_msg_time;
|
||||
struct termios orig_termios; /**< Terminal communication interface */
|
||||
|
||||
struct const_t constantes;
|
||||
int quit_times_buffer;
|
||||
|
||||
FILE *fd_init_file;
|
||||
Lisp env;
|
||||
LispContext ctx; /** Lisp context */
|
||||
Lisp ctx_data; /** Lisp data context */
|
||||
LispError ctx_error; /** Lisp ctx error */
|
||||
|
||||
struct keyBind_t* key_binds;
|
||||
int number_of_keybinds;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -53,4 +83,5 @@ struct abuf {
|
||||
|
||||
extern struct editorConfig E;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+1
-3
@@ -24,8 +24,6 @@ enum editorKey {
|
||||
|
||||
#define ABUF_INIT {NULL, 0}
|
||||
|
||||
#define BELUGA_VERSION "1.0"
|
||||
#define TAB_LENGTH 4
|
||||
#define QUIT_TIMES 1
|
||||
#define BELUGA_VERSION "1.1"
|
||||
|
||||
#endif // DEFINE_H_
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
|
||||
char *editorRowsToString(int *buffer_len);
|
||||
|
||||
|
||||
void editorCloseFile(void);
|
||||
|
||||
void editorOpen(char *filename);
|
||||
|
||||
void editorSave();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef INIT_H_
|
||||
#define INIT_H_
|
||||
|
||||
#include "builtins.h"
|
||||
#include "data.h"
|
||||
#include "terminal.h"
|
||||
#include <stdio.h>
|
||||
@@ -10,6 +11,8 @@
|
||||
* \brief Job's function is to initialize all the fields of editorConfig.
|
||||
* */
|
||||
|
||||
void initBuiltins();
|
||||
|
||||
void initEditor();
|
||||
|
||||
#endif // INIT_H_
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "define.h"
|
||||
#include "output.h"
|
||||
#include "terminal.h"
|
||||
#include "builtins.h"
|
||||
#include <unistd.h>
|
||||
|
||||
// KEYS keycode
|
||||
@@ -21,8 +22,12 @@
|
||||
|
||||
char *editorPrompt(char *prompt);
|
||||
|
||||
char *key_to_string(int key);
|
||||
|
||||
void editorMoveCursor(int key);
|
||||
|
||||
int executeKeyBind(char *key_sequence);
|
||||
|
||||
/**
|
||||
* \fn void editorProcessKeypress()
|
||||
* \brief Get the last key input and do the proper action.
|
||||
|
||||
+3215
File diff suppressed because it is too large
Load Diff
+2180
File diff suppressed because it is too large
Load Diff
Executable
+42
@@ -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"
|
||||
Submodule lisp-interpreter deleted from 366bfb9bdb
@@ -5,6 +5,11 @@
|
||||
* interactions. \version 0.1 \date 21 septembre 2024
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define _DEFAULT_SOURCE
|
||||
#define _BSD_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
@@ -20,14 +25,24 @@ struct editorConfig E;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
char * splash_screen = (char *) calloc(256, sizeof(char));
|
||||
|
||||
enableRawMode();
|
||||
initEditor();
|
||||
if (argc >= 2) {
|
||||
E.state = READ_AND_WRITE;
|
||||
editorOpen(argv[1]);
|
||||
} else {
|
||||
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");
|
||||
|
||||
|
||||
while (1) {
|
||||
editorRefreshScreen();
|
||||
editorProcessKeypress();
|
||||
|
||||
+8
-35
@@ -1,39 +1,12 @@
|
||||
project('editor', 'c',
|
||||
version : '1.0.0',
|
||||
project('beluga', 'c',
|
||||
version : '1.1',
|
||||
default_options : [
|
||||
'warning_level=2',
|
||||
'c_std=c99'
|
||||
'c_std=none',
|
||||
]
|
||||
)
|
||||
|
||||
# Check if we're using Clang and add Clang-specific options
|
||||
cc = meson.get_compiler('c')
|
||||
if cc.get_id() == 'clang'
|
||||
add_project_arguments([
|
||||
'-Wextra',
|
||||
'-Wpedantic',
|
||||
'-Wno-unused-parameter',
|
||||
'-fcolor-diagnostics' # Colored output
|
||||
], language : 'c')
|
||||
|
||||
# Add debug options for debug builds
|
||||
if get_option('buildtype') == 'debug'
|
||||
add_project_arguments([
|
||||
'-fsanitize=address', # AddressSanitizer
|
||||
'-fsanitize=undefined', # UndefinedBehaviorSanitizer
|
||||
'-g3', # Full debug info
|
||||
'-O0' # No optimization
|
||||
], language : 'c')
|
||||
|
||||
add_project_link_arguments([
|
||||
'-fsanitize=address',
|
||||
'-fsanitize=undefined'
|
||||
], language : 'c')
|
||||
endif
|
||||
endif
|
||||
|
||||
# Include directory
|
||||
inc_dir = include_directories('include')
|
||||
m = cc.find_library('m', required: false)
|
||||
|
||||
# Source files
|
||||
src_files = files(
|
||||
@@ -45,12 +18,12 @@ src_files = files(
|
||||
'src/input.c',
|
||||
'src/output.c',
|
||||
'src/row_op.c',
|
||||
'src/terminal.c'
|
||||
'src/terminal.c',
|
||||
'src/builtins.c',
|
||||
)
|
||||
|
||||
# Executable
|
||||
executable('editor',
|
||||
executable('beluga',
|
||||
src_files,
|
||||
include_directories : inc_dir,
|
||||
install : true
|
||||
dependencies: [m]
|
||||
)
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
#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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
Lisp mapKey(Lisp args, LispError *e, LispContext ctx) {
|
||||
const char *key_sequence = lisp_string(lisp_car(args));
|
||||
args = lisp_cdr(args);
|
||||
// second argument
|
||||
Lisp func = lisp_car(args);
|
||||
|
||||
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 - 1].key_sequence = (char *) malloc(50 * sizeof(char));
|
||||
|
||||
strncpy(E.key_binds[E.number_of_keybinds - 1].key_sequence, key_sequence, 50);
|
||||
|
||||
E.key_binds[E.number_of_keybinds - 1].command = func;
|
||||
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp moveCursor(Lisp args, LispError *e, LispContext ctx) {
|
||||
const char *direction = lisp_string(lisp_car(args));
|
||||
switch (direction[0]) {
|
||||
case 'u':
|
||||
editorMoveCursor(ARROW_UP);
|
||||
break;
|
||||
case 'd':
|
||||
editorMoveCursor(ARROW_DOWN);
|
||||
break;
|
||||
case 'r':
|
||||
editorMoveCursor(ARROW_RIGHT);
|
||||
break;
|
||||
case 'l':
|
||||
editorMoveCursor(ARROW_LEFT);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp editorQuit(Lisp args, LispError* e, LispContext ctx) {
|
||||
if (E.dirty && E.quit_times_buffer > 0) {
|
||||
editorSetStatusMessage("WARNING! Changes hasn't been saved. Press Ctrl-Q "
|
||||
"another time to quit.");
|
||||
--E.quit_times_buffer;
|
||||
return lisp_null();
|
||||
}
|
||||
write(STDOUT_FILENO, "\x1b[2J", 4);
|
||||
write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3);
|
||||
disableRawMode();
|
||||
exit(0);
|
||||
|
||||
return lisp_null();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Lisp l_editorSave(Lisp args, LispError* e, LispContext ctx) {
|
||||
|
||||
editorSave();
|
||||
|
||||
return lisp_null();
|
||||
|
||||
|
||||
}
|
||||
|
||||
Lisp l_editorInsertNewLine(Lisp args, LispError* e, LispContext ctx) {
|
||||
|
||||
editorInsertNewLine();
|
||||
|
||||
return lisp_null();
|
||||
|
||||
|
||||
}
|
||||
|
||||
Lisp moveCursorBeginLine(Lisp args, LispError *e, LispContext ctx) {
|
||||
E.cursor_x = 0;
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp moveCursorEndLine(Lisp args, LispError* e, LispContext ctx) {
|
||||
if (E.cursor_y < E.numrows) {
|
||||
E.cursor_x = E.row[E.cursor_y].size;
|
||||
}
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
|
||||
Lisp deletePreviousChar(Lisp args, LispError* e, LispContext ctx) {
|
||||
editorDelChar();
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp editorMoveCursorPageUp(Lisp args, LispError* e, LispContext ctx) {
|
||||
E.cursor_y = E.row_offset;
|
||||
int times = E.screenrows;
|
||||
while (--times) {
|
||||
editorMoveCursor(ARROW_UP);
|
||||
}
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp editorMoveCursorPageDown(Lisp args, LispError* e, LispContext ctx) {
|
||||
E.cursor_y = E.row_offset + E.screenrows - 1;
|
||||
if (E.cursor_y > E.numrows) {
|
||||
E.cursor_y = E.numrows;
|
||||
}
|
||||
int times = E.screenrows;
|
||||
while (--times) {
|
||||
editorMoveCursor(ARROW_DOWN);
|
||||
}
|
||||
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp editorOpenFile(Lisp args, LispError *e, LispContext ctx) {
|
||||
char *filename = editorPrompt("Path : %s");
|
||||
if (filename)
|
||||
editorOpen(filename);
|
||||
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
|
||||
Lisp editorPrintC(Lisp args, LispError *e, LispContext ctx) {
|
||||
char c = lisp_string(lisp_car(args))[0];
|
||||
editorInsertChar(c);
|
||||
return lisp_null();
|
||||
}
|
||||
|
||||
Lisp addPackage(Lisp args, LispError *e, LispContext ctx) {
|
||||
const char *package_name = lisp_string(lisp_car(args));
|
||||
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");
|
||||
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();
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "../include/editor_op.h"
|
||||
#include "../include/row_op.h"
|
||||
|
||||
|
||||
extern struct editorConfig E;
|
||||
|
||||
void editorInsertChar(int c) {
|
||||
|
||||
+21
-1
@@ -36,13 +36,33 @@ char *editorRowsToString(int *buffer_len) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
void editorCloseFile(void) {
|
||||
E.cursor_x = 0;
|
||||
E.cursor_y = 0;
|
||||
E.rx = 0;
|
||||
E.row_offset = 0;
|
||||
E.col_offset = 0;
|
||||
E.numrows = 0;
|
||||
E.row = NULL;
|
||||
E.dirty = 0;
|
||||
E.filename = NULL;
|
||||
E.status_msg[0] = '\0';
|
||||
E.status_msg_time = 0;
|
||||
}
|
||||
|
||||
void editorOpen(char *filename) {
|
||||
FILE *fp;
|
||||
|
||||
// Test if a file is already open
|
||||
if (E.filename != NULL) {
|
||||
editorCloseFile();
|
||||
E.state = READ_AND_WRITE;
|
||||
}
|
||||
|
||||
free(E.filename);
|
||||
E.filename = strdup(filename);
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
fp = fopen(filename, "a+");
|
||||
if (!fp)
|
||||
die("fopen");
|
||||
|
||||
|
||||
+66
-2
@@ -1,11 +1,41 @@
|
||||
#include "../include/init.h"
|
||||
#include "data.h"
|
||||
#include "../include/data.h"
|
||||
#include "../include/terminal.h"
|
||||
#include "../include/builtins.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define LISP_IMPLEMENTATION
|
||||
#include "../include/lisp.h"
|
||||
#include "../include/lisp_lib.h"
|
||||
|
||||
extern struct editorConfig;
|
||||
|
||||
|
||||
void registerBuiltin(char *key_sequence, LispCFunc f) {
|
||||
lisp_env_define(E.ctx.p->env, lisp_make_symbol(key_sequence, E.ctx),
|
||||
lisp_make_func(f), E.ctx);
|
||||
|
||||
}
|
||||
|
||||
void initBuiltins() {
|
||||
// move cursor
|
||||
registerBuiltin("MOVE-CURSOR", moveCursor);
|
||||
registerBuiltin("MAP-KEY", mapKey);
|
||||
registerBuiltin("EDITOR-QUIT", editorQuit);
|
||||
registerBuiltin("EDITOR-SAVE", l_editorSave);
|
||||
registerBuiltin("EDITOR-INSERT-NEW-LINE", l_editorInsertNewLine);
|
||||
registerBuiltin("MOVE-CURSOR-BEG-LINE", moveCursorBeginLine);
|
||||
registerBuiltin("MOVE-CURSOR-END-LINE", moveCursorEndLine);
|
||||
registerBuiltin("EDITOR-DELETE-PREVIOUS-CHAR", deletePreviousChar);
|
||||
registerBuiltin("MOVE-CURSOR-PAGE-UP", editorMoveCursorPageUp);
|
||||
registerBuiltin("MOVE-CURSOR-PAGE-DOWN", editorMoveCursorPageDown);
|
||||
registerBuiltin("EDITOR-OPEN-FILE", editorOpenFile);
|
||||
registerBuiltin("EDITOR-INSERT-CHAR", editorPrintC);
|
||||
registerBuiltin("ADD-PACKAGE", addPackage);
|
||||
}
|
||||
|
||||
void initEditor() {
|
||||
char * init_file_path = (char *) calloc(256, sizeof(char));
|
||||
E.cursor_x = 0;
|
||||
E.cursor_y = 0;
|
||||
E.rx = 0;
|
||||
@@ -15,10 +45,44 @@ void initEditor() {
|
||||
E.row = NULL;
|
||||
E.dirty = 0;
|
||||
E.filename = NULL;
|
||||
E.state = READ_ONLY;
|
||||
E.status_msg[0] = '\0';
|
||||
E.status_msg_time = 0;
|
||||
if (getWindowSize(&E.screenrows, &E.screencols) == -1) {
|
||||
die("getWindowSize");
|
||||
}
|
||||
E.screenrows -= 2;
|
||||
|
||||
E.number_of_keybinds = 0;
|
||||
|
||||
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.env = lisp_env(E.ctx);
|
||||
lisp_lib_load(E.ctx);
|
||||
// Init builtins lisp functions
|
||||
initBuiltins();
|
||||
|
||||
// Read config file
|
||||
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) {
|
||||
die("init failed");
|
||||
}
|
||||
lisp_eval(E.ctx_data, &E.ctx_error, E.ctx);
|
||||
|
||||
// To modify
|
||||
|
||||
E.constantes.TAB_LENGTH =
|
||||
(int)lisp_eval(lisp_read("TAB-LENGTH", &E.ctx_error, E.ctx), &E.ctx_error,
|
||||
E.ctx)
|
||||
.val.int_val;
|
||||
E.constantes.QUIT_TIMES =
|
||||
(int)lisp_eval(lisp_read("QUIT-TIMES", &E.ctx_error, E.ctx), &E.ctx_error,
|
||||
E.ctx)
|
||||
.val.int_val;
|
||||
|
||||
E.quit_times_buffer = E.constantes.QUIT_TIMES;
|
||||
}
|
||||
|
||||
+87
-73
@@ -1,11 +1,12 @@
|
||||
#include "../include/input.h"
|
||||
#include "../include/editor_op.h"
|
||||
#include "../include/file_io.h"
|
||||
#include "../include/output.h"
|
||||
#include "../include/define.h"
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern struct editorConfig E;
|
||||
@@ -30,7 +31,6 @@ char *editorPrompt(char *prompt) {
|
||||
buf[--buf_len] = '\0';
|
||||
}
|
||||
} else if (c == ESCAPE) {
|
||||
fprintf(stderr, "escape");
|
||||
editorSetStatusMessage("");
|
||||
free(buf);
|
||||
return NULL;
|
||||
@@ -50,6 +50,73 @@ char *editorPrompt(char *prompt) {
|
||||
}
|
||||
}
|
||||
|
||||
char *key_to_string(int key) {
|
||||
static char key_str[32];
|
||||
|
||||
char tmp[10];
|
||||
sprintf(tmp, "%d", key);
|
||||
|
||||
|
||||
// First test enter key
|
||||
|
||||
if (key == '\r') {
|
||||
strcpy(key_str, "ENTER");
|
||||
} else if (key >= 1 && key <= 26) { // CTRL keys
|
||||
snprintf(key_str, sizeof(key_str), "CTRL-%c", 'a' + key - 1);
|
||||
} else {
|
||||
switch (key) {
|
||||
case ARROW_UP:
|
||||
strcpy(key_str, "ARROW-UP");
|
||||
break;
|
||||
case ARROW_DOWN:
|
||||
strcpy(key_str, "ARROW-DOWN");
|
||||
break;
|
||||
case ARROW_LEFT:
|
||||
strcpy(key_str, "ARROW-LEFT");
|
||||
break;
|
||||
case ARROW_RIGHT:
|
||||
strcpy(key_str, "ARROW-RIGHT");
|
||||
break;
|
||||
case PAGE_UP:
|
||||
strcpy(key_str, "PAGE-UP");
|
||||
fprintf(stderr, "pagr up\n");
|
||||
break;
|
||||
case PAGE_DOWN:
|
||||
strcpy(key_str, "PAGE-DOWN");
|
||||
break;
|
||||
case DEL_KEY:
|
||||
fprintf(stderr, "delete key\n");
|
||||
strcpy(key_str, "DEL");
|
||||
|
||||
break;
|
||||
case BACKSPACE:
|
||||
strcpy(key_str, "BACKSPACE");
|
||||
break;
|
||||
case '\r':
|
||||
strcpy(key_str, "ENTER");
|
||||
break;
|
||||
case '\x1b':
|
||||
strcpy(key_str, "ESCAPE");
|
||||
break;
|
||||
case BEG_LINE:
|
||||
strcpy(key_str, "HOME");
|
||||
break;
|
||||
case END_LINE:
|
||||
strcpy(key_str, "END");
|
||||
break;
|
||||
default:
|
||||
// For regular characters
|
||||
if (isprint(key)) {
|
||||
snprintf(key_str, sizeof(key_str), "%c", key);
|
||||
} else {
|
||||
snprintf(key_str, sizeof(key_str), "KEY-%d", key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return key_str;
|
||||
}
|
||||
|
||||
|
||||
void editorMoveCursor(int key) {
|
||||
erow *row = (E.cursor_y >= E.numrows) ? NULL : &E.row[E.cursor_y];
|
||||
int row_len;
|
||||
@@ -89,81 +156,28 @@ void editorMoveCursor(int key) {
|
||||
}
|
||||
}
|
||||
|
||||
int executeKeyBind(char *key_sequence) {
|
||||
int i;
|
||||
for (i = 0; i < E.number_of_keybinds; ++i) {
|
||||
if (!strcmp(key_sequence, E.key_binds[i].key_sequence)) {
|
||||
|
||||
fprintf(stderr, "lisp function %s\n", key_sequence);
|
||||
// It's a symbol, create a function call
|
||||
lisp_eval(lisp_cons(E.key_binds[i].command, lisp_null(), E.ctx),
|
||||
&E.ctx_error, E.ctx);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void editorProcessKeypress() {
|
||||
static int quit_times = QUIT_TIMES;
|
||||
int c = editorReadKey();
|
||||
int times;
|
||||
|
||||
switch (c) {
|
||||
|
||||
case '\r':
|
||||
editorInsertNewLine();
|
||||
break;
|
||||
case CTRL_KEY('q'):
|
||||
if (E.dirty && quit_times > 0) {
|
||||
editorSetStatusMessage("WARNING! Changes hasn't been saved. Press Ctrl-Q "
|
||||
"another time to quit.");
|
||||
--quit_times;
|
||||
if (executeKeyBind(key_to_string(c))) {
|
||||
return;
|
||||
}
|
||||
write(STDOUT_FILENO, "\x1b[2J", 4);
|
||||
write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3);
|
||||
disableRawMode();
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
case CTRL_KEY('s'):
|
||||
editorSave();
|
||||
break;
|
||||
|
||||
case BEG_LINE:
|
||||
E.cursor_x = 0;
|
||||
break;
|
||||
|
||||
case END_LINE:
|
||||
if (E.cursor_y < E.numrows) {
|
||||
E.cursor_x = E.row[E.cursor_y].size;
|
||||
}
|
||||
break;
|
||||
|
||||
case BACKSPACE:
|
||||
case CTRL_KEY('h'):
|
||||
case DEL_KEY:
|
||||
if (c == DEL_KEY) {
|
||||
editorMoveCursor(ARROW_RIGHT);
|
||||
}
|
||||
editorDelChar();
|
||||
break;
|
||||
|
||||
case PAGE_UP:
|
||||
case PAGE_DOWN: {
|
||||
if (c == PAGE_UP) {
|
||||
E.cursor_y = E.row_offset;
|
||||
} else if (c == PAGE_DOWN) {
|
||||
E.cursor_y = E.row_offset + E.screenrows - 1;
|
||||
if (E.cursor_y > E.numrows) {
|
||||
E.cursor_y = E.numrows;
|
||||
}
|
||||
}
|
||||
times = E.screenrows;
|
||||
while (--times) {
|
||||
editorMoveCursor(c == PAGE_UP ? ARROW_UP : ARROW_DOWN);
|
||||
}
|
||||
} break;
|
||||
|
||||
case ARROW_UP:
|
||||
case ARROW_DOWN:
|
||||
case ARROW_LEFT:
|
||||
case ARROW_RIGHT:
|
||||
editorMoveCursor(c);
|
||||
break;
|
||||
|
||||
case CTRL_KEY('l'):
|
||||
case '\x1b':
|
||||
break;
|
||||
default:
|
||||
editorInsertChar(c);
|
||||
break;
|
||||
}
|
||||
quit_times = QUIT_TIMES;
|
||||
E.quit_times_buffer = E.constantes.QUIT_TIMES;
|
||||
|
||||
}
|
||||
|
||||
+13
-6
@@ -1,4 +1,5 @@
|
||||
#include "../include/row_op.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@@ -10,7 +11,7 @@ int editorRowCxToRx(erow *row, int cursor_x) {
|
||||
int i;
|
||||
for (i = 0; i < cursor_x; ++i) {
|
||||
if (row->chars[i] == '\t') {
|
||||
render_x += (TAB_LENGTH - 1) - (render_x % TAB_LENGTH);
|
||||
render_x += (E.constantes.TAB_LENGTH - 1) - (render_x % E.constantes.TAB_LENGTH);
|
||||
}
|
||||
render_x++;
|
||||
}
|
||||
@@ -34,8 +35,8 @@ void editorUpdateRow(erow *row) {
|
||||
}
|
||||
|
||||
free(row->render);
|
||||
row->render = malloc(row->size + tabs * (TAB_LENGTH - 1) +
|
||||
1); /**< Tabs needs TAB_LENGTH chars so TAB_LENGTH - 1
|
||||
row->render = malloc(row->size + tabs * (E.constantes.TAB_LENGTH - 1) +
|
||||
1); /**< Tabs needs E.constantes.TAB_LENGTH chars so E.constantes.TAB_LENGTH - 1
|
||||
more than the first already counted. */
|
||||
|
||||
// end of counting
|
||||
@@ -43,7 +44,7 @@ void editorUpdateRow(erow *row) {
|
||||
for (i = 0; i < row->size; ++i) {
|
||||
if (row->chars[i] == '\t') {
|
||||
row->render[i_render++] = ' ';
|
||||
while (i_render % TAB_LENGTH) {
|
||||
while (i_render % E.constantes.TAB_LENGTH) {
|
||||
row->render[i_render++] =
|
||||
' '; /**< Addind the right amount of spaces for tabs */
|
||||
}
|
||||
@@ -57,10 +58,14 @@ void editorUpdateRow(erow *row) {
|
||||
|
||||
void editorInsertRow(int at, char *s, size_t len) {
|
||||
if (at < 0 || at > E.numrows) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
E.row = realloc(E.row, sizeof(erow) * (E.numrows + 1));
|
||||
erow *tmp = (erow *)realloc(E.row, sizeof(erow) * (E.numrows + 1));
|
||||
if (!tmp) {
|
||||
return;
|
||||
}
|
||||
E.row = tmp;
|
||||
memmove(&E.row[at + 1], &E.row[at], sizeof(erow) * (E.numrows - at));
|
||||
|
||||
E.row[at].size = len;
|
||||
@@ -96,6 +101,8 @@ void editorDelRow(int at) {
|
||||
* \param at Index of where we want to insert the char */
|
||||
|
||||
void editorRowInsertChar(erow *row, int at, int c) {
|
||||
if (E.state == READ_ONLY)
|
||||
return;
|
||||
if (at < 0 || at > row->size) {
|
||||
at = row->size;
|
||||
}
|
||||
|
||||
+4
-1
@@ -1,9 +1,12 @@
|
||||
#include "../include/terminal.h"
|
||||
#include "data.h"
|
||||
#include "../include/data.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void die(const char *s) {
|
||||
write(STDOUT_FILENO, "\x1b[2J", 4);
|
||||
write(STDOUT_FILENO, CURSOR_TOP_LEFT, 3);
|
||||
lisp_shutdown(E.ctx);
|
||||
perror(s);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user