Changes in uspace/app/edit/edit.c [743e17b:cd82bb1] in mainline


Ignore:
File:
1 edited

Legend:

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

    r743e17b rcd82bb1  
    3636
    3737#include <stdio.h>
     38#include <stdlib.h>
    3839#include <sys/types.h>
    3940#include <vfs/vfs.h>
     
    4445#include <align.h>
    4546#include <macros.h>
     47#include <clipboard.h>
    4648#include <bool.h>
    4749
     
    7375        tag_t caret_pos;
    7476
     77        /** Start of selection */
     78        tag_t sel_start;
     79
    7580        /**
    7681         * Ideal column where the caret should try to get. This is used
     
    101106#define ED_INFTY 65536
    102107
     108/** Maximum filename length that can be entered. */
     109#define INFNAME_MAX_LEN 128
     110
    103111static void key_handle_unmod(console_event_t const *ev);
    104112static void key_handle_ctrl(console_event_t const *ev);
     113static void key_handle_shift(console_event_t const *ev);
     114static void key_handle_movement(unsigned int key, bool shift);
     115
    105116static int file_save(char const *fname);
     117static void file_save_as(void);
    106118static int file_insert(char *fname);
    107119static int file_save_range(char const *fname, spt_t const *spos,
    108120    spt_t const *epos);
     121static char *filename_prompt(char const *prompt, char const *init_value);
     122static char *range_get_str(spt_t const *spos, spt_t const *epos);
     123
    109124static void pane_text_display(void);
    110125static void pane_row_display(void);
     
    112127static void pane_status_display(void);
    113128static void pane_caret_display(void);
     129
    114130static void insert_char(wchar_t c);
    115131static void delete_char_before(void);
     
    117133static void caret_update(void);
    118134static void caret_move(int drow, int dcolumn, enum dir_spec align_dir);
     135
     136static bool selection_active(void);
     137static void selection_sel_all(void);
     138static void selection_get_points(spt_t *pa, spt_t *pb);
     139static void selection_delete(void);
     140static void selection_copy(void);
     141static void insert_clipboard_data(void);
     142
    119143static void pt_get_sof(spt_t *pt);
    120144static void pt_get_eof(spt_t *pt);
     145static int tag_cmp(tag_t const *a, tag_t const *b);
     146static int spt_cmp(spt_t const *a, spt_t const *b);
     147static int coord_cmp(coord_t const *a, coord_t const *b);
     148
    121149static void status_display(char const *str);
    122150
     
    150178
    151179        if (argc == 2) {
    152                 doc.file_name = argv[1];
     180                doc.file_name = str_dup(argv[1]);
    153181        } else if (argc > 1) {
    154182                printf("Invalid arguments.\n");
    155183                return -2;
    156184        } else {
    157                 doc.file_name = "/edit.txt";
     185                doc.file_name = NULL;
    158186        }
    159187
    160188        new_file = false;
    161189
    162         if (file_insert(doc.file_name) != EOK)
     190        if (doc.file_name == NULL || file_insert(doc.file_name) != EOK)
    163191                new_file = true;
    164192
    165193        /* Move to beginning of file. */
    166194        caret_move(-ED_INFTY, -ED_INFTY, dir_before);
     195
     196        /* Place selection start tag. */
     197        tag_get_pt(&pane.caret_pos, &pt);
     198        sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
    167199
    168200        /* Initial display */
     
    170202        pane_text_display();
    171203        pane_status_display();
    172         if (new_file)
    173                 status_display("File not found. Created empty file.");
     204        if (new_file && doc.file_name != NULL)
     205                status_display("File not found. Starting empty file.");
    174206        pane_caret_display();
    175207
     
    184216                        /* Handle key press. */
    185217                        if (((ev.mods & KM_ALT) == 0) &&
     218                            ((ev.mods & KM_SHIFT) == 0) &&
    186219                             (ev.mods & KM_CTRL) != 0) {
    187220                                key_handle_ctrl(&ev);
    188                         } else if ((ev.mods & (KM_CTRL | KM_ALT)) == 0) {
     221                        } else if (((ev.mods & KM_ALT) == 0) &&
     222                            ((ev.mods & KM_CTRL) == 0) &&
     223                             (ev.mods & KM_SHIFT) != 0) {
     224                                key_handle_shift(&ev);
     225                        } else if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
    189226                                key_handle_unmod(&ev);
    190227                        }
     
    201238                if (pane.rflags & REDRAW_CARET)
    202239                        pane_caret_display();
    203                        
    204240        }
    205241
     
    214250        switch (ev->key) {
    215251        case KC_ENTER:
     252                selection_delete();
    216253                insert_char('\n');
    217254                caret_update();
    218255                break;
    219256        case KC_LEFT:
    220                 caret_move(0, -1, dir_before);
    221                 break;
    222257        case KC_RIGHT:
    223                 caret_move(0, 0, dir_after);
    224                 break;
    225258        case KC_UP:
    226                 caret_move(-1, 0, dir_before);
    227                 break;
    228259        case KC_DOWN:
    229                 caret_move(+1, 0, dir_before);
    230                 break;
    231260        case KC_HOME:
    232                 caret_move(0, -ED_INFTY, dir_before);
    233                 break;
    234261        case KC_END:
    235                 caret_move(0, +ED_INFTY, dir_before);
    236                 break;
    237262        case KC_PAGE_UP:
    238                 caret_move(-pane.rows, 0, dir_before);
    239                 break;
    240263        case KC_PAGE_DOWN:
    241                 caret_move(+pane.rows, 0, dir_before);
     264                key_handle_movement(ev->key, false);
    242265                break;
    243266        case KC_BACKSPACE:
    244                 delete_char_before();
     267                if (selection_active())
     268                        selection_delete();
     269                else
     270                        delete_char_before();
    245271                caret_update();
    246272                break;
    247273        case KC_DELETE:
    248                 delete_char_after();
     274                if (selection_active())
     275                        selection_delete();
     276                else
     277                        delete_char_after();
    249278                caret_update();
    250279                break;
    251280        default:
    252281                if (ev->c >= 32 || ev->c == '\t') {
     282                        selection_delete();
    253283                        insert_char(ev->c);
    254284                        caret_update();
     
    258288}
    259289
     290/** Handle Shift-key combination. */
     291static void key_handle_shift(console_event_t const *ev)
     292{
     293        switch (ev->key) {
     294        case KC_LEFT:
     295        case KC_RIGHT:
     296        case KC_UP:
     297        case KC_DOWN:
     298        case KC_HOME:
     299        case KC_END:
     300        case KC_PAGE_UP:
     301        case KC_PAGE_DOWN:
     302                key_handle_movement(ev->key, true);
     303                break;
     304        default:
     305                if (ev->c >= 32 || ev->c == '\t') {
     306                        selection_delete();
     307                        insert_char(ev->c);
     308                        caret_update();
     309                }
     310                break;
     311        }
     312}
     313
    260314/** Handle Ctrl-key combination. */
    261315static void key_handle_ctrl(console_event_t const *ev)
     
    266320                break;
    267321        case KC_S:
    268                 (void) file_save(doc.file_name);
     322                if (doc.file_name != NULL)
     323                        file_save(doc.file_name);
     324                else
     325                        file_save_as();
     326                break;
     327        case KC_E:
     328                file_save_as();
     329                break;
     330        case KC_C:
     331                selection_copy();
     332                break;
     333        case KC_V:
     334                selection_delete();
     335                insert_clipboard_data();
     336                pane.rflags |= REDRAW_TEXT;
     337                caret_update();
     338                break;
     339        case KC_X:
     340                selection_copy();
     341                selection_delete();
     342                pane.rflags |= REDRAW_TEXT;
     343                caret_update();
     344                break;
     345        case KC_A:
     346                selection_sel_all();
    269347                break;
    270348        default:
     
    273351}
    274352
     353static void key_handle_movement(unsigned int key, bool select)
     354{
     355        spt_t pt;
     356        spt_t caret_pt;
     357        coord_t c_old, c_new;
     358        bool had_sel;
     359
     360        /* Check if we had selection before. */
     361        tag_get_pt(&pane.caret_pos, &caret_pt);
     362        tag_get_pt(&pane.sel_start, &pt);
     363        had_sel = !spt_equal(&caret_pt, &pt);
     364
     365        switch (key) {
     366        case KC_LEFT:
     367                caret_move(0, -1, dir_before);
     368                break;
     369        case KC_RIGHT:
     370                caret_move(0, 0, dir_after);
     371                break;
     372        case KC_UP:
     373                caret_move(-1, 0, dir_before);
     374                break;
     375        case KC_DOWN:
     376                caret_move(+1, 0, dir_before);
     377                break;
     378        case KC_HOME:
     379                caret_move(0, -ED_INFTY, dir_before);
     380                break;
     381        case KC_END:
     382                caret_move(0, +ED_INFTY, dir_before);
     383                break;
     384        case KC_PAGE_UP:
     385                caret_move(-pane.rows, 0, dir_before);
     386                break;
     387        case KC_PAGE_DOWN:
     388                caret_move(+pane.rows, 0, dir_before);
     389                break;
     390        default:
     391                break;
     392        }
     393
     394        if (select == false) {
     395                /* Move sel_start to the same point as caret. */
     396                sheet_remove_tag(&doc.sh, &pane.sel_start);
     397                tag_get_pt(&pane.caret_pos, &pt);
     398                sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
     399        }
     400
     401        if (select) {
     402                tag_get_pt(&pane.caret_pos, &pt);
     403                spt_get_coord(&caret_pt, &c_old);
     404                spt_get_coord(&pt, &c_new);
     405
     406                if (c_old.row == c_new.row)
     407                        pane.rflags |= REDRAW_ROW;
     408                else
     409                        pane.rflags |= REDRAW_TEXT;
     410
     411        } else if (had_sel == true) {
     412                /* Redraw because text was unselected. */
     413                pane.rflags |= REDRAW_TEXT;
     414        }
     415}
    275416
    276417/** Save the document. */
     
    285426
    286427        rc = file_save_range(fname, &sp, &ep);
    287         status_display("File saved.");
     428
     429        switch (rc) {
     430        case EINVAL:
     431                status_display("Error opening file!");
     432                break;
     433        case EIO:
     434                status_display("Error writing data!");
     435                break;
     436        default:
     437                status_display("File saved.");
     438                break;
     439        }
    288440
    289441        return rc;
     442}
     443
     444/** Change document name and save. */
     445static void file_save_as(void)
     446{
     447        char *old_fname, *fname;
     448        int rc;
     449
     450        old_fname = (doc.file_name != NULL) ? doc.file_name : "";
     451        fname = filename_prompt("Save As", old_fname);
     452        if (fname == NULL) {
     453                status_display("Save cancelled.");
     454                return;
     455        }
     456
     457        rc = file_save(fname);
     458        if (rc != EOK)
     459                return;
     460
     461        if (doc.file_name != NULL)
     462                free(doc.file_name);
     463        doc.file_name = fname;
     464}
     465
     466/** Ask for a file name. */
     467static char *filename_prompt(char const *prompt, char const *init_value)
     468{
     469        console_event_t ev;
     470        char *str;
     471        wchar_t buffer[INFNAME_MAX_LEN + 1];
     472        int max_len;
     473        int nc;
     474        bool done;
     475
     476        asprintf(&str, "%s: %s", prompt, init_value);
     477        status_display(str);
     478        console_goto(con, 1 + str_length(str), scr_rows - 1);
     479        free(str);
     480
     481        console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
     482
     483        max_len = min(INFNAME_MAX_LEN, scr_columns - 4 - str_length(prompt));
     484        str_to_wstr(buffer, max_len + 1, init_value);
     485        nc = wstr_length(buffer);
     486        done = false;
     487
     488        while (!done) {
     489                console_get_event(con, &ev);
     490
     491                if (ev.type == KEY_PRESS) {
     492                        /* Handle key press. */
     493                        if (((ev.mods & KM_ALT) == 0) &&
     494                             (ev.mods & KM_CTRL) != 0) {
     495                                ;
     496                        } else if ((ev.mods & (KM_CTRL | KM_ALT)) == 0) {
     497                                switch (ev.key) {
     498                                case KC_ESCAPE:
     499                                        return NULL;
     500                                case KC_BACKSPACE:
     501                                        if (nc > 0) {
     502                                                putchar('\b');
     503                                                fflush(stdout);
     504                                                --nc;
     505                                        }
     506                                        break;
     507                                case KC_ENTER:
     508                                        done = true;
     509                                        break;
     510                                default:
     511                                        if (ev.c >= 32 && nc < max_len) {
     512                                                putchar(ev.c);
     513                                                fflush(stdout);
     514                                                buffer[nc++] = ev.c;
     515                                        }
     516                                        break;
     517                                }
     518                        }
     519                }
     520        }
     521
     522        buffer[nc] = '\0';
     523        str = wstr_to_astr(buffer);
     524
     525        console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
     526
     527        return str;
    290528}
    291529
     
    359597        } while (!spt_equal(&bep, epos));
    360598
    361         fclose(f);
     599        if (fclose(f) != EOK)
     600                return EIO;
    362601
    363602        return EOK;
     603}
     604
     605/** Return contents of range as a new string. */
     606static char *range_get_str(spt_t const *spos, spt_t const *epos)
     607{
     608        char *buf;
     609        spt_t sp, bep;
     610        size_t bytes;
     611        size_t buf_size, bpos;
     612
     613        buf_size = 1;
     614
     615        buf = malloc(buf_size);
     616        if (buf == NULL)
     617                return NULL;
     618
     619        bpos = 0;
     620        sp = *spos;
     621
     622        while (true) {
     623                sheet_copy_out(&doc.sh, &sp, epos, &buf[bpos], buf_size - bpos,
     624                    &bep);
     625                bytes = str_size(&buf[bpos]);
     626                bpos += bytes;
     627                sp = bep;
     628
     629                if (spt_equal(&bep, epos))
     630                        break;
     631
     632                buf_size *= 2;
     633                buf = realloc(buf, buf_size);
     634                if (buf == NULL)
     635                        return NULL;
     636        }
     637
     638        return buf;
    364639}
    365640
     
    408683{
    409684        int i, j, fill;
    410         spt_t rb, re, dep;
     685        spt_t rb, re, dep, pt;
    411686        coord_t rbc, rec;
    412687        char row_buf[ROW_BUF_SIZE];
     
    414689        size_t pos, size;
    415690        unsigned s_column;
     691        coord_t csel_start, csel_end, ctmp;
     692
     693        /* Determine selection start and end. */
     694
     695        tag_get_pt(&pane.sel_start, &pt);
     696        spt_get_coord(&pt, &csel_start);
     697
     698        tag_get_pt(&pane.caret_pos, &pt);
     699        spt_get_coord(&pt, &csel_end);
     700
     701        if (coord_cmp(&csel_start, &csel_end) > 0) {
     702                ctmp = csel_start;
     703                csel_start = csel_end;
     704                csel_end = ctmp;
     705        }
    416706
    417707        /* Draw rows from the sheet. */
     
    434724                /* Display text from the buffer. */
    435725
     726                if (coord_cmp(&csel_start, &rbc) <= 0 &&
     727                    coord_cmp(&rbc, &csel_end) < 0) {
     728                        fflush(stdout);
     729                        console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
     730                        fflush(stdout);
     731                }
     732
    436733                console_goto(con, 0, i);
    437734                size = str_size(row_buf);
    438735                pos = 0;
    439                 s_column = 1;
     736                s_column = pane.sh_column;
    440737                while (pos < size) {
     738                        if (csel_start.row == rbc.row && csel_start.column == s_column) {
     739                                fflush(stdout);
     740                                console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
     741                                fflush(stdout);
     742                        }
     743       
     744                        if (csel_end.row == rbc.row && csel_end.column == s_column) {
     745                                fflush(stdout);
     746                                console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
     747                                fflush(stdout);
     748                        }
     749       
    441750                        c = str_decode(row_buf, &pos, size);
    442751                        if (c != '\t') {
     
    453762                }
    454763
     764                if (csel_end.row == rbc.row && csel_end.column == s_column) {
     765                        fflush(stdout);
     766                        console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
     767                        fflush(stdout);
     768                }
     769
    455770                /* Fill until the end of display area. */
    456771
     
    463778                        putchar(' ');
    464779                fflush(stdout);
     780                console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
    465781        }
    466782
     
    473789        spt_t caret_pt;
    474790        coord_t coord;
     791        char *fname;
    475792        int n;
    476793
     
    478795        spt_get_coord(&caret_pt, &coord);
    479796
     797        fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>";
     798
    480799        console_goto(con, 0, scr_rows - 1);
    481800        console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
    482         n = printf(" %d, %d: File '%s'. Ctrl-S Save  Ctrl-Q Quit",
    483             coord.row, coord.column, doc.file_name);
     801        n = printf(" %d, %d: File '%s'. Ctrl-Q Quit  Ctrl-S Save  "
     802            "Ctrl-E Save As", coord.row, coord.column, fname);
    484803        printf("%*s", scr_columns - 1 - n, "");
    485804        fflush(stdout);
     
    648967}
    649968
     969/** Check for non-empty selection. */
     970static bool selection_active(void)
     971{
     972        return (tag_cmp(&pane.caret_pos, &pane.sel_start) != 0);
     973}
     974
     975static void selection_get_points(spt_t *pa, spt_t *pb)
     976{
     977        spt_t pt;
     978
     979        tag_get_pt(&pane.sel_start, pa);
     980        tag_get_pt(&pane.caret_pos, pb);
     981
     982        if (spt_cmp(pa, pb) > 0) {
     983                pt = *pa;
     984                *pa = *pb;
     985                *pb = pt;
     986        }
     987}
     988
     989/** Delete selected text. */
     990static void selection_delete(void)
     991{
     992        spt_t pa, pb;
     993        coord_t ca, cb;
     994        int rel;
     995
     996        tag_get_pt(&pane.sel_start, &pa);
     997        tag_get_pt(&pane.caret_pos, &pb);
     998        spt_get_coord(&pa, &ca);
     999        spt_get_coord(&pb, &cb);
     1000        rel = coord_cmp(&ca, &cb);
     1001
     1002        if (rel == 0)
     1003                return;
     1004
     1005        if (rel < 0)
     1006                sheet_delete(&doc.sh, &pa, &pb);
     1007        else
     1008                sheet_delete(&doc.sh, &pb, &pa);
     1009
     1010        if (ca.row == cb.row)
     1011                pane.rflags |= REDRAW_ROW;
     1012        else
     1013                pane.rflags |= REDRAW_TEXT;
     1014}
     1015
     1016static void selection_sel_all(void)
     1017{
     1018        spt_t spt, ept;
     1019
     1020        pt_get_sof(&spt);
     1021        pt_get_eof(&ept);
     1022        sheet_remove_tag(&doc.sh, &pane.sel_start);
     1023        sheet_place_tag(&doc.sh, &spt, &pane.sel_start);
     1024        sheet_remove_tag(&doc.sh, &pane.caret_pos);
     1025        sheet_place_tag(&doc.sh, &ept, &pane.caret_pos);
     1026
     1027        pane.rflags |= REDRAW_TEXT;
     1028        caret_update();
     1029}
     1030
     1031static void selection_copy(void)
     1032{
     1033        spt_t pa, pb;
     1034        char *str;
     1035
     1036        selection_get_points(&pa, &pb);
     1037        str = range_get_str(&pa, &pb);
     1038        if (str == NULL || clipboard_put_str(str) != EOK) {
     1039                status_display("Copying to clipboard failed!");
     1040        }
     1041        free(str);
     1042}
     1043
     1044static void insert_clipboard_data(void)
     1045{
     1046        char *str;
     1047        size_t off;
     1048        wchar_t c;
     1049        int rc;
     1050
     1051        rc = clipboard_get_str(&str);
     1052        if (rc != EOK || str == NULL)
     1053                return;
     1054
     1055        off = 0;
     1056
     1057        while (true) {
     1058                c = str_decode(str, &off, STR_NO_LIMIT);
     1059                if (c == '\0')
     1060                        break;
     1061
     1062                insert_char(c);
     1063        }
     1064
     1065        free(str);
     1066}
    6501067
    6511068/** Get start-of-file s-point. */
     
    6651082
    6661083        sheet_get_num_rows(&doc.sh, &num_rows);
    667         coord.row = num_rows;
     1084        coord.row = num_rows + 1;
    6681085        coord.column = 1;
    6691086
    6701087        sheet_get_cell_pt(&doc.sh, &coord, dir_after, pt);
     1088}
     1089
     1090/** Compare tags. */
     1091static int tag_cmp(tag_t const *a, tag_t const *b)
     1092{
     1093        spt_t pa, pb;
     1094
     1095        tag_get_pt(a, &pa);
     1096        tag_get_pt(b, &pb);
     1097
     1098        return spt_cmp(&pa, &pb);
     1099}
     1100
     1101/** Compare s-points. */
     1102static int spt_cmp(spt_t const *a, spt_t const *b)
     1103{
     1104        coord_t ca, cb;
     1105
     1106        spt_get_coord(a, &ca);
     1107        spt_get_coord(b, &cb);
     1108
     1109        return coord_cmp(&ca, &cb);
     1110}
     1111
     1112/** Compare coordinats. */
     1113static int coord_cmp(coord_t const *a, coord_t const *b)
     1114{
     1115        if (a->row - b->row != 0)
     1116                return a->row - b->row;
     1117
     1118        return a->column - b->column;
    6711119}
    6721120
Note: See TracChangeset for help on using the changeset viewer.