Exemplo n.º 1
0
/*
 * create_swindow: (re)create window with specified position and size.
 */
static void create_swindow(SWINDOW **win, int nlines, int ncols, int begin_y, int begin_x)
{
    if (*win)
    {
        int x = swin_getbegx(*win);
        int y = swin_getbegy(*win);
        int w = swin_getmaxx(*win);
        int h = swin_getmaxy(*win);

        /* If the window position + size hasn't changed, bail */
        if (x == begin_x && y == begin_y && w == ncols && h == nlines)
            return;

        /* Delete the existing window */
        swin_delwin(*win);
        *win = NULL;
    }

    if ((nlines > 0) && (ncols > 0))
    {
        /* Create the ncurses window */
        *win = swin_newwin(nlines, ncols, begin_y, begin_x);
        swin_werase(*win);
    }
}
Exemplo n.º 2
0
void source_hscroll(struct sviewer *sview, int offset)
{
    int lwidth;
    int max_width;
    int width, height;

    if (sview->cur) {
        height = swin_getmaxy(sview->win);
        width = swin_getmaxx(sview->win);

        lwidth = log10_uint(sbcount(sview->cur->file_buf.lines)) + 1;
        max_width = sview->cur->file_buf.max_width - width + lwidth + 6;

        sview->cur->sel_col += offset;
        if (sview->cur->sel_col > max_width)
            sview->cur->sel_col = max_width;
        if (sview->cur->sel_col < 0)
            sview->cur->sel_col = 0;
    }
}
Exemplo n.º 3
0
void filedlg_display_message(struct filedlg *fd, char *message)
{
    int height, width, i;
    int attr;

    attr = hl_groups_get_attr(hl_groups_instance, HLG_STATUS_BAR);

    height = swin_getmaxy(fd->win);
    width = swin_getmaxx(fd->win);

    /* Print white background */
    swin_wattron(fd->win, attr);

    for (i = 0; i < width; i++)
        swin_mvwprintw(fd->win, height - 1, i, " ");

    swin_mvwprintw(fd->win, height - 1, 0, "%s", message);
    swin_wattroff(fd->win, attr);
    swin_wrefresh(fd->win);
}
Exemplo n.º 4
0
/** 
 * Display the source.
 *
 * A line in the source viewer looks like,
 *   # │ marker text
 * where,
 *   # is the line number to display or ~ if no line number
 *   │ is the divider between the line number or it is a mark
 *   marker is shortarrow, longarrow, highlight, block, etc
 *   text is the source code to display
 *
 * The syntax highlighting works as follows,
 *
 * The #
 * - If breakpoint is set, use Breakpoint
 * - If breakpoint is disabled, use DisabledBreakpoint
 * - If selected line, use SelectedLineNr
 * - If executing line, use ExecutingLineNr
 * - Otherwise, no highlighting group
 *
 * The │ 
 * - When source window is in focus, the character is bolded, otherwise normal
 * - If the user has a mark set, the mark will be displayed instead of any
 *   other character.
 * - Edge case: When the marker is long or short arrow, CGDB prints ├
 *   instead of │ the ├ is colored based on highlighting group for 
 *   the selected or executing arrow.
 *
 * The marker
 * - The marker is the shortarrow, longarrow, highlight or block
 * - The color is based off the corresponding highlighting group
 *
 * The text
 * - The syntax highlighting source code to display
 * - Will be colored with SelectedLineHighlight or ExecutingLineHighlight
 *   if the line is the selected or executing line and the display is set
 *   to highlight.
 */
