Changeset 61c0402 in mainline for uspace/app/edit/edit.c


Ignore:
Timestamp:
2010-01-15T19:36:53Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
92bee46
Parents:
50f9c3a (diff), 963462af (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

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

    r50f9c3a r61c0402  
    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
     
    9398static bool done;
    9499static pane_t pane;
     100static bool cursor_visible;
    95101
    96102static int scr_rows, scr_columns;
     
    101107#define ED_INFTY 65536
    102108
     109/** Maximum filename length that can be entered. */
     110#define INFNAME_MAX_LEN 128
     111
     112static void cursor_show(void);
     113static void cursor_hide(void);
     114static void cursor_setvis(bool visible);
     115
    103116static void key_handle_unmod(console_event_t const *ev);
    104117static void key_handle_ctrl(console_event_t const *ev);
     118static void key_handle_shift(console_event_t const *ev);
     119static void key_handle_movement(unsigned int key, bool shift);
     120
    105121static int file_save(char const *fname);
     122static void file_save_as(void);
    106123static int file_insert(char *fname);
    107124static int file_save_range(char const *fname, spt_t const *spos,
    108125    spt_t const *epos);
     126static char *filename_prompt(char const *prompt, char const *init_value);
     127static char *range_get_str(spt_t const *spos, spt_t const *epos);
     128
    109129static void pane_text_display(void);
    110130static void pane_row_display(void);
     
    112132static void pane_status_display(void);
    113133static void pane_caret_display(void);
     134
    114135static void insert_char(wchar_t c);
    115136static void delete_char_before(void);
     
    117138static void caret_update(void);
    118139static void caret_move(int drow, int dcolumn, enum dir_spec align_dir);
     140
     141static bool selection_active(void);
     142static void selection_sel_all(void);
     143static void selection_get_points(spt_t *pa, spt_t *pb);
     144static void selection_delete(void);
     145static void selection_copy(void);
     146static void insert_clipboard_data(void);
     147
    119148static void pt_get_sof(spt_t *pt);
    120149static void pt_get_eof(spt_t *pt);
     150static int tag_cmp(tag_t const *a, tag_t const *b);
     151static int spt_cmp(spt_t const *a, spt_t const *b);
     152static int coord_cmp(coord_t const *a, coord_t const *b);
     153
    121154static void status_display(char const *str);
    122155
     
    150183
    151184        if (argc == 2) {
    152                 doc.file_name = argv[1];
     185                doc.file_name = str_dup(argv[1]);
    153186        } else if (argc > 1) {
    154187                printf("Invalid arguments.\n");
    155188                return -2;
    156189        } else {
    157                 doc.file_name = "/edit.txt";
     190                doc.file_name = NULL;
    158191        }
    159192
    160193        new_file = false;
    161194
    162         if (file_insert(doc.file_name) != EOK)
     195        if (doc.file_name == NULL || file_insert(doc.file_name) != EOK)
    163196                new_file = true;
    164197
     
    166199        caret_move(-ED_INFTY, -ED_INFTY, dir_before);
    167200
     201        /* Place selection start tag. */
     202        tag_get_pt(&pane.caret_pos, &pt);
     203        sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
     204
    168205        /* Initial display */
     206        cursor_visible = true;
     207
     208        cursor_hide();
    169209        console_clear(con);
    170210        pane_text_display();
    171211        pane_status_display();
    172         if (new_file)
    173                 status_display("File not found. Created empty file.");
     212        if (new_file && doc.file_name != NULL)
     213                status_display("File not found. Starting empty file.");
    174214        pane_caret_display();
    175 
     215        cursor_show();
    176216
    177217        done = false;
     
    184224                        /* Handle key press. */
    185225                        if (((ev.mods & KM_ALT) == 0) &&
     226                            ((ev.mods & KM_SHIFT) == 0) &&
    186227                             (ev.mods & KM_CTRL) != 0) {
    187228                                key_handle_ctrl(&ev);
    188                         } else if ((ev.mods & (KM_CTRL | KM_ALT)) == 0) {
     229                        } else if (((ev.mods & KM_ALT) == 0) &&
     230                            ((ev.mods & KM_CTRL) == 0) &&
     231                             (ev.mods & KM_SHIFT) != 0) {
     232                                key_handle_shift(&ev);
     233                        } else if ((ev.mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
    189234                                key_handle_unmod(&ev);
    190235                        }
     
    192237
    193238                /* Redraw as necessary. */
     239
     240                cursor_hide();
    194241
    195242                if (pane.rflags & REDRAW_TEXT)
     
    201248                if (pane.rflags & REDRAW_CARET)
    202249                        pane_caret_display();
    203                        
     250
     251                cursor_show();
    204252        }
    205253
     
    207255
    208256        return 0;
     257}
     258
     259static void cursor_show(void)
     260{
     261        cursor_setvis(true);
     262}
     263
     264static void cursor_hide(void)
     265{
     266        cursor_setvis(false);
     267}
     268
     269static void cursor_setvis(bool visible)
     270{
     271        if (cursor_visible != visible) {
     272                console_cursor_visibility(con, visible);
     273                cursor_visible = visible;
     274        }
    209275}
    210276
     
    214280        switch (ev->key) {
    215281        case KC_ENTER:
     282                selection_delete();
    216283                insert_char('\n');
    217284                caret_update();
    218285                break;
    219286        case KC_LEFT:
    220                 caret_move(0, -1, dir_before);
    221                 break;
    222287        case KC_RIGHT:
    223                 caret_move(0, 0, dir_after);
    224                 break;
    225288        case KC_UP:
    226                 caret_move(-1, 0, dir_before);
    227                 break;
    228289        case KC_DOWN:
    229                 caret_move(+1, 0, dir_before);
    230                 break;
    231290        case KC_HOME:
    232                 caret_move(0, -ED_INFTY, dir_before);
    233                 break;
    234291        case KC_END:
    235                 caret_move(0, +ED_INFTY, dir_before);
    236                 break;
    237292        case KC_PAGE_UP:
    238                 caret_move(-pane.rows, 0, dir_before);
    239                 break;
    240293        case KC_PAGE_DOWN:
    241                 caret_move(+pane.rows, 0, dir_before);
     294                key_handle_movement(ev->key, false);
    242295                break;
    243296        case KC_BACKSPACE:
    244                 delete_char_before();
     297                if (selection_active())
     298                        selection_delete();
     299                else
     300                        delete_char_before();
    245301                caret_update();
    246302                break;
    247303        case KC_DELETE:
    248                 delete_char_after();
     304                if (selection_active())
     305                        selection_delete();
     306                else
     307                        delete_char_after();
    249308                caret_update();
    250309                break;
    251310        default:
    252311                if (ev->c >= 32 || ev->c == '\t') {
     312                        selection_delete();
    253313                        insert_char(ev->c);
    254314                        caret_update();
     
    258318}
    259319
     320/** Handle Shift-key combination. */
     321static void key_handle_shift(console_event_t const *ev)
     322{
     323        switch (ev->key) {
     324        case KC_LEFT:
     325        case KC_RIGHT:
     326        case KC_UP:
     327        case KC_DOWN:
     328        case KC_HOME:
     329        case KC_END:
     330        case KC_PAGE_UP:
     331        case KC_PAGE_DOWN:
     332                key_handle_movement(ev->key, true);
     333                break;
     334        default:
     335                if (ev->c >= 32 || ev->c == '\t') {
     336                        selection_delete();
     337                        insert_char(ev->c);
     338                        caret_update();
     339                }
     340                break;
     341        }
     342}
     343
    260344/** Handle Ctrl-key combination. */
    261345static void key_handle_ctrl(console_event_t const *ev)
     
    266350                break;
    267351        case KC_S:
    268                 (void) file_save(doc.file_name);
     352                if (doc.file_name != NULL)
     353                        file_save(doc.file_name);
     354                else
     355                        file_save_as();
     356                break;
     357        case KC_E:
     358                file_save_as();
     359                break;
     360        case KC_C:
     361                selection_copy();
     362                break;
     363        case KC_V:
     364                selection_delete();
     365                insert_clipboard_data();
     366                pane.rflags |= REDRAW_TEXT;
     367                caret_update();
     368                break;
     369        case KC_X:
     370                selection_copy();
     371                selection_delete();
     372                pane.rflags |= REDRAW_TEXT;
     373                caret_update();
     374                break;
     375        case KC_A:
     376                selection_sel_all();
    269377                break;
    270378        default:
     
    273381}
    274382
     383static void key_handle_movement(unsigned int key, bool select)
     384{
     385        spt_t pt;
     386        spt_t caret_pt;
     387        coord_t c_old, c_new;
     388        bool had_sel;
     389
     390        /* Check if we had selection before. */
     391        tag_get_pt(&pane.caret_pos, &caret_pt);
     392        tag_get_pt(&pane.sel_start, &pt);
     393        had_sel = !spt_equal(&caret_pt, &pt);
     394
     395        switch (key) {
     396        case KC_LEFT:
     397                caret_move(0, -1, dir_before);
     398                break;
     399        case KC_RIGHT:
     400                caret_move(0, 0, dir_after);
     401                break;
     402        case KC_UP:
     403                caret_move(-1, 0, dir_before);
     404                break;
     405        case KC_DOWN:
     406                caret_move(+1, 0, dir_before);
     407                break;
     408        case KC_HOME:
     409                caret_move(0, -ED_INFTY, dir_before);
     410                break;
     411        case KC_END:
     412                caret_move(0, +ED_INFTY, dir_before);
     413                break;
     414        case KC_PAGE_UP:
     415                caret_move(-pane.rows, 0, dir_before);
     416                break;
     417        case KC_PAGE_DOWN:
     418                caret_move(+pane.rows, 0, dir_before);
     419                break;
     420        default:
     421                break;
     422        }
     423
     424        if (select == false) {
     425                /* Move sel_start to the same point as caret. */
     426                sheet_remove_tag(&doc.sh, &pane.sel_start);
     427                tag_get_pt(&pane.caret_pos, &pt);
     428                sheet_place_tag(&doc.sh, &pt, &pane.sel_start);
     429        }
     430
     431        if (select) {
     432                tag_get_pt(&pane.caret_pos, &pt);
     433                spt_get_coord(&caret_pt, &c_old);
     434                spt_get_coord(&pt, &c_new);
     435
     436                if (c_old.row == c_new.row)
     437                        pane.rflags |= REDRAW_ROW;
     438                else
     439                        pane.rflags |= REDRAW_TEXT;
     440
     441        } else if (had_sel == true) {
     442                /* Redraw because text was unselected. */
     443                pane.rflags |= REDRAW_TEXT;
     444        }
     445}
    275446
    276447/** Save the document. */
     
    285456
    286457        rc = file_save_range(fname, &sp, &ep);
    287         status_display("File saved.");
     458
     459        switch (rc) {
     460        case EINVAL:
     461                status_display("Error opening file!");
     462                break;
     463        case EIO:
     464                status_display("Error writing data!");
     465                break;
     466        default:
     467                status_display("File saved.");
     468                break;
     469        }
    288470
    289471        return rc;
     472}
     473
     474/** Change document name and save. */
     475static void file_save_as(void)
     476{
     477        char *old_fname, *fname;
     478        int rc;
     479
     480        old_fname = (doc.file_name != NULL) ? doc.file_name : "";
     481        fname = filename_prompt("Save As", old_fname);
     482        if (fname == NULL) {
     483                status_display("Save cancelled.");
     484                return;
     485        }
     486
     487        rc = file_save(fname);
     488        if (rc != EOK)
     489                return;
     490
     491        if (doc.file_name != NULL)
     492                free(doc.file_name);
     493        doc.file_name = fname;
     494}
     495
     496/** Ask for a file name. */
     497static char *filename_prompt(char const *prompt, char const *init_value)
     498{
     499        console_event_t ev;
     500        char *str;
     501        wchar_t buffer[INFNAME_MAX_LEN + 1];
     502        int max_len;
     503        int nc;
     504        bool done;
     505
     506        asprintf(&str, "%s: %s", prompt, init_value);
     507        status_display(str);
     508        console_goto(con, 1 + str_length(str), scr_rows - 1);
     509        free(str);
     510
     511        console_set_color(con, COLOR_WHITE, COLOR_BLACK, 0);
     512
     513        max_len = min(INFNAME_MAX_LEN, scr_columns - 4 - str_length(prompt));
     514        str_to_wstr(buffer, max_len + 1, init_value);
     515        nc = wstr_length(buffer);
     516        done = false;
     517
     518        while (!done) {
     519                console_get_event(con, &ev);
     520
     521                if (ev.type == KEY_PRESS) {
     522                        /* Handle key press. */
     523                        if (((ev.mods & KM_ALT) == 0) &&
     524                             (ev.mods & KM_CTRL) != 0) {
     525                                ;
     526                        } else if ((ev.mods & (KM_CTRL | KM_ALT)) == 0) {
     527                                switch (ev.key) {
     528                                case KC_ESCAPE:
     529                                        return NULL;
     530                                case KC_BACKSPACE:
     531                                        if (nc > 0) {
     532                                                putchar('\b');
     533                                                fflush(stdout);
     534                                                --nc;
     535                                        }
     536                                        break;
     537                                case KC_ENTER:
     538                                        done = true;
     539                                        break;
     540                                default:
     541                                        if (ev.c >= 32 && nc < max_len) {
     542                                                putchar(ev.c);
     543                                                fflush(stdout);
     544                                                buffer[nc++] = ev.c;
     545                                        }
     546                                        break;
     547                                }
     548                        }
     549                }
     550        }
     551
     552        buffer[nc] = '\0';
     553        str = wstr_to_astr(buffer);
     554
     555        console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
     556
     557        return str;
    290558}
    291559
     
    359627        } while (!spt_equal(&bep, epos));
    360628
    361         fclose(f);
     629        if (fclose(f) != EOK)
     630                return EIO;
    362631
    363632        return EOK;
     633}
     634
     635/** Return contents of range as a new string. */
     636static char *range_get_str(spt_t const *spos, spt_t const *epos)
     637{
     638        char *buf;
     639        spt_t sp, bep;
     640        size_t bytes;
     641        size_t buf_size, bpos;
     642
     643        buf_size = 1;
     644
     645        buf = malloc(buf_size);
     646        if (buf == NULL)
     647                return NULL;
     648
     649        bpos = 0;
     650        sp = *spos;
     651
     652        while (true) {
     653                sheet_copy_out(&doc.sh, &sp, epos, &buf[bpos], buf_size - bpos,
     654                    &bep);
     655                bytes = str_size(&buf[bpos]);
     656                bpos += bytes;
     657                sp = bep;
     658
     659                if (spt_equal(&bep, epos))
     660                        break;
     661
     662                buf_size *= 2;
     663                buf = realloc(buf, buf_size);
     664                if (buf == NULL)
     665                        return NULL;
     666        }
     667
     668        return buf;
    364669}
    365670
     
    408713{
    409714        int i, j, fill;
    410         spt_t rb, re, dep;
     715        spt_t rb, re, dep, pt;
    411716        coord_t rbc, rec;
    412717        char row_buf[ROW_BUF_SIZE];
     
    414719        size_t pos, size;
    415720        unsigned s_column;
     721        coord_t csel_start, csel_end, ctmp;
     722
     723        /* Determine selection start and end. */
     724
     725        tag_get_pt(&pane.sel_start, &pt);
     726        spt_get_coord(&pt, &csel_start);
     727
     728        tag_get_pt(&pane.caret_pos, &pt);
     729        spt_get_coord(&pt, &csel_end);
     730
     731        if (coord_cmp(&csel_start, &csel_end) > 0) {
     732                ctmp = csel_start;
     733                csel_start = csel_end;
     734                csel_end = ctmp;
     735        }
    416736
    417737        /* Draw rows from the sheet. */
     
    434754                /* Display text from the buffer. */
    435755
     756                if (coord_cmp(&csel_start, &rbc) <= 0 &&
     757                    coord_cmp(&rbc, &csel_end) < 0) {
     758                        fflush(stdout);
     759                        console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
     760                        fflush(stdout);
     761                }
     762
    436763                console_goto(con, 0, i);
    437764                size = str_size(row_buf);
    438765                pos = 0;
    439                 s_column = 1;
     766                s_column = pane.sh_column;
    440767                while (pos < size) {
     768                        if (csel_start.row == rbc.row && csel_start.column == s_column) {
     769                                fflush(stdout);
     770                                console_set_color(con, COLOR_BLACK, COLOR_RED, 0);
     771                                fflush(stdout);
     772                        }
     773       
     774                        if (csel_end.row == rbc.row && csel_end.column == s_column) {
     775                                fflush(stdout);
     776                                console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
     777                                fflush(stdout);
     778                        }
     779       
    441780                        c = str_decode(row_buf, &pos, size);
    442781                        if (c != '\t') {
     
    453792                }
    454793
     794                if (csel_end.row == rbc.row && csel_end.column == s_column) {
     795                        fflush(stdout);
     796                        console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
     797                        fflush(stdout);
     798                }
     799
    455800                /* Fill until the end of display area. */
    456801
     
    463808                        putchar(' ');
    464809                fflush(stdout);
     810                console_set_color(con, COLOR_BLACK, COLOR_WHITE, 0);
    465811        }
    466812
     
    473819        spt_t caret_pt;
    474820        coord_t coord;
     821        char *fname;
    475822        int n;
    476823
     
    478825        spt_get_coord(&caret_pt, &coord);
    479826
     827        fname = (doc.file_name != NULL) ? doc.file_name : "<unnamed>";
     828
    480829        console_goto(con, 0, scr_rows - 1);
    481830        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);
     831        n = printf(" %d, %d: File '%s'. Ctrl-Q Quit  Ctrl-S Save  "
     832            "Ctrl-E Save As", coord.row, coord.column, fname);
    484833        printf("%*s", scr_columns - 1 - n, "");
    485834        fflush(stdout);
     
    648997}
    649998
     999/** Check for non-empty selection. */
     1000static bool selection_active(void)
     1001{
     1002        return (tag_cmp(&pane.caret_pos, &pane.sel_start) != 0);
     1003}
     1004
     1005static void selection_get_points(spt_t *pa, spt_t *pb)
     1006{
     1007        spt_t pt;
     1008
     1009        tag_get_pt(&pane.sel_start, pa);
     1010        tag_get_pt(&pane.caret_pos, pb);
     1011
     1012        if (spt_cmp(pa, pb) > 0) {
     1013                pt = *pa;
     1014                *pa = *pb;
     1015                *pb = pt;
     1016        }
     1017}
     1018
     1019/** Delete selected text. */
     1020static void selection_delete(void)
     1021{
     1022        spt_t pa, pb;
     1023        coord_t ca, cb;
     1024        int rel;
     1025
     1026        tag_get_pt(&pane.sel_start, &pa);
     1027        tag_get_pt(&pane.caret_pos, &pb);
     1028        spt_get_coord(&pa, &ca);
     1029        spt_get_coord(&pb, &cb);
     1030        rel = coord_cmp(&ca, &cb);
     1031
     1032        if (rel == 0)
     1033                return;
     1034
     1035        if (rel < 0)
     1036                sheet_delete(&doc.sh, &pa, &pb);
     1037        else
     1038                sheet_delete(&doc.sh, &pb, &pa);
     1039
     1040        if (ca.row == cb.row)
     1041                pane.rflags |= REDRAW_ROW;
     1042        else
     1043                pane.rflags |= REDRAW_TEXT;
     1044}
     1045
     1046static void selection_sel_all(void)
     1047{
     1048        spt_t spt, ept;
     1049
     1050        pt_get_sof(&spt);
     1051        pt_get_eof(&ept);
     1052        sheet_remove_tag(&doc.sh, &pane.sel_start);
     1053        sheet_place_tag(&doc.sh, &spt, &pane.sel_start);
     1054        sheet_remove_tag(&doc.sh, &pane.caret_pos);
     1055        sheet_place_tag(&doc.sh, &ept, &pane.caret_pos);
     1056
     1057        pane.rflags |= REDRAW_TEXT;
     1058        caret_update();
     1059}
     1060
     1061static void selection_copy(void)
     1062{
     1063        spt_t pa, pb;
     1064        char *str;
     1065
     1066        selection_get_points(&pa, &pb);
     1067        str = range_get_str(&pa, &pb);
     1068        if (str == NULL || clipboard_put_str(str) != EOK) {
     1069                status_display("Copying to clipboard failed!");
     1070        }
     1071        free(str);
     1072}
     1073
     1074static void insert_clipboard_data(void)
     1075{
     1076        char *str;
     1077        size_t off;
     1078        wchar_t c;
     1079        int rc;
     1080
     1081        rc = clipboard_get_str(&str);
     1082        if (rc != EOK || str == NULL)
     1083                return;
     1084
     1085        off = 0;
     1086
     1087        while (true) {
     1088                c = str_decode(str, &off, STR_NO_LIMIT);
     1089                if (c == '\0')
     1090                        break;
     1091
     1092                insert_char(c);
     1093        }
     1094
     1095        free(str);
     1096}
    6501097
    6511098/** Get start-of-file s-point. */
     
    6691116
    6701117        sheet_get_cell_pt(&doc.sh, &coord, dir_after, pt);
     1118}
     1119
     1120/** Compare tags. */
     1121static int tag_cmp(tag_t const *a, tag_t const *b)
     1122{
     1123        spt_t pa, pb;
     1124
     1125        tag_get_pt(a, &pa);
     1126        tag_get_pt(b, &pb);
     1127
     1128        return spt_cmp(&pa, &pb);
     1129}
     1130
     1131/** Compare s-points. */
     1132static int spt_cmp(spt_t const *a, spt_t const *b)
     1133{
     1134        coord_t ca, cb;
     1135
     1136        spt_get_coord(a, &ca);
     1137        spt_get_coord(b, &cb);
     1138
     1139        return coord_cmp(&ca, &cb);
     1140}
     1141
     1142/** Compare coordinats. */
     1143static int coord_cmp(coord_t const *a, coord_t const *b)
     1144{
     1145        if (a->row - b->row != 0)
     1146                return a->row - b->row;
     1147
     1148        return a->column - b->column;
    6711149}
    6721150
Note: See TracChangeset for help on using the changeset viewer.