Skip to content

Instantly share code, notes, and snippets.

@anthonyquizon
Created November 25, 2024 23:50
Show Gist options
  • Save anthonyquizon/732b01426f188607a59013c07125107a to your computer and use it in GitHub Desktop.
Save anthonyquizon/732b01426f188607a59013c07125107a to your computer and use it in GitHub Desktop.
bqn ffi for replxx
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <wchar.h>
#include <locale.h>
#include "replxx.h"
#include "sqlite3.h"
#include "bqnffi.h"
Replxx* replxx;
typedef int8_t i8; typedef uint8_t u8; typedef int16_t i16; typedef uint16_t u16; typedef int32_t i32; typedef uint32_t u32; typedef int64_t i64; typedef uint64_t u64; typedef double f64; typedef float f32; typedef size_t ux;
bool inBackslash=false;
#define IS_CONT(x) (((x) & 0xc0) == 0x80)
int utf8str_codepoint_len( char const* s, int utf8len ) {
int codepointLen = 0;
unsigned char m4 = 128 + 64 + 32 + 16;
unsigned char m3 = 128 + 64 + 32;
unsigned char m2 = 128 + 64;
for ( int i = 0; i < utf8len; ++ i, ++ codepointLen ) {
char c = s[i];
if ( ( c & m4 ) == m4 ) {
i += 3;
} else if ( ( c & m3 ) == m3 ) {
i += 2;
} else if ( ( c & m2 ) == m2 ) {
i += 1;
}
}
return ( codepointLen );
}
int context_len( char const* prefix ) {
char const wb[] = " \t\n\r\v\f-=+*&^%$#@!,./?<>;:`~'\"[]{}()\\|";
int i = (int)strlen( prefix ) - 1;
int cl = 0;
while ( i >= 0 ) {
if ( strchr( wb, prefix[i] ) != NULL ) {
break;
}
++ cl;
-- i;
}
return ( cl );
}
/*
* convert cursor position from utf8 character space to char space eg. πabc -> π_abc since π is 2 chars long
*/
i32 utf8str_pos(char const* s, i32 utf8pos) {
i32 i=0;
unsigned char m4 = 128 + 64 + 32 + 16;
unsigned char m3 = 128 + 64 + 32;
unsigned char m2 = 128 + 64;
for (i32 j=0; j<utf8pos; j++, i++) {
char c = s[i];
if ((c & m4) == m4 ) { i += 3; }
else if ((c & m3) == m3) { i += 2; }
else if ((c & m2) == m2) { i += 1; }
}
return i;
}
i32 decode_code_point(const char **s) {
i32 k = **s ? __builtin_clz(~(**s << 24)) : 0; // Count # of leading 1 bits.
i32 mask = (1 << (8 - k)) - 1; // All 1s with k leading 0s.
i32 value = **s & mask;
// k = 0 for one-byte code points; otherwise, k = #total bytes.
for (++(*s), --k; k > 0 && IS_CONT(**s); --k, ++(*s)) {
value <<= 6;
value += (**s & 0x3F);
}
return value;
}
void encode_code_point(char **s, char *end, int code) {
char val[4];
int lead_byte_max = 0x7F;
int val_index = 0;
while (code > lead_byte_max) {
val[val_index++] = (code & 0x3F) | 0x80;
code >>= 6;
lead_byte_max >>= (val_index == 1 ? 2 : 1);
}
val[val_index++] = (code & lead_byte_max) | (~lead_byte_max << 1);
while (val_index-- && *s < end) {
**s = val[val_index];
(*s)++;
}
}
/*
* Removes current char and replaces with utf8 string
*/
void modify_unicode(wchar_t wchar, char **line, i32 pos) {
char* s = *line;
char utf8[MB_CUR_MAX];
int m = wctomb(utf8, wchar);
if (m == -1) {
printf("Conversion failed.\n");
exit(1);
}
i32 n = strlen(s), j=0;
char *new_s = *line = calloc(n+m, sizeof(char));
for (i32 i=0; i<n; i++) {
if (i!=(pos-1)) { new_s[j++] = s[i]; }
else { for (i32 k=0; k<m; k++) { new_s[j++] = utf8[k]; } }
}
free(s);
inBackslash=false;
}
void modify_callback(char** line, i32* cursor_pos, void* ud) {
char* s = *line;
i32 pos=utf8str_pos(s, *cursor_pos);
char p = *(s+(pos-1));
/*
* copy string without \ character
*/
if (p=='\\') {
i32 n = strlen(s), j=0;
char *new_s = *line = calloc(n-1, sizeof(char));
for (i32 i=0; i<n; i++) { if (i!=(pos-1)) { new_s[j++] = s[i]; } }
*cursor_pos-=1;
inBackslash=true;
}
if (inBackslash) {
switch (p) {
case 'w': { modify_unicode(L'𝕨', line, pos); break; }
case 'x': { modify_unicode(L'𝕩', line, pos); break; }
case 'p': { modify_unicode(L'π', line, pos); break; }
case '[': { modify_unicode(L'←', line, pos); break; }
case '0': { modify_unicode(L'•', line, pos); break; }
}
}
}
void completion_callback(char const* context, replxx_completions* lc, int* contextLen, void* ud) {
char** examples = (char**)( ud );
size_t i;
int utf8ContextLen = context_len( context );
int prefixLen = (int)strlen( context ) - utf8ContextLen;
*contextLen = utf8str_codepoint_len( context + prefixLen, utf8ContextLen );
for (i = 0; examples[i] != NULL; ++i) {
if (strncmp(context + prefixLen, examples[i], utf8ContextLen) == 0) {
replxx_add_completion(lc, examples[i]);
}
}
}
void colorHook( char const* str_, ReplxxColor* colors_, int size_, void* ud ) {
int i = 0;
for ( ; i < size_; ++ i ) {
if ( isdigit( str_[i] ) ) {
colors_[i] = REPLXX_COLOR_BRIGHTMAGENTA;
}
}
if ( ( size_ > 0 ) && ( str_[size_ - 1] == '(' ) ) {
replxx_emulate_key_press( ud, ')' );
replxx_emulate_key_press( ud, REPLXX_KEY_LEFT );
}
}
void hintHook(char const* context, replxx_hints* lc, int* contextLen, ReplxxColor* c, void* ud) {
char** examples = (char**)( ud );
int i;
int utf8ContextLen = context_len( context );
int prefixLen = (int)strlen( context ) - utf8ContextLen;
*contextLen = utf8str_codepoint_len( context + prefixLen, utf8ContextLen );
if ( *contextLen > 0 ) {
for (i = 0; examples[i] != NULL; ++i) {
if (strncmp(context + prefixLen, examples[i], utf8ContextLen) == 0) {
replxx_add_hint(lc, examples[i]);
}
}
}
}
void init() {
#define MAX_EXAMPLE_COUNT 128
char* examples[MAX_EXAMPLE_COUNT + 1] = {
"db", "hello", "hallo", "hans", "hansekogge", "seamann", "quetzalcoatl", "quit", "power", NULL
};
setlocale(LC_ALL, "");
replxx = replxx_init();
replxx_install_window_change_handler(replxx);
const char* file = "./replxx_history.txt";
replxx_history_load( replxx, file );
replxx_set_indent_multiline( replxx, 0 );
replxx_set_modify_callback(replxx, modify_callback, NULL);
/*replxx_set_completion_callback(replxx, completion_callback, examples );*/
/*replxx_set_highlighter_callback( replxx, colorHook, replxx );*/
/*replxx_set_hint_callback( replxx, hintHook, examples );*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment