#ifndef _BIM_CORE_H #define _BIM_CORE_H #define _XOPEN_SOURCE 700 #define _DARWIN_C_SOURCE #define _DEFAULT_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __DATE__ # define BIM_BUILD_DATE " built " __DATE__ " at " __TIME__ #else # define BIM_BUILD_DATE DATE "" #endif #ifdef GIT_TAG # define TAG "-" GIT_TAG #else # define TAG "-alpha" #endif #define BLOCK_SIZE 4096 #define ENTER_KEY '\r' #define LINE_FEED '\n' #define BACKSPACE_KEY 0x08 #define DELETE_KEY 0x7F #define DEFAULT_KEY_WAIT (global_config.background_task ? 0 : -1) enum Key { KEY_TIMEOUT = -1, KEY_CTRL_AT = 0, /* Base */ KEY_CTRL_A, KEY_CTRL_B, KEY_CTRL_C, KEY_CTRL_D, KEY_CTRL_E, KEY_CTRL_F, KEY_CTRL_G, KEY_CTRL_H, KEY_CTRL_I, KEY_CTRL_J, KEY_CTRL_K, KEY_CTRL_L, KEY_CTRL_M, KEY_CTRL_N, KEY_CTRL_O, KEY_CTRL_P, KEY_CTRL_Q, KEY_CTRL_R, KEY_CTRL_S, KEY_CTRL_T, KEY_CTRL_U, KEY_CTRL_V, KEY_CTRL_W, KEY_CTRL_X, KEY_CTRL_Y, KEY_CTRL_Z, /* Note we keep ctrl-z mapped in termios as suspend */ KEY_CTRL_OPEN, KEY_CTRL_BACKSLASH, KEY_CTRL_CLOSE, KEY_CTRL_CARAT, KEY_CTRL_UNDERSCORE, /* Space... */ /* Some of these are equivalent to things above */ KEY_BACKSPACE = 0x08, KEY_LINEFEED = '\n', KEY_ENTER = '\r', KEY_TAB = '\t', /* Basic printable characters go here. */ /* Delete is special */ KEY_DELETE = 0x7F, /* Unicode codepoints go here */ KEY_ESCAPE = 0x400000, /* Escape would normally be 27, but is special because reasons */ KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, /* TODO ALT, SHIFT, etc., for F keys */ KEY_MOUSE, /* Must be followed with a 3-byte mouse read */ KEY_MOUSE_SGR, /* Followed by an SGR-style sequence of mouse data */ KEY_HOME, KEY_END, KEY_PAGE_UP, KEY_PAGE_DOWN, KEY_UP, KEY_DOWN, KEY_RIGHT, KEY_LEFT, KEY_SHIFT_UP, KEY_SHIFT_DOWN, KEY_SHIFT_RIGHT, KEY_SHIFT_LEFT, KEY_CTRL_UP, KEY_CTRL_DOWN, KEY_CTRL_RIGHT, KEY_CTRL_LEFT, KEY_ALT_UP, KEY_ALT_DOWN, KEY_ALT_RIGHT, KEY_ALT_LEFT, KEY_ALT_SHIFT_UP, KEY_ALT_SHIFT_DOWN, KEY_ALT_SHIFT_RIGHT, KEY_ALT_SHIFT_LEFT, KEY_SHIFT_TAB, /* Special signals for paste start, paste end */ KEY_PASTE_BEGIN, KEY_PASTE_END, }; struct key_name_map { enum Key keycode; char * name; }; extern struct key_name_map KeyNames[]; /** * Syntax highlighting flags. */ #define FLAG_NONE 0 #define FLAG_KEYWORD 1 #define FLAG_STRING 2 #define FLAG_COMMENT 3 #define FLAG_TYPE 4 #define FLAG_PRAGMA 5 #define FLAG_NUMERAL 6 #define FLAG_ERROR 7 #define FLAG_DIFFPLUS 8 #define FLAG_DIFFMINUS 9 #define FLAG_NOTICE 10 #define FLAG_BOLD 11 #define FLAG_LINK (12 + (1<<4)) #define FLAG_ESCAPE 13 #define FLAG_EXTRA 14 #define FLAG_SPECIAL 15 #define FLAG_LINK_COLOR 12 #define FLAG_UNDERLINE (1 << 4) #define FLAG_SELECT (1 << 5) #define FLAG_SEARCH (1 << 6) #define FLAG_MASK_COLORS 0x0F #define FLAG_MASK_ATTRIB 0x70 /** * Line buffer definitions * * Lines are essentially resizable vectors of char_t structs, * which represent single codepoints in the file. */ typedef struct { uint32_t display_width:4; uint32_t flags:7; uint32_t codepoint:21; } __attribute__((packed)) char_t; /** * Lines have available and actual lengths, describing * how much space was allocated vs. how much is being * used at the moment. */ typedef struct { int available; int actual; int istate; int is_current; int rev_status; char_t text[]; } line_t; typedef struct background_task { struct _env * env; void (*func)(struct background_task*); struct background_task * next; int _private_i; void * _private_p; } background_task_t; /** * Global configuration state * * At the moment, this is all in a global, but in the future * this should be passed around to various functions. */ typedef struct { /* Terminal size */ int term_width, term_height; int bottom_size; line_t ** yanks; size_t yank_count; int yank_is_full_lines; int tty_in; const char * bimrc_path; const char * syntax_fallback; uint32_t * search; int overlay_mode; line_t * command_buffer; int command_offset, command_col_no; struct syntax_definition * command_syn, * command_syn_back; int history_point; int search_point; int search_direction; int prev_line, prev_col, prev_coffset, prev_offset; unsigned int highlight_on_open:1; unsigned int initial_file_is_read_only:1; unsigned int go_to_line:1; unsigned int break_from_selection:1; unsigned int can_scroll:1; unsigned int can_hideshow:1; unsigned int can_altscreen:1; unsigned int can_mouse:1; unsigned int can_unicode:1; unsigned int can_bright:1; unsigned int can_title:1; unsigned int can_bce:1; unsigned int can_24bit:1; unsigned int can_256color:1; unsigned int can_italic:1; unsigned int can_insert:1; unsigned int can_bracketedpaste:1; unsigned int can_sgrmouse:1; unsigned int history_enabled:1; unsigned int highlight_parens:1; unsigned int smart_case:1; unsigned int highlight_current_line:1; unsigned int shift_scrolling:1; unsigned int check_git:1; unsigned int color_gutter:1; unsigned int relative_lines:1; unsigned int numbers:1; unsigned int horizontal_shift_scrolling:1; unsigned int hide_statusbar:1; unsigned int tabs_visible:1; unsigned int autohide_tabs:1; unsigned int smart_complete:1; unsigned int has_terminal:1; unsigned int search_wraps:1; unsigned int had_error:1; unsigned int use_biminfo:1; int cursor_padding; int split_percent; int scroll_amount; int tab_offset; char * tab_indicator; char * space_indicator; background_task_t * background_task; background_task_t * tail_task; } global_config_t; #define OVERLAY_MODE_NONE 0 #define OVERLAY_MODE_READ_ONE 1 #define OVERLAY_MODE_COMMAND 2 #define OVERLAY_MODE_SEARCH 3 #define OVERLAY_MODE_COMPLETE 4 #define OVERLAY_MODE_FILESEARCH 5 #define HISTORY_SENTINEL 0 #define HISTORY_INSERT 1 #define HISTORY_DELETE 2 #define HISTORY_REPLACE 3 #define HISTORY_REMOVE_LINE 4 #define HISTORY_ADD_LINE 5 #define HISTORY_REPLACE_LINE 6 #define HISTORY_MERGE_LINES 7 #define HISTORY_SPLIT_LINE 8 #define HISTORY_BREAK 10 typedef struct history { struct history * previous; struct history * next; int type; int line; int col; union { struct { int lineno; int offset; int codepoint; int old_codepoint; } insert_delete_replace; struct { int lineno; line_t * contents; line_t * old_contents; } remove_replace_line; struct { int lineno; int split; } add_merge_split_lines; } contents; } history_t; /** * Buffer data * * A buffer describes a file, and stores * its name as well as the editor state * (cursor offsets, etc.) and the actual * line buffers. */ typedef struct _env { unsigned int loading:1; unsigned int tabs:1; unsigned int modified:1; unsigned int readonly:1; unsigned int indent:1; unsigned int checkgitstatusonwrite:1; unsigned int crnl:1; unsigned int numbers:1; unsigned int gutter:1; unsigned int slowop:1; int highlighting_paren; int maxcolumn; short mode; short tabstop; char * file_name; int offset; int coffset; int line_no; int line_count; int line_avail; int col_no; int preferred_column; struct syntax_definition * syntax; line_t ** lines; history_t * history; history_t * last_save_history; int width; int left; int start_line; int sel_col; int start_col; int prev_line; } buffer_t; struct theme_def { const char * name; void * callable; }; extern struct theme_def * themes; extern void add_colorscheme(struct theme_def theme); struct syntax_state { buffer_t * env; line_t * line; int line_no; int state; int i; }; struct completion_match { char * string; char * file; char * search; }; struct syntax_definition { char * name; char ** ext; int (*calculate)(struct syntax_state *); int prefers_spaces; int (*completion_qualifier)(int c); int (*completion_matcher)(uint32_t * comp, struct completion_match ** matches, int * matches_count, int complete_match, int * matches_len, buffer_t * env); void * krkFunc; void * krkClass; }; extern struct syntax_definition * syntaxes; /** * Editor mode states */ #define MODE_NORMAL 0 #define MODE_INSERT 1 #define MODE_LINE_SELECTION 2 #define MODE_REPLACE 3 #define MODE_CHAR_SELECTION 4 #define MODE_COL_SELECTION 5 #define MODE_COL_INSERT 6 #define MODE_DIRECTORY_BROWSE 7 struct action_def { char * name; uintptr_t action; int options; const char * description; }; extern struct action_def * mappable_actions; #define ARG_IS_INPUT 0x01 /* Takes the key that triggered it as the first argument */ #define ARG_IS_CUSTOM 0x02 /* Takes a custom argument which is specific to the method */ #define ARG_IS_PROMPT 0x04 /* Prompts for an argument. */ #define ACTION_IS_RW 0x08 /* Needs to be able to write. */ #define BIM_ACTION(name, options, description, ...) \ extern void name(__VA_ARGS__); /* Define the action with unknown arguments */ \ void __attribute__((constructor)) _install_ ## name (void) { \ add_action((struct action_def){#name, (uintptr_t)name, options, description}); \ } \ void name(__VA_ARGS__) struct command_def { char * name; int (*command)(char *, int, char * arg[]); const char * description; }; #define BIM_COMMAND(cmd_name, cmd_str, description) \ int bim_command_ ## cmd_name (char * cmd, int argc, char * argv[]); \ void __attribute__((constructor)) _install_cmd_ ## cmd_name (void) { \ add_command((struct command_def){cmd_str, bim_command_ ## cmd_name, description}); \ } \ int bim_command_ ## cmd_name (char * cmd __attribute__((unused)), int argc __attribute__((unused)), char * argv[] __attribute__((unused))) #define BIM_ALIAS(alias, alias_name, cmd_name) \ void __attribute__((constructor)) _install_alias_ ## alias_name (void) { \ add_command((struct command_def){alias, bim_command_ ## cmd_name, "Alias for " #cmd_name}); \ } #define BIM_PREFIX_COMMAND(cmd_name, cmd_prefix, description) \ int bim_command_ ## cmd_name (char * cmd, int argc, char * argv[]); \ void __attribute__((constructor)) _install_cmd_ ## cmd_name (void) { \ add_prefix_command((struct command_def){cmd_prefix, bim_command_ ## cmd_name, description}); \ } \ int bim_command_ ## cmd_name (char * cmd __attribute__((unused)), int argc __attribute__((unused)), char * argv[] __attribute__((unused))) extern const char * flag_to_color(int _flag); extern void redraw_line(int x); extern int git_examine(char * filename); extern void search_next(void); extern void set_preferred_column(void); extern void quit(const char * message); extern void close_buffer(void); extern void set_syntax_by_name(const char * name); extern void rehighlight_search(line_t * line); extern void try_to_center(void); extern int read_one_character(char * message); extern void bim_unget(int c); #define bim_getch() bim_getch_timeout(200) extern int bim_getch_timeout(int timeout); extern buffer_t * buffer_new(void); extern FILE * open_biminfo(void); extern int fetch_from_biminfo(buffer_t * buf); extern int update_biminfo(buffer_t * buf, int is_open); extern buffer_t * buffer_close(buffer_t * buf); extern int to_eight(uint32_t codepoint, char * out); extern char * name_from_key(enum Key keycode); extern void add_action(struct action_def action); extern void open_file(char * file); extern void recalculate_selected_lines(void); extern void add_command(struct command_def command); extern void add_prefix_command(struct command_def command); extern void render_command_input_buffer(void); extern void unhighlight_matching_paren(void); extern void add_syntax(struct syntax_definition def); struct ColorName { const char * name; const char ** value; }; extern struct ColorName color_names[]; struct bim_function { char * command; struct bim_function * next; }; extern struct bim_function ** user_functions; extern int run_function(char * name); extern int has_function(char * name); extern void find_matching_paren(int * out_line, int * out_col, int in_col); extern void render_error(char * message, ...); extern void render_commandline_message(char * message, ...); extern void pause_for_key(void); #define add_match(match_string, match_file, match_search) do { \ if (*matches_count == *matches_len) { \ (*matches_len) *= 2; \ *matches = realloc(*matches, sizeof(struct completion_match) * (*matches_len)); \ } \ (*matches)[*matches_count].string = strdup(match_string); \ (*matches)[*matches_count].file = strdup(match_file); \ (*matches)[*matches_count].search = strdup(match_search); \ (*matches_count)++; \ } while (0) #define add_if_match(name,desc) do { \ int i = 0; \ while (comp[i] && comp[i] == (unsigned char)name[i]) i++; \ if (comp[i] == '\0') { \ add_match(name,desc,""); \ } \ } while (0) struct action_map { int key; int options; union { struct { uintptr_t method; int arg; }; KrkValue callable; }; }; #define opt_rep 0x1 /* This action will be repeated */ #define opt_arg 0x2 /* This action will take a specified argument */ #define opt_char 0x4 /* This action will read a character to pass as an argument */ #define opt_nav 0x8 /* This action will consume the nav buffer as its argument */ #define opt_rw 0x10 /* Must not be read-only */ #define opt_norm 0x20 /* Returns to normal mode */ #define opt_byte 0x40 /* Same as opt_char but forces a byte */ #define opt_krk 0x80 struct mode_names { const char * description; const char * name; struct action_map ** mode; }; extern struct mode_names mode_names[]; #define paint(length, flag) do { for (int i = 0; i < (length) && state->i < state->line->actual; i++, state->i++) { \ state->line->text[state->i].flags = (state->line->text[state->i].flags & (3 << 5)) | (flag); \ } } while (0) #define charat() (state->i < state->line->actual ? state->line->text[(state->i)].codepoint : -1) #define nextchar() (state->i + 1 < state->line->actual ? state->line->text[(state->i+1)].codepoint : -1) #define lastchar() (state->i - 1 >= 0 ? state->line->text[(state->i-1)].codepoint : -1) #define skip() (state->i++) #define charrel(x) ((state->i + (x) >= 0 && state->i + (x) < state->line->actual) ? state->line->text[(state->i+(x))].codepoint : -1) static int match_and_paint(struct syntax_state * state, const char * keyword, int flag, int (*keyword_qualifier)(int c)); static int common_comment_buzzwords(struct syntax_state * state); static int paint_comment(struct syntax_state * state); static struct syntax_definition * find_syntax_calculator(const char * name); #define nest(lang, low) \ do { \ state->state = (state->state < 1 ? 0 : state->state - low); \ do { state->state = lang(state); } while (state->state == 0); \ if (state->state == -1) return low; \ return state->state + low; \ } while (0) /* Hacky workaround for isdigit not really accepting Unicode stuff */ static __attribute__((used)) int _isdigit(int c) { if (c > 128) return 0; return isdigit(c); } static __attribute__((used)) int _isxdigit(int c) { if (c > 128) return 0; return isxdigit(c); } #undef isdigit #undef isxdigit #define isdigit(c) _isdigit(c) #define isxdigit(c) _isxdigit(c) #endif /* _BIM_CORE_H */