Changes in uspace/app/edit/edit.c [69cf3a4:8312577] in mainline


Ignore:
File:
1 edited

Legend:

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

    r69cf3a4 r8312577  
    11/*
    22 * Copyright (c) 2009 Jiri Svoboda
     3 * Copyright (c) 2012 Martin Sucha
    34 * All rights reserved.
    45 *
     
    4950
    5051#include "sheet.h"
     52#include "search.h"
    5153
    5254enum redraw_flags {
     
    8385         */
    8486        int ideal_column;
     87       
     88        char *previous_search;
     89        bool previous_search_reverse;
    8590} pane_t;
    8691
     
    140145static void delete_char_after(void);
    141146static void caret_update(void);
    142 static void caret_move(int drow, int dcolumn, enum dir_spec align_dir);
    143 static void caret_move_word_left(void);
    144 static void caret_move_word_right(void);
    145 static void caret_move_to_line(int row);
     147static void caret_move_relative(int drow, int dcolumn, enum dir_spec align_dir, bool select);
     148static void caret_move_absolute(int row, int column, enum dir_spec align_dir, bool select);
     149static void caret_move(spt_t spt, bool select, bool update_ideal_column);
     150static void caret_move_word_left(bool select);
     151static void caret_move_word_right(bool select);
    146152static void caret_go_to_line_ask(void);
    147153
     
    149155static void selection_sel_all(void);
    150156static void selection_sel_range(spt_t pa, spt_t pb);
    151 static void selection_sel_prev_word(void);
    152 static void selection_sel_next_word(void);
    153157static void selection_get_points(spt_t *pa, spt_t *pb);
    154158static void selection_delete(void);
    155159static void selection_copy(void);
    156160static void insert_clipboard_data(void);
     161
     162static void search(char *pattern, bool reverse);
     163static void search_prompt(bool reverse);
     164static void search_repeat(void);
    157165
    158166static void pt_get_sof(spt_t *pt);
     
    163171static bool pt_is_delimiter(spt_t *pt);
    164172static bool pt_is_punctuation(spt_t *pt);
     173static spt_t pt_find_word_left(spt_t spt);
     174static spt_t pt_find_word_left(spt_t spt);
     175
    165176static int tag_cmp(tag_t const *a, tag_t const *b);
    166177static int spt_cmp(spt_t const *a, spt_t const *b);
     
    173184{
    174185        kbd_event_t ev;
    175         coord_t coord;
    176186        bool new_file;
    177187        int rc;
    178 
    179         spt_t pt;
    180188
    181189        con = console_init(stdin, stdout);
     
    197205
    198206        /* Place caret at the beginning of file. */
    199         coord.row = coord.column = 1;
    200         sheet_get_cell_pt(doc.sh, &coord, dir_before, &pt);
    201         sheet_place_tag(doc.sh, &pt, &pane.caret_pos);
    202         pane.ideal_column = coord.column;
     207        spt_t sof;
     208        pt_get_sof(&sof);
     209        sheet_place_tag(doc.sh, &sof, &pane.caret_pos);
     210        pane.ideal_column = 1;
    203211
    204212        if (argc == 2) {
     
    216224                new_file = true;
    217225
     226        /* Place selection start tag. */
     227        sheet_place_tag(doc.sh, &sof, &pane.sel_start);
     228
    218229        /* Move to beginning of file. */
    219         caret_move(-ED_INFTY, -ED_INFTY, dir_before);
    220 
    221         /* Place selection start tag. */
    222         tag_get_pt(&pane.caret_pos, &pt);
    223         sheet_place_tag(doc.sh, &pt, &pane.sel_start);
     230        pt_get_sof(&sof);
     231        caret_move(sof, true, true);
    224232
    225233        /* Initial display */
     
    400408                selection_sel_all();
    401409                break;
    402         case KC_W:
    403                 if (selection_active())
    404                         break;
    405                 selection_sel_prev_word();
    406                 selection_delete();
    407                 break;
    408410        case KC_RIGHT:
    409                 caret_move_word_right();
     411                caret_move_word_right(false);
    410412                break;
    411413        case KC_LEFT:
    412                 caret_move_word_left();
     414                caret_move_word_left(false);
    413415                break;
    414416        case KC_L:
    415417                caret_go_to_line_ask();
    416418                break;
     419        case KC_F:
     420                search_prompt(false);
     421                break;
     422        case KC_N:
     423                search_repeat();
     424                break;
    417425        default:
    418426                break;
     
    424432        switch(ev->key) {
    425433        case KC_LEFT:
    426                 selection_sel_prev_word();
     434                caret_move_word_left(true);
    427435                break;
    428436        case KC_RIGHT:
    429                 selection_sel_next_word();
     437                caret_move_word_right(true);
     438                break;
     439        case KC_F:
     440                search_prompt(true);
    430441                break;
    431442        default:
     
    435446
    436447/** Move caret while preserving or resetting selection. */
    437 static void caret_movement(int drow, int dcolumn, enum dir_spec align_dir,
    438     bool select)
    439 {
    440         spt_t pt;
    441         spt_t caret_pt;
     448static void caret_move(spt_t new_caret_pt, bool select, bool update_ideal_column)
     449{
     450        spt_t old_caret_pt, old_sel_pt;
    442451        coord_t c_old, c_new;
    443452        bool had_sel;
    444453
    445454        /* Check if we had selection before. */
    446         tag_get_pt(&pane.caret_pos, &caret_pt);
    447         tag_get_pt(&pane.sel_start, &pt);
    448         had_sel = !spt_equal(&caret_pt, &pt);
    449 
    450         caret_move(drow, dcolumn, align_dir);
     455        tag_get_pt(&pane.caret_pos, &old_caret_pt);
     456        tag_get_pt(&pane.sel_start, &old_sel_pt);
     457        had_sel = !spt_equal(&old_caret_pt, &old_sel_pt);
     458
     459        /* Place tag of the caret */
     460        sheet_remove_tag(doc.sh, &pane.caret_pos);
     461        sheet_place_tag(doc.sh, &new_caret_pt, &pane.caret_pos);
    451462
    452463        if (select == false) {
    453464                /* Move sel_start to the same point as caret. */
    454465                sheet_remove_tag(doc.sh, &pane.sel_start);
    455                 tag_get_pt(&pane.caret_pos, &pt);
    456                 sheet_place_tag(doc.sh, &pt, &pane.sel_start);
    457         }
    458 
     466                sheet_place_tag(doc.sh, &new_caret_pt, &pane.sel_start);
     467        }
     468
     469        spt_get_coord(&new_caret_pt, &c_new);
    459470        if (select) {
    460                 tag_get_pt(&pane.caret_pos, &pt);
    461                 spt_get_coord(&caret_pt, &c_old);
    462                 spt_get_coord(&pt, &c_new);
     471                spt_get_coord(&old_caret_pt, &c_old);
    463472
    464473                if (c_old.row == c_new.row)
     
    471480                pane.rflags |= REDRAW_TEXT;
    472481        }
     482       
     483        if (update_ideal_column)
     484                pane.ideal_column = c_new.column;
     485       
     486        caret_update();
    473487}
    474488
     
    477491        switch (key) {
    478492        case KC_LEFT:
    479                 caret_movement(0, -1, dir_before, select);
     493                caret_move_relative(0, -1, dir_before, select);
    480494                break;
    481495        case KC_RIGHT:
    482                 caret_movement(0, 0, dir_after, select);
     496                caret_move_relative(0, 0, dir_after, select);
    483497                break;
    484498        case KC_UP:
    485                 caret_movement(-1, 0, dir_before, select);
     499                caret_move_relative(-1, 0, dir_before, select);
    486500                break;
    487501        case KC_DOWN:
    488                 caret_movement(+1, 0, dir_before, select);
     502                caret_move_relative(+1, 0, dir_before, select);
    489503                break;
    490504        case KC_HOME:
    491                 caret_movement(0, -ED_INFTY, dir_before, select);
     505                caret_move_relative(0, -ED_INFTY, dir_after, select);
    492506                break;
    493507        case KC_END:
    494                 caret_movement(0, +ED_INFTY, dir_before, select);
     508                caret_move_relative(0, +ED_INFTY, dir_before, select);
    495509                break;
    496510        case KC_PAGE_UP:
    497                 caret_movement(-pane.rows, 0, dir_before, select);
     511                caret_move_relative(-pane.rows, 0, dir_before, select);
    498512                break;
    499513        case KC_PAGE_DOWN:
    500                 caret_movement(+pane.rows, 0, dir_before, select);
     514                caret_move_relative(+pane.rows, 0, dir_before, select);
    501515                break;
    502516        default:
     
    10121026}
    10131027
    1014 /** Change the caret position.
     1028/** Relatively move caret position.
    10151029 *
    10161030 * Moves caret relatively to the current position. Looking at the first
     
    10181032 * to a new character cell, and thus a new character. Then we either go to the
    10191033 * point before the the character or after it, depending on @a align_dir.
     1034 *
     1035 * @param select true if the selection tag should stay where it is
    10201036 */
    1021 static void caret_move(int drow, int dcolumn, enum dir_spec align_dir)
     1037static void caret_move_relative(int drow, int dcolumn, enum dir_spec align_dir,
     1038    bool select)
    10221039{
    10231040        spt_t pt;
     
    10551072         */
    10561073        sheet_get_cell_pt(doc.sh, &coord, align_dir, &pt);
    1057         sheet_remove_tag(doc.sh, &pane.caret_pos);
    1058         sheet_place_tag(doc.sh, &pt, &pane.caret_pos);
    10591074
    10601075        /* For non-vertical movement set the new value for @c ideal_column. */
    1061         if (!pure_vertical) {
    1062                 spt_get_coord(&pt, &coord);
    1063                 pane.ideal_column = coord.column;
    1064         }
    1065 
    1066         caret_update();
    1067 }
    1068 
    1069 static void caret_move_word_left(void)
    1070 {
     1076        caret_move(pt, select, !pure_vertical);
     1077}
     1078
     1079/** Absolutely move caret position.
     1080 *
     1081 * Moves caret to a specified position. We get to a new character cell, and
     1082 * thus a new character. Then we either go to the point before the the character
     1083 * or after it, depending on @a align_dir.
     1084 *
     1085 * @param select true if the selection tag should stay where it is
     1086 */
     1087static void caret_move_absolute(int row, int column, enum dir_spec align_dir,
     1088    bool select)
     1089{
     1090        coord_t coord;
     1091        coord.row = row;
     1092        coord.column = column;
     1093       
    10711094        spt_t pt;
    1072 
     1095        sheet_get_cell_pt(doc.sh, &coord, align_dir, &pt);
     1096       
     1097        caret_move(pt, select, true);
     1098}
     1099
     1100/** Find beginning of a word to the left of spt */
     1101static spt_t pt_find_word_left(spt_t spt)
     1102{
    10731103        do {
    1074                 caret_move(0, -1, dir_before);
    1075 
    1076                 tag_get_pt(&pane.caret_pos, &pt);
    1077 
    1078                 sheet_remove_tag(doc.sh, &pane.sel_start);
    1079                 sheet_place_tag(doc.sh, &pt, &pane.sel_start);
    1080         } while (!pt_is_word_beginning(&pt));
    1081 
    1082         pane.rflags |= REDRAW_TEXT;
    1083 }
    1084 
    1085 static void caret_move_word_right(void)
     1104                spt_prev_char(spt, &spt);
     1105        } while (!pt_is_word_beginning(&spt));
     1106        return spt;
     1107}
     1108
     1109/** Find beginning of a word to the right of spt */
     1110static spt_t pt_find_word_right(spt_t spt)
     1111{
     1112        do {
     1113                spt_next_char(spt, &spt);
     1114        } while (!pt_is_word_beginning(&spt));
     1115        return spt;
     1116}
     1117
     1118static void caret_move_word_left(bool select)
    10861119{
    10871120        spt_t pt;
    1088 
    1089         do {
    1090                 caret_move(0, 0, dir_after);
    1091 
    1092                 tag_get_pt(&pane.caret_pos, &pt);
    1093 
    1094                 sheet_remove_tag(doc.sh, &pane.sel_start);
    1095                 sheet_place_tag(doc.sh, &pt, &pane.sel_start);
    1096         } while (!pt_is_word_beginning(&pt));
    1097 
    1098         pane.rflags |= REDRAW_TEXT;
    1099 }
    1100 
    1101 /** Change the caret position to a beginning of a given line
    1102  */
    1103 static void caret_move_to_line(int row)
     1121        tag_get_pt(&pane.caret_pos, &pt);
     1122        spt_t word_left = pt_find_word_left(pt);
     1123        caret_move(word_left, select, true);
     1124}
     1125
     1126static void caret_move_word_right(bool select)
    11041127{
    11051128        spt_t pt;
    1106         coord_t coord;
    1107 
    11081129        tag_get_pt(&pane.caret_pos, &pt);
    1109         spt_get_coord(&pt, &coord);
    1110 
    1111         caret_movement(row - coord.row, 0, dir_before, false);
     1130        spt_t word_right = pt_find_word_right(pt);
     1131        caret_move(word_right, select, true);
    11121132}
    11131133
     
    11261146        int line = strtol(sline, &endptr, 10);
    11271147        if (*endptr != '\0') {
     1148                free(sline);
    11281149                status_display("Invalid number entered.");
    11291150                return;
    11301151        }
    1131        
    1132         caret_move_to_line(line);
    1133 }
    1134 
     1152        free(sline);
     1153       
     1154        caret_move_absolute(line, pane.ideal_column, dir_before, false);
     1155}
     1156
     1157/* Search operations */
     1158static int search_spt_producer(void *data, wchar_t *ret)
     1159{
     1160        assert(data != NULL);
     1161        assert(ret != NULL);
     1162        spt_t *spt = data;
     1163        *ret = spt_next_char(*spt, spt);
     1164        return EOK;
     1165}
     1166
     1167static int search_spt_reverse_producer(void *data, wchar_t *ret)
     1168{
     1169        assert(data != NULL);
     1170        assert(ret != NULL);
     1171        spt_t *spt = data;
     1172        *ret = spt_prev_char(*spt, spt);
     1173        return EOK;
     1174}
     1175
     1176static int search_spt_mark(void *data, void **mark)
     1177{
     1178        assert(data != NULL);
     1179        assert(mark != NULL);
     1180        spt_t *spt = data;
     1181        spt_t *new = calloc(1, sizeof(spt_t));
     1182        *mark = new;
     1183        if (new == NULL)
     1184                return ENOMEM;
     1185        *new = *spt;
     1186        return EOK;
     1187}
     1188
     1189static void search_spt_mark_free(void *data)
     1190{
     1191        free(data);
     1192}
     1193
     1194static search_ops_t search_spt_ops = {
     1195        .equals = char_exact_equals,
     1196        .producer = search_spt_producer,
     1197        .mark = search_spt_mark,
     1198        .mark_free = search_spt_mark_free,
     1199};
     1200
     1201static search_ops_t search_spt_reverse_ops = {
     1202        .equals = char_exact_equals,
     1203        .producer = search_spt_reverse_producer,
     1204        .mark = search_spt_mark,
     1205        .mark_free = search_spt_mark_free,
     1206};
     1207
     1208/** Ask for line and go to it. */
     1209static void search_prompt(bool reverse)
     1210{
     1211        char *pattern;
     1212       
     1213        const char *prompt_text = "Find next";
     1214        if (reverse)
     1215                prompt_text = "Find previous";
     1216       
     1217        const char *default_value = "";
     1218        if (pane.previous_search)
     1219                default_value = pane.previous_search;
     1220       
     1221        pattern = prompt(prompt_text, default_value);
     1222        if (pattern == NULL) {
     1223                status_display("Search cancelled.");
     1224                return;
     1225        }
     1226       
     1227        if (pane.previous_search)
     1228                free(pane.previous_search);
     1229        pane.previous_search = pattern;
     1230        pane.previous_search_reverse = reverse;
     1231       
     1232        search(pattern, reverse);
     1233}
     1234
     1235static void search_repeat(void)
     1236{
     1237        if (pane.previous_search == NULL) {
     1238                status_display("No previous search to repeat.");
     1239                return;
     1240        }
     1241       
     1242        search(pane.previous_search, pane.previous_search_reverse);
     1243}
     1244
     1245static void search(char *pattern, bool reverse)
     1246{
     1247        status_display("Searching...");
     1248       
     1249        spt_t sp, producer_pos;
     1250        tag_get_pt(&pane.caret_pos, &sp);
     1251       
     1252        /* Start searching on the position before/after caret */
     1253        if (!reverse) {
     1254                spt_next_char(sp, &sp);
     1255        }
     1256        else {
     1257                spt_prev_char(sp, &sp);
     1258        }
     1259        producer_pos = sp;
     1260       
     1261        search_ops_t ops = search_spt_ops;
     1262        if (reverse)
     1263                ops = search_spt_reverse_ops;
     1264       
     1265        search_t *search = search_init(pattern, &producer_pos, ops, reverse);
     1266        if (search == NULL) {
     1267                status_display("Failed initializing search.");
     1268                return;
     1269        }
     1270       
     1271        match_t match;
     1272        int rc = search_next_match(search, &match);
     1273        if (rc != EOK) {
     1274                status_display("Failed searching.");
     1275                search_fini(search);
     1276        }
     1277       
     1278        if (match.end) {
     1279                status_display("Match found.");
     1280                assert(match.end != NULL);
     1281                spt_t *end = match.end;
     1282                caret_move(*end, false, true);
     1283                while (match.length > 0) {
     1284                        match.length--;
     1285                        if (reverse) {
     1286                                spt_next_char(*end, end);
     1287                        }
     1288                        else {
     1289                                spt_prev_char(*end, end);
     1290                        }
     1291                }
     1292                caret_move(*end, true, true);
     1293                free(end);
     1294        }
     1295        else {
     1296                status_display("Not found.");
     1297        }
     1298       
     1299        search_fini(search);
     1300}
    11351301
    11361302/** Check for non-empty selection. */
     
    12021368        pane.rflags |= REDRAW_TEXT;
    12031369        caret_update();
    1204 }
    1205 
    1206 /** Add the previous word to the selection */
    1207 static void selection_sel_prev_word(void)
    1208 {
    1209         spt_t cpt, wpt, spt, ept;
    1210 
    1211         selection_get_points(&spt, &ept);
    1212 
    1213         tag_get_pt(&pane.caret_pos, &cpt);
    1214         caret_move_word_left();
    1215         tag_get_pt(&pane.caret_pos, &wpt);
    1216 
    1217         if (spt_cmp(&spt, &cpt) == 0)
    1218                 selection_sel_range(ept, wpt);
    1219         else
    1220                 selection_sel_range(spt, wpt);
    1221 }
    1222 
    1223 /** Add the next word to the selection */
    1224 static void selection_sel_next_word(void)
    1225 {
    1226         spt_t cpt, wpt, spt, ept;
    1227 
    1228         selection_get_points(&spt, &ept);
    1229 
    1230         tag_get_pt(&pane.caret_pos, &cpt);
    1231         caret_move_word_right();
    1232         tag_get_pt(&pane.caret_pos, &wpt);
    1233 
    1234         if (spt_cmp(&ept, &cpt) == 0)
    1235                 selection_sel_range(spt, wpt);
    1236         else
    1237                 selection_sel_range(ept, wpt);
    12381370}
    12391371
Note: See TracChangeset for help on using the changeset viewer.