Changeset 8e7c9fe in mainline for uspace/dist/src/c/demos/edit/edit.c
- Timestamp:
- 2014-09-12T03:45:25Z (10 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- c53b58e
- Parents:
- 3eb0c85 (diff), 105d8d6 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/dist/src/c/demos/edit/edit.c
r3eb0c85 r8e7c9fe 1 1 /* 2 2 * Copyright (c) 2009 Jiri Svoboda 3 * Copyright (c) 2012 Martin Sucha 3 4 * All rights reserved. 4 5 * … … 49 50 50 51 #include "sheet.h" 52 #include "search.h" 51 53 52 54 enum redraw_flags { … … 78 80 tag_t sel_start; 79 81 82 /** Active keyboard modifiers */ 83 keymod_t keymod; 84 80 85 /** 81 86 * Ideal column where the caret should try to get. This is used … … 83 88 */ 84 89 int ideal_column; 90 91 char *previous_search; 92 bool previous_search_reverse; 85 93 } pane_t; 86 94 … … 91 99 typedef struct { 92 100 char *file_name; 93 sheet_t sh;101 sheet_t *sh; 94 102 } doc_t; 95 103 … … 106 114 #define BUF_SIZE 64 107 115 #define TAB_WIDTH 8 108 #define ED_INFTY 65536109 116 110 117 /** Maximum filename length that can be entered. */ … … 115 122 static void cursor_setvis(bool visible); 116 123 124 static void key_handle_press(kbd_event_t *ev); 117 125 static void key_handle_unmod(kbd_event_t const *ev); 118 126 static void key_handle_ctrl(kbd_event_t const *ev); 119 127 static void key_handle_shift(kbd_event_t const *ev); 128 static void key_handle_shift_ctrl(kbd_event_t const *ev); 120 129 static void key_handle_movement(unsigned int key, bool shift); 130 131 static void pos_handle(pos_event_t *ev); 121 132 122 133 static int file_save(char const *fname); … … 125 136 static int file_save_range(char const *fname, spt_t const *spos, 126 137 spt_t const *epos); 127 static char *filename_prompt(char const *prompt, char const *init_value);128 138 static char *range_get_str(spt_t const *spos, spt_t const *epos); 139 140 static char *prompt(char const *prompt, char const *init_value); 129 141 130 142 static void pane_text_display(void); … … 138 150 static void delete_char_after(void); 139 151 static void caret_update(void); 140 static void caret_move(int drow, int dcolumn, enum dir_spec align_dir); 152 static void caret_move_relative(int drow, int dcolumn, enum dir_spec align_dir, bool select); 153 static void caret_move_absolute(int row, int column, enum dir_spec align_dir, bool select); 154 static void caret_move(spt_t spt, bool select, bool update_ideal_column); 155 static void caret_move_word_left(bool select); 156 static void caret_move_word_right(bool select); 157 static void caret_go_to_line_ask(void); 141 158 142 159 static bool selection_active(void); 143 160 static void selection_sel_all(void); 161 static void selection_sel_range(spt_t pa, spt_t pb); 144 162 static void selection_get_points(spt_t *pa, spt_t *pb); 145 163 static void selection_delete(void); … … 147 165 static void insert_clipboard_data(void); 148 166 167 static void search(char *pattern, bool reverse); 168 static void search_prompt(bool reverse); 169 static void search_repeat(void); 170 149 171 static void pt_get_sof(spt_t *pt); 150 172 static void pt_get_eof(spt_t *pt); 173 static void pt_get_sol(spt_t *cpt, spt_t *spt); 174 static void pt_get_eol(spt_t *cpt, spt_t *ept); 175 static bool pt_is_word_beginning(spt_t *pt); 176 static bool pt_is_delimiter(spt_t *pt); 177 static bool pt_is_punctuation(spt_t *pt); 178 static spt_t pt_find_word_left(spt_t spt); 179 static spt_t pt_find_word_left(spt_t spt); 180 151 181 static int tag_cmp(tag_t const *a, tag_t const *b); 152 182 static int spt_cmp(spt_t const *a, spt_t const *b); … … 158 188 int main(int argc, char *argv[]) 159 189 { 160 kbd_event_t ev; 161 coord_t coord; 190 cons_event_t ev; 162 191 bool new_file; 163 164 spt_t pt; 192 int rc; 165 193 166 194 con = console_init(stdin, stdout); … … 175 203 176 204 /* Start with an empty sheet. */ 177 sheet_init(&doc.sh); 205 rc = sheet_create(&doc.sh); 206 if (rc != EOK) { 207 printf("Out of memory.\n"); 208 return -1; 209 } 178 210 179 211 /* Place caret at the beginning of file. */ 180 coord.row = coord.column = 1;181 sheet_get_cell_pt(&doc.sh, &coord, dir_before, &pt);182 sheet_place_tag( &doc.sh, &pt, &pane.caret_pos);183 pane.ideal_column = coord.column;212 spt_t sof; 213 pt_get_sof(&sof); 214 sheet_place_tag(doc.sh, &sof, &pane.caret_pos); 215 pane.ideal_column = 1; 184 216 185 217 if (argc == 2) { … … 197 229 new_file = true; 198 230 231 /* Place selection start tag. */ 232 sheet_place_tag(doc.sh, &sof, &pane.sel_start); 233 199 234 /* Move to beginning of file. */ 200 caret_move(-ED_INFTY, -ED_INFTY, dir_before); 201 202 /* Place selection start tag. */ 203 tag_get_pt(&pane.caret_pos, &pt); 204 sheet_place_tag(&doc.sh, &pt, &pane.sel_start); 235 pt_get_sof(&sof); 236 caret_move(sof, true, true); 205 237 206 238 /* Initial display */ … … 219 251 220 252 while (!done) { 221 console_get_ kbd_event(con, &ev);253 console_get_event(con, &ev); 222 254 pane.rflags = 0; 223 255 224 if (ev.type == KEY_PRESS) { 225 /* Handle key press. */ 226 if (((ev.mods & KM_ALT) == 0) && 227 ((ev.mods & KM_SHIFT) == 0) && 228 (ev.mods & KM_CTRL) != 0) { 229 key_handle_ctrl(&ev); 230 } else if (((ev.mods & KM_ALT) == 0) && 231 ((ev.mods & KM_CTRL) == 0) && 232 (ev.mods & KM_SHIFT) != 0) { 233 key_handle_shift(&ev); 234 } else if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) { 235 key_handle_unmod(&ev); 236 } 256 switch (ev.type) { 257 case CEV_KEY: 258 pane.keymod = ev.ev.key.mods; 259 if (ev.ev.key.type == KEY_PRESS) 260 key_handle_press(&ev.ev.key); 261 break; 262 case CEV_POS: 263 pos_handle(&ev.ev.pos); 264 break; 237 265 } 238 266 … … 256 284 257 285 return 0; 286 } 287 288 /* Handle key press. */ 289 static void key_handle_press(kbd_event_t *ev) 290 { 291 if (((ev->mods & KM_ALT) == 0) && 292 ((ev->mods & KM_SHIFT) == 0) && 293 (ev->mods & KM_CTRL) != 0) { 294 key_handle_ctrl(ev); 295 } else if (((ev->mods & KM_ALT) == 0) && 296 ((ev->mods & KM_CTRL) == 0) && 297 (ev->mods & KM_SHIFT) != 0) { 298 key_handle_shift(ev); 299 } else if (((ev->mods & KM_ALT) == 0) && 300 ((ev->mods & KM_CTRL) != 0) && 301 (ev->mods & KM_SHIFT) != 0) { 302 key_handle_shift_ctrl(ev); 303 } else if ((ev->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) { 304 key_handle_unmod(ev); 305 } 258 306 } 259 307 … … 346 394 static void key_handle_ctrl(kbd_event_t const *ev) 347 395 { 396 spt_t pt; 348 397 switch (ev->key) { 349 398 case KC_Q: … … 377 426 selection_sel_all(); 378 427 break; 428 case KC_RIGHT: 429 caret_move_word_right(false); 430 break; 431 case KC_LEFT: 432 caret_move_word_left(false); 433 break; 434 case KC_L: 435 caret_go_to_line_ask(); 436 break; 437 case KC_F: 438 search_prompt(false); 439 break; 440 case KC_N: 441 search_repeat(); 442 break; 443 case KC_HOME: 444 pt_get_sof(&pt); 445 caret_move(pt, false, true); 446 break; 447 case KC_END: 448 pt_get_eof(&pt); 449 caret_move(pt, false, true); 450 break; 379 451 default: 380 452 break; … … 382 454 } 383 455 384 static void key_handle_ movement(unsigned int key, bool select)456 static void key_handle_shift_ctrl(kbd_event_t const *ev) 385 457 { 386 458 spt_t pt; 387 spt_t caret_pt; 459 switch(ev->key) { 460 case KC_LEFT: 461 caret_move_word_left(true); 462 break; 463 case KC_RIGHT: 464 caret_move_word_right(true); 465 break; 466 case KC_F: 467 search_prompt(true); 468 break; 469 case KC_HOME: 470 pt_get_sof(&pt); 471 caret_move(pt, true, true); 472 break; 473 case KC_END: 474 pt_get_eof(&pt); 475 caret_move(pt, true, true); 476 break; 477 default: 478 break; 479 } 480 } 481 482 static void pos_handle(pos_event_t *ev) 483 { 484 coord_t bc; 485 spt_t pt; 486 bool select; 487 488 if (ev->type == POS_PRESS && ev->vpos < (unsigned)pane.rows) { 489 bc.row = pane.sh_row + ev->vpos; 490 bc.column = pane.sh_column + ev->hpos; 491 sheet_get_cell_pt(doc.sh, &bc, dir_before, &pt); 492 493 select = (pane.keymod & KM_SHIFT) != 0; 494 495 caret_move(pt, select, true); 496 } 497 } 498 499 /** Move caret while preserving or resetting selection. */ 500 static void caret_move(spt_t new_caret_pt, bool select, bool update_ideal_column) 501 { 502 spt_t old_caret_pt, old_sel_pt; 388 503 coord_t c_old, c_new; 389 504 bool had_sel; 390 505 391 506 /* Check if we had selection before. */ 392 tag_get_pt(&pane.caret_pos, &caret_pt); 393 tag_get_pt(&pane.sel_start, &pt); 394 had_sel = !spt_equal(&caret_pt, &pt); 395 396 switch (key) { 397 case KC_LEFT: 398 caret_move(0, -1, dir_before); 399 break; 400 case KC_RIGHT: 401 caret_move(0, 0, dir_after); 402 break; 403 case KC_UP: 404 caret_move(-1, 0, dir_before); 405 break; 406 case KC_DOWN: 407 caret_move(+1, 0, dir_before); 408 break; 409 case KC_HOME: 410 caret_move(0, -ED_INFTY, dir_before); 411 break; 412 case KC_END: 413 caret_move(0, +ED_INFTY, dir_before); 414 break; 415 case KC_PAGE_UP: 416 caret_move(-pane.rows, 0, dir_before); 417 break; 418 case KC_PAGE_DOWN: 419 caret_move(+pane.rows, 0, dir_before); 420 break; 421 default: 422 break; 423 } 507 tag_get_pt(&pane.caret_pos, &old_caret_pt); 508 tag_get_pt(&pane.sel_start, &old_sel_pt); 509 had_sel = !spt_equal(&old_caret_pt, &old_sel_pt); 510 511 /* Place tag of the caret */ 512 sheet_remove_tag(doc.sh, &pane.caret_pos); 513 sheet_place_tag(doc.sh, &new_caret_pt, &pane.caret_pos); 424 514 425 515 if (select == false) { 426 516 /* Move sel_start to the same point as caret. */ 427 sheet_remove_tag( &doc.sh, &pane.sel_start);428 tag_get_pt(&pane.caret_pos, &pt);429 sheet_place_tag(&doc.sh, &pt, &pane.sel_start);430 } 431 517 sheet_remove_tag(doc.sh, &pane.sel_start); 518 sheet_place_tag(doc.sh, &new_caret_pt, &pane.sel_start); 519 } 520 521 spt_get_coord(&new_caret_pt, &c_new); 432 522 if (select) { 433 tag_get_pt(&pane.caret_pos, &pt); 434 spt_get_coord(&caret_pt, &c_old); 435 spt_get_coord(&pt, &c_new); 523 spt_get_coord(&old_caret_pt, &c_old); 436 524 437 525 if (c_old.row == c_new.row) … … 444 532 pane.rflags |= REDRAW_TEXT; 445 533 } 534 535 if (update_ideal_column) 536 pane.ideal_column = c_new.column; 537 538 caret_update(); 539 } 540 541 static void key_handle_movement(unsigned int key, bool select) 542 { 543 spt_t pt; 544 switch (key) { 545 case KC_LEFT: 546 caret_move_relative(0, -1, dir_before, select); 547 break; 548 case KC_RIGHT: 549 caret_move_relative(0, 0, dir_after, select); 550 break; 551 case KC_UP: 552 caret_move_relative(-1, 0, dir_before, select); 553 break; 554 case KC_DOWN: 555 caret_move_relative(+1, 0, dir_before, select); 556 break; 557 case KC_HOME: 558 tag_get_pt(&pane.caret_pos, &pt); 559 pt_get_sol(&pt, &pt); 560 caret_move(pt, select, true); 561 break; 562 case KC_END: 563 tag_get_pt(&pane.caret_pos, &pt); 564 pt_get_eol(&pt, &pt); 565 caret_move(pt, select, true); 566 break; 567 case KC_PAGE_UP: 568 caret_move_relative(-pane.rows, 0, dir_before, select); 569 break; 570 case KC_PAGE_DOWN: 571 caret_move_relative(+pane.rows, 0, dir_before, select); 572 break; 573 default: 574 break; 575 } 446 576 } 447 577 … … 479 609 char *fname; 480 610 481 fname = filename_prompt("Save As", old_fname);611 fname = prompt("Save As", old_fname); 482 612 if (fname == NULL) { 483 613 status_display("Save cancelled."); … … 494 624 } 495 625 496 /** Ask for a file name. */ 497 static char *filename_prompt(char const *prompt, char const *init_value) 498 { 499 kbd_event_t ev; 626 /** Ask for a string. */ 627 static char *prompt(char const *prompt, char const *init_value) 628 { 629 cons_event_t ev; 630 kbd_event_t *kev; 500 631 char *str; 501 632 wchar_t buffer[INFNAME_MAX_LEN + 1]; … … 517 648 518 649 while (!done) { 519 console_get_kbd_event(con, &ev); 520 521 if (ev.type == KEY_PRESS) { 650 console_get_event(con, &ev); 651 652 if (ev.type == CEV_KEY && ev.ev.key.type == KEY_PRESS) { 653 kev = &ev.ev.key; 654 522 655 /* Handle key press. */ 523 if ((( ev.mods & KM_ALT) == 0) &&524 ( ev.mods & KM_CTRL) != 0) {656 if (((kev->mods & KM_ALT) == 0) && 657 (kev->mods & KM_CTRL) != 0) { 525 658 ; 526 } else if (( ev.mods & (KM_CTRL | KM_ALT)) == 0) {527 switch ( ev.key) {659 } else if ((kev->mods & (KM_CTRL | KM_ALT)) == 0) { 660 switch (kev->key) { 528 661 case KC_ESCAPE: 529 662 return NULL; … … 539 672 break; 540 673 default: 541 if ( ev.c >= 32 && nc < max_len) {542 putchar( ev.c);674 if (kev->c >= 32 && nc < max_len) { 675 putchar(kev->c); 543 676 console_flush(con); 544 buffer[nc++] = ev.c;677 buffer[nc++] = kev->c; 545 678 } 546 679 break; … … 616 749 617 750 do { 618 sheet_copy_out( &doc.sh, &sp, epos, buf, BUF_SIZE, &bep);751 sheet_copy_out(doc.sh, &sp, epos, buf, BUF_SIZE, &bep); 619 752 bytes = str_size(buf); 620 753 … … 651 784 652 785 while (true) { 653 sheet_copy_out( &doc.sh, &sp, epos, &buf[bpos], buf_size - bpos,786 sheet_copy_out(doc.sh, &sp, epos, &buf[bpos], buf_size - bpos, 654 787 &bep); 655 788 bytes = str_size(&buf[bpos]); … … 673 806 int sh_rows, rows; 674 807 675 sheet_get_num_rows( &doc.sh, &sh_rows);808 sheet_get_num_rows(doc.sh, &sh_rows); 676 809 rows = min(sh_rows - pane.sh_row + 1, pane.rows); 677 810 … … 743 876 rbc.row = pane.sh_row + i; 744 877 rbc.column = pane.sh_column; 745 sheet_get_cell_pt( &doc.sh, &rbc, dir_before, &rb);878 sheet_get_cell_pt(doc.sh, &rbc, dir_before, &rb); 746 879 747 880 /* Ending point for row display */ 748 881 rec.row = pane.sh_row + i; 749 882 rec.column = pane.sh_column + pane.columns; 750 sheet_get_cell_pt( &doc.sh, &rec, dir_before, &re);883 sheet_get_cell_pt(doc.sh, &rec, dir_before, &re); 751 884 752 885 /* Copy the text of the row to the buffer. */ 753 sheet_copy_out( &doc.sh, &rb, &re, row_buf, ROW_BUF_SIZE, &dep);886 sheet_copy_out(doc.sh, &rb, &re, row_buf, ROW_BUF_SIZE, &dep); 754 887 755 888 /* Display text from the buffer. */ … … 801 934 /* Fill until the end of display area. */ 802 935 803 if ( str_length(row_buf) < (unsigned)scr_columns)804 fill = scr_columns - str_length(row_buf);936 if ((unsigned)s_column - 1 < scr_columns) 937 fill = scr_columns - (s_column - 1); 805 938 else 806 939 fill = 0; … … 820 953 spt_t caret_pt; 821 954 coord_t coord; 955 int last_row; 822 956 823 957 tag_get_pt(&pane.caret_pos, &caret_pt); 824 958 spt_get_coord(&caret_pt, &coord); 825 959 960 sheet_get_num_rows(doc.sh, &last_row); 961 826 962 const char *fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>"; 827 963 828 964 console_set_pos(con, 0, scr_rows - 1); 829 965 console_set_style(con, STYLE_INVERTED); 830 int n = printf(" %d, %d : File '%s'. Ctrl-Q Quit Ctrl-S Save "831 "Ctrl-E Save As", coord.row, coord.column, fname);966 int n = printf(" %d, %d (%d): File '%s'. Ctrl-Q Quit Ctrl-S Save " 967 "Ctrl-E Save As", coord.row, coord.column, last_row, fname); 832 968 833 969 int pos = scr_columns - 1 - n; … … 865 1001 cbuf[offs] = '\0'; 866 1002 867 (void) sheet_insert( &doc.sh, &pt, dir_before, cbuf);1003 (void) sheet_insert(doc.sh, &pt, dir_before, cbuf); 868 1004 869 1005 pane.rflags |= REDRAW_ROW; … … 882 1018 883 1019 coord.column -= 1; 884 sheet_get_cell_pt( &doc.sh, &coord, dir_before, &sp);885 886 (void) sheet_delete( &doc.sh, &sp, &ep);1020 sheet_get_cell_pt(doc.sh, &coord, dir_before, &sp); 1021 1022 (void) sheet_delete(doc.sh, &sp, &ep); 887 1023 888 1024 pane.rflags |= REDRAW_ROW; … … 900 1036 spt_get_coord(&sp, &sc); 901 1037 902 sheet_get_cell_pt( &doc.sh, &sc, dir_after, &ep);1038 sheet_get_cell_pt(doc.sh, &sc, dir_after, &ep); 903 1039 spt_get_coord(&ep, &ec); 904 1040 905 (void) sheet_delete( &doc.sh, &sp, &ep);1041 (void) sheet_delete(doc.sh, &sp, &ep); 906 1042 907 1043 pane.rflags |= REDRAW_ROW; … … 950 1086 } 951 1087 952 /** Change the caret position.1088 /** Relatively move caret position. 953 1089 * 954 1090 * Moves caret relatively to the current position. Looking at the first … … 956 1092 * to a new character cell, and thus a new character. Then we either go to the 957 1093 * point before the the character or after it, depending on @a align_dir. 1094 * 1095 * @param select true if the selection tag should stay where it is 958 1096 */ 959 static void caret_move(int drow, int dcolumn, enum dir_spec align_dir) 1097 static void caret_move_relative(int drow, int dcolumn, enum dir_spec align_dir, 1098 bool select) 960 1099 { 961 1100 spt_t pt; … … 970 1109 /* Clamp coordinates. */ 971 1110 if (drow < 0 && coord.row < 1) coord.row = 1; 972 if (dcolumn < 0 && coord.column < 1) coord.column = 1; 1111 if (dcolumn < 0 && coord.column < 1) { 1112 if (coord.row < 2) 1113 coord.column = 1; 1114 else { 1115 coord.row--; 1116 sheet_get_row_width(doc.sh, coord.row, &coord.column); 1117 } 1118 } 973 1119 if (drow > 0) { 974 sheet_get_num_rows( &doc.sh, &num_rows);1120 sheet_get_num_rows(doc.sh, &num_rows); 975 1121 if (coord.row > num_rows) coord.row = num_rows; 976 1122 } … … 985 1131 * coordinates. The character can be wider than one cell (e.g. tab). 986 1132 */ 987 sheet_get_cell_pt(&doc.sh, &coord, align_dir, &pt); 988 sheet_remove_tag(&doc.sh, &pane.caret_pos); 989 sheet_place_tag(&doc.sh, &pt, &pane.caret_pos); 1133 sheet_get_cell_pt(doc.sh, &coord, align_dir, &pt); 990 1134 991 1135 /* For non-vertical movement set the new value for @c ideal_column. */ 992 if (!pure_vertical) { 993 spt_get_coord(&pt, &coord); 994 pane.ideal_column = coord.column; 995 } 996 997 caret_update(); 1136 caret_move(pt, select, !pure_vertical); 1137 } 1138 1139 /** Absolutely move caret position. 1140 * 1141 * Moves caret to a specified position. We get to a new character cell, and 1142 * thus a new character. Then we either go to the point before the the character 1143 * or after it, depending on @a align_dir. 1144 * 1145 * @param select true if the selection tag should stay where it is 1146 */ 1147 static void caret_move_absolute(int row, int column, enum dir_spec align_dir, 1148 bool select) 1149 { 1150 coord_t coord; 1151 coord.row = row; 1152 coord.column = column; 1153 1154 spt_t pt; 1155 sheet_get_cell_pt(doc.sh, &coord, align_dir, &pt); 1156 1157 caret_move(pt, select, true); 1158 } 1159 1160 /** Find beginning of a word to the left of spt */ 1161 static spt_t pt_find_word_left(spt_t spt) 1162 { 1163 do { 1164 spt_prev_char(spt, &spt); 1165 } while (!pt_is_word_beginning(&spt)); 1166 return spt; 1167 } 1168 1169 /** Find beginning of a word to the right of spt */ 1170 static spt_t pt_find_word_right(spt_t spt) 1171 { 1172 do { 1173 spt_next_char(spt, &spt); 1174 } while (!pt_is_word_beginning(&spt)); 1175 return spt; 1176 } 1177 1178 static void caret_move_word_left(bool select) 1179 { 1180 spt_t pt; 1181 tag_get_pt(&pane.caret_pos, &pt); 1182 spt_t word_left = pt_find_word_left(pt); 1183 caret_move(word_left, select, true); 1184 } 1185 1186 static void caret_move_word_right(bool select) 1187 { 1188 spt_t pt; 1189 tag_get_pt(&pane.caret_pos, &pt); 1190 spt_t word_right = pt_find_word_right(pt); 1191 caret_move(word_right, select, true); 1192 } 1193 1194 /** Ask for line and go to it. */ 1195 static void caret_go_to_line_ask(void) 1196 { 1197 char *sline; 1198 1199 sline = prompt("Go to line", ""); 1200 if (sline == NULL) { 1201 status_display("Go to line cancelled."); 1202 return; 1203 } 1204 1205 char *endptr; 1206 int line = strtol(sline, &endptr, 10); 1207 if (*endptr != '\0') { 1208 free(sline); 1209 status_display("Invalid number entered."); 1210 return; 1211 } 1212 free(sline); 1213 1214 caret_move_absolute(line, pane.ideal_column, dir_before, false); 1215 } 1216 1217 /* Search operations */ 1218 static int search_spt_producer(void *data, wchar_t *ret) 1219 { 1220 assert(data != NULL); 1221 assert(ret != NULL); 1222 spt_t *spt = data; 1223 *ret = spt_next_char(*spt, spt); 1224 return EOK; 1225 } 1226 1227 static int search_spt_reverse_producer(void *data, wchar_t *ret) 1228 { 1229 assert(data != NULL); 1230 assert(ret != NULL); 1231 spt_t *spt = data; 1232 *ret = spt_prev_char(*spt, spt); 1233 return EOK; 1234 } 1235 1236 static int search_spt_mark(void *data, void **mark) 1237 { 1238 assert(data != NULL); 1239 assert(mark != NULL); 1240 spt_t *spt = data; 1241 spt_t *new = calloc(1, sizeof(spt_t)); 1242 *mark = new; 1243 if (new == NULL) 1244 return ENOMEM; 1245 *new = *spt; 1246 return EOK; 1247 } 1248 1249 static void search_spt_mark_free(void *data) 1250 { 1251 free(data); 1252 } 1253 1254 static search_ops_t search_spt_ops = { 1255 .equals = char_exact_equals, 1256 .producer = search_spt_producer, 1257 .mark = search_spt_mark, 1258 .mark_free = search_spt_mark_free, 1259 }; 1260 1261 static search_ops_t search_spt_reverse_ops = { 1262 .equals = char_exact_equals, 1263 .producer = search_spt_reverse_producer, 1264 .mark = search_spt_mark, 1265 .mark_free = search_spt_mark_free, 1266 }; 1267 1268 /** Ask for line and go to it. */ 1269 static void search_prompt(bool reverse) 1270 { 1271 char *pattern; 1272 1273 const char *prompt_text = "Find next"; 1274 if (reverse) 1275 prompt_text = "Find previous"; 1276 1277 const char *default_value = ""; 1278 if (pane.previous_search) 1279 default_value = pane.previous_search; 1280 1281 pattern = prompt(prompt_text, default_value); 1282 if (pattern == NULL) { 1283 status_display("Search cancelled."); 1284 return; 1285 } 1286 1287 if (pane.previous_search) 1288 free(pane.previous_search); 1289 pane.previous_search = pattern; 1290 pane.previous_search_reverse = reverse; 1291 1292 search(pattern, reverse); 1293 } 1294 1295 static void search_repeat(void) 1296 { 1297 if (pane.previous_search == NULL) { 1298 status_display("No previous search to repeat."); 1299 return; 1300 } 1301 1302 search(pane.previous_search, pane.previous_search_reverse); 1303 } 1304 1305 static void search(char *pattern, bool reverse) 1306 { 1307 status_display("Searching..."); 1308 1309 spt_t sp, producer_pos; 1310 tag_get_pt(&pane.caret_pos, &sp); 1311 1312 /* Start searching on the position before/after caret */ 1313 if (!reverse) { 1314 spt_next_char(sp, &sp); 1315 } 1316 else { 1317 spt_prev_char(sp, &sp); 1318 } 1319 producer_pos = sp; 1320 1321 search_ops_t ops = search_spt_ops; 1322 if (reverse) 1323 ops = search_spt_reverse_ops; 1324 1325 search_t *search = search_init(pattern, &producer_pos, ops, reverse); 1326 if (search == NULL) { 1327 status_display("Failed initializing search."); 1328 return; 1329 } 1330 1331 match_t match; 1332 int rc = search_next_match(search, &match); 1333 if (rc != EOK) { 1334 status_display("Failed searching."); 1335 search_fini(search); 1336 } 1337 1338 if (match.end) { 1339 status_display("Match found."); 1340 assert(match.end != NULL); 1341 spt_t *end = match.end; 1342 caret_move(*end, false, true); 1343 while (match.length > 0) { 1344 match.length--; 1345 if (reverse) { 1346 spt_next_char(*end, end); 1347 } 1348 else { 1349 spt_prev_char(*end, end); 1350 } 1351 } 1352 caret_move(*end, true, true); 1353 free(end); 1354 } 1355 else { 1356 status_display("Not found."); 1357 } 1358 1359 search_fini(search); 998 1360 } 999 1361 … … 1035 1397 1036 1398 if (rel < 0) 1037 sheet_delete( &doc.sh, &pa, &pb);1399 sheet_delete(doc.sh, &pa, &pb); 1038 1400 else 1039 sheet_delete( &doc.sh, &pb, &pa);1401 sheet_delete(doc.sh, &pb, &pa); 1040 1402 1041 1403 if (ca.row == cb.row) … … 1045 1407 } 1046 1408 1409 /** Select all text in the editor */ 1047 1410 static void selection_sel_all(void) 1048 1411 { … … 1051 1414 pt_get_sof(&spt); 1052 1415 pt_get_eof(&ept); 1053 sheet_remove_tag(&doc.sh, &pane.sel_start); 1054 sheet_place_tag(&doc.sh, &spt, &pane.sel_start); 1055 sheet_remove_tag(&doc.sh, &pane.caret_pos); 1056 sheet_place_tag(&doc.sh, &ept, &pane.caret_pos); 1416 1417 selection_sel_range(spt, ept); 1418 } 1419 1420 /** Select select all text in a given range with the given direction */ 1421 static void selection_sel_range(spt_t pa, spt_t pb) 1422 { 1423 sheet_remove_tag(doc.sh, &pane.sel_start); 1424 sheet_place_tag(doc.sh, &pa, &pane.sel_start); 1425 sheet_remove_tag(doc.sh, &pane.caret_pos); 1426 sheet_place_tag(doc.sh, &pb, &pane.caret_pos); 1057 1427 1058 1428 pane.rflags |= REDRAW_TEXT; … … 1103 1473 1104 1474 coord.row = coord.column = 1; 1105 sheet_get_cell_pt( &doc.sh, &coord, dir_before, pt);1475 sheet_get_cell_pt(doc.sh, &coord, dir_before, pt); 1106 1476 } 1107 1477 … … 1112 1482 int num_rows; 1113 1483 1114 sheet_get_num_rows( &doc.sh, &num_rows);1484 sheet_get_num_rows(doc.sh, &num_rows); 1115 1485 coord.row = num_rows + 1; 1116 1486 coord.column = 1; 1117 1487 1118 sheet_get_cell_pt(&doc.sh, &coord, dir_after, pt); 1488 sheet_get_cell_pt(doc.sh, &coord, dir_after, pt); 1489 } 1490 1491 /** Get start-of-line s-point for given s-point cpt */ 1492 static void pt_get_sol(spt_t *cpt, spt_t *spt) 1493 { 1494 coord_t coord; 1495 1496 spt_get_coord(cpt, &coord); 1497 coord.column = 1; 1498 1499 sheet_get_cell_pt(doc.sh, &coord, dir_before, spt); 1500 } 1501 1502 /** Get end-of-line s-point for given s-point cpt */ 1503 static void pt_get_eol(spt_t *cpt, spt_t *ept) 1504 { 1505 coord_t coord; 1506 int row_width; 1507 1508 spt_get_coord(cpt, &coord); 1509 sheet_get_row_width(doc.sh, coord.row, &row_width); 1510 coord.column = row_width - 1; 1511 1512 sheet_get_cell_pt(doc.sh, &coord, dir_after, ept); 1513 } 1514 1515 /** Check whether the spt is at a beginning of a word */ 1516 static bool pt_is_word_beginning(spt_t *pt) 1517 { 1518 spt_t lp, sfp, efp, slp, elp; 1519 coord_t coord; 1520 1521 pt_get_sof(&sfp); 1522 pt_get_eof(&efp); 1523 pt_get_sol(pt, &slp); 1524 pt_get_eol(pt, &elp); 1525 1526 /* the spt is at the beginning or end of the file or line */ 1527 if ((spt_cmp(&sfp, pt) == 0) || (spt_cmp(&efp, pt) == 0) 1528 || (spt_cmp(&slp, pt) == 0) || (spt_cmp(&elp, pt) == 0)) 1529 return true; 1530 1531 /* the spt is a delimiter */ 1532 if (pt_is_delimiter(pt)) 1533 return false; 1534 1535 spt_get_coord(pt, &coord); 1536 1537 coord.column -= 1; 1538 sheet_get_cell_pt(doc.sh, &coord, dir_before, &lp); 1539 1540 return pt_is_delimiter(&lp) 1541 || (pt_is_punctuation(pt) && !pt_is_punctuation(&lp)) 1542 || (pt_is_punctuation(&lp) && !pt_is_punctuation(pt)); 1543 } 1544 1545 static wchar_t get_first_wchar(const char *str) 1546 { 1547 size_t offset = 0; 1548 return str_decode(str, &offset, str_size(str)); 1549 } 1550 1551 static bool pt_is_delimiter(spt_t *pt) 1552 { 1553 spt_t rp; 1554 coord_t coord; 1555 char *ch = NULL; 1556 1557 spt_get_coord(pt, &coord); 1558 1559 coord.column += 1; 1560 sheet_get_cell_pt(doc.sh, &coord, dir_after, &rp); 1561 1562 ch = range_get_str(pt, &rp); 1563 if (ch == NULL) 1564 return false; 1565 1566 wchar_t first_char = get_first_wchar(ch); 1567 switch(first_char) { 1568 case ' ': 1569 case '\t': 1570 case '\n': 1571 return true; 1572 default: 1573 return false; 1574 } 1575 } 1576 1577 static bool pt_is_punctuation(spt_t *pt) 1578 { 1579 spt_t rp; 1580 coord_t coord; 1581 char *ch = NULL; 1582 1583 spt_get_coord(pt, &coord); 1584 1585 coord.column += 1; 1586 sheet_get_cell_pt(doc.sh, &coord, dir_after, &rp); 1587 1588 ch = range_get_str(pt, &rp); 1589 if (ch == NULL) 1590 return false; 1591 1592 wchar_t first_char = get_first_wchar(ch); 1593 switch(first_char) { 1594 case ',': 1595 case '.': 1596 case ';': 1597 case ':': 1598 case '/': 1599 case '?': 1600 case '\\': 1601 case '|': 1602 case '_': 1603 case '+': 1604 case '-': 1605 case '*': 1606 case '=': 1607 case '<': 1608 case '>': 1609 return true; 1610 default: 1611 return false; 1612 } 1119 1613 } 1120 1614
Note:
See TracChangeset
for help on using the changeset viewer.