/* command.c, Atto Emacs, Public Domain, Hugh Barney, 2016, Derived from: Anthony's Editor January 93 */ #include // for MIN() #include "header.h" void quit(void) { done = 1; } void up(void) { curbp->b_point = lncolumn(curbp, upup(curbp, curbp->b_point),curbp->b_col); } void down(void) { curbp->b_point = lncolumn(curbp, dndn(curbp, curbp->b_point),curbp->b_col); } void lnbegin(void) { curbp->b_point = segstart(curbp, lnstart(curbp,curbp->b_point), curbp->b_point); } void version(void) { msg(VERSION); } void top(void) { curbp->b_point = 0; } void bottom(void) { curbp->b_point = pos(curbp, curbp->b_ebuf); if (curbp->b_epage < pos(curbp, curbp->b_ebuf)) curbp->b_reframe = 1;} void block(void) { curbp->b_mark = curbp->b_point; } void copy(void) { copy_cut(FALSE); } void cut(void) { copy_cut(TRUE); } void resize_terminal(void) { one_window(curwp); } void quit_ask(void) { if (modified_buffers() > 0) { mvaddstr(MSGLINE, 0, "Modified buffers exist; really exit (y/n) ?"); clrtoeol(); if (!yesno(FALSE)) return; } quit(); } /* flag = default answer, FALSE=n, TRUE=y */ int yesno(int flag) { int ch; addstr(flag ? " y\b" : " n\b"); refresh(); ch = getch(); if (ch == '\r' || ch == '\n') return (flag); return (tolower(ch) == 'y'); } void redraw(void) { window_t *wp; clear(); for (wp=wheadp; wp != NULL; wp = wp->w_next) wp->w_update = TRUE; update_display(); } void left(void) { int n = prev_utf8_char_size(); while (0 < curbp->b_point && n-- > 0) --curbp->b_point; } void right(void) { if (curbp->b_point >= pos(curbp, curbp->b_ebuf)) return; int n = utf8_size(*ptr(curbp,curbp->b_point)); while ((curbp->b_point < pos(curbp, curbp->b_ebuf)) && n-- > 0) ++curbp->b_point; } /* work out number of bytes based on first byte */ int utf8_size(char_t c) { if (c >= 192 && c < 224) return 2; if (c >= 224 && c < 240) return 3; if (c >= 240 && c < 248) return 4; return 1; /* if in doubt it is 1 */ } int prev_utf8_char_size(void) { int n; for (n=2;n<5;n++) if (-1 < curbp->b_point - n && (utf8_size(*(ptr(curbp, curbp->b_point - n))) == n)) return n; return 1; } void lnend(void) { if (curbp->b_point == pos(curbp, curbp->b_ebuf)) return; /* do nothing if EOF */ curbp->b_point = dndn(curbp, curbp->b_point); point_t p = curbp->b_point; left(); curbp->b_point = (*ptr(curbp, curbp->b_point) == '\n') ? curbp->b_point : p; } void wleft(void) { while (curbp->b_point > 0 && !isspace(*ptr(curbp, curbp->b_point))) --curbp->b_point; while (curbp->b_point > 0 && isspace(*ptr(curbp, curbp->b_point))) --curbp->b_point; } void pgdown(void) { curbp->b_page = curbp->b_point = upup(curbp, curbp->b_epage); while (0 < curbp->b_row--) down(); curbp->b_epage = pos(curbp, curbp->b_ebuf); } void pgup(void) { int i = curwp->w_rows; while (0 < --i) { curbp->b_page = upup(curbp, curbp->b_page); up(); } } void wright(void) { point_t end_p = pos(curbp, curbp->b_ebuf); while (curbp->b_point < end_p && !isspace(*ptr(curbp, curbp->b_point))) ++curbp->b_point; while (curbp->b_point < end_p && isspace(*ptr(curbp, curbp->b_point))) ++curbp->b_point; } void insert(void) { assert(curbp->b_gap <= curbp->b_egap); if (curbp->b_gap == curbp->b_egap && !growgap(curbp, CHUNK)) return; curbp->b_point = movegap(curbp, curbp->b_point); /* overwrite if mid line, not EOL or EOF, CR will insert as normal */ if ((curbp->b_flags & B_OVERWRITE) && *input != '\r' && curbp->b_point < pos(curbp,curbp->b_ebuf) && *(ptr(curbp, curbp->b_point)) != '\n') { *(ptr(curbp, curbp->b_point)) = *input; if (curbp->b_point < pos(curbp, curbp->b_ebuf)) ++curbp->b_point; } else { *curbp->b_gap++ = *input == '\r' ? '\n' : *input; curbp->b_point = pos(curbp, curbp->b_egap); // force reframe if scrolled off bottom of screen and at EOF if (curbp->b_point == pos(curbp, curbp->b_ebuf) && curbp->b_point >= curbp->b_epage) curbp->b_reframe = 1; } curbp->b_flags |= B_MODIFIED; } void backsp(void) { curbp->b_point = movegap(curbp, curbp->b_point); if (curbp->b_buf < curbp->b_gap) { curbp->b_gap -= prev_utf8_char_size(); curbp->b_flags |= B_MODIFIED; } curbp->b_point = pos(curbp, curbp->b_egap); } void delete(void) { curbp->b_point = movegap(curbp, curbp->b_point); if (curbp->b_egap < curbp->b_ebuf) { curbp->b_egap += MIN(utf8_size(*curbp->b_egap), curbp->b_ebuf - curbp->b_egap); curbp->b_point = pos(curbp, curbp->b_egap); curbp->b_flags |= B_MODIFIED; } } void gotoline(void) { long lline; int line; char *ep; point_t p; if (getinput("Goto line: ", temp, STRBUF_S, F_CLEAR)) { errno = 0; lline = strtol(temp, &ep, 10); if (ep == temp || *ep != '\0' || errno != 0 || lline < INT_MIN || INT_MAX < lline) { msg("Line %s, not valid", temp); return; } line = (int) lline; p = line_to_point(line); if (p != -1) { curbp->b_point = p; msg("Line %d", line); } else { msg("Line %d, not found", line); } } } void insertfile(void) { if (getfilename("Insert file: ", temp, sizeof(temp))) (void)insert_file(temp, TRUE); } void readfile(void) { buffer_t *bp; temp[0] = '\0'; int result = getfilename("Find file: ", (char*)temp, sizeof(temp)); if (result) { bp = find_buffer(temp, TRUE); if (bp == NULL) { msg("Failed to allocate buffer."); return; } disassociate_b(curwp); /* we are leaving the old buffer for a new one */ curbp = bp; associate_b2w(curbp, curwp); /* load the file if not already loaded */ if (bp->b_fname[0] == '\0') { if (!load_file(temp)) { msg("New file %s", temp); } strlcpy(curbp->b_fname, temp, sizeof(curbp->b_fname)); } } } void savebuffer(void) { if (curbp->b_fname[0] != '\0') { save(curbp->b_fname); return; } else { writefile(); } refresh(); } void writefile(void) { strlcpy(temp, curbp->b_fname, sizeof(temp)); if (getinput("Write file: ", temp, sizeof(temp), F_NONE)) if (save(temp) == TRUE) strlcpy(curbp->b_fname, temp, sizeof(curbp->b_fname)); } void killbuffer(void) { buffer_t *kill_bp = curbp; int bcount = count_buffers(); /* do nothing if only buffer left is the scratch buffer */ if (bcount == 1 && 0 == strcmp(get_buffer_name(curbp), "*scratch*")) return; if (curbp->b_flags & B_MODIFIED) { mvaddstr(MSGLINE, 0, "Discard changes (y/n) ?"); clrtoeol(); if (!yesno(FALSE)) return; } if (bcount == 1) { /* create a scratch buffer */ if (create_scratch() == NULL) { msg("Failed to allocate buffer."); return; } } next_buffer(); assert(kill_bp != curbp); delete_buffer(kill_bp); } void iblock(void) { block(); msg("Mark set"); } void toggle_overwrite_mode(void) { if (curbp->b_flags & B_OVERWRITE) curbp->b_flags &= ~B_OVERWRITE; else curbp->b_flags |= B_OVERWRITE; } void killtoeol(void) { if (curbp->b_point == pos(curbp, curbp->b_ebuf)) return; /* do nothing if at end of file */ if (*(ptr(curbp, curbp->b_point)) == 0xa) { delete(); /* delete CR if at start of empty line */ } else { curbp->b_mark = curbp->b_point; lnend(); if (curbp->b_mark != curbp->b_point) copy_cut(TRUE); } } void copy_cut(int cut) { char_t *p; /* if no mark or point == marker, nothing doing */ if (curbp->b_mark == NOMARK || curbp->b_point == curbp->b_mark) return; if (scrap != NULL) { free(scrap); scrap = NULL; } if (curbp->b_point < curbp->b_mark) { /* point above marker: move gap under point, region = marker - point */ (void) movegap(curbp, curbp->b_point); p = ptr(curbp, curbp->b_point); nscrap = curbp->b_mark - curbp->b_point; } else { /* if point below marker: move gap under marker, region = point - marker */ (void) movegap(curbp, curbp->b_mark); p = ptr(curbp, curbp->b_mark); nscrap = curbp->b_point - curbp->b_mark; } if ((scrap = malloc(nscrap)) == NULL) { nscrap = 0; msg("No more memory available."); } else { (void) memcpy(scrap, p, nscrap * sizeof (char_t)); if (cut) { curbp->b_egap += nscrap; /* if cut expand gap down */ curbp->b_point = pos(curbp, curbp->b_egap); /* set point to after region */ curbp->b_flags |= B_MODIFIED; msg("%ld bytes cut.", nscrap); } else { msg("%ld bytes copied.", nscrap); } curbp->b_mark = NOMARK; /* unmark */ } } void paste(void) { if(curbp->b_flags & B_OVERWRITE) return; if (nscrap <= 0) { msg("Scrap is empty. Nothing to paste."); } else if (nscrap < curbp->b_egap - curbp->b_gap || growgap(curbp, nscrap)) { curbp->b_point = movegap(curbp, curbp->b_point); memcpy(curbp->b_gap, scrap, nscrap * sizeof (char_t)); curbp->b_gap += nscrap; curbp->b_point = pos(curbp, curbp->b_egap); curbp->b_flags |= B_MODIFIED; } } void showpos(void) { int current, lastln; point_t end_p = pos(curbp, curbp->b_ebuf); get_line_stats(¤t, &lastln); if (curbp->b_point == end_p) { msg("[EOB] Line = %d/%d Point = %ld/%td", current, lastln, curbp->b_point, ((curbp->b_ebuf - curbp->b_buf) - (curbp->b_egap - curbp->b_gap))); } else { msg("Char = %s 0x%x Line = %d/%d Point = %ld/%td", unctrl(*(ptr(curbp, curbp->b_point))), *(ptr(curbp, curbp->b_point)), current, lastln, curbp->b_point, ((curbp->b_ebuf - curbp->b_buf) - (curbp->b_egap - curbp->b_gap))); } }