Ignore:
File:
1 edited

Legend:

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

    r79ae36dd rc80be58  
    11/*
    22 * Copyright (c) 2009 Jiri Svoboda
     3 * Copyright (c) 2012 Martin Sucha
    34 * All rights reserved.
    45 *
     
    4647#include <macros.h>
    4748#include <clipboard.h>
    48 #include <bool.h>
     49#include <stdbool.h>
    4950
    5051#include "sheet.h"
     52#include "search.h"
    5153
    5254enum redraw_flags {
     
    7880        tag_t sel_start;
    7981
     82        /** Active keyboard modifiers */
     83        keymod_t keymod;
     84
    8085        /**
    8186         * Ideal column where the caret should try to get. This is used
     
    8388         */
    8489        int ideal_column;
     90       
     91        char *previous_search;
     92        bool previous_search_reverse;
    8593} pane_t;
    8694
     
    9199typedef struct {
    92100        char *file_name;
    93         sheet_t sh;
     101        sheet_t *sh;
    94102} doc_t;
    95103
     
    106114#define BUF_SIZE 64
    107115#define TAB_WIDTH 8
    108 #define ED_INFTY 65536
    109116
    110117/** Maximum filename length that can be entered. */
     
    115122static void cursor_setvis(bool visible);
    116123
     124static void key_handle_press(kbd_event_t *ev);
    117125static void key_handle_unmod(kbd_event_t const *ev);
    118126static void key_handle_ctrl(kbd_event_t const *ev);
    119127static void key_handle_shift(kbd_event_t const *ev);
     128static void key_handle_shift_ctrl(kbd_event_t const *ev);
    120129static void key_handle_movement(unsigned int key, bool shift);
     130
     131static void pos_handle(pos_event_t *ev);
    121132
    122133static int file_save(char const *fname);
     
    125136static int file_save_range(char const *fname, spt_t const *spos,
    126137    spt_t const *epos);
    127 static char *filename_prompt(char const *prompt, char const *init_value);
    128138static char *range_get_str(spt_t const *spos, spt_t const *epos);
     139
     140static char *prompt(char const *prompt, char const *init_value);
    129141
    130142static void pane_text_display(void);
     
    138150static void delete_char_after(void);
    139151static void caret_update(void);
    140 static void caret_move(int drow, int dcolumn, enum dir_spec align_dir);
     152static void caret_move_relative(int drow, int dcolumn, enum dir_spec align_dir, bool select);
     153static void caret_move_absolute(int row, int column, enum dir_spec align_dir, bool select);
     154static void caret_move(spt_t spt, bool select, bool update_ideal_column);
     155static void caret_move_word_left(bool select);
     156static void caret_move_word_right(bool select);
     157static void caret_go_to_line_ask(void);
    141158
    142159static bool selection_active(void);
    143160static void selection_sel_all(void);
     161static void selection_sel_range(spt_t pa, spt_t pb);
    144162static void selection_get_points(spt_t *pa, spt_t *pb);
    145163static void selection_delete(void);
     
    147165static void insert_clipboard_data(void);
    148166
     167static void search(char *pattern, bool reverse);
     168static void search_prompt(bool reverse);
     169static void search_repeat(void);
     170
    149171static void pt_get_sof(spt_t *pt);
    150172static void pt_get_eof(spt_t *pt);
     173static void pt_get_sol(spt_t *cpt, spt_t *spt);
     174static void pt_get_eol(spt_t *cpt, spt_t *ept);
     175static bool pt_is_word_beginning(spt_t *pt);
     176static bool pt_is_delimiter(spt_t *pt);
     177static bool pt_is_punctuation(spt_t *pt);
     178static spt_t pt_find_word_left(spt_t spt);
     179static spt_t pt_find_word_left(spt_t spt);
     180
    151181static int tag_cmp(tag_t const *a, tag_t const *b);
    152182static int spt_cmp(spt_t const *a, spt_t const *b);
     
    158188int main(int argc, char *argv[])
    159189{
    160         kbd_event_t ev;
    161         coord_t coord;
     190        cons_event_t ev;
    162191        bool new_file;
    163 
    164         spt_t pt;
     192        int rc;
    165193
    166194        con = console_init(stdin, stdout);
     
    175203
    176204        /* 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        }
    178210
    179211        /* 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;
    184216
    185217        if (argc == 2) {
     
    197229                new_file = true;
    198230
     231        /* Place selection start tag. */
     232        sheet_place_tag(doc.sh, &sof, &pane.sel_start);
     233
    199234        /* 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);
    205237
    206238        /* Initial display */
     
    219251
    220252        while (!done) {
    221                 console_get_kbd_event(con, &ev);
     253                console_get_event(con, &ev);
    222254                pane.rflags = 0;
    223255
    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;
    237265                }
    238266
     
    256284
    257285        return 0;
     286}
     287
     288/* Handle key press. */
     289static 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        }
    258306}
    259307
     
    346394static void key_handle_ctrl(kbd_event_t const *ev)
    347395{
     396        spt_t pt;
    348397        switch (ev->key) {
    349398        case KC_Q:
     
    377426                selection_sel_all();
    378427                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;
    379451        default:
    380452                break;
     
    382454}
    383455
    384 static void key_handle_movement(unsigned int key, bool select)
     456static void key_handle_shift_ctrl(kbd_event_t const *ev)
    385457{
    386458        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
     482static 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. */
     500static void caret_move(spt_t new_caret_pt, bool select, bool update_ideal_column)
     501{
     502        spt_t old_caret_pt, old_sel_pt;
    388503        coord_t c_old, c_new;
    389504        bool had_sel;
    390505
    391506        /* 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);
    424514
    425515        if (select == false) {
    426516                /* 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);
    432522        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);
    436524
    437525                if (c_old.row == c_new.row)
     
    444532                pane.rflags |= REDRAW_TEXT;
    445533        }
     534       
     535        if (update_ideal_column)
     536                pane.ideal_column = c_new.column;
     537       
     538        caret_update();
     539}
     540
     541static 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        }
    446576}
    447577
     
    479609        char *fname;
    480610       
    481         fname = filename_prompt("Save As", old_fname);
     611        fname = prompt("Save As", old_fname);
    482612        if (fname == NULL) {
    483613                status_display("Save cancelled.");
     
    494624}
    495625
    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. */
     627static char *prompt(char const *prompt, char const *init_value)
     628{
     629        cons_event_t ev;
     630        kbd_event_t *kev;
    500631        char *str;
    501632        wchar_t buffer[INFNAME_MAX_LEN + 1];
     
    517648
    518649        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
    522655                        /* 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) {
    525658                                ;
    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) {
    528661                                case KC_ESCAPE:
    529662                                        return NULL;
     
    539672                                        break;
    540673                                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);
    543676                                                console_flush(con);
    544                                                 buffer[nc++] = ev.c;
     677                                                buffer[nc++] = kev->c;
    545678                                        }
    546679                                        break;
     
    616749
    617750        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);
    619752                bytes = str_size(buf);
    620753
     
    651784
    652785        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,
    654787                    &bep);
    655788                bytes = str_size(&buf[bpos]);
     
    673806        int sh_rows, rows;
    674807
    675         sheet_get_num_rows(&doc.sh, &sh_rows);
     808        sheet_get_num_rows(doc.sh, &sh_rows);
    676809        rows = min(sh_rows - pane.sh_row + 1, pane.rows);
    677810
     
    743876                rbc.row = pane.sh_row + i;
    744877                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);
    746879
    747880                /* Ending point for row display */
    748881                rec.row = pane.sh_row + i;
    749882                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);
    751884
    752885                /* 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);
    754887
    755888                /* Display text from the buffer. */
     
    801934                /* Fill until the end of display area. */
    802935
    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);
    805938                else
    806939                        fill = 0;
     
    820953        spt_t caret_pt;
    821954        coord_t coord;
     955        int last_row;
    822956
    823957        tag_get_pt(&pane.caret_pos, &caret_pt);
    824958        spt_get_coord(&caret_pt, &coord);
    825959
     960        sheet_get_num_rows(doc.sh, &last_row);
     961
    826962        const char *fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>";
    827963
    828964        console_set_pos(con, 0, scr_rows - 1);
    829965        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);
    832968       
    833969        int pos = scr_columns - 1 - n;
     
    8651001        cbuf[offs] = '\0';
    8661002
    867         (void) sheet_insert(&doc.sh, &pt, dir_before, cbuf);
     1003        (void) sheet_insert(doc.sh, &pt, dir_before, cbuf);
    8681004
    8691005        pane.rflags |= REDRAW_ROW;
     
    8821018
    8831019        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);
    8871023
    8881024        pane.rflags |= REDRAW_ROW;
     
    9001036        spt_get_coord(&sp, &sc);
    9011037
    902         sheet_get_cell_pt(&doc.sh, &sc, dir_after, &ep);
     1038        sheet_get_cell_pt(doc.sh, &sc, dir_after, &ep);
    9031039        spt_get_coord(&ep, &ec);
    9041040
    905         (void) sheet_delete(&doc.sh, &sp, &ep);
     1041        (void) sheet_delete(doc.sh, &sp, &ep);
    9061042
    9071043        pane.rflags |= REDRAW_ROW;
     
    9501086}
    9511087
    952 /** Change the caret position.
     1088/** Relatively move caret position.
    9531089 *
    9541090 * Moves caret relatively to the current position. Looking at the first
     
    9561092 * to a new character cell, and thus a new character. Then we either go to the
    9571093 * 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
    9581096 */
    959 static void caret_move(int drow, int dcolumn, enum dir_spec align_dir)
     1097static void caret_move_relative(int drow, int dcolumn, enum dir_spec align_dir,
     1098    bool select)
    9601099{
    9611100        spt_t pt;
     
    9701109        /* Clamp coordinates. */
    9711110        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        }
    9731119        if (drow > 0) {
    974                 sheet_get_num_rows(&doc.sh, &num_rows);
     1120                sheet_get_num_rows(doc.sh, &num_rows);
    9751121                if (coord.row > num_rows) coord.row = num_rows;
    9761122        }
     
    9851131         * coordinates. The character can be wider than one cell (e.g. tab).
    9861132         */
    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);
    9901134
    9911135        /* 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 */
     1147static 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 */
     1161static 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 */
     1170static 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
     1178static 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
     1186static 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. */
     1195static 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 */
     1218static 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
     1227static 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
     1236static 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
     1249static void search_spt_mark_free(void *data)
     1250{
     1251        free(data);
     1252}
     1253
     1254static 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
     1261static 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. */
     1269static 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
     1295static 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
     1305static 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);
    9981360}
    9991361
     
    10351397
    10361398        if (rel < 0)
    1037                 sheet_delete(&doc.sh, &pa, &pb);
     1399                sheet_delete(doc.sh, &pa, &pb);
    10381400        else
    1039                 sheet_delete(&doc.sh, &pb, &pa);
     1401                sheet_delete(doc.sh, &pb, &pa);
    10401402
    10411403        if (ca.row == cb.row)
     
    10451407}
    10461408
     1409/** Select all text in the editor */
    10471410static void selection_sel_all(void)
    10481411{
     
    10511414        pt_get_sof(&spt);
    10521415        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 */
     1421static 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);
    10571427
    10581428        pane.rflags |= REDRAW_TEXT;
     
    11031473
    11041474        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);
    11061476}
    11071477
     
    11121482        int num_rows;
    11131483
    1114         sheet_get_num_rows(&doc.sh, &num_rows);
     1484        sheet_get_num_rows(doc.sh, &num_rows);
    11151485        coord.row = num_rows + 1;
    11161486        coord.column = 1;
    11171487
    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 */
     1492static 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 */
     1503static 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 */
     1516static 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
     1545static 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
     1551static 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
     1577static 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        }
    11191613}
    11201614
Note: See TracChangeset for help on using the changeset viewer.