int source_display(struct sviewer *sview, int focus, enum win_refresh dorefresh)
{
    int i;
    int lwidth;
    int line;
    int count;

    enum LineDisplayStyle exe_display_style, sel_display_style;
    int sellineno, exelineno;
    int enabled_bp, disabled_bp;
    int exe_line_display_is_arrow, sel_line_display_is_arrow;
    int exe_arrow_attr, sel_arrow_attr;
    int exe_block_attr, sel_block_attr;
    char fmt[16];
    int width, height;
    int focus_attr = focus ? SWIN_A_BOLD : 0;
    int showmarks = cgdbrc_get_int(CGDBRC_SHOWMARKS);
    int hlsearch = cgdbrc_get_int(CGDBRC_HLSEARCH);
    int mark_attr;

    struct hl_line_attr *sel_highlight_attrs = 0;
    struct hl_line_attr *exe_highlight_attrs = 0;

    /* Check that a file is loaded */
    if (!sview->cur || !sview->cur->file_buf.lines) {
        logo_display(sview->win);

        if (dorefresh == WIN_REFRESH)
            swin_wrefresh(sview->win);
        else
            swin_wnoutrefresh(sview->win);

        return 0;
    }

    sellineno = hl_groups_get_attr(
        hl_groups_instance, HLG_SELECTED_LINE_NUMBER);
    exelineno = hl_groups_get_attr(
        hl_groups_instance, HLG_EXECUTING_LINE_NUMBER);
    enabled_bp = hl_groups_get_attr(
        hl_groups_instance, HLG_ENABLED_BREAKPOINT);
    disabled_bp = hl_groups_get_attr(
        hl_groups_instance, HLG_DISABLED_BREAKPOINT);

    exe_display_style = cgdbrc_get_displaystyle(CGDBRC_EXECUTING_LINE_DISPLAY);
    exe_arrow_attr = hl_groups_get_attr(
        hl_groups_instance, HLG_EXECUTING_LINE_ARROW);
    exe_block_attr = hl_groups_get_attr(
        hl_groups_instance, HLG_EXECUTING_LINE_BLOCK);

    sel_display_style = cgdbrc_get_displaystyle(CGDBRC_SELECTED_LINE_DISPLAY);
    sel_arrow_attr = hl_groups_get_attr(
        hl_groups_instance, HLG_SELECTED_LINE_ARROW);
    sel_block_attr = hl_groups_get_attr(
        hl_groups_instance, HLG_SELECTED_LINE_BLOCK);

    exe_line_display_is_arrow =
        exe_display_style == LINE_DISPLAY_SHORT_ARROW ||
        exe_display_style == LINE_DISPLAY_LONG_ARROW;
    sel_line_display_is_arrow = 
        sel_display_style == LINE_DISPLAY_SHORT_ARROW ||
        sel_display_style == LINE_DISPLAY_LONG_ARROW;

    mark_attr = hl_groups_get_attr(hl_groups_instance, HLG_MARK);

    sbpush(sel_highlight_attrs, hl_line_attr(0, HLG_SELECTED_LINE_HIGHLIGHT));
    sbpush(exe_highlight_attrs, hl_line_attr(0, HLG_EXECUTING_LINE_HIGHLIGHT));
    
    /* Make sure cursor is visible */
    swin_curs_set(!!focus);

    /* Initialize variables */
    height = swin_getmaxy(sview->win);
    width = swin_getmaxx(sview->win);

    /* Set starting line number (center source file if it's small enough) */
    count = sbcount(sview->cur->file_buf.lines);
    if (count < height) {
        line = (count - height) / 2;
    } else {
        line = sview->cur->sel_line - height / 2;
        if (line > count - height)
            line = count - height;
        else if (line < 0)
            line = 0;
    }

    /* Print 'height' lines of the file, starting at 'line' */
    lwidth = log10_uint(count) + 1;
    snprintf(fmt, sizeof(fmt), "%%%dd", lwidth);

    for (i = 0; i < height; i++, line++) {

        int column_offset = 0;
        /* Is this the current selected line? */
        int is_sel_line = (line >= 0 && sview->cur->sel_line == line);
        /* Is this the current executing line */
        int is_exe_line = (line >= 0 && sview->cur->exe_line == line);
        struct source_line *sline = (line < 0 || line >= count)?
            NULL:&sview->cur->file_buf.lines[line];
        struct hl_line_attr *printline_attrs = (sline)?sline->attrs:0;

        swin_wmove(sview->win, i, 0);

        /* Print the line number */
        if (line < 0 || line >= count) {
            for (int j = 1; j < lwidth; j++)
                swin_waddch(sview->win, ' ');
            swin_waddch(sview->win, '~');
        } else {
            int line_attr = 0;
            int bp_val = sview->cur->lflags[line].breakpt;
            if (bp_val == 1) {
                line_attr = enabled_bp;
            } else if (bp_val == 2) {
                line_attr = disabled_bp;
            } else if (bp_val == 0 && is_exe_line) {
                line_attr = exelineno;
            } else if (bp_val == 0 && is_sel_line) {
                line_attr = sellineno;
            }

            swin_wattron(sview->win, line_attr);
            swin_wprintw(sview->win, fmt, line + 1);
            swin_wattroff(sview->win, line_attr);
        }

        if (!swin_has_colors()) {
            /* TODO:
            swin_wprintw(sview->win, "%.*s\n",
                    sview->cur->file_buf.lines[line].line,
                    sview->cur->file_buf.lines[line].len);
            */
            continue;
        }

        /* Print the vertical bar or mark */
        {
            SWIN_CHTYPE vert_bar_char;
            int vert_bar_attr;
            int mc;

            if (showmarks &&
                ((mc = source_get_mark_char(sview, sview->cur, line)) > 0)) {
                vert_bar_char = mc;
                vert_bar_attr = mark_attr;
            } else if (is_exe_line && exe_line_display_is_arrow) {
                vert_bar_attr = exe_arrow_attr;
                vert_bar_char = SWIN_SYM_LTEE;
            } else if (is_sel_line && sel_line_display_is_arrow) {
                vert_bar_attr = sel_arrow_attr;
                vert_bar_char = SWIN_SYM_LTEE;
            } else {
                vert_bar_attr = focus_attr;
                vert_bar_char = SWIN_SYM_VLINE;
            }

            swin_wattron(sview->win, vert_bar_attr);
            swin_waddch(sview->win, vert_bar_char);
            swin_wattroff(sview->win, vert_bar_attr);
        }

        /* Print the marker */
        if (is_exe_line || is_sel_line) {
            enum LineDisplayStyle display_style;
            int arrow_attr, block_attr;
            struct hl_line_attr *highlight_attr;

            if (is_exe_line) {
                display_style = exe_display_style;
                arrow_attr = exe_arrow_attr;
                block_attr = exe_block_attr;
                highlight_attr = exe_highlight_attrs;
            } else {
                display_style = sel_display_style;
                arrow_attr = sel_arrow_attr;
                block_attr = sel_block_attr;
                highlight_attr = sel_highlight_attrs;
            }

            switch (display_style) {
                case LINE_DISPLAY_SHORT_ARROW:
                    swin_wattron(sview->win, arrow_attr);
                    swin_waddch(sview->win, '>');
                    swin_wattroff(sview->win, arrow_attr);
                    break;
                case LINE_DISPLAY_LONG_ARROW:
                    swin_wattron(sview->win, arrow_attr);
                    column_offset = get_line_leading_ws_count(
                        sline->line, sline->len);
                    column_offset -= (sview->cur->sel_col + 1);
                    if (column_offset < 0)
                        column_offset = 0;

                    /* Now actually draw the arrow */
                    for (int j = 0; j < column_offset; j++)
                        swin_waddch(sview->win, SWIN_SYM_HLINE);

                    swin_waddch(sview->win, '>');
                    swin_wattroff(sview->win, arrow_attr);

                    break;
                case LINE_DISPLAY_HIGHLIGHT:
                    swin_waddch(sview->win, ' ');
                    printline_attrs = highlight_attr;
                    break;
                case LINE_DISPLAY_BLOCK:
                    column_offset = get_line_leading_ws_count(
                        sline->line, sline->len);
                    column_offset -= (sview->cur->sel_col + 1);
                    if (column_offset < 0)
                        column_offset = 0;

                    /* Now actually draw the space to the block */
                    for (int j = 0; j < column_offset; j++)
                        swin_waddch(sview->win, ' ');

                    /* Draw the block */
                    swin_wattron(sview->win, block_attr);
                    swin_waddch(sview->win, ' ');
                    swin_wattroff(sview->win, block_attr);
                    break;
            }
        } else {
            swin_waddch(sview->win, ' ');
        }


        /* Print the text */
        if (line < 0 || line >= count) {
            for (int j = 2 + lwidth; j < width; j++)
                swin_waddch(sview->win, ' ');
        } else {
            int x, y;
            y = swin_getcury(sview->win);
            x = swin_getcurx(sview->win);

            hl_printline(sview->win, sline->line, sline->len,
                printline_attrs, -1, -1, sview->cur->sel_col + column_offset,
                width - lwidth - 2);

            if (hlsearch && sview->last_hlregex) {
                struct hl_line_attr *attrs = hl_regex_highlight(
                        &sview->last_hlregex, sline->line, HLG_SEARCH);
                if (sbcount(attrs)) {
                    hl_printline_highlight(sview->win, sline->line, sline->len,
                        attrs, x, y, sview->cur->sel_col + column_offset,
                        width - lwidth - 2);
                    sbfree(attrs);
                }
            }

            if (is_sel_line && sview->hlregex) {
                struct hl_line_attr *attrs = hl_regex_highlight(
                        &sview->hlregex, sline->line, HLG_INCSEARCH);
                if (sbcount(attrs)) {
                    hl_printline_highlight(sview->win, sline->line, sline->len,
                        attrs, x, y, sview->cur->sel_col + column_offset,
                        width - lwidth - 2);
                    sbfree(attrs);
                }
            }
        }
    }

    switch(dorefresh) {
        case WIN_NO_REFRESH:
            swin_wnoutrefresh(sview->win);
            break;
        case WIN_REFRESH:
            swin_wrefresh(sview->win);
            break;
    }

    sbfree(sel_highlight_attrs);
    sbfree(exe_highlight_attrs);

    return 0;
}
Exemplo n.º 5
0
/* parse: Translates special characters in a string.  (i.e. backspace, tab...)
 * ------
 *
 *   buf:  The string to parse
 *
 * Return Value:  A newly allocated copy of buf, with modifications made.
 */
static char *parse(struct scroller *scr, struct hl_line_attr **attrs,
    const char *orig, const char *buf, int buflen, enum ScrInputKind kind)
{
    // Read in tabstop settings, but don't change them on the fly as we'd have to
    //  store each previous line and recalculate every one of them.
    static const int tab_size = cgdbrc_get_int(CGDBRC_TABSTOP);
    int tabcount = count(buf, buflen, '\t');
    int orig_len = strlen(orig);
    int length = MAX(orig_len, scr->current.pos) + buflen +
        (tab_size - 1) * tabcount + 1;
    char *rv = (char *) cgdb_calloc(length, 1);
    int i, j;
    int debugwincolor = cgdbrc_get_int(CGDBRC_DEBUGWINCOLOR);
    int width, height;

    height = swin_getmaxy(scr->win);
    width = swin_getmaxx(scr->win);

    /* Copy over original buffer */
    strcpy(rv, orig);

    i = scr->current.pos;

    /* Expand special characters */
    for (j = 0; j < buflen; j++) {
        switch (buf[j]) {
                /* Backspace/Delete -> Erase last character */
            case 8:
            case 127:
                if (i > 0)
                    i--;
                break;
                /* Tab -> Translating to spaces */
            case '\t':
                do {
                    rv[i++] = ' ';
                } while (i % tab_size != 0);
                break;
                /* Carriage return -> Move back to the beginning of the line */
            case '\r':
                i = 0;
                if (buf[j + 1] != '\n') {
                    sbfree(*attrs);
                    *attrs = NULL;
                }
                break;
            case '\033':
                /* Handle ansi escape characters */
                if (hl_ansi_color_support(hl_groups_instance) &&
                    debugwincolor) {
                    int attr;
                    int ansi_count = hl_ansi_get_color_attrs(
                            hl_groups_instance, buf + j, &attr);
                    if (ansi_count) {
                        j += ansi_count - 1;
                        sbpush(*attrs, hl_line_attr(i, attr));
                    }
                } else {
                    rv[i++] = buf[j];
                }
                break;
            default:
                rv[i++] = buf[j];
                break;
        }
    }

    scr->current.pos = i;

    /**
     * The prompt should never be longer than the width of the terminal.
     *
     * The below should only be done for the readline prompt interaction,
     * not for text coming from gdb/inferior. Otherwise you'll truncate
     * their text in the scroller!
     *
     * When readline is working with the prompt (at least in "dumb" mode)
     * it assumes that the terminal will only display as many characters as
     * the terminal is wide. If the terminal is reduced in size (resized to a
     * smaller width) readline will only clear the number of characters
     * that will fit into the new terminal width. Our prompt may still
     * have a lot more characters than that (the characters that existed
     * in the prompt before the resize). This truncation of the prompt
     * is solving that problem.
     */
    size_t rvlength = strlen(rv);
    if (kind == SCR_INPUT_READLINE && rvlength >= width) {
        rv[width - 1] = 0;
    }

    return rv;
}
Exemplo n.º 6
0
void scr_refresh(struct scroller *scr, int focus, enum win_refresh dorefresh)
{
    int length;                 /* Length of current line */
    int nlines;                 /* Number of lines written so far */
    int r;                      /* Current row in scroller */
    int c;                      /* Current column in row */
    int width, height;          /* Width and height of window */
    int highlight_attr;
    int hlsearch = cgdbrc_get_int(CGDBRC_HLSEARCH);
    int rows_to_display = 0;

    /* Steal line highlight attribute for our scroll mode status */
    highlight_attr = hl_groups_get_attr(hl_groups_instance,
        HLG_SCROLL_MODE_STATUS);

    /* Sanity check */
    height = swin_getmaxy(scr->win);
    width = swin_getmaxx(scr->win);

    if (scr->current.c > 0) {
        if (scr->current.c % width != 0)
            scr->current.c = (scr->current.c / width) * width;
    }
    r = scr->current.r;
    c = scr->current.c;


    rows_to_display = number_rows_to_display(scr, height, width);

    /**
     * Printing the scroller to the gdb window.
     *
     * The gdb window has a certain dimension (height and width).
     * The scroller has a certain number of rows to print.
     *
     * When starting cgdb, or when the user clears the screen with Ctrl-L,
     * the entire scroller buffer is not displayed in the gdb window.
     *
     * The gdb readline input will be displayed just below the last
     * line of output in the scroller.
     *
     * In order to display the scroller buffer, first determine how many
     * lines should be displayed. Then start drawing from the bottom of
     * the viewable space and work our way up.
     */
    for (nlines = 1; nlines <= height; nlines++) {
        /* Empty lines below the scroller prompt should be empty.
         * When in scroller mode, there should be no empty lines on the
         * bottom. */
        if (!scr->in_scroll_mode && nlines <= height - rows_to_display) {
            swin_wmove(scr->win, height - nlines, 0);
            swin_wclrtoeol(scr->win);
        } 
        /* Print the current line [segment] */
        else if (r >= 0) {
            struct scroller_line *sline = &scr->lines[r];

            hl_printline(scr->win, sline->line, sline->line_len, sline->attrs, 0, height - nlines, c, width);

            /* If we're searching right now or we finished search
             * and have focus... */
            if (hlsearch && scr->last_hlregex && focus) {
                struct hl_line_attr *attrs = hl_regex_highlight(
                    &scr->last_hlregex, sline->line, HLG_SEARCH);

                if (sbcount(attrs)) {
                    hl_printline_highlight(scr->win, sline->line,
                        sline->line_len, attrs, 0, height - nlines, c, width);
                    sbfree(attrs);
                }
            }

            if (scr->hlregex && scr->current.r == r) {
                struct hl_line_attr *attrs = hl_regex_highlight(
                    &scr->hlregex, sline->line, HLG_INCSEARCH);

                if (sbcount(attrs)) {
                    hl_printline_highlight(scr->win, sline->line,
                        sline->line_len, attrs, 0, height - nlines, c, width);
                    sbfree(attrs);
                }
            }

            /* Update our position */
            if (c >= width)
                c -= width;
            else {
                r--;
                if (r >= 0) {
                    length = scr->lines[r].line_len;
                    if (length > width)
                        c = ((length - 1) / width) * width;
                }
            }
        /* Empty lines above the first line in the scroller should be empty.
         * Since the scroller starts at the top, this should only occur when
         * in the scroll mode. */
        } else {
            swin_wmove(scr->win, height - nlines, 0);
            swin_wclrtoeol(scr->win);
        }

        /* If we're in scroll mode and this is the top line, spew status on right */
        if (scr->in_scroll_mode && (nlines == height)) {
            char status[ 64 ];
            size_t status_len;

            snprintf(status, sizeof(status), "[%d/%d]", scr->current.r + 1, sbcount(scr->lines));

            status_len = strlen(status);
            if ( status_len < width ) {
                swin_wattron(scr->win, highlight_attr);
                swin_mvwprintw(scr->win, height - nlines, width - status_len, "%s", status);
                swin_wattroff(scr->win, highlight_attr);
            }
        }
    }

    length = scr->lines[scr->current.r].line_len - scr->current.c;

    /* Only show the cursor when
     * - the scroller is in focus
     * - on the last line
     * - when it is within the width of the screen
     * - when not in scroller mode
     */ 
    if (focus && scr->current.r == sbcount(scr->lines) - 1 &&
        length <= width && !scr->in_scroll_mode) {
        swin_curs_set(1);
        swin_wmove(scr->win, rows_to_display-1, scr->current.pos % width);
    } else {
        /* Hide the cursor */
        swin_curs_set(0);
    }

    switch(dorefresh) {
        case WIN_NO_REFRESH:
            swin_wnoutrefresh(scr->win);
            break;
        case WIN_REFRESH:
            swin_wrefresh(scr->win);
            break;
    }
}
Exemplo n.º 7
0
int filedlg_recv_char(struct filedlg *fd, int key, char *file, int last_key_pressed)
{
    /* Initialize size variables */
    int height = swin_getmaxy(fd->win);

    filedlg_display(fd);

    switch (key) {
        case 'q':
            return -1;
            /* Vertical scrolling */
        case CGDB_KEY_DOWN:
        case 'j':
            filedlg_vscroll(fd, 1);
            break;
        case CGDB_KEY_NPAGE:
        case CGDB_KEY_CTRL_F:  /* VI-style page down */
            filedlg_vscroll(fd, height - 1);
            break;
        case CGDB_KEY_CTRL_D:  /* VI-style 1/2 page down */
            filedlg_vscroll(fd, height / 2);
            break;
        case CGDB_KEY_CTRL_U:  /* VI-style 1/2 page up */
            filedlg_vscroll(fd, -height / 2);
            break;
        case CGDB_KEY_UP:
        case 'k':
            filedlg_vscroll(fd, -1);
            break;
        case CGDB_KEY_PPAGE:
        case CGDB_KEY_CTRL_B:  /* VI-style page up */
            filedlg_vscroll(fd, -(height - 1));
            break;
            /* Horizontal scrolling */
        case CGDB_KEY_RIGHT:
        case 'l':
            filedlg_hscroll(fd, 1);
            break;
        case CGDB_KEY_LEFT:
        case 'h':
            filedlg_hscroll(fd, -1);
            break;
        case '/':
        case '?':
            regex_direction = ('/' == key);

            /* Capturing regular expressions */
            filedlg_search_regex_init(fd);
            capture_regex(fd);
            break;
        case 'n':
            filedlg_search_regex(fd, regex_line, 2, regex_direction, 1);
            break;
        case 'N':
            filedlg_search_regex(fd, regex_line, 2, !regex_direction, 1);
            break;
            /* User selected a file */
        case '\n':
        case '\r':
        case CGDB_KEY_CTRL_M:
            strcpy(file, fd->buf->files[fd->buf->sel_line]);
            return 1;

        case 'g':              /* beginning of file */
            if (last_key_pressed == 'g')
                filedlg_set_sel_line(fd, 0);
            break;
        case 'G': {             /* end of file, or a line number*/
            int lineno = -1, result;
            result = cgdb_string_to_int(ibuf_get(fd->G_line_number), &lineno);
            if (result == 0) {
                filedlg_set_sel_line(fd, lineno -1);
            }
            break;
        }
        default:
            break;
    }

    /* Store digits into G_line_number for 'G' command. */
    if (key >= '0' && key <= '9') {
        ibuf_addchar(fd->G_line_number, key);
    } else {
        ibuf_clear(fd->G_line_number);
    }

    filedlg_display(fd);

    return 0;
}
Exemplo n.º 8
0
int filedlg_display(struct filedlg *fd)
{
    char fmt[16];
    int width, height;
    int lwidth;
    int file;
    int i;
    int statusbar;
    int arrow_attr;
    int count = sbcount(fd->buf->files);
    int hlsearch = cgdbrc_get_int(CGDBRC_HLSEARCH);
    static const char label[] = "Select a file or press q to cancel.";
    int inc_search_attr = hl_groups_get_attr(hl_groups_instance, HLG_INCSEARCH);
    int search_attr = hl_groups_get_attr(hl_groups_instance, HLG_SEARCH);

    swin_curs_set(0);

    statusbar = hl_groups_get_attr(hl_groups_instance, HLG_STATUS_BAR);
    arrow_attr = hl_groups_get_attr(hl_groups_instance, HLG_SELECTED_LINE_ARROW);

    /* Check that a file is loaded */
    if (fd == NULL || fd->buf == NULL || fd->buf->files == NULL) {
        swin_wrefresh(fd->win);
        return 0;
    }

    /* Initialize variables */
    height = swin_getmaxy(fd->win);
    width = swin_getmaxx(fd->win);

    /* The status bar and display line 
     * Fake the display function to think the height is 2 lines less */
    height -= 2;

    /* Set starting line number (center source file if it's small enough) */
    if (count < height)
        file = (count - height) / 2;
    else {
        file = fd->buf->sel_line - height / 2;
        if (file > count - height)
            file = count - height;
        else if (file < 0)
            file = 0;
    }

    /* Print 'height' lines of the file, starting at 'file' */
    lwidth = log10_uint(count) + 1;
    snprintf(fmt, sizeof(fmt), "%%%dd", lwidth);

    print_in_middle(fd->win, 0, width, label);

    swin_wmove(fd->win, 0, 0);

    for (i = 1; i < height + 1; i++, file++) {
        swin_wmove(fd->win, i, 0);

        /* Outside of filename, just finish drawing the vertical file */
        if (file < 0 || file >= count) {
            int j;

            for (j = 1; j < lwidth; j++)
                swin_waddch(fd->win, ' ');
            swin_waddch(fd->win, '~');

            swin_wattron(fd->win, SWIN_A_BOLD);
            swin_waddch(fd->win, SWIN_SYM_VLINE);
            swin_wattroff(fd->win, SWIN_A_BOLD);

            for (j = 2 + lwidth; j < width; j++)
                swin_waddch(fd->win, ' ');
            continue;
        }

        int x, y;
        char *filename = fd->buf->files[file];

        /* Mark the current file with an arrow */
        if (file == fd->buf->sel_line) {
            swin_wattron(fd->win, SWIN_A_BOLD);
            swin_wprintw(fd->win, fmt, file + 1);
            swin_wattroff(fd->win, SWIN_A_BOLD);

            swin_wattron(fd->win, arrow_attr);
            swin_waddch(fd->win, '-');
            swin_waddch(fd->win, '>');
            swin_wattroff(fd->win, arrow_attr);

        }
        else {
            /* Ordinary file */
            swin_wprintw(fd->win, fmt, file + 1);

            swin_wattron(fd->win, SWIN_A_BOLD);
            swin_waddch(fd->win, SWIN_SYM_VLINE);
            swin_wattroff(fd->win, SWIN_A_BOLD);

            swin_waddch(fd->win, ' ');
        }

        y = swin_getcury(fd->win);
        x = swin_getcurx(fd->win);

        hl_printline(fd->win, filename, strlen(filename),
                     NULL, -1, -1, fd->buf->sel_col, width - lwidth - 2);

        if (hlsearch && fd->last_hlregex) {
            struct hl_line_attr *attrs = hl_regex_highlight(
                    &fd->last_hlregex, filename, search_attr);

            if (sbcount(attrs)) {
                hl_printline_highlight(fd->win, filename, strlen(filename),
                             attrs, x, y, fd->buf->sel_col, width - lwidth - 2);
                sbfree(attrs);
            }
        }

        if (regex_search && file == fd->buf->sel_line) {
            struct hl_line_attr *attrs = hl_regex_highlight(
                    &fd->hlregex, filename, inc_search_attr);

            if (sbcount(attrs)) {
                hl_printline_highlight(fd->win, filename, strlen(filename),
                             attrs, x, y, fd->buf->sel_col, width - lwidth - 2);
                sbfree(attrs);
            }
        }
    }

    /* Add the 2 lines back in so the status bar can be drawn */
    height += 2;

    /* Update status bar */
    swin_wmove(fd->win, height, 0);

    /* Print white background */
    swin_wattron(fd->win, statusbar);

    for (i = 0; i < width; i++)
        swin_mvwprintw(fd->win, height - 1, i, " ");

    if (regex_search && regex_direction)
        swin_mvwprintw(fd->win, height - 1, 0, "Search:%s", regex_line);
    else if (regex_search)
        swin_mvwprintw(fd->win, height - 1, 0, "RSearch:%s", regex_line);

    swin_wattroff(fd->win, statusbar);

    swin_wmove(fd->win, height - (file - fd->buf->sel_line) - 1, lwidth + 2);
    swin_wrefresh(fd->win);

    return 0;
}