static void do_tex_insert_quote(EditState *s) { int offset_bol, len, offset1; unsigned int buf[MAX_BUF_SIZE]; int p; offset_bol = eb_goto_bol(s->b, s->offset); offset1 = offset_bol; len = eb_get_line(s->b, buf, MAX_BUF_SIZE - 1, &offset1); p = s->offset - offset_bol; if(p >= 1 && buf[p-1] == '\"') { eb_insert(s->b, s->offset, (unsigned char *)"\"", 1); s->offset++; } else if(p >= 2 && (buf[p-1] == '`' || buf[p-1] == '\'') && buf[p-1] == buf[p-2]) { eb_delete(s->b, s->offset - 2, 2); eb_insert(s->b, s->offset, (unsigned char *)"\"", 1); s->offset++; } else { if(p == 0 || buf[p-1] == ' ') { eb_insert(s->b, s->offset, (unsigned char *)"``", 2); s->offset += 2; } else { eb_insert(s->b, s->offset, (unsigned char *)"''", 2); s->offset += 2; } } }
static void rectangle_cut(EditState *s) { int line, col, start_line, i, loff; eb_get_pos(s->b, &start_line, &col, s->b->mark); eb_get_pos(s->b, &line, &col, s->offset); for (i = start_line; i <= line; i++) { loff = eb_goto_pos(s->b, i, 0); if (eb_is_empty_line(s->b, loff)) continue; eb_delete(s->b, loff, col); } s->region_style = 0; put_status(s, "Rectangle cut done on line %d to line %d\n", start_line, line); }
static void do_org_insert_heading(EditState *s, int flags) { int offset, offset0, offset1, level = 1; if (check_read_only(s)) return; offset = org_find_heading(s, s->offset, &level, 1); offset0 = eb_goto_bol(s->b, s->offset); offset1 = eb_goto_eol(s->b, s->offset); /* if at beginning of heading line, insert sibling heading before, * if in the middle of a heading line, split the heading, * otherwise, make the current line a heading line at current level. */ if (flags & 2) { /* respect-content: insert heading at end of subtree */ offset = org_next_heading(s, offset, level, NULL); eb_insert_uchar(s->b, offset, '\n'); eb_insert_uchar(s->b, offset, '\n'); } else if (s->offset <= offset + level + 1) { eb_insert_uchar(s->b, offset, '\n'); } else if (offset == offset0 || offset == offset1) { offset = s->offset; offset += eb_insert_uchar(s->b, offset, '\n'); } else { offset = offset0; } offset1 = offset; while (eb_match_uchar(s->b, offset1, ' ', &offset1)) continue; eb_delete(s->b, offset, offset1 - offset); while (level-- > 0) { offset += eb_insert_uchar(s->b, offset, '*'); } offset += eb_insert_uchar(s->b, offset, ' '); s->offset = eb_goto_eol(s->b, offset); if (flags & 1) { /* insert-todo-heading */ do_org_todo(s); } }
static void do_org_move_subtree(EditState *s, int dir) { int offset, offset1, offset2, level, level1, level2, size; EditBuffer *b1; if (check_read_only(s)) return; if (!org_is_header_line(s, s->offset)) { put_status(s, "Not on header line"); return; } offset = org_find_heading(s, s->offset, &level, 0); if (offset < 0) return; offset1 = org_next_heading(s, offset, level, &level1); size = offset1 - offset; if (dir < 0) { offset2 = org_prev_heading(s, offset, level, &level2); if (level2 < level) { put_status(s, "Cannot move substree"); return; } } else { if (offset1 == s->b->total_size || level1 < level) { put_status(s, "Cannot move substree"); return; } offset2 = org_next_heading(s, offset1, level, &level2); } b1 = eb_new("*tmp*", BF_SYSTEM | (s->b->flags & BF_STYLES)); eb_set_charset(b1, s->b->charset, s->b->eol_type); eb_insert_buffer_convert(b1, 0, s->b, offset, size); eb_delete(s->b, offset, size); if (offset2 > offset) offset2 -= size; eb_insert_buffer_convert(s->b, offset2, b1, 0, b1->total_size); eb_free(&b1); s->offset = offset2; }
/* modify the color according to the current one (may be incorrect if we are editing because we should write default color) */ static void shell_color_callback(EditBuffer *b, void *opaque, enum LogOperation op, int offset, int size) { ShellState *s = opaque; unsigned char buf[32]; int len; switch (op) { case LOGOP_WRITE: while (size > 0) { len = size; if (len > (int)sizeof(buf)) len = (int)sizeof(buf); memset(buf, s->color, len); eb_write(s->b_color, offset, buf, len); size -= len; offset += len; } break; case LOGOP_INSERT: while (size > 0) { len = size; if (len > (int)sizeof(buf)) len = (int)sizeof(buf); memset(buf, s->color, len); eb_insert(s->b_color, offset, buf, len); size -= len; } break; case LOGOP_DELETE: eb_delete(s->b_color, offset, size); break; default: break; } }
void eb_free(EditBuffer *b) { QEmacsState *qs = &qe_state; EditBuffer **pb; EditBufferCallbackList *l, *l1; /* call user defined close */ if (b->close) b->close(b); /* free each callback */ for (l = b->first_callback; l != NULL;) { l1 = l->next; free(l); l = l1; } b->first_callback = NULL; b->save_log = 0; eb_delete(b, 0, b->total_size); log_reset(b); /* suppress mmap file handle */ if (b->file_handle > 0) { close(b->file_handle); } /* suppress from buffer list */ pb = &qs->first_buffer; while (*pb != NULL) { if (*pb == b) break; pb = &(*pb)->next; } *pb = (*pb)->next; free(b); }
static void build_bufed_list(EditState *s) { QEmacsState *qs = s->qe_state; EditBuffer *b; BufedState *hs; int i; hs = s->mode_data; free_strings(&hs->items); for(b = qs->first_buffer; b != NULL; b = b->next) { if (!(b->flags & BF_SYSTEM)) add_string(&hs->items, b->name); } /* build buffer */ b = s->b; eb_delete(b, 0, b->total_size); for(i=0;i<hs->items.nb_items;i++) { eb_printf(b, " %s", hs->items.items[i]->str); if (i != hs->items.nb_items - 1) eb_printf(b, "\n"); } }
static void tty_emulate(ShellState *s, int c) { int i, offset, offset1, offset2, n; char buf1[10]; #define ESC2(c1,c2) (((c1)<<8)|((unsigned char)c2)) /* some bytes are state independent */ switch (c) { case 0x18: case 0x1A: s->state = TTY_STATE_NORM; return; case 0x1B: s->state = TTY_STATE_ESC; return; #if 0 case 0x9B: goto csi_entry; #endif } switch (s->state) { case TTY_STATE_NORM: switch (c) { /* BEL Bell (Ctrl-G) */ /* FF Form Feed or New Page (NP) (Ctrl-L) same as LF */ /* TAB Horizontal Tab (HT) (Ctrl-I) */ /* VT Vertical Tab (Ctrl-K) same as LF */ case 8: /* ^H BS = backspace */ { int c1; c1 = eb_prevc(s->b, s->cur_offset, &offset); if (c1 != '\n') s->cur_offset = offset; } break; case 10: /* ^J NL = line feed */ /* go to next line */ /* CG: should check if column should be kept */ offset = s->cur_offset; for (;;) { if (offset == s->b->total_size) { /* add a new line */ buf1[0] = '\n'; eb_insert(s->b, offset, buf1, 1); offset = s->b->total_size; break; } c = eb_nextc(s->b, offset, &offset); if (c == '\n') break; } s->cur_offset = offset; break; case 13: /* ^M CR = carriage return */ /* move to bol */ for (;;) { c = eb_prevc(s->b, s->cur_offset, &offset1); if (c == '\n') break; s->cur_offset = offset1; } break; case 14: /* ^N SO = shift out */ s->shifted = 1; break; case 15: /* ^O SI = shift in */ s->shifted = 0; break; default: if (c >= 32 || c == 9) { int c1, cur_len, len; /* CG: assuming ISO-8859-1 characters */ /* CG: horrible kludge for alternate charset support */ if (s->shifted && c >= 96 && c < 128) c += 32; /* write char (should factorize with do_char() code */ len = unicode_to_charset(buf1, c, s->b->charset); c1 = eb_nextc(s->b, s->cur_offset, &offset); /* XXX: handle tab case */ if (c1 == '\n') { /* insert */ eb_insert(s->b, s->cur_offset, buf1, len); } else { cur_len = offset - s->cur_offset; if (cur_len == len) { eb_write(s->b, s->cur_offset, buf1, len); } else { eb_delete(s->b, s->cur_offset, cur_len); eb_insert(s->b, s->cur_offset, buf1, len); } } s->cur_offset += len; } break; } break; case TTY_STATE_ESC: if (c == '[') { for (i = 0; i < MAX_ESC_PARAMS; i++) { s->esc_params[i] = 0; s->has_params[i] = 0; } s->nb_esc_params = 0; s->esc1 = 0; s->state = TTY_STATE_CSI; } else { /* CG: should deal with other sequences: * ansi: hts=\EH, s0ds=\E(B, s1ds=\E)B, s2ds=\E*B, s3ds=\E+B, * linux: hts=\EH, rc=\E8, ri=\EM, rs1=\Ec\E]R, sc=\E7, * vt100: enacs=\E(B\E)0, hts=\EH, rc=\E8, ri=\EM$<5>, * rmkx=\E[?1l\E>, * rs2=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h, sc=\E7, * smkx=\E[?1h\E=, * xterm: enacs=\E(B\E)0, hts=\EH, is2=\E[!p\E[?3;4l\E[4l\E>, * rc=\E8, ri=\EM, rmkx=\E[?1l\E>, rs1=\Ec, * rs2=\E[!p\E[?3;4l\E[4l\E>, sc=\E7, smkx=\E[?1h\E=, */ switch (c) { case '(': case ')': case '*': case '+': case ']': s->esc1 = c; s->state = TTY_STATE_ESC2; break; case 'H': // hts case '7': // sc case '8': // rc case 'M': // ri case 'c': // rs1 case '>': // rmkx, is2, rs2 case '=': // smkx // XXX: do these default: s->state = TTY_STATE_NORM; break; } } break; case TTY_STATE_ESC2: s->state = TTY_STATE_NORM; switch (ESC2(s->esc1, c)) { case ESC2('(','B'): case ESC2(')','B'): case ESC2('(','0'): case ESC2(')','0'): case ESC2('*','B'): case ESC2('+','B'): case ESC2(']','R'): /* XXX: ??? */ break; } break; case TTY_STATE_CSI: if (c == '?') { s->esc1 = c; break; } if (c >= '0' && c <= '9') { if (s->nb_esc_params < MAX_ESC_PARAMS) { s->esc_params[s->nb_esc_params] = s->esc_params[s->nb_esc_params] * 10 + c - '0'; s->has_params[s->nb_esc_params] = 1; } } else { s->nb_esc_params++; if (c == ';') break; s->state = TTY_STATE_NORM; switch (ESC2(s->esc1,c)) { case ESC2('?','h'): /* set terminal mode */ /* 1047, 1048 -> cup mode: * xterm 1049 private mode, * should grab all keys while active! */ if (s->esc_params[0] == 1047 || s->esc_params[0] == 1048 || s->esc_params[0] == 1049) { s->grab_keys = 1; qe_grab_keys(shell_key, s); /* Should also clear screen */ } break; case ESC2('?','l'): /* reset terminal mode */ if (s->esc_params[0] == 1047 || s->esc_params[0] == 1048 || s->esc_params[0] == 1049) { qe_ungrab_keys(); s->grab_keys = 0; } break; case 'A': /* move relative up */ tty_gotoxy(s, 0, -(s->esc_params[0] + 1 - s->has_params[0]), 1); break; case 'B': /* move relative down */ tty_gotoxy(s, 0, (s->esc_params[0] + 1 - s->has_params[0]), 1); break; case 'C': /* move relative forward */ tty_gotoxy(s, (s->esc_params[0] + 1 - s->has_params[0]), 0, 1); break; case 'D': /* move relative backward */ tty_gotoxy(s, -(s->esc_params[0] + 1 - s->has_params[0]), 0, 1); break; case 'H': /* goto xy */ tty_gotoxy(s, s->esc_params[1] - s->has_params[1], s->esc_params[0] - s->has_params[0], 0); break; case 'J': /* clear to end of screen */ case 'L': /* insert lines */ case 'M': /* delete lines */ case 'S': /* scroll forward P lines */ case 'T': /* scroll back P lines */ case 'X': /* erase P characters */ break; case 'K': /* clear eol (parm=1 -> bol) */ offset1 = s->cur_offset; for (;;) { c = eb_nextc(s->b, offset1, &offset2); if (c == '\n') break; offset1 = offset2; } eb_delete(s->b, s->cur_offset, offset1 - s->cur_offset); break; case 'P': /* delete chars */ n = s->esc_params[0]; if (n <= 0) n = 1; offset1 = s->cur_offset; for (; n > 0; n--) { c = eb_nextc(s->b, offset1, &offset2); if (c == '\n') break; offset1 = offset2; } eb_delete(s->b, s->cur_offset, offset1 - s->cur_offset); break; case '@': /* insert chars */ n = s->esc_params[0]; if (n <= 0) n = 1; buf1[0] = ' '; for (; n > 0; n--) { eb_insert(s->b, s->cur_offset, buf1, 1); } break; case 'm': /* colors */ n = s->nb_esc_params; if (n == 0) n = 1; for (i = 0; i < n; i++) tty_csi_m(s, s->esc_params[i]); break; case 'n': if (s->esc_params[0] == 6) { /* XXX: send cursor position, just to be able to launch qemacs in qemacs (in 8859-1) ! */ char buf2[20]; snprintf(buf2, sizeof(buf2), "\033[%d;%dR", 1, 1); tty_write(s, buf2, -1); } break; default: break; } } break; } #undef ESC2 tty_update_cursor(s); }
void do_undo(EditState *s) { EditBuffer *b = s->b; int log_index, saved, size_trailer; LogBuffer lb; if (!b->log_buffer) return; if (s->qe_state->last_cmd_func != do_undo) b->log_current = 0; if (b->log_current == 0) { log_index = b->log_new_index; } else { log_index = b->log_current - 1; } if (log_index == 0) { put_status(s, "No futher undo information"); return; } else { put_status(s, "Undo!"); } /* go backward */ log_index -= sizeof(int); eb_read(b->log_buffer, log_index, (unsigned char *)&size_trailer, sizeof(int)); log_index -= size_trailer + sizeof(LogBuffer); /* log_current is 1 + index to have zero as default value */ b->log_current = log_index + 1; /* play the log entry */ eb_read(b->log_buffer, log_index, (unsigned char *)&lb, sizeof(LogBuffer)); log_index += sizeof(LogBuffer); switch (lb.op) { case LOGOP_WRITE: /* we must disable the log because we want to record a single write (we should have the single operation: eb_write_buffer) */ saved = b->save_log; b->save_log = 0; eb_delete(b, lb.offset, lb.size); eb_insert_buffer(b, lb.offset, b->log_buffer, log_index, lb.size); b->save_log = saved; eb_addlog(b, LOGOP_WRITE, lb.offset, lb.size); s->offset = lb.offset + lb.size; break; case LOGOP_DELETE: /* we must also disable the log there because the log buffer would be modified BEFORE we insert it by the implicit eb_addlog */ saved = b->save_log; b->save_log = 0; eb_insert_buffer(b, lb.offset, b->log_buffer, log_index, lb.size); b->save_log = saved; eb_addlog(b, LOGOP_INSERT, lb.offset, lb.size); s->offset = lb.offset + lb.size; break; case LOGOP_INSERT: eb_delete(b, lb.offset, lb.size); s->offset = lb.offset; break; default: abort(); } b->modified = lb.was_modified; }
static void eb_addlog(EditBuffer *b, enum LogOperation op, int offset, int size) { int was_modified, len, size_trailer; LogBuffer lb; EditBufferCallbackList *l; /* call each callback */ for (l = b->first_callback; l != NULL; l = l->next) { l->callback(b, l->opaque, op, offset, size); } was_modified = b->modified; b->modified = 1; if (!b->save_log) return; if (!b->log_buffer) { char buf[256]; snprintf(buf, sizeof(buf), "*log <%s>*", b->name); b->log_buffer = eb_new(buf, BF_SYSTEM); if (!b->log_buffer) return; } /* XXX: better test to limit size */ if (b->nb_logs >= (NB_LOGS_MAX-1)) { /* no free space, delete least recent entry */ eb_read(b->log_buffer, 0, (unsigned char *)&lb, sizeof(LogBuffer)); len = lb.size; if (lb.op == LOGOP_INSERT) len = 0; len += sizeof(LogBuffer) + sizeof(int); eb_delete(b->log_buffer, 0, len); b->log_new_index -= len; if (b->log_current > 1) b->log_current -= len; b->nb_logs--; } /* header */ lb.op = op; lb.offset = offset; lb.size = size; lb.was_modified = was_modified; eb_write(b->log_buffer, b->log_new_index, (unsigned char *) &lb, sizeof(LogBuffer)); b->log_new_index += sizeof(LogBuffer); /* data */ switch (op) { case LOGOP_DELETE: case LOGOP_WRITE: eb_insert_buffer(b->log_buffer, b->log_new_index, b, offset, size); b->log_new_index += size; size_trailer = size; break; default: size_trailer = 0; break; } /* trailer */ eb_write(b->log_buffer, b->log_new_index, (unsigned char *)&size_trailer, sizeof(int)); b->log_new_index += sizeof(int); b->nb_logs++; }
/* invalidate buffer raw data */ void eb_invalidate_raw_data(EditBuffer *b) { b->save_log = 0; eb_delete(b, 0, b->total_size); log_reset(b); }
void hex_write_char(EditState *s, int key) { unsigned int cur_ch, ch; int hsize, shift, cur_len, len, h; char buf[10]; if (s->hex_mode) { if (s->unihex_mode) hsize = 4; else hsize = 2; h = to_hex(key); if (h < 0) return; if (s->insert && s->hex_nibble == 0) { ch = h << ((hsize - 1) * 4); if (s->unihex_mode) { len = unicode_to_charset(buf, ch, s->b->charset); } else { len = 1; buf[0] = ch; } eb_insert(s->b, s->offset, buf, len); } else { if (s->unihex_mode) { cur_ch = eb_nextc(s->b, s->offset, &cur_len); cur_len -= s->offset; } else { eb_read(s->b, s->offset, buf, 1); cur_ch = buf[0]; cur_len = 1; } shift = (hsize - s->hex_nibble - 1) * 4; ch = (cur_ch & ~(0xf << shift)) | (h << shift); if (s->unihex_mode) { len = unicode_to_charset(buf, ch, s->b->charset); } else { len = 1; buf[0] = ch; } #if 1 eb_replace(s->b, s->offset, cur_len, buf, len); #else if (cur_len == len) { eb_write(s->b, s->offset, buf, len); } else { eb_delete(s->b, s->offset, cur_len); eb_insert(s->b, s->offset, buf, len); } #endif } if (++s->hex_nibble == hsize) { s->hex_nibble = 0; if (s->offset < s->b->total_size) s->offset += len; } } else { text_write_char(s, key); } }
static void tty_emulate(ShellState *s, int c) { int i, offset, offset1, offset2, n; unsigned char buf1[10]; switch(s->state) { case TTY_STATE_NORM: switch(c) { case 8: { int c1; c1 = eb_prevc(s->b, s->cur_offset, &offset); if (c1 != '\n') s->cur_offset = offset; } break; case 10: /* go to next line */ offset = s->cur_offset; for(;;) { if (offset == s->b->total_size) { /* add a new line */ buf1[0] = '\n'; eb_insert(s->b, offset, buf1, 1); offset = s->b->total_size; break; } c = eb_nextc(s->b, offset, &offset); if (c == '\n') break; } s->cur_offset = offset; break; case 13: /* move to bol */ for(;;) { c = eb_prevc(s->b, s->cur_offset, &offset1); if (c == '\n') break; s->cur_offset = offset1; } break; case 27: s->state = TTY_STATE_ESC; break; default: if (c >= 32 || c == 9) { int c1, cur_len, len; /* write char (should factorize with do_char() code */ len = unicode_to_charset(buf1, c, s->b->charset); c1 = eb_nextc(s->b, s->cur_offset, &offset); /* XXX: handle tab case */ if (c1 == '\n') { /* insert */ eb_insert(s->b, s->cur_offset, buf1, len); } else { cur_len = offset - s->cur_offset; if (cur_len == len) { eb_write(s->b, s->cur_offset, buf1, len); } else { eb_delete(s->b, s->cur_offset, cur_len); eb_insert(s->b, s->cur_offset, buf1, len); } } s->cur_offset += len; } break; } break; case TTY_STATE_ESC: if (c == '[') { for(i=0;i<MAX_ESC_PARAMS;i++) s->esc_params[i] = 0; s->nb_esc_params = 0; s->state = TTY_STATE_CSI; } else { s->state = TTY_STATE_NORM; } break; case TTY_STATE_CSI: if (c >= '0' && c <= '9') { if (s->nb_esc_params < MAX_ESC_PARAMS) { s->esc_params[s->nb_esc_params] = s->esc_params[s->nb_esc_params] * 10 + c - '0'; } } else { s->nb_esc_params++; if (c == ';') break; s->state = TTY_STATE_NORM; switch(c) { case 'H': /* goto xy */ { int x, y; y = s->esc_params[0] - 1; x = s->esc_params[1] - 1; if (y < 0) y = 0; else if (y >= TTY_YSIZE) y = TTY_YSIZE - 1; if (x < 0) x = 0; tty_gotoxy(s, x, y); } break; case 'K': /* clear to eol */ offset1 = s->cur_offset; for(;;) { c = eb_nextc(s->b, offset1, &offset2); if (c == '\n') break; offset1 = offset2; } eb_delete(s->b, s->cur_offset, offset1 - s->cur_offset); break; case 'P': /* delete chars */ n = s->esc_params[0]; if (n <= 0) n = 1; offset1 = s->cur_offset; for(;n > 0;n--) { c = eb_nextc(s->b, offset1, &offset2); if (c == '\n') break; offset1 = offset2; } eb_delete(s->b, s->cur_offset, offset1 - s->cur_offset); break; case '@': /* insert chars */ n = s->esc_params[0]; if (n <= 0) n = 1; buf1[0] = ' '; for(;n > 0;n--) { eb_insert(s->b, s->cur_offset, buf1, 1); } break; case 'm': /* colors */ n = s->nb_esc_params; if (n == 0) n = 1; for(i=0;i<n;i++) tty_csi_m(s, s->esc_params[i]); break; case 'n': if (s->esc_params[0] == 6) { /* XXX: send cursor position, just to be able to launch qemacs in qemacs ! */ char buf2[20]; snprintf(buf2, sizeof(buf2), "\033[%d;%dR", 1, 1); tty_write(s, buf2, -1); } break; default: break; } } break; } tty_update_cursor(s); }