[BACK]Return to mode-tree.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/mode-tree.c, Revision 1.2

1.2     ! nicm        1: /* $OpenBSD: mode-tree.c,v 1.1 2017/05/30 21:44:59 nicm Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
                     15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                     16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20:
                     21: #include <ctype.h>
                     22: #include <stdio.h>
                     23: #include <stdlib.h>
                     24: #include <string.h>
                     25:
                     26: #include "tmux.h"
                     27:
                     28: struct mode_tree_item;
                     29: TAILQ_HEAD(mode_tree_list, mode_tree_item);
                     30:
                     31: struct mode_tree_data {
                     32:        struct window_pane       *wp;
                     33:        void                     *modedata;
                     34:
                     35:        const char              **sort_list;
                     36:        u_int                     sort_size;
                     37:        u_int                     sort_type;
                     38:
                     39:        void                     (*buildcb)(void *, u_int, uint64_t *);
                     40:        struct screen           *(*drawcb)(void *, void *, u_int, u_int);
                     41:
                     42:        struct mode_tree_list     children;
                     43:        struct mode_tree_list     saved;
                     44:
                     45:        struct mode_tree_line    *line_list;
                     46:        u_int                     line_size;
                     47:
                     48:        u_int                     depth;
                     49:
                     50:        u_int                     width;
                     51:        u_int                     height;
                     52:
                     53:        u_int                     offset;
                     54:        u_int                     current;
                     55:
                     56:        struct screen             screen;
                     57: };
                     58:
                     59: struct mode_tree_item {
                     60:        struct mode_tree_item           *parent;
                     61:        void                            *itemdata;
                     62:        u_int                            line;
                     63:
                     64:        uint64_t                         tag;
                     65:        const char                      *name;
                     66:        const char                      *text;
                     67:
                     68:        int                              expanded;
                     69:        int                              tagged;
                     70:
                     71:        struct mode_tree_list            children;
                     72:        TAILQ_ENTRY(mode_tree_item)      entry;
                     73: };
                     74:
                     75: struct mode_tree_line {
                     76:        struct mode_tree_item           *item;
                     77:        u_int                            depth;
                     78:        int                              last;
                     79:        int                              flat;
                     80: };
                     81:
                     82: static void mode_tree_free_items(struct mode_tree_list *);
                     83:
                     84: static struct mode_tree_item *
                     85: mode_tree_find_item(struct mode_tree_list *mtl, uint64_t tag)
                     86: {
                     87:        struct mode_tree_item   *mti, *child;
                     88:
                     89:        TAILQ_FOREACH(mti, mtl, entry) {
                     90:                if (mti->tag == tag)
                     91:                        return (mti);
                     92:                child = mode_tree_find_item(&mti->children, tag);
                     93:                if (child != NULL)
                     94:                        return (child);
                     95:        }
                     96:        return (NULL);
                     97: }
                     98:
                     99: static void
                    100: mode_tree_free_item(struct mode_tree_item *mti)
                    101: {
                    102:        mode_tree_free_items(&mti->children);
                    103:
                    104:        free((void *)mti->name);
                    105:        free((void *)mti->text);
                    106:
                    107:        free(mti);
                    108: }
                    109:
                    110: static void
                    111: mode_tree_free_items(struct mode_tree_list *mtl)
                    112: {
                    113:        struct mode_tree_item   *mti, *mti1;
                    114:
                    115:        TAILQ_FOREACH_SAFE(mti, mtl, entry, mti1) {
                    116:                TAILQ_REMOVE(mtl, mti, entry);
                    117:                mode_tree_free_item(mti);
                    118:        }
                    119: }
                    120:
                    121: static void
                    122: mode_tree_clear_lines(struct mode_tree_data *mtd)
                    123: {
                    124:        free(mtd->line_list);
                    125:        mtd->line_list = NULL;
                    126:        mtd->line_size = 0;
                    127: }
                    128:
                    129: static void
                    130: mode_tree_build_lines(struct mode_tree_data *mtd,
                    131:     struct mode_tree_list *mtl, u_int depth)
                    132: {
                    133:        struct mode_tree_item   *mti;
                    134:        struct mode_tree_line   *line;
                    135:        u_int                    i;
                    136:        int                      flat = 1;
                    137:
                    138:        mtd->depth = depth;
                    139:        TAILQ_FOREACH(mti, mtl, entry) {
                    140:                mtd->line_list = xreallocarray(mtd->line_list,
                    141:                    mtd->line_size + 1, sizeof *mtd->line_list);
                    142:
                    143:                line = &mtd->line_list[mtd->line_size++];
                    144:                line->item = mti;
                    145:                line->depth = depth;
                    146:                line->last = (mti == TAILQ_LAST(mtl, mode_tree_list));
                    147:
                    148:                mti->line = (mtd->line_size - 1);
                    149:                if (!TAILQ_EMPTY(&mti->children))
                    150:                        flat = 0;
                    151:                if (mti->expanded)
                    152:                        mode_tree_build_lines(mtd, &mti->children, depth + 1);
                    153:        }
                    154:        TAILQ_FOREACH(mti, mtl, entry) {
                    155:                for (i = 0; i < mtd->line_size; i++) {
                    156:                        line = &mtd->line_list[i];
                    157:                        if (line->item == mti)
                    158:                                line->flat = flat;
                    159:                }
                    160:        }
                    161: }
                    162:
                    163: static void
                    164: mode_tree_clear_tagged(struct mode_tree_list *mtl)
                    165: {
                    166:        struct mode_tree_item   *mti;
                    167:
                    168:        TAILQ_FOREACH(mti, mtl, entry) {
                    169:                mti->tagged = 0;
                    170:                mode_tree_clear_tagged(&mti->children);
                    171:        }
                    172: }
                    173:
                    174: void
                    175: mode_tree_up(struct mode_tree_data *mtd, int wrap)
                    176: {
                    177:        if (mtd->current == 0) {
                    178:                if (wrap) {
                    179:                        mtd->current = mtd->line_size - 1;
                    180:                        if (mtd->line_size >= mtd->height)
                    181:                                mtd->offset = mtd->line_size - mtd->height;
                    182:                }
                    183:        } else {
                    184:                mtd->current--;
                    185:                if (mtd->current < mtd->offset)
                    186:                        mtd->offset--;
                    187:        }
                    188: }
                    189:
                    190: void
                    191: mode_tree_down(struct mode_tree_data *mtd, int wrap)
                    192: {
                    193:        if (mtd->current == mtd->line_size - 1) {
                    194:                if (wrap) {
                    195:                        mtd->current = 0;
                    196:                        mtd->offset = 0;
                    197:                }
                    198:        } else {
                    199:                mtd->current++;
                    200:                if (mtd->current > mtd->offset + mtd->height - 1)
                    201:                        mtd->offset++;
                    202:        }
                    203: }
                    204:
                    205: void *
                    206: mode_tree_get_current(struct mode_tree_data *mtd)
                    207: {
                    208:        return (mtd->line_list[mtd->current].item->itemdata);
                    209: }
                    210:
                    211: u_int
                    212: mode_tree_count_tagged(struct mode_tree_data *mtd)
                    213: {
                    214:        struct mode_tree_item   *mti;
                    215:        u_int                    i, tagged;
                    216:
                    217:        tagged = 0;
                    218:        for (i = 0; i < mtd->line_size; i++) {
                    219:                mti = mtd->line_list[i].item;
                    220:                if (mti->tagged)
                    221:                        tagged++;
                    222:        }
                    223:        return (tagged);
                    224: }
                    225:
                    226: void
                    227: mode_tree_each_tagged(struct mode_tree_data *mtd, void (*cb)(void *, void *,
                    228:     key_code), key_code key, int current)
                    229: {
                    230:        struct mode_tree_item   *mti;
                    231:        u_int                    i;
                    232:        int                      fired;
                    233:
                    234:        fired = 0;
                    235:        for (i = 0; i < mtd->line_size; i++) {
                    236:                mti = mtd->line_list[i].item;
                    237:                if (mti->tagged) {
                    238:                        fired = 1;
                    239:                        cb(mtd->modedata, mti->itemdata, key);
                    240:                }
                    241:        }
                    242:        if (!fired && current) {
                    243:                mti = mtd->line_list[mtd->current].item;
                    244:                cb(mtd->modedata, mti->itemdata, key);
                    245:        }
                    246: }
                    247:
                    248: struct mode_tree_data *
                    249: mode_tree_start(struct window_pane *wp, void (*buildcb)(void *, u_int,
                    250:     uint64_t *), struct screen *(*drawcb)(void *, void *, u_int, u_int),
                    251:     void *modedata, const char **sort_list, u_int sort_size, struct screen **s)
                    252: {
                    253:        struct mode_tree_data   *mtd;
                    254:
                    255:        mtd = xcalloc(1, sizeof *mtd);
                    256:        mtd->wp = wp;
                    257:        mtd->modedata = modedata;
                    258:
                    259:        mtd->sort_list = sort_list;
                    260:        mtd->sort_size = sort_size;
                    261:        mtd->sort_type = 0;
                    262:
                    263:        mtd->buildcb = buildcb;
                    264:        mtd->drawcb = drawcb;
                    265:
                    266:        TAILQ_INIT(&mtd->children);
                    267:
                    268:        *s = &mtd->screen;
                    269:        screen_init(*s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
                    270:        (*s)->mode &= ~MODE_CURSOR;
                    271:
                    272:        return (mtd);
                    273: }
                    274:
                    275: void
                    276: mode_tree_build(struct mode_tree_data *mtd)
                    277: {
                    278:        struct screen   *s = &mtd->screen;
                    279:        uint64_t         tag;
                    280:        u_int            i;
                    281:
                    282:        if (mtd->line_list != NULL)
                    283:                tag = mtd->line_list[mtd->current].item->tag;
                    284:        else
                    285:                tag = 0;
                    286:
                    287:        TAILQ_CONCAT(&mtd->saved, &mtd->children, entry);
                    288:        TAILQ_INIT(&mtd->children);
                    289:
                    290:        mtd->buildcb(mtd->modedata, mtd->sort_type, &tag);
                    291:
                    292:        mode_tree_free_items(&mtd->saved);
                    293:        TAILQ_INIT(&mtd->saved);
                    294:
                    295:        mode_tree_clear_lines(mtd);
                    296:        mode_tree_build_lines(mtd, &mtd->children, 0);
                    297:
                    298:        for (i = 0; i < mtd->line_size; i++) {
                    299:                if (mtd->line_list[i].item->tag == tag)
                    300:                        break;
                    301:        }
                    302:        if (i != mtd->line_size)
                    303:                mtd->current = i;
                    304:        else {
                    305:                mtd->current = 0;
                    306:                mtd->offset = 0;
                    307:        }
                    308:
                    309:        mtd->width = screen_size_x(s);
                    310:        mtd->height = (screen_size_y(s) / 3) * 2;
                    311:        if (mtd->height > mtd->line_size)
                    312:                mtd->height = screen_size_y(s) / 2;
                    313:        if (mtd->height < 10)
                    314:                mtd->height = screen_size_y(s);
                    315:        if (screen_size_y(s) - mtd->height < 2)
                    316:                mtd->height = screen_size_y(s);
                    317: }
                    318:
                    319: void
                    320: mode_tree_free(struct mode_tree_data *mtd)
                    321: {
                    322:        mode_tree_free_items(&mtd->children);
                    323:        mode_tree_clear_lines(mtd);
                    324:        screen_free(&mtd->screen);
                    325:        free(mtd);
                    326: }
                    327:
                    328: void
                    329: mode_tree_resize(struct mode_tree_data *mtd, u_int sx, u_int sy)
                    330: {
                    331:        struct screen   *s = &mtd->screen;
                    332:
                    333:        screen_resize(s, sx, sy, 0);
                    334:
                    335:        mode_tree_build(mtd);
                    336:        mode_tree_draw(mtd);
                    337:
                    338:        mtd->wp->flags |= PANE_REDRAW;
                    339: }
                    340:
                    341: struct mode_tree_item *
                    342: mode_tree_add(struct mode_tree_data *mtd, struct mode_tree_item *parent,
                    343:     void *itemdata, uint64_t tag, const char *name, const char *text,
                    344:     int expanded)
                    345: {
                    346:        struct mode_tree_item   *mti, *saved;
                    347:
                    348:        log_debug("%s: %llu, %s %s", __func__, (unsigned long long)tag,
                    349:            name, text);
                    350:
                    351:        mti = xcalloc(1, sizeof *mti);
                    352:        mti->parent = parent;
                    353:        mti->itemdata = itemdata;
                    354:
                    355:        mti->tag = tag;
                    356:        mti->name = xstrdup(name);
                    357:        mti->text = xstrdup(text);
                    358:
                    359:        saved = mode_tree_find_item(&mtd->saved, tag);
                    360:        if (saved != NULL) {
                    361:                if (parent == NULL || (parent != NULL && parent->expanded))
                    362:                        mti->tagged = saved->tagged;
                    363:                mti->expanded = saved->expanded;
                    364:        } else if (expanded == -1)
                    365:                mti->expanded = 1;
                    366:        else
                    367:                mti->expanded = expanded;
                    368:
                    369:        TAILQ_INIT(&mti->children);
                    370:
                    371:        if (parent != NULL)
                    372:                TAILQ_INSERT_TAIL(&parent->children, mti, entry);
                    373:        else
                    374:                TAILQ_INSERT_TAIL(&mtd->children, mti, entry);
                    375:
                    376:        return (mti);
                    377: }
                    378:
                    379: void
                    380: mode_tree_remove(struct mode_tree_data *mtd, struct mode_tree_item *mti)
                    381: {
                    382:        struct mode_tree_item   *parent = mti->parent;
                    383:
                    384:        if (parent != NULL)
                    385:                TAILQ_REMOVE(&parent->children, mti, entry);
                    386:        else
                    387:                TAILQ_REMOVE(&mtd->children, mti, entry);
                    388:        mode_tree_free_item(mti);
                    389: }
                    390:
                    391: void
                    392: mode_tree_draw(struct mode_tree_data *mtd)
                    393: {
                    394:        struct window_pane      *wp = mtd->wp;
                    395:        struct screen           *s = &mtd->screen, *box;
                    396:        struct mode_tree_line   *line;
                    397:        struct mode_tree_item   *mti;
                    398:        struct options          *oo = wp->window->options;
                    399:        struct screen_write_ctx  ctx;
                    400:        struct grid_cell         gc0, gc;
                    401:        u_int                    w, h, i, j, sy, box_x, box_y;
                    402:        char                    *text, *start, key[7];
                    403:        const char              *tag, *symbol;
                    404:        size_t                   size;
                    405:        int                      keylen;
                    406:
                    407:        if (mtd->line_size == 0)
                    408:                return;
                    409:
                    410:        memcpy(&gc0, &grid_default_cell, sizeof gc0);
                    411:        memcpy(&gc, &grid_default_cell, sizeof gc);
                    412:        style_apply(&gc, oo, "mode-style");
                    413:
                    414:        w = mtd->width;
                    415:        h = mtd->height;
                    416:
                    417:        screen_write_start(&ctx, NULL, s);
                    418:        screen_write_clearscreen(&ctx, 8);
                    419:
                    420:        if (mtd->line_size > 10)
                    421:                keylen = 6;
                    422:        else
                    423:                keylen = 4;
                    424:
                    425:        for (i = 0; i < mtd->line_size; i++) {
                    426:                if (i < mtd->offset)
                    427:                        continue;
                    428:                if (i > mtd->offset + h - 1)
                    429:                        break;
                    430:
                    431:                line = &mtd->line_list[i];
                    432:                mti = line->item;
                    433:
                    434:                screen_write_cursormove(&ctx, 0, i - mtd->offset);
                    435:
                    436:                if (i < 10)
                    437:                        snprintf(key, sizeof key, "(%c)", '0' + i);
                    438:                else if (i < 36)
                    439:                        snprintf(key, sizeof key, "(M-%c)", 'a' + (i - 10));
                    440:                else
                    441:                        *key = '\0';
                    442:
                    443:                if (line->flat)
                    444:                        symbol = "";
                    445:                else if (TAILQ_EMPTY(&mti->children))
                    446:                        symbol = "  ";
                    447:                else if (mti->expanded)
                    448:                        symbol = "- ";
                    449:                else
                    450:                        symbol = "+ ";
                    451:
                    452:                if (line->depth == 0)
                    453:                        start = xstrdup(symbol);
                    454:                else {
                    455:                        size = (4 * line->depth) + 32;
                    456:
                    457:                        start = xcalloc(1, size);
                    458:                        for (j = 1; j < line->depth; j++) {
                    459:                                if (mti->parent != NULL &&
                    460:                                    mtd->line_list[mti->parent->line].last)
                    461:                                        strlcat(start, "    ", size);
                    462:                                else
                    463:                                        strlcat(start, "\001x\001   ", size);
                    464:                        }
                    465:                        if (line->last)
                    466:                                strlcat(start, "\001mq\001> ", size);
                    467:                        else
                    468:                                strlcat(start, "\001tq\001> ", size);
                    469:                        strlcat(start, symbol, size);
                    470:                }
                    471:
                    472:                if (mti->tagged)
                    473:                        tag = "*";
                    474:                else
                    475:                        tag = "";
                    476:                xasprintf(&text, "%-*s%s%s%s: %s", keylen, key, start,
                    477:                    mti->name, tag, mti->text);
                    478:                free(start);
                    479:
                    480:                if (mti->tagged) {
                    481:                        gc.attr ^= GRID_ATTR_BRIGHT;
                    482:                        gc0.attr ^= GRID_ATTR_BRIGHT;
                    483:                }
                    484:
                    485:                if (i != mtd->current) {
                    486:                        screen_write_puts(&ctx, &gc0, "%.*s", w, text);
                    487:                        screen_write_clearendofline(&ctx, 8);
                    488:                } else
                    489:                        screen_write_puts(&ctx, &gc, "%-*.*s", w, w, text);
                    490:                free(text);
                    491:
                    492:                if (mti->tagged) {
                    493:                        gc.attr ^= GRID_ATTR_BRIGHT;
                    494:                        gc0.attr ^= GRID_ATTR_BRIGHT;
                    495:                }
                    496:        }
                    497:
                    498:        sy = screen_size_y(s);
                    499:        if (sy <= 4 || h <= 4 || sy - h <= 4 || w <= 4) {
                    500:                screen_write_stop(&ctx);
                    501:                return;
                    502:        }
                    503:
                    504:        line = &mtd->line_list[mtd->current];
                    505:        mti = line->item;
                    506:
                    507:        screen_write_cursormove(&ctx, 0, h);
                    508:        screen_write_box(&ctx, w, sy - h);
                    509:
                    510:        xasprintf(&text, " %s (sort: %s) ", mti->name,
                    511:            mtd->sort_list[mtd->sort_type]);
                    512:        if (w - 2 >= strlen(text)) {
                    513:                screen_write_cursormove(&ctx, 1, h);
                    514:                screen_write_puts(&ctx, &gc0, "%s", text);
                    515:        }
                    516:        free(text);
                    517:
                    518:        box_x = w - 4;
                    519:        box_y = sy - h - 2;
                    520:
                    521:        box = mtd->drawcb(mtd->modedata, mti->itemdata, box_x, box_y);
                    522:        if (box != NULL) {
                    523:                screen_write_cursormove(&ctx, 2, h + 1);
                    524:                screen_write_copy(&ctx, box, 0, 0, box_x, box_y, NULL, NULL);
                    525:
                    526:                screen_free(box);
                    527:        }
                    528:
                    529:        screen_write_stop(&ctx);
                    530: }
                    531:
                    532: int
                    533: mode_tree_key(struct mode_tree_data *mtd, key_code *key, struct mouse_event *m)
                    534: {
                    535:        struct mode_tree_line   *line;
                    536:        struct mode_tree_item   *current, *parent;
                    537:        u_int                    i, x, y;
                    538:        int                      choice;
                    539:        key_code                 tmp;
                    540:
                    541:        if (*key == KEYC_MOUSEDOWN1_PANE) {
                    542:                if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) {
                    543:                        *key = KEYC_NONE;
                    544:                        return (0);
                    545:                }
                    546:                if (x > mtd->width || y > mtd->height) {
                    547:                        *key = KEYC_NONE;
                    548:                        return (0);
                    549:                }
                    550:                if (mtd->offset + y < mtd->line_size) {
                    551:                        mtd->current = mtd->offset + y;
                    552:                        *key = '\r';
                    553:                        return (0);
                    554:                }
                    555:        }
                    556:
                    557:        line = &mtd->line_list[mtd->current];
                    558:        current = line->item;
                    559:
                    560:        choice = -1;
                    561:        if (*key >= '0' && *key <= '9')
                    562:                choice = (*key) - '0';
                    563:        else if (((*key) & KEYC_MASK_MOD) == KEYC_ESCAPE) {
                    564:                tmp = (*key) & KEYC_MASK_KEY;
                    565:                if (tmp >= 'a' && tmp <= 'z')
                    566:                        choice = 10 + (tmp - 'a');
                    567:        }
                    568:        if (choice != -1) {
                    569:                if ((u_int)choice > mtd->line_size - 1) {
                    570:                        *key = KEYC_NONE;
                    571:                        return (0);
                    572:                }
                    573:                mtd->current = choice;
                    574:                *key = '\r';
                    575:                return (0);
                    576:        }
                    577:
                    578:        switch (*key) {
                    579:        case 'q':
                    580:        case '\033': /* Escape */
                    581:                return (1);
                    582:        case KEYC_UP:
                    583:        case 'k':
                    584:        case KEYC_WHEELUP_PANE:
                    585:                mode_tree_up(mtd, 1);
                    586:                break;
                    587:        case KEYC_DOWN:
                    588:        case 'j':
                    589:        case KEYC_WHEELDOWN_PANE:
                    590:                mode_tree_down(mtd, 1);
                    591:                break;
                    592:        case KEYC_PPAGE:
                    593:        case '\002': /* C-b */
                    594:                for (i = 0; i < mtd->height; i++) {
                    595:                        if (mtd->current == 0)
                    596:                                break;
                    597:                        mode_tree_up(mtd, 1);
                    598:                }
                    599:                break;
                    600:        case KEYC_NPAGE:
                    601:        case '\006': /* C-f */
                    602:                for (i = 0; i < mtd->height; i++) {
                    603:                        if (mtd->current == mtd->line_size - 1)
                    604:                                break;
                    605:                        mode_tree_down(mtd, 1);
                    606:                }
                    607:                break;
                    608:        case KEYC_HOME:
                    609:                mtd->current = 0;
                    610:                mtd->offset = 0;
                    611:                break;
                    612:        case KEYC_END:
                    613:                mtd->current = mtd->line_size - 1;
                    614:                if (mtd->current > mtd->height - 1)
                    615:                        mtd->offset = mtd->current - mtd->height;
                    616:                else
                    617:                        mtd->offset = 0;
                    618:                break;
                    619:        case 't':
                    620:                /*
                    621:                 * Do not allow parents and children to both be tagged: untag
                    622:                 * all parents and children of current.
                    623:                 */
                    624:                if (!current->tagged) {
                    625:                        parent = current->parent;
                    626:                        while (parent != NULL) {
                    627:                                parent->tagged = 0;
                    628:                                parent = parent->parent;
                    629:                        }
                    630:                        mode_tree_clear_tagged(&current->children);
                    631:                        current->tagged = 1;
                    632:                } else
                    633:                        current->tagged = 0;
                    634:                mode_tree_down(mtd, 0);
                    635:                break;
                    636:        case 'T':
                    637:                for (i = 0; i < mtd->line_size; i++)
                    638:                        mtd->line_list[i].item->tagged = 0;
                    639:                break;
                    640:        case '\024': /* C-t */
                    641:                for (i = 0; i < mtd->line_size; i++) {
                    642:                        if (mtd->line_list[i].item->parent == NULL)
                    643:                                mtd->line_list[i].item->tagged = 1;
                    644:                        else
                    645:                                mtd->line_list[i].item->tagged = 0;
                    646:                }
                    647:                break;
                    648:        case 'O':
                    649:                mtd->sort_type++;
                    650:                if (mtd->sort_type == mtd->sort_size)
                    651:                        mtd->sort_type = 0;
                    652:                mode_tree_build(mtd);
                    653:                break;
                    654:        case KEYC_LEFT:
                    655:        case '-':
                    656:                if (line->flat || !current->expanded)
                    657:                        current = current->parent;
                    658:                if (current == NULL)
                    659:                        mode_tree_up(mtd, 0);
                    660:                else {
                    661:                        current->expanded = 0;
                    662:                        mtd->current = current->line;
                    663:                        mode_tree_build(mtd);
                    664:                }
                    665:                break;
                    666:        case KEYC_RIGHT:
                    667:        case '+':
                    668:                if (line->flat || current->expanded)
                    669:                        mode_tree_down(mtd, 0);
                    670:                else if (!line->flat) {
                    671:                        current->expanded = 1;
                    672:                        mode_tree_build(mtd);
                    673:                }
                    674:                break;
                    675:        }
                    676:        return (0);
                    677: }
                    678:
                    679: void
                    680: mode_tree_run_command(struct client *c, struct cmd_find_state *fs,
                    681:     const char *template, const char *name)
                    682: {
                    683:        struct cmdq_item        *new_item;
                    684:        struct cmd_list         *cmdlist;
                    685:        char                    *command, *cause;
                    686:
                    687:        command = cmd_template_replace(template, name, 1);
1.2     ! nicm      688:        if (command == NULL || *command == '\0') {
        !           689:                free(command);
1.1       nicm      690:                return;
1.2     ! nicm      691:        }
1.1       nicm      692:
                    693:        cmdlist = cmd_string_parse(command, NULL, 0, &cause);
                    694:        if (cmdlist == NULL) {
                    695:                if (cause != NULL && c != NULL) {
                    696:                        *cause = toupper((u_char)*cause);
                    697:                        status_message_set(c, "%s", cause);
                    698:                }
                    699:                free(cause);
                    700:        } else {
                    701:                new_item = cmdq_get_command(cmdlist, fs, NULL, 0);
                    702:                cmdq_append(c, new_item);
                    703:                cmd_list_free(cmdlist);
                    704:        }
                    705:
                    706:        free(command);
                    707: }