Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/edit/edit.c

    rc80be58 r79ae36dd  
    11/*
    22 * Copyright (c) 2009 Jiri Svoboda
    3  * Copyright (c) 2012 Martin Sucha
    43 * All rights reserved.
    54 *
     
    4746#include <macros.h>
    4847#include <clipboard.h>
    49 #include <stdbool.h>
     48#include <bool.h>
    5049
    5150#include "sheet.h"
    52 #include "search.h"
    5351
    5452enum redraw_flags {
     
    8078        tag_t sel_start;
    8179
    82         /** Active keyboard modifiers */
    83         keymod_t keymod;
    84 
    8580        /**
    8681         * Ideal column where the caret should try to get. This is used
     
    8883         */
    8984        int ideal_column;
    90        
    91         char *previous_search;
    92         bool previous_search_reverse;
    9385} pane_t;
    9486
     
    9991typedef struct {
    10092        char *file_name;
    101         sheet_t *sh;
     93        sheet_t sh;
    10294} doc_t;
    10395
     
    114106#define BUF_SIZE 64
    115107#define TAB_WIDTH 8
     108#define ED_INFTY 65536
    116109
    117110/** Maximum filename length that can be entered. */
     
    122115static void cursor_setvis(bool visible);
    123116
    124 static void key_handle_press(kbd_event_t *ev);
    125117static void key_handle_unmod(kbd_event_t const *ev);
    126118static void key_handle_ctrl(kbd_event_t const *ev);
    127119static void key_handle_shift(kbd_event_t const *ev);
    128 static void key_handle_shift_ctrl(kbd_event_t const *ev);
    129120static void key_handle_movement(unsigned int key, bool shift);
    130 
    131 static void pos_handle(pos_event_t *ev);
    132121
    133122static int file_save(char const *fname);
     
    136125static int file_save_range(char const *fname, spt_t const *spos,
    137126    spt_t const *epos);
     127static char *filename_prompt(char const *prompt, char const *init_value);
    138128static char *range_get_str(spt_t const *spos, spt_t const *epos);
    139 
    140 static char *prompt(char const *prompt, char const *init_value);
    141129
    142130static void pane_text_display(void);
     
    150138static void delete_char_after(void);
    151139static void caret_update(void);
    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);
     140static void caret_move(int drow, int dcolumn, enum dir_spec align_dir);
    158141
    159142static bool selection_active(void);
    160143static void selection_sel_all(void);
    161 static void selection_sel_range(spt_t pa, spt_t pb);
    162144static void selection_get_points(spt_t *pa, spt_t *pb);
    163145static void selection_delete(void);
     
    165147static void insert_clipboard_data(void);
    166148
    167 static void search(char *pattern, bool reverse);
    168 static void search_prompt(bool reverse);
    169 static void search_repeat(void);
    170 
    171149static void pt_get_sof(spt_t *pt);
    172150static 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 
    181151static int tag_cmp(tag_t const *a, tag_t const *b);
    182152static int spt_cmp(spt_t const *a, spt_t const *b);
     
    188158int main(int argc, char *argv[])
    189159{
    190         cons_event_t ev;
     160        kbd_event_t ev;
     161        coord_t coord;
    191162        bool new_file;
    192         int rc;
     163
     164        spt_t pt;
    193165
    194166        con = console_init(stdin, stdout);
     
    203175
    204176        /* Start with an empty sheet. */
    205         rc = sheet_create(&doc.sh);
    206         if (rc != EOK) {
    207                 printf("Out of memory.\n");
    208                 return -1;
    209         }
     177        sheet_init(&doc.sh);
    210178
    211179        /* Place caret at the beginning of file. */
    212         spt_t sof;
    213         pt_get_sof(&sof);
    214         sheet_place_tag(doc.sh, &sof, &pane.caret_pos);
    215         pane.ideal_column = 1;
     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;
    216184
    217185        if (argc == 2) {
     
    229197                new_file = true;
    230198
     199        /* Move to beginning of file. */
     200        caret_move(-ED_INFTY, -ED_INFTY, dir_before);
     201
    231202        /* Place selection start tag. */
    232         sheet_place_tag(doc.sh, &sof, &pane.sel_start);
    233 
    234         /* Move to beginning of file. */
    235         pt_get_sof(&sof);
    236         caret_move(sof, true, true);
     203        tag_get_pt(&pane.caret_pos, &pt);
     204        sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
    237205
    238206        /* Initial display */
     
    251219
    252220        while (!done) {
    253                 console_get_event(con, &ev);
     221                console_get_kbd_event(con, &ev);
    254222                pane.rflags = 0;
    255223
    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;
     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                        }
    265237                }
    266238
     
    284256
    285257        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         }
    306258}
    307259
     
    394346static void key_handle_ctrl(kbd_event_t const *ev)
    395347{
    396         spt_t pt;
    397348        switch (ev->key) {
    398349        case KC_Q:
     
    426377                selection_sel_all();
    427378                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;
    451379        default:
    452380                break;
     
    454382}
    455383
    456 static void key_handle_shift_ctrl(kbd_event_t const *ev)
     384static void key_handle_movement(unsigned int key, bool select)
    457385{
    458386        spt_t 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;
     387        spt_t caret_pt;
    503388        coord_t c_old, c_new;
    504389        bool had_sel;
    505390
    506391        /* Check if we had selection before. */
    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);
     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        }
    514424
    515425        if (select == false) {
    516426                /* Move sel_start to the same point as caret. */
    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);
     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
    522432        if (select) {
    523                 spt_get_coord(&old_caret_pt, &c_old);
     433                tag_get_pt(&pane.caret_pos, &pt);
     434                spt_get_coord(&caret_pt, &c_old);
     435                spt_get_coord(&pt, &c_new);
    524436
    525437                if (c_old.row == c_new.row)
     
    532444                pane.rflags |= REDRAW_TEXT;
    533445        }
    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         }
    576446}
    577447
     
    609479        char *fname;
    610480       
    611         fname = prompt("Save As", old_fname);
     481        fname = filename_prompt("Save As", old_fname);
    612482        if (fname == NULL) {
    613483                status_display("Save cancelled.");
     
    624494}
    625495
    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;
     496/** Ask for a file name. */
     497static char *filename_prompt(char const *prompt, char const *init_value)
     498{
     499        kbd_event_t ev;
    631500        char *str;
    632501        wchar_t buffer[INFNAME_MAX_LEN + 1];
     
    648517
    649518        while (!done) {
    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 
     519                console_get_kbd_event(con, &ev);
     520
     521                if (ev.type == KEY_PRESS) {
    655522                        /* Handle key press. */
    656                         if (((kev->mods & KM_ALT) == 0) &&
    657                              (kev->mods & KM_CTRL) != 0) {
     523                        if (((ev.mods & KM_ALT) == 0) &&
     524                             (ev.mods & KM_CTRL) != 0) {
    658525                                ;
    659                         } else if ((kev->mods & (KM_CTRL | KM_ALT)) == 0) {
    660                                 switch (kev->key) {
     526                        } else if ((ev.mods & (KM_CTRL | KM_ALT)) == 0) {
     527                                switch (ev.key) {
    661528                                case KC_ESCAPE:
    662529                                        return NULL;
     
    672539                                        break;
    673540                                default:
    674                                         if (kev->c >= 32 && nc < max_len) {
    675                                                 putchar(kev->c);
     541                                        if (ev.c >= 32 && nc < max_len) {
     542                                                putchar(ev.c);
    676543                                                console_flush(con);
    677                                                 buffer[nc++] = kev->c;
     544                                                buffer[nc++] = ev.c;
    678545                                        }
    679546                                        break;
     
    749616
    750617        do {
    751                 sheet_copy_out(doc.sh, &sp, epos, buf, BUF_SIZE, &bep);
     618                sheet_copy_out(&doc.sh, &sp, epos, buf, BUF_SIZE, &bep);
    752619                bytes = str_size(buf);
    753620
     
    784651
    785652        while (true) {
    786                 sheet_copy_out(doc.sh, &sp, epos, &buf[bpos], buf_size - bpos,
     653                sheet_copy_out(&doc.sh, &sp, epos, &buf[bpos], buf_size - bpos,
    787654                    &bep);
    788655                bytes = str_size(&buf[bpos]);
     
    806673        int sh_rows, rows;
    807674
    808         sheet_get_num_rows(doc.sh, &sh_rows);
     675        sheet_get_num_rows(&doc.sh, &sh_rows);
    809676        rows = min(sh_rows - pane.sh_row + 1, pane.rows);
    810677
     
    876743                rbc.row = pane.sh_row + i;
    877744                rbc.column = pane.sh_column;
    878                 sheet_get_cell_pt(doc.sh, &rbc, dir_before, &rb);
     745                sheet_get_cell_pt(&doc.sh, &rbc, dir_before, &rb);
    879746
    880747                /* Ending point for row display */
    881748                rec.row = pane.sh_row + i;
    882749                rec.column = pane.sh_column + pane.columns;
    883                 sheet_get_cell_pt(doc.sh, &rec, dir_before, &re);
     750                sheet_get_cell_pt(&doc.sh, &rec, dir_before, &re);
    884751
    885752                /* Copy the text of the row to the buffer. */
    886                 sheet_copy_out(doc.sh, &rb, &re, row_buf, ROW_BUF_SIZE, &dep);
     753                sheet_copy_out(&doc.sh, &rb, &re, row_buf, ROW_BUF_SIZE, &dep);
    887754
    888755                /* Display text from the buffer. */
     
    934801                /* Fill until the end of display area. */
    935802
    936                 if ((unsigned)s_column - 1 < scr_columns)
    937                         fill = scr_columns - (s_column - 1);
     803                if (str_length(row_buf) < (unsigned) scr_columns)
     804                        fill = scr_columns - str_length(row_buf);
    938805                else
    939806                        fill = 0;
     
    953820        spt_t caret_pt;
    954821        coord_t coord;
    955         int last_row;
    956822
    957823        tag_get_pt(&pane.caret_pos, &caret_pt);
    958824        spt_get_coord(&caret_pt, &coord);
    959825
    960         sheet_get_num_rows(doc.sh, &last_row);
    961 
    962826        const char *fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>";
    963827
    964828        console_set_pos(con, 0, scr_rows - 1);
    965829        console_set_style(con, STYLE_INVERTED);
    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);
     830        int n = printf(" %d, %d: File '%s'. Ctrl-Q Quit  Ctrl-S Save  "
     831            "Ctrl-E Save As", coord.row, coord.column, fname);
    968832       
    969833        int pos = scr_columns - 1 - n;
     
    1001865        cbuf[offs] = '\0';
    1002866
    1003         (void) sheet_insert(doc.sh, &pt, dir_before, cbuf);
     867        (void) sheet_insert(&doc.sh, &pt, dir_before, cbuf);
    1004868
    1005869        pane.rflags |= REDRAW_ROW;
     
    1018882
    1019883        coord.column -= 1;
    1020         sheet_get_cell_pt(doc.sh, &coord, dir_before, &sp);
    1021 
    1022         (void) sheet_delete(doc.sh, &sp, &ep);
     884        sheet_get_cell_pt(&doc.sh, &coord, dir_before, &sp);
     885
     886        (void) sheet_delete(&doc.sh, &sp, &ep);
    1023887
    1024888        pane.rflags |= REDRAW_ROW;
     
    1036900        spt_get_coord(&sp, &sc);
    1037901
    1038         sheet_get_cell_pt(doc.sh, &sc, dir_after, &ep);
     902        sheet_get_cell_pt(&doc.sh, &sc, dir_after, &ep);
    1039903        spt_get_coord(&ep, &ec);
    1040904
    1041         (void) sheet_delete(doc.sh, &sp, &ep);
     905        (void) sheet_delete(&doc.sh, &sp, &ep);
    1042906
    1043907        pane.rflags |= REDRAW_ROW;
     
    1086950}
    1087951
    1088 /** Relatively move caret position.
     952/** Change the caret position.
    1089953 *
    1090954 * Moves caret relatively to the current position. Looking at the first
     
    1092956 * to a new character cell, and thus a new character. Then we either go to the
    1093957 * 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
    1096958 */
    1097 static void caret_move_relative(int drow, int dcolumn, enum dir_spec align_dir,
    1098     bool select)
     959static void caret_move(int drow, int dcolumn, enum dir_spec align_dir)
    1099960{
    1100961        spt_t pt;
     
    1109970        /* Clamp coordinates. */
    1110971        if (drow < 0 && coord.row < 1) coord.row = 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         }
     972        if (dcolumn < 0 && coord.column < 1) coord.column = 1;
    1119973        if (drow > 0) {
    1120                 sheet_get_num_rows(doc.sh, &num_rows);
     974                sheet_get_num_rows(&doc.sh, &num_rows);
    1121975                if (coord.row > num_rows) coord.row = num_rows;
    1122976        }
     
    1131985         * coordinates. The character can be wider than one cell (e.g. tab).
    1132986         */
    1133         sheet_get_cell_pt(doc.sh, &coord, align_dir, &pt);
     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);
    1134990
    1135991        /* For non-vertical movement set the new value for @c ideal_column. */
    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);
     992        if (!pure_vertical) {
     993                spt_get_coord(&pt, &coord);
     994                pane.ideal_column = coord.column;
     995        }
     996
     997        caret_update();
    1360998}
    1361999
     
    13971035
    13981036        if (rel < 0)
    1399                 sheet_delete(doc.sh, &pa, &pb);
     1037                sheet_delete(&doc.sh, &pa, &pb);
    14001038        else
    1401                 sheet_delete(doc.sh, &pb, &pa);
     1039                sheet_delete(&doc.sh, &pb, &pa);
    14021040
    14031041        if (ca.row == cb.row)
     
    14071045}
    14081046
    1409 /** Select all text in the editor */
    14101047static void selection_sel_all(void)
    14111048{
     
    14141051        pt_get_sof(&spt);
    14151052        pt_get_eof(&ept);
    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);
     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);
    14271057
    14281058        pane.rflags |= REDRAW_TEXT;
     
    14731103
    14741104        coord.row = coord.column = 1;
    1475         sheet_get_cell_pt(doc.sh, &coord, dir_before, pt);
     1105        sheet_get_cell_pt(&doc.sh, &coord, dir_before, pt);
    14761106}
    14771107
     
    14821112        int num_rows;
    14831113
    1484         sheet_get_num_rows(doc.sh, &num_rows);
     1114        sheet_get_num_rows(&doc.sh, &num_rows);
    14851115        coord.row = num_rows + 1;
    14861116        coord.column = 1;
    14871117
    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         }
     1118        sheet_get_cell_pt(&doc.sh, &coord, dir_after, pt);
    16131119}
    16141120
Note: See TracChangeset for help on using the changeset viewer.