00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <sys/types.h>
00040 #include <vfs/vfs.h>
00041 #include <io/console.h>
00042 #include <io/style.h>
00043 #include <io/keycode.h>
00044 #include <errno.h>
00045 #include <align.h>
00046 #include <macros.h>
00047 #include <clipboard.h>
00048 #include <bool.h>
00049
00050 #include "sheet.h"
00051
00052 enum redraw_flags {
00053 REDRAW_TEXT = (1 << 0),
00054 REDRAW_ROW = (1 << 1),
00055 REDRAW_STATUS = (1 << 2),
00056 REDRAW_CARET = (1 << 3)
00057 };
00058
00064 typedef struct {
00065
00066 int rows, columns;
00067
00068
00069 int sh_row, sh_column;
00070
00072 enum redraw_flags rflags;
00073
00075 tag_t caret_pos;
00076
00078 tag_t sel_start;
00079
00084 int ideal_column;
00085 } pane_t;
00086
00091 typedef struct {
00092 char *file_name;
00093 sheet_t sh;
00094 } doc_t;
00095
00096 static int con;
00097 static doc_t doc;
00098 static bool done;
00099 static pane_t pane;
00100 static bool cursor_visible;
00101
00102 static sysarg_t scr_rows;
00103 static sysarg_t scr_columns;
00104
00105 #define ROW_BUF_SIZE 4096
00106 #define BUF_SIZE 64
00107 #define TAB_WIDTH 8
00108 #define ED_INFTY 65536
00109
00111 #define INFNAME_MAX_LEN 128
00112
00113 static void cursor_show(void);
00114 static void cursor_hide(void);
00115 static void cursor_setvis(bool visible);
00116
00117 static void key_handle_unmod(console_event_t const *ev);
00118 static void key_handle_ctrl(console_event_t const *ev);
00119 static void key_handle_shift(console_event_t const *ev);
00120 static void key_handle_movement(unsigned int key, bool shift);
00121
00122 static int file_save(char const *fname);
00123 static void file_save_as(void);
00124 static int file_insert(char *fname);
00125 static int file_save_range(char const *fname, spt_t const *spos,
00126 spt_t const *epos);
00127 static char *filename_prompt(char const *prompt, char const *init_value);
00128 static char *range_get_str(spt_t const *spos, spt_t const *epos);
00129
00130 static void pane_text_display(void);
00131 static void pane_row_display(void);
00132 static void pane_row_range_display(int r0, int r1);
00133 static void pane_status_display(void);
00134 static void pane_caret_display(void);
00135
00136 static void insert_char(wchar_t c);
00137 static void delete_char_before(void);
00138 static void delete_char_after(void);
00139 static void caret_update(void);
00140 static void caret_move(int drow, int dcolumn, enum dir_spec align_dir);
00141
00142 static bool selection_active(void);
00143 static void selection_sel_all(void);
00144 static void selection_get_points(spt_t *pa, spt_t *pb);
00145 static void selection_delete(void);
00146 static void selection_copy(void);
00147 static void insert_clipboard_data(void);
00148
00149 static void pt_get_sof(spt_t *pt);
00150 static void pt_get_eof(spt_t *pt);
00151 static int tag_cmp(tag_t const *a, tag_t const *b);
00152 static int spt_cmp(spt_t const *a, spt_t const *b);
00153 static int coord_cmp(coord_t const *a, coord_t const *b);
00154
00155 static void status_display(char const *str);
00156
00157
00158 int main(int argc, char *argv[])
00159 {
00160 console_event_t ev;
00161 coord_t coord;
00162 bool new_file;
00163
00164 spt_t pt;
00165
00166 con = fphone(stdout);
00167 console_clear(con);
00168
00169 console_get_size(con, &scr_columns, &scr_rows);
00170
00171 pane.rows = scr_rows - 1;
00172 pane.columns = scr_columns;
00173 pane.sh_row = 1;
00174 pane.sh_column = 1;
00175
00176
00177 sheet_init(&doc.sh);
00178
00179
00180 coord.row = coord.column = 1;
00181 sheet_get_cell_pt(&doc.sh, &coord, dir_before, &pt);
00182 sheet_place_tag(&doc.sh, &pt, &pane.caret_pos);
00183 pane.ideal_column = coord.column;
00184
00185 if (argc == 2) {
00186 doc.file_name = str_dup(argv[1]);
00187 } else if (argc > 1) {
00188 printf("Invalid arguments.\n");
00189 return -2;
00190 } else {
00191 doc.file_name = NULL;
00192 }
00193
00194 new_file = false;
00195
00196 if (doc.file_name == NULL || file_insert(doc.file_name) != EOK)
00197 new_file = true;
00198
00199
00200 caret_move(-ED_INFTY, -ED_INFTY, dir_before);
00201
00202
00203 tag_get_pt(&pane.caret_pos, &pt);
00204 sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
00205
00206
00207 cursor_visible = true;
00208
00209 cursor_hide();
00210 console_clear(con);
00211 pane_text_display();
00212 pane_status_display();
00213 if (new_file && doc.file_name != NULL)
00214 status_display("File not found. Starting empty file.");
00215 pane_caret_display();
00216 cursor_show();
00217
00218 done = false;
00219
00220 while (!done) {
00221 console_get_event(con, &ev);
00222 pane.rflags = 0;
00223
00224 if (ev.type == KEY_PRESS) {
00225
00226 if (((ev.mods & KM_ALT) == 0) &&
00227 ((ev.mods & KM_SHIFT) == 0) &&
00228 (ev.mods & KM_CTRL) != 0) {
00229 key_handle_ctrl(&ev);
00230 } else if (((ev.mods & KM_ALT) == 0) &&
00231 ((ev.mods & KM_CTRL) == 0) &&
00232 (ev.mods & KM_SHIFT) != 0) {
00233 key_handle_shift(&ev);
00234 } else if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
00235 key_handle_unmod(&ev);
00236 }
00237 }
00238
00239
00240
00241 cursor_hide();
00242
00243 if (pane.rflags & REDRAW_TEXT)
00244 pane_text_display();
00245 if (pane.rflags & REDRAW_ROW)
00246 pane_row_display();
00247 if (pane.rflags & REDRAW_STATUS)
00248 pane_status_display();
00249 if (pane.rflags & REDRAW_CARET)
00250 pane_caret_display();
00251
00252 cursor_show();
00253 }
00254
00255 console_clear(con);
00256
00257 return 0;
00258 }
00259
00260 static void cursor_show(void)
00261 {
00262 cursor_setvis(true);
00263 }
00264
00265 static void cursor_hide(void)
00266 {
00267 cursor_setvis(false);
00268 }
00269
00270 static void cursor_setvis(bool visible)
00271 {
00272 if (cursor_visible != visible) {
00273 console_cursor_visibility(con, visible);
00274 cursor_visible = visible;
00275 }
00276 }
00277
00279 static void key_handle_unmod(console_event_t const *ev)
00280 {
00281 switch (ev->key) {
00282 case KC_ENTER:
00283 selection_delete();
00284 insert_char('\n');
00285 caret_update();
00286 break;
00287 case KC_LEFT:
00288 case KC_RIGHT:
00289 case KC_UP:
00290 case KC_DOWN:
00291 case KC_HOME:
00292 case KC_END:
00293 case KC_PAGE_UP:
00294 case KC_PAGE_DOWN:
00295 key_handle_movement(ev->key, false);
00296 break;
00297 case KC_BACKSPACE:
00298 if (selection_active())
00299 selection_delete();
00300 else
00301 delete_char_before();
00302 caret_update();
00303 break;
00304 case KC_DELETE:
00305 if (selection_active())
00306 selection_delete();
00307 else
00308 delete_char_after();
00309 caret_update();
00310 break;
00311 default:
00312 if (ev->c >= 32 || ev->c == '\t') {
00313 selection_delete();
00314 insert_char(ev->c);
00315 caret_update();
00316 }
00317 break;
00318 }
00319 }
00320
00322 static void key_handle_shift(console_event_t const *ev)
00323 {
00324 switch (ev->key) {
00325 case KC_LEFT:
00326 case KC_RIGHT:
00327 case KC_UP:
00328 case KC_DOWN:
00329 case KC_HOME:
00330 case KC_END:
00331 case KC_PAGE_UP:
00332 case KC_PAGE_DOWN:
00333 key_handle_movement(ev->key, true);
00334 break;
00335 default:
00336 if (ev->c >= 32 || ev->c == '\t') {
00337 selection_delete();
00338 insert_char(ev->c);
00339 caret_update();
00340 }
00341 break;
00342 }
00343 }
00344
00346 static void key_handle_ctrl(console_event_t const *ev)
00347 {
00348 switch (ev->key) {
00349 case KC_Q:
00350 done = true;
00351 break;
00352 case KC_S:
00353 if (doc.file_name != NULL)
00354 file_save(doc.file_name);
00355 else
00356 file_save_as();
00357 break;
00358 case KC_E:
00359 file_save_as();
00360 break;
00361 case KC_C:
00362 selection_copy();
00363 break;
00364 case KC_V:
00365 selection_delete();
00366 insert_clipboard_data();
00367 pane.rflags |= REDRAW_TEXT;
00368 caret_update();
00369 break;
00370 case KC_X:
00371 selection_copy();
00372 selection_delete();
00373 pane.rflags |= REDRAW_TEXT;
00374 caret_update();
00375 break;
00376 case KC_A:
00377 selection_sel_all();
00378 break;
00379 default:
00380 break;
00381 }
00382 }
00383
00384 static void key_handle_movement(unsigned int key, bool select)
00385 {
00386 spt_t pt;
00387 spt_t caret_pt;
00388 coord_t c_old, c_new;
00389 bool had_sel;
00390
00391
00392 tag_get_pt(&pane.caret_pos, &caret_pt);
00393 tag_get_pt(&pane.sel_start, &pt);
00394 had_sel = !spt_equal(&caret_pt, &pt);
00395
00396 switch (key) {
00397 case KC_LEFT:
00398 caret_move(0, -1, dir_before);
00399 break;
00400 case KC_RIGHT:
00401 caret_move(0, 0, dir_after);
00402 break;
00403 case KC_UP:
00404 caret_move(-1, 0, dir_before);
00405 break;
00406 case KC_DOWN:
00407 caret_move(+1, 0, dir_before);
00408 break;
00409 case KC_HOME:
00410 caret_move(0, -ED_INFTY, dir_before);
00411 break;
00412 case KC_END:
00413 caret_move(0, +ED_INFTY, dir_before);
00414 break;
00415 case KC_PAGE_UP:
00416 caret_move(-pane.rows, 0, dir_before);
00417 break;
00418 case KC_PAGE_DOWN:
00419 caret_move(+pane.rows, 0, dir_before);
00420 break;
00421 default:
00422 break;
00423 }
00424
00425 if (select == false) {
00426
00427 sheet_remove_tag(&doc.sh, &pane.sel_start);
00428 tag_get_pt(&pane.caret_pos, &pt);
00429 sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
00430 }
00431
00432 if (select) {
00433 tag_get_pt(&pane.caret_pos, &pt);
00434 spt_get_coord(&caret_pt, &c_old);
00435 spt_get_coord(&pt, &c_new);
00436
00437 if (c_old.row == c_new.row)
00438 pane.rflags |= REDRAW_ROW;
00439 else
00440 pane.rflags |= REDRAW_TEXT;
00441
00442 } else if (had_sel == true) {
00443
00444 pane.rflags |= REDRAW_TEXT;
00445 }
00446 }
00447
00449 static int file_save(char const *fname)
00450 {
00451 spt_t sp, ep;
00452 int rc;
00453
00454 status_display("Saving...");
00455 pt_get_sof(&sp);
00456 pt_get_eof(&ep);
00457
00458 rc = file_save_range(fname, &sp, &ep);
00459
00460 switch (rc) {
00461 case EINVAL:
00462 status_display("Error opening file!");
00463 break;
00464 case EIO:
00465 status_display("Error writing data!");
00466 break;
00467 default:
00468 status_display("File saved.");
00469 break;
00470 }
00471
00472 return rc;
00473 }
00474
00476 static void file_save_as(void)
00477 {
00478 const char *old_fname = (doc.file_name != NULL) ? doc.file_name : "";
00479 char *fname;
00480
00481 fname = filename_prompt("Save As", old_fname);
00482 if (fname == NULL) {
00483 status_display("Save cancelled.");
00484 return;
00485 }
00486
00487 int rc = file_save(fname);
00488 if (rc != EOK)
00489 return;
00490
00491 if (doc.file_name != NULL)
00492 free(doc.file_name);
00493 doc.file_name = fname;
00494 }
00495
00497 static char *filename_prompt(char const *prompt, char const *init_value)
00498 {
00499 console_event_t ev;
00500 char *str;
00501 wchar_t buffer[INFNAME_MAX_LEN + 1];
00502 int max_len;
00503 int nc;
00504 bool done;
00505
00506 asprintf(&str, "%s: %s", prompt, init_value);
00507 status_display(str);
00508 console_set_pos(con, 1 + str_length(str), scr_rows - 1);
00509 free(str);
00510
00511 console_set_style(con, STYLE_INVERTED);
00512
00513 max_len = min(INFNAME_MAX_LEN, scr_columns - 4 - str_length(prompt));
00514 str_to_wstr(buffer, max_len + 1, init_value);
00515 nc = wstr_length(buffer);
00516 done = false;
00517
00518 while (!done) {
00519 console_get_event(con, &ev);
00520
00521 if (ev.type == KEY_PRESS) {
00522
00523 if (((ev.mods & KM_ALT) == 0) &&
00524 (ev.mods & KM_CTRL) != 0) {
00525 ;
00526 } else if ((ev.mods & (KM_CTRL | KM_ALT)) == 0) {
00527 switch (ev.key) {
00528 case KC_ESCAPE:
00529 return NULL;
00530 case KC_BACKSPACE:
00531 if (nc > 0) {
00532 putchar('\b');
00533 fflush(stdout);
00534 --nc;
00535 }
00536 break;
00537 case KC_ENTER:
00538 done = true;
00539 break;
00540 default:
00541 if (ev.c >= 32 && nc < max_len) {
00542 putchar(ev.c);
00543 fflush(stdout);
00544 buffer[nc++] = ev.c;
00545 }
00546 break;
00547 }
00548 }
00549 }
00550 }
00551
00552 buffer[nc] = '\0';
00553 str = wstr_to_astr(buffer);
00554
00555 console_set_style(con, STYLE_NORMAL);
00556
00557 return str;
00558 }
00559
00565 static int file_insert(char *fname)
00566 {
00567 FILE *f;
00568 wchar_t c;
00569 char buf[BUF_SIZE];
00570 int bcnt;
00571 int n_read;
00572 size_t off;
00573
00574 f = fopen(fname, "rt");
00575 if (f == NULL)
00576 return EINVAL;
00577
00578 bcnt = 0;
00579
00580 while (true) {
00581 if (bcnt < STR_BOUNDS(1)) {
00582 n_read = fread(buf + bcnt, 1, BUF_SIZE - bcnt, f);
00583 bcnt += n_read;
00584 }
00585
00586 off = 0;
00587 c = str_decode(buf, &off, bcnt);
00588 if (c == '\0')
00589 break;
00590
00591 bcnt -= off;
00592 memcpy(buf, buf + off, bcnt);
00593
00594 insert_char(c);
00595 }
00596
00597 fclose(f);
00598
00599 return EOK;
00600 }
00601
00603 static int file_save_range(char const *fname, spt_t const *spos,
00604 spt_t const *epos)
00605 {
00606 FILE *f;
00607 char buf[BUF_SIZE];
00608 spt_t sp, bep;
00609 size_t bytes, n_written;
00610
00611 f = fopen(fname, "wt");
00612 if (f == NULL)
00613 return EINVAL;
00614
00615 sp = *spos;
00616
00617 do {
00618 sheet_copy_out(&doc.sh, &sp, epos, buf, BUF_SIZE, &bep);
00619 bytes = str_size(buf);
00620
00621 n_written = fwrite(buf, 1, bytes, f);
00622 if (n_written != bytes) {
00623 return EIO;
00624 }
00625
00626 sp = bep;
00627 } while (!spt_equal(&bep, epos));
00628
00629 if (fclose(f) != EOK)
00630 return EIO;
00631
00632 return EOK;
00633 }
00634
00636 static char *range_get_str(spt_t const *spos, spt_t const *epos)
00637 {
00638 char *buf;
00639 spt_t sp, bep;
00640 size_t bytes;
00641 size_t buf_size, bpos;
00642
00643 buf_size = 1;
00644
00645 buf = malloc(buf_size);
00646 if (buf == NULL)
00647 return NULL;
00648
00649 bpos = 0;
00650 sp = *spos;
00651
00652 while (true) {
00653 sheet_copy_out(&doc.sh, &sp, epos, &buf[bpos], buf_size - bpos,
00654 &bep);
00655 bytes = str_size(&buf[bpos]);
00656 bpos += bytes;
00657 sp = bep;
00658
00659 if (spt_equal(&bep, epos))
00660 break;
00661
00662 buf_size *= 2;
00663 buf = realloc(buf, buf_size);
00664 if (buf == NULL)
00665 return NULL;
00666 }
00667
00668 return buf;
00669 }
00670
00671 static void pane_text_display(void)
00672 {
00673 int sh_rows, rows;
00674
00675 sheet_get_num_rows(&doc.sh, &sh_rows);
00676 rows = min(sh_rows - pane.sh_row + 1, pane.rows);
00677
00678
00679
00680 console_set_pos(con, 0, 0);
00681 pane_row_range_display(0, rows);
00682
00683
00684
00685 int i;
00686 sysarg_t j;
00687 for (i = rows; i < pane.rows; ++i) {
00688 console_set_pos(con, 0, i);
00689 for (j = 0; j < scr_columns; ++j)
00690 putchar(' ');
00691 fflush(stdout);
00692 }
00693
00694 pane.rflags |= (REDRAW_STATUS | REDRAW_CARET);
00695 pane.rflags &= ~REDRAW_ROW;
00696 }
00697
00699 static void pane_row_display(void)
00700 {
00701 spt_t caret_pt;
00702 coord_t coord;
00703 int ridx;
00704
00705 tag_get_pt(&pane.caret_pos, &caret_pt);
00706 spt_get_coord(&caret_pt, &coord);
00707
00708 ridx = coord.row - pane.sh_row;
00709 pane_row_range_display(ridx, ridx + 1);
00710 pane.rflags |= (REDRAW_STATUS | REDRAW_CARET);
00711 }
00712
00713 static void pane_row_range_display(int r0, int r1)
00714 {
00715 int i, j, fill;
00716 spt_t rb, re, dep, pt;
00717 coord_t rbc, rec;
00718 char row_buf[ROW_BUF_SIZE];
00719 wchar_t c;
00720 size_t pos, size;
00721 int s_column;
00722 coord_t csel_start, csel_end, ctmp;
00723
00724
00725
00726 tag_get_pt(&pane.sel_start, &pt);
00727 spt_get_coord(&pt, &csel_start);
00728
00729 tag_get_pt(&pane.caret_pos, &pt);
00730 spt_get_coord(&pt, &csel_end);
00731
00732 if (coord_cmp(&csel_start, &csel_end) > 0) {
00733 ctmp = csel_start;
00734 csel_start = csel_end;
00735 csel_end = ctmp;
00736 }
00737
00738
00739
00740 console_set_pos(con, 0, 0);
00741 for (i = r0; i < r1; ++i) {
00742
00743 rbc.row = pane.sh_row + i;
00744 rbc.column = pane.sh_column;
00745 sheet_get_cell_pt(&doc.sh, &rbc, dir_before, &rb);
00746
00747
00748 rec.row = pane.sh_row + i;
00749 rec.column = pane.sh_column + pane.columns;
00750 sheet_get_cell_pt(&doc.sh, &rec, dir_before, &re);
00751
00752
00753 sheet_copy_out(&doc.sh, &rb, &re, row_buf, ROW_BUF_SIZE, &dep);
00754
00755
00756
00757 if (coord_cmp(&csel_start, &rbc) <= 0 &&
00758 coord_cmp(&rbc, &csel_end) < 0) {
00759 fflush(stdout);
00760 console_set_style(con, STYLE_SELECTED);
00761 fflush(stdout);
00762 }
00763
00764 console_set_pos(con, 0, i);
00765 size = str_size(row_buf);
00766 pos = 0;
00767 s_column = pane.sh_column;
00768 while (pos < size) {
00769 if ((csel_start.row == rbc.row) && (csel_start.column == s_column)) {
00770 fflush(stdout);
00771 console_set_style(con, STYLE_SELECTED);
00772 fflush(stdout);
00773 }
00774
00775 if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
00776 fflush(stdout);
00777 console_set_style(con, STYLE_NORMAL);
00778 fflush(stdout);
00779 }
00780
00781 c = str_decode(row_buf, &pos, size);
00782 if (c != '\t') {
00783 printf("%lc", (wint_t) c);
00784 s_column += 1;
00785 } else {
00786 fill = 1 + ALIGN_UP(s_column, TAB_WIDTH)
00787 - s_column;
00788
00789 for (j = 0; j < fill; ++j)
00790 putchar(' ');
00791 s_column += fill;
00792 }
00793 }
00794
00795 if ((csel_end.row == rbc.row) && (csel_end.column == s_column)) {
00796 fflush(stdout);
00797 console_set_style(con, STYLE_NORMAL);
00798 fflush(stdout);
00799 }
00800
00801
00802
00803 if (str_length(row_buf) < (unsigned) scr_columns)
00804 fill = scr_columns - str_length(row_buf);
00805 else
00806 fill = 0;
00807
00808 for (j = 0; j < fill; ++j)
00809 putchar(' ');
00810 fflush(stdout);
00811 console_set_style(con, STYLE_NORMAL);
00812 }
00813
00814 pane.rflags |= REDRAW_CARET;
00815 }
00816
00818 static void pane_status_display(void)
00819 {
00820 spt_t caret_pt;
00821 coord_t coord;
00822
00823 tag_get_pt(&pane.caret_pos, &caret_pt);
00824 spt_get_coord(&caret_pt, &coord);
00825
00826 const char *fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>";
00827
00828 console_set_pos(con, 0, scr_rows - 1);
00829 console_set_style(con, STYLE_INVERTED);
00830 int n = printf(" %d, %d: File '%s'. Ctrl-Q Quit Ctrl-S Save "
00831 "Ctrl-E Save As", coord.row, coord.column, fname);
00832
00833 int pos = scr_columns - 1 - n;
00834 printf("%*s", pos, "");
00835 fflush(stdout);
00836 console_set_style(con, STYLE_NORMAL);
00837
00838 pane.rflags |= REDRAW_CARET;
00839 }
00840
00842 static void pane_caret_display(void)
00843 {
00844 spt_t caret_pt;
00845 coord_t coord;
00846
00847 tag_get_pt(&pane.caret_pos, &caret_pt);
00848
00849 spt_get_coord(&caret_pt, &coord);
00850 console_set_pos(con, coord.column - pane.sh_column,
00851 coord.row - pane.sh_row);
00852 }
00853
00855 static void insert_char(wchar_t c)
00856 {
00857 spt_t pt;
00858 char cbuf[STR_BOUNDS(1) + 1];
00859 size_t offs;
00860
00861 tag_get_pt(&pane.caret_pos, &pt);
00862
00863 offs = 0;
00864 chr_encode(c, cbuf, &offs, STR_BOUNDS(1) + 1);
00865 cbuf[offs] = '\0';
00866
00867 (void) sheet_insert(&doc.sh, &pt, dir_before, cbuf);
00868
00869 pane.rflags |= REDRAW_ROW;
00870 if (c == '\n')
00871 pane.rflags |= REDRAW_TEXT;
00872 }
00873
00875 static void delete_char_before(void)
00876 {
00877 spt_t sp, ep;
00878 coord_t coord;
00879
00880 tag_get_pt(&pane.caret_pos, &ep);
00881 spt_get_coord(&ep, &coord);
00882
00883 coord.column -= 1;
00884 sheet_get_cell_pt(&doc.sh, &coord, dir_before, &sp);
00885
00886 (void) sheet_delete(&doc.sh, &sp, &ep);
00887
00888 pane.rflags |= REDRAW_ROW;
00889 if (coord.column < 1)
00890 pane.rflags |= REDRAW_TEXT;
00891 }
00892
00894 static void delete_char_after(void)
00895 {
00896 spt_t sp, ep;
00897 coord_t sc, ec;
00898
00899 tag_get_pt(&pane.caret_pos, &sp);
00900 spt_get_coord(&sp, &sc);
00901
00902 sheet_get_cell_pt(&doc.sh, &sc, dir_after, &ep);
00903 spt_get_coord(&ep, &ec);
00904
00905 (void) sheet_delete(&doc.sh, &sp, &ep);
00906
00907 pane.rflags |= REDRAW_ROW;
00908 if (ec.row != sc.row)
00909 pane.rflags |= REDRAW_TEXT;
00910 }
00911
00917 static void caret_update(void)
00918 {
00919 spt_t pt;
00920 coord_t coord;
00921
00922 tag_get_pt(&pane.caret_pos, &pt);
00923 spt_get_coord(&pt, &coord);
00924
00925
00926
00927 if (coord.row < pane.sh_row) {
00928 pane.sh_row = coord.row;
00929 pane.rflags |= REDRAW_TEXT;
00930 }
00931
00932 if (coord.row > pane.sh_row + pane.rows - 1) {
00933 pane.sh_row = coord.row - pane.rows + 1;
00934 pane.rflags |= REDRAW_TEXT;
00935 }
00936
00937
00938
00939 if (coord.column < pane.sh_column) {
00940 pane.sh_column = coord.column;
00941 pane.rflags |= REDRAW_TEXT;
00942 }
00943
00944 if (coord.column > pane.sh_column + pane.columns - 1) {
00945 pane.sh_column = coord.column - pane.columns + 1;
00946 pane.rflags |= REDRAW_TEXT;
00947 }
00948
00949 pane.rflags |= (REDRAW_CARET | REDRAW_STATUS);
00950 }
00951
00959 static void caret_move(int drow, int dcolumn, enum dir_spec align_dir)
00960 {
00961 spt_t pt;
00962 coord_t coord;
00963 int num_rows;
00964 bool pure_vertical;
00965
00966 tag_get_pt(&pane.caret_pos, &pt);
00967 spt_get_coord(&pt, &coord);
00968 coord.row += drow; coord.column += dcolumn;
00969
00970
00971 if (drow < 0 && coord.row < 1) coord.row = 1;
00972 if (dcolumn < 0 && coord.column < 1) coord.column = 1;
00973 if (drow > 0) {
00974 sheet_get_num_rows(&doc.sh, &num_rows);
00975 if (coord.row > num_rows) coord.row = num_rows;
00976 }
00977
00978
00979 pure_vertical = (dcolumn == 0 && align_dir == dir_before);
00980 if (pure_vertical)
00981 coord.column = pane.ideal_column;
00982
00983
00984
00985
00986
00987 sheet_get_cell_pt(&doc.sh, &coord, align_dir, &pt);
00988 sheet_remove_tag(&doc.sh, &pane.caret_pos);
00989 sheet_place_tag(&doc.sh, &pt, &pane.caret_pos);
00990
00991
00992 if (!pure_vertical) {
00993 spt_get_coord(&pt, &coord);
00994 pane.ideal_column = coord.column;
00995 }
00996
00997 caret_update();
00998 }
00999
01001 static bool selection_active(void)
01002 {
01003 return (tag_cmp(&pane.caret_pos, &pane.sel_start) != 0);
01004 }
01005
01006 static void selection_get_points(spt_t *pa, spt_t *pb)
01007 {
01008 spt_t pt;
01009
01010 tag_get_pt(&pane.sel_start, pa);
01011 tag_get_pt(&pane.caret_pos, pb);
01012
01013 if (spt_cmp(pa, pb) > 0) {
01014 pt = *pa;
01015 *pa = *pb;
01016 *pb = pt;
01017 }
01018 }
01019
01021 static void selection_delete(void)
01022 {
01023 spt_t pa, pb;
01024 coord_t ca, cb;
01025 int rel;
01026
01027 tag_get_pt(&pane.sel_start, &pa);
01028 tag_get_pt(&pane.caret_pos, &pb);
01029 spt_get_coord(&pa, &ca);
01030 spt_get_coord(&pb, &cb);
01031 rel = coord_cmp(&ca, &cb);
01032
01033 if (rel == 0)
01034 return;
01035
01036 if (rel < 0)
01037 sheet_delete(&doc.sh, &pa, &pb);
01038 else
01039 sheet_delete(&doc.sh, &pb, &pa);
01040
01041 if (ca.row == cb.row)
01042 pane.rflags |= REDRAW_ROW;
01043 else
01044 pane.rflags |= REDRAW_TEXT;
01045 }
01046
01047 static void selection_sel_all(void)
01048 {
01049 spt_t spt, ept;
01050
01051 pt_get_sof(&spt);
01052 pt_get_eof(&ept);
01053 sheet_remove_tag(&doc.sh, &pane.sel_start);
01054 sheet_place_tag(&doc.sh, &spt, &pane.sel_start);
01055 sheet_remove_tag(&doc.sh, &pane.caret_pos);
01056 sheet_place_tag(&doc.sh, &ept, &pane.caret_pos);
01057
01058 pane.rflags |= REDRAW_TEXT;
01059 caret_update();
01060 }
01061
01062 static void selection_copy(void)
01063 {
01064 spt_t pa, pb;
01065 char *str;
01066
01067 selection_get_points(&pa, &pb);
01068 str = range_get_str(&pa, &pb);
01069 if (str == NULL || clipboard_put_str(str) != EOK) {
01070 status_display("Copying to clipboard failed!");
01071 }
01072 free(str);
01073 }
01074
01075 static void insert_clipboard_data(void)
01076 {
01077 char *str;
01078 size_t off;
01079 wchar_t c;
01080 int rc;
01081
01082 rc = clipboard_get_str(&str);
01083 if (rc != EOK || str == NULL)
01084 return;
01085
01086 off = 0;
01087
01088 while (true) {
01089 c = str_decode(str, &off, STR_NO_LIMIT);
01090 if (c == '\0')
01091 break;
01092
01093 insert_char(c);
01094 }
01095
01096 free(str);
01097 }
01098
01100 static void pt_get_sof(spt_t *pt)
01101 {
01102 coord_t coord;
01103
01104 coord.row = coord.column = 1;
01105 sheet_get_cell_pt(&doc.sh, &coord, dir_before, pt);
01106 }
01107
01109 static void pt_get_eof(spt_t *pt)
01110 {
01111 coord_t coord;
01112 int num_rows;
01113
01114 sheet_get_num_rows(&doc.sh, &num_rows);
01115 coord.row = num_rows + 1;
01116 coord.column = 1;
01117
01118 sheet_get_cell_pt(&doc.sh, &coord, dir_after, pt);
01119 }
01120
01122 static int tag_cmp(tag_t const *a, tag_t const *b)
01123 {
01124 spt_t pa, pb;
01125
01126 tag_get_pt(a, &pa);
01127 tag_get_pt(b, &pb);
01128
01129 return spt_cmp(&pa, &pb);
01130 }
01131
01133 static int spt_cmp(spt_t const *a, spt_t const *b)
01134 {
01135 coord_t ca, cb;
01136
01137 spt_get_coord(a, &ca);
01138 spt_get_coord(b, &cb);
01139
01140 return coord_cmp(&ca, &cb);
01141 }
01142
01144 static int coord_cmp(coord_t const *a, coord_t const *b)
01145 {
01146 if (a->row - b->row != 0)
01147 return a->row - b->row;
01148
01149 return a->column - b->column;
01150 }
01151
01153 static void status_display(char const *str)
01154 {
01155 console_set_pos(con, 0, scr_rows - 1);
01156 console_set_style(con, STYLE_INVERTED);
01157
01158 int pos = -(scr_columns - 3);
01159 printf(" %*s ", pos, str);
01160 fflush(stdout);
01161 console_set_style(con, STYLE_NORMAL);
01162
01163 pane.rflags |= REDRAW_CARET;
01164 }
01165