📄 edit.c
字号:
edit->stat.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; edit->stat.st_uid = getuid (); edit->stat.st_gid = getgid (); edit->bracket = -1; edit->last_get_mb_rule = -2; if (!dir) dir = ""; f = (char *) filename; if (filename) { f = catstrs (dir, filename, 0); if (edit_file_is_open) if ((*edit_file_is_open) (f)) { if (to_free) free (edit); return 0; } } if (edit_find_filter (f) < 0) {#ifdef CR_LF_TRANSLATION use_filter = 1;#endif if (edit_open_file (edit, f, text, text_size)) {/* edit_load_file already gives an error message */ if (to_free) free (edit); return 0; } } else { use_filter = 1; if (edit_open_file (edit, 0, "", 0)) { if (to_free) free (edit); return 0; } } edit->force |= REDRAW_PAGE; if (filename) { filename = catstrs (dir, filename, 0); edit_split_filename (edit, (char *) filename); } else { edit->filename = (char *) strdup (""); edit->dir = (char *) strdup (dir); } edit->stack_size = START_STACK_SIZE; edit->stack_size_mask = START_STACK_SIZE - 1; edit->undo_stack = malloc ((edit->stack_size + 10) * sizeof (long)); edit->total_lines = edit_count_lines (edit, 0, edit->last_byte); if (use_filter) { struct stat st; push_action_disabled = 1; if (check_file_access (edit, filename, &st)) { edit_clean (edit); if (to_free) free (edit); return 0; } edit->stat = st; if (!edit_insert_file (edit, f)) { edit_clean (edit); if (to_free) free (edit); return 0; }/* FIXME: this should be an unmodification() function */ push_action_disabled = 0; } edit->modified = 0; edit_load_syntax (edit, 0, 0); { int fg, bg; edit_get_syntax_color (edit, -1, &fg, &bg); } return edit;}/* clear the edit struct, freeing everything in it. returns 1 on success */int edit_clean (WEdit * edit){ if (edit) { int j = 0; edit_free_syntax_rules (edit); edit_get_wide_byte (edit, -1); book_mark_flush (edit, -1); for (; j <= MAXBUFF; j++) { if (edit->buffers1[j] != NULL) free (edit->buffers1[j]); if (edit->buffers2[j] != NULL) free (edit->buffers2[j]); } if (edit->undo_stack) free (edit->undo_stack); if (edit->filename) free (edit->filename); if (edit->dir) free (edit->dir);/* we don't want to clear the widget */ memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here)); return 1; } return 0;}/* returns 1 on success */int edit_renew (WEdit * edit){ int lines = edit->num_widget_lines; int columns = edit->num_widget_columns; char *dir; if (edit->dir) dir = (char *) strdup (edit->dir); else dir = 0; edit_clean (edit); if (!edit_init (edit, lines, columns, 0, "", dir, 0)) return 0; return 1;}/* returns 1 on success, if returns 0, the edit struct would have been free'd */int edit_reload (WEdit * edit, const char *filename, const char *text, const char *dir, unsigned long text_size){ WEdit *e; int lines = edit->num_widget_lines; int columns = edit->num_widget_columns; e = malloc (sizeof (WEdit)); memset (e, 0, sizeof (WEdit)); e->widget = edit->widget; e->macro_i = -1; if (!edit_init (e, lines, columns, filename, text, dir, text_size)) { free (e); return 0; } edit_clean (edit); memcpy (edit, e, sizeof (WEdit)); free (e); return 1;}/* Recording stack for undo: The following is an implementation of a compressed stack. Identical pushes are recorded by a negative prefix indicating the number of times the same char was pushed. This saves space for repeated curs-left or curs-right delete etc. eg: pushed: stored: a b a b -3 b b c --> -4 c c c d c d If the stack long int is 0-255 it represents a normal insert (from a backspace), 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one of the cursor functions #define'd in edit.h. 1000 through 700'000'000 is to set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2 position. The only way the cursor moves or the buffer is changed is through the routines: insert, backspace, insert_ahead, delete, and cursor_move. These record the reverse undo movements onto the stack each time they are called. Each key press results in a set of actions (insert; delete ...). So each time a key is pressed the current position of start_display is pushed as KEY_PRESS + start_display. Then for undoing, we pop until we get to a number over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)*/void edit_push_action (WEdit * edit, long c,...){ unsigned long sp = edit->stack_pointer; unsigned long spm1; long *t;/* first enlarge the stack if necessary */ if (sp > edit->stack_size - 10) { /* say */ if (option_max_undo < 256) option_max_undo = 256; if (edit->stack_size < option_max_undo) { t = malloc ((edit->stack_size * 2 + 10) * sizeof (long)); if (t) { memcpy (t, edit->undo_stack, sizeof (long) * edit->stack_size); free (edit->undo_stack); edit->undo_stack = t; edit->stack_size <<= 1; edit->stack_size_mask = edit->stack_size - 1; } } } spm1 = (edit->stack_pointer - 1) & edit->stack_size_mask; if (push_action_disabled) return;#ifdef FAST_MOVE_CURSOR if (c == CURS_LEFT_LOTS || c == CURS_RIGHT_LOTS) { va_list ap; edit->undo_stack[sp] = c == CURS_LEFT_LOTS ? CURS_LEFT : CURS_RIGHT; edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask; va_start (ap, c); c = -(va_arg (ap, int)); va_end (ap); } else#endif /* ! FAST_MOVE_CURSOR */ if (spm1 != edit->stack_bottom && ((sp - 2) & edit->stack_size_mask) != edit->stack_bottom) { int d; if (edit->undo_stack[spm1] < 0) { d = edit->undo_stack[(sp - 2) & edit->stack_size_mask]; if (d == c) { if (edit->undo_stack[spm1] > -1000000000) { if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */ edit->undo_stack[spm1]--; return; } }/* #define NO_STACK_CURSMOVE_ANIHILATION */#ifndef NO_STACK_CURSMOVE_ANIHILATION else if ((c == CURS_LEFT && d == CURS_RIGHT) || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */ if (edit->undo_stack[spm1] == -2) edit->stack_pointer = spm1; else edit->undo_stack[spm1]++; return; }#endif } else { d = edit->undo_stack[spm1]; if (d == c) { if (c >= KEY_PRESS) return; /* --> no need to push multiple do-nothings */ edit->undo_stack[sp] = -2; goto check_bottom; }#ifndef NO_STACK_CURSMOVE_ANIHILATION else if ((c == CURS_LEFT && d == CURS_RIGHT) || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */ edit->stack_pointer = spm1; return; }#endif } } edit->undo_stack[sp] = c; check_bottom: edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;/*if the sp wraps round and catches the stack_bottom then erase the first set of actions on the stack to make space - by moving stack_bottom forward one "key press" */ c = (edit->stack_pointer + 2) & edit->stack_size_mask; if (c == edit->stack_bottom || ((c + 1) & edit->stack_size_mask) == edit->stack_bottom) do { edit->stack_bottom = (edit->stack_bottom + 1) & edit->stack_size_mask; } while (edit->undo_stack[edit->stack_bottom] < KEY_PRESS && edit->stack_bottom != edit->stack_pointer);/*If a single key produced enough pushes to wrap all the way round then we would notice that the [stack_bottom] does not contain KEY_PRESS. The stack is then initialised: */ if (edit->stack_pointer != edit->stack_bottom && edit->undo_stack[edit->stack_bottom] < KEY_PRESS) edit->stack_bottom = edit->stack_pointer = 0;}/* TODO: if the user undos until the stack bottom, and the stack has not wrapped, then the file should be as it was when he loaded up. Then set edit->modified to 0. */long pop_action (WEdit * edit){ long c; unsigned long sp = edit->stack_pointer; if (sp == edit->stack_bottom) { return STACK_BOTTOM; } sp = (sp - 1) & edit->stack_size_mask; if ((c = edit->undo_stack[sp]) >= 0) {/* edit->undo_stack[sp] = '@'; */ edit->stack_pointer = (edit->stack_pointer - 1) & edit->stack_size_mask; return c; } if (sp == edit->stack_bottom) { return STACK_BOTTOM; } c = edit->undo_stack[(sp - 1) & edit->stack_size_mask]; if (edit->undo_stack[sp] == -2) {/* edit->undo_stack[sp] = '@'; */ edit->stack_pointer = sp; } else edit->undo_stack[sp]++; return c;}/* is called whenever a modification is made by one of the four routines below */static inline void edit_modification (WEdit * edit, long p){ edit->caches_valid = 0; edit->modified = 1; edit->screen_modified = 1; if (edit->last_get_mb_rule > p - 1) { edit->last_get_mb_rule = p - 1; edit->mb_invalidate = 1; } if (edit->last_get_mb_rule > p - 1) { edit->last_get_rule = p - 1; edit->syntax_invalidate = 1; }}/* Basic low level single character buffer alterations and movements at the cursor. Returns char passed over, inserted or removed. */void edit_insert (WEdit * edit, int c){/* check if file has grown to large */ if (edit->last_byte >= SIZE_LIMIT) return;/* first we must update the position of the display window */ if (edit->curs1 < edit->start_display) { edit->start_display++; if (c == '\n') edit->start_line++; }/* now we must update some info on the file and check if a redraw is required */ if (c == '\n') { if (edit->book_mark) book_mark_inc (edit, edit->curs_line); edit->curs_line++; edit->total_lines++; edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR; }/* tell that we've modified the file */ edit_modification (edit, edit->curs1);/* save the reverse command onto the undo stack */ edit_push_action (edit, BACKSPACE);/* update markers */ edit->mark1 += (edit->mark1 > edit->curs1); edit->mark2 += (edit->mark2 > edit->curs1);/* add a new buffer if we've reached the end of the last one */ if (!(edit->curs1 & M_EDIT_BUF_SIZE)) edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);/* perfprm the insertion */ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = (unsigned char) c;/* update file length */ edit->last_byte++;/* update cursor position */ edit->curs1++;}/* same as edit_insert and move left */void edit_insert_ahead (WEdit * edit, int c){ if (edit->last_byte >= SIZE_LIMIT) return; if (edit->curs1 < edit->start_display) { edit->start_display++; if (c == '\n') edit->start_line++; } if (c == '\n') { if (edit->book_mark) book_mark_inc (edit, edit->curs_line); edit->total_lines++; edit->force |= REDRAW_AFTER_CURSOR; } edit_modification (edit, edit->curs1); edit_push_action (edit, DELETE); edit->mark1 += (edit->mark1 >= edit->curs1); edit->mark2 += (edit->mark2 >= edit->curs1); if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE)) edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE); edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c; edit->last_byte++; edit->curs2++;}int edit_delete (WEdit * edit){ int p; if (!edit->curs2) return 0; edit->mark1 -= (edit->mark1 > edit->curs1); edit->mark2 -= (edit->mark2 > edit->curs1); p = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1]; if (!(edit->curs2 & M_EDIT_BUF_SIZE)) { free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]); edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = NULL; } edit->last_byte--; edit->curs2--; if (p == '\n') { if (edit->book_mark) book_mark_dec (edit, edit->curs_line); edit->total_lines--; edit->force |= REDRAW_AFTER_CURSOR; } edit_push_action (edit, p + 256); if (edit->curs1 < edit->start_display) { edit->start_display--; if (p == '\n') edit->start_line--; } edit_modification (edit, edit->curs1); return p;}int edit_backspace (WEdit * edit){ int p; if (!edit->curs1) return 0; edit->mark1 -= (edit->mark1 >= edit->curs1); edit->mark2 -= (edit->mark2 >= edit->curs1); p = *(edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE] + ((edit->curs1 - 1) & M_EDIT_BUF_SIZE)); if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) { free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]); edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL; } edit->last_byte--; edit->curs1--; if (p == '\n') { if (edit->book_mark) book_mark_dec (edit, edit->curs_line); edit->curs_line--; edit->total_lines--; edit->force |= REDRAW_AFTER_CURSOR; } edit_push_action (edit, p); if (edit->curs1 < edit->start_display) { edit->start_display--; if (p == '\n') edit->start_line--; } edit_modification (edit, edit->curs1); return p;}int edit_delete_wide (WEdit * edit){ struct mb_rule r; r = get_mb_rule (edit, edit->curs1); edit_delete (edit); while (r.end--) edit_delete (edit); return r.ch;}extern int option_utf_interpretation;void edit_insert_wide (WEdit * edit, wchar_t wc){ unsigned char *c; if (!option_utf_interpretation) { edit_insert (edit, wc & 0xFF); return; } c = wcrtomb_ucs4_to_utf8 (wc); if (!*c) { edit_insert (edit, *c);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -