mirror of
https://github.com/tmux/tmux.git
synced 2025-03-25 15:28:49 +00:00
Merge branch 'obsd-master'
This commit is contained in:
commit
962f255ee8
@ -132,6 +132,7 @@ dist_tmux_SOURCES = \
|
|||||||
control.c \
|
control.c \
|
||||||
environ.c \
|
environ.c \
|
||||||
format.c \
|
format.c \
|
||||||
|
format-draw.c \
|
||||||
grid-view.c \
|
grid-view.c \
|
||||||
grid.c \
|
grid.c \
|
||||||
hooks.c \
|
hooks.c \
|
||||||
|
871
format-draw.c
Normal file
871
format-draw.c
Normal file
@ -0,0 +1,871 @@
|
|||||||
|
/* $OpenBSD$ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tmux.h"
|
||||||
|
|
||||||
|
/* Format range. */
|
||||||
|
struct format_range {
|
||||||
|
u_int index;
|
||||||
|
struct screen *s;
|
||||||
|
|
||||||
|
u_int start;
|
||||||
|
u_int end;
|
||||||
|
|
||||||
|
enum style_range_type type;
|
||||||
|
u_int argument;
|
||||||
|
|
||||||
|
TAILQ_ENTRY(format_range) entry;
|
||||||
|
};
|
||||||
|
TAILQ_HEAD(format_ranges, format_range);
|
||||||
|
|
||||||
|
/* Does this range match this style? */
|
||||||
|
static int
|
||||||
|
format_is_type(struct format_range *fr, struct style *sy)
|
||||||
|
{
|
||||||
|
if (fr->type != sy->range_type)
|
||||||
|
return (0);
|
||||||
|
if (fr->type == STYLE_RANGE_WINDOW &&
|
||||||
|
fr->argument != sy->range_argument)
|
||||||
|
return (0);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free a range. */
|
||||||
|
static void
|
||||||
|
format_free_range(struct format_ranges *frs, struct format_range *fr)
|
||||||
|
{
|
||||||
|
TAILQ_REMOVE(frs, fr, entry);
|
||||||
|
free(fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix range positions. */
|
||||||
|
static void
|
||||||
|
format_update_ranges(struct format_ranges *frs, struct screen *s, u_int offset,
|
||||||
|
u_int start, u_int width)
|
||||||
|
{
|
||||||
|
struct format_range *fr, *fr1;
|
||||||
|
|
||||||
|
if (frs == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(fr, frs, entry, fr1) {
|
||||||
|
if (fr->s != s)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (fr->end <= start || fr->start >= start + width) {
|
||||||
|
format_free_range(frs, fr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fr->start < start)
|
||||||
|
fr->start = start;
|
||||||
|
if (fr->end > start + width)
|
||||||
|
fr->end = start + width;
|
||||||
|
if (fr->start == fr->end) {
|
||||||
|
format_free_range(frs, fr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fr->start += offset;
|
||||||
|
fr->end += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a part of the format. */
|
||||||
|
static void
|
||||||
|
format_draw_put(struct screen_write_ctx *octx, u_int ocx, u_int ocy,
|
||||||
|
struct screen *s, struct format_ranges *frs, u_int offset, u_int start,
|
||||||
|
u_int width)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The offset is how far from the cursor on the target screen; start
|
||||||
|
* and width how much to copy from the source screen.
|
||||||
|
*/
|
||||||
|
screen_write_cursormove(octx, ocx + offset, ocy, 0);
|
||||||
|
screen_write_fast_copy(octx, s, start, 0, width, 1);
|
||||||
|
format_update_ranges(frs, s, offset, start, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw list part of format. */
|
||||||
|
static void
|
||||||
|
format_draw_put_list(struct screen_write_ctx *octx,
|
||||||
|
u_int ocx, u_int ocy, u_int offset, u_int width, struct screen *list,
|
||||||
|
struct screen *list_left, struct screen *list_right, int focus_start,
|
||||||
|
int focus_end, struct format_ranges *frs)
|
||||||
|
{
|
||||||
|
u_int start, focus_centre;
|
||||||
|
|
||||||
|
/* If there is enough space for the list, draw it entirely. */
|
||||||
|
if (width >= list->cx) {
|
||||||
|
format_draw_put(octx, ocx, ocy, list, frs, offset, 0, width);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The list needs to be trimmed. Try to keep the focus visible. */
|
||||||
|
focus_centre = focus_start + (focus_end - focus_start) / 2;
|
||||||
|
if (focus_centre < width / 2)
|
||||||
|
start = 0;
|
||||||
|
else
|
||||||
|
start = focus_centre - width / 2;
|
||||||
|
if (start + width > list->cx)
|
||||||
|
start = list->cx - width;
|
||||||
|
|
||||||
|
/* Draw <> markers at either side if needed. */
|
||||||
|
if (start != 0 && width > list_left->cx) {
|
||||||
|
screen_write_cursormove(octx, ocx + offset, ocy, 0);
|
||||||
|
screen_write_fast_copy(octx, list_left, 0, 0, list_left->cx, 1);
|
||||||
|
offset += list_left->cx;
|
||||||
|
start += list_left->cx;
|
||||||
|
width -= list_left->cx;
|
||||||
|
}
|
||||||
|
if (start + width < list->cx && width > list_right->cx) {
|
||||||
|
screen_write_cursormove(octx, ocx + offset + width - 1, ocy, 0);
|
||||||
|
screen_write_fast_copy(octx, list_right, 0, 0, list_right->cx,
|
||||||
|
1);
|
||||||
|
width -= list_right->cx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw the list screen itself. */
|
||||||
|
format_draw_put(octx, ocx, ocy, list, frs, offset, start, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw format with no list. */
|
||||||
|
static void
|
||||||
|
format_draw_none(struct screen_write_ctx *octx, u_int available, u_int ocx,
|
||||||
|
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
|
||||||
|
struct format_ranges *frs)
|
||||||
|
{
|
||||||
|
u_int width_left, width_centre, width_right;
|
||||||
|
|
||||||
|
width_left = left->cx;
|
||||||
|
width_centre = centre->cx;
|
||||||
|
width_right = right->cx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to keep as much of the left and right as possible at the expense
|
||||||
|
* of the centre.
|
||||||
|
*/
|
||||||
|
while (width_left + width_centre + width_right > available) {
|
||||||
|
if (width_centre > 0)
|
||||||
|
width_centre--;
|
||||||
|
else if (width_right > 0)
|
||||||
|
width_right--;
|
||||||
|
else
|
||||||
|
width_left--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write left. */
|
||||||
|
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
|
||||||
|
|
||||||
|
/* Write right at available - width_right. */
|
||||||
|
format_draw_put(octx, ocx, ocy, right, frs,
|
||||||
|
available - width_right,
|
||||||
|
right->cx - width_right,
|
||||||
|
width_right);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write centre halfway between
|
||||||
|
* width_left
|
||||||
|
* and
|
||||||
|
* available - width_right.
|
||||||
|
*/
|
||||||
|
format_draw_put(octx, ocx, ocy, centre, frs,
|
||||||
|
width_left
|
||||||
|
+ ((available - width_right) - width_left) / 2
|
||||||
|
- width_centre / 2,
|
||||||
|
centre->cx / 2 - width_centre / 2,
|
||||||
|
width_centre);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw format with list on the left. */
|
||||||
|
static void
|
||||||
|
format_draw_left(struct screen_write_ctx *octx, u_int available, u_int ocx,
|
||||||
|
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
|
||||||
|
struct screen *list, struct screen *list_left, struct screen *list_right,
|
||||||
|
struct screen *after, int focus_start, int focus_end,
|
||||||
|
struct format_ranges *frs)
|
||||||
|
{
|
||||||
|
u_int width_left, width_centre, width_right;
|
||||||
|
u_int width_list, width_after;
|
||||||
|
struct screen_write_ctx ctx;
|
||||||
|
|
||||||
|
width_left = left->cx;
|
||||||
|
width_centre = centre->cx;
|
||||||
|
width_right = right->cx;
|
||||||
|
width_list = list->cx;
|
||||||
|
width_after = after->cx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trim first the centre, then the list, then the right, then after the
|
||||||
|
* list, then the left.
|
||||||
|
*/
|
||||||
|
while (width_left +
|
||||||
|
width_centre +
|
||||||
|
width_right +
|
||||||
|
width_list +
|
||||||
|
width_after > available) {
|
||||||
|
if (width_centre > 0)
|
||||||
|
width_centre--;
|
||||||
|
else if (width_list > 0)
|
||||||
|
width_list--;
|
||||||
|
else if (width_right > 0)
|
||||||
|
width_right--;
|
||||||
|
else if (width_after > 0)
|
||||||
|
width_after--;
|
||||||
|
else
|
||||||
|
width_left--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there is no list left, pass off to the no list function. */
|
||||||
|
if (width_list == 0) {
|
||||||
|
screen_write_start(&ctx, NULL, left);
|
||||||
|
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
|
||||||
|
screen_write_stop(&ctx);
|
||||||
|
|
||||||
|
format_draw_none(octx, available, ocx, ocy, left, centre,
|
||||||
|
right, frs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write left at 0. */
|
||||||
|
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
|
||||||
|
|
||||||
|
/* Write right at available - width_right. */
|
||||||
|
format_draw_put(octx, ocx, ocy, right, frs,
|
||||||
|
available - width_right,
|
||||||
|
right->cx - width_right,
|
||||||
|
width_right);
|
||||||
|
|
||||||
|
/* Write after at width_left + width_list. */
|
||||||
|
format_draw_put(octx, ocx, ocy, after, frs,
|
||||||
|
width_left + width_list,
|
||||||
|
0,
|
||||||
|
width_after);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write centre halfway between
|
||||||
|
* width_left + width_list + width_after
|
||||||
|
* and
|
||||||
|
* available - width_right.
|
||||||
|
*/
|
||||||
|
format_draw_put(octx, ocx, ocy, centre, frs,
|
||||||
|
(width_left + width_list + width_after)
|
||||||
|
+ ((available - width_right)
|
||||||
|
- (width_left + width_list + width_after)) / 2
|
||||||
|
- width_centre / 2,
|
||||||
|
centre->cx / 2 - width_centre / 2,
|
||||||
|
width_centre);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The list now goes from
|
||||||
|
* width_left
|
||||||
|
* to
|
||||||
|
* width_left + width_list.
|
||||||
|
* If there is no focus given, keep the left in focus.
|
||||||
|
*/
|
||||||
|
if (focus_start == -1 || focus_end == -1)
|
||||||
|
focus_start = focus_end = 0;
|
||||||
|
format_draw_put_list(octx, ocx, ocy, width_left, width_list, list,
|
||||||
|
list_left, list_right, focus_start, focus_end, frs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw format with list in the centre. */
|
||||||
|
static void
|
||||||
|
format_draw_centre(struct screen_write_ctx *octx, u_int available, u_int ocx,
|
||||||
|
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
|
||||||
|
struct screen *list, struct screen *list_left, struct screen *list_right,
|
||||||
|
struct screen *after, int focus_start, int focus_end,
|
||||||
|
struct format_ranges *frs)
|
||||||
|
{
|
||||||
|
u_int width_left, width_centre, width_right;
|
||||||
|
u_int width_list, width_after, middle;
|
||||||
|
struct screen_write_ctx ctx;
|
||||||
|
|
||||||
|
width_left = left->cx;
|
||||||
|
width_centre = centre->cx;
|
||||||
|
width_right = right->cx;
|
||||||
|
width_list = list->cx;
|
||||||
|
width_after = after->cx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trim first the list, then after the list, then the centre, then the
|
||||||
|
* right, then the left.
|
||||||
|
*/
|
||||||
|
while (width_left +
|
||||||
|
width_centre +
|
||||||
|
width_right +
|
||||||
|
width_list +
|
||||||
|
width_after > available) {
|
||||||
|
if (width_list > 0)
|
||||||
|
width_list--;
|
||||||
|
else if (width_after > 0)
|
||||||
|
width_after--;
|
||||||
|
else if (width_centre > 0)
|
||||||
|
width_centre--;
|
||||||
|
else if (width_right > 0)
|
||||||
|
width_right--;
|
||||||
|
else
|
||||||
|
width_left--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there is no list left, pass off to the no list function. */
|
||||||
|
if (width_list == 0) {
|
||||||
|
screen_write_start(&ctx, NULL, centre);
|
||||||
|
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
|
||||||
|
screen_write_stop(&ctx);
|
||||||
|
|
||||||
|
format_draw_none(octx, available, ocx, ocy, left, centre,
|
||||||
|
right, frs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write left at 0. */
|
||||||
|
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
|
||||||
|
|
||||||
|
/* Write after at available - width_after. */
|
||||||
|
format_draw_put(octx, ocx, ocy, after, frs,
|
||||||
|
available - width_after,
|
||||||
|
after->cx - width_after,
|
||||||
|
width_after);
|
||||||
|
|
||||||
|
/* Write right at available - width_right. */
|
||||||
|
format_draw_put(octx, ocx, ocy, right, frs,
|
||||||
|
available - width_right,
|
||||||
|
right->cx - width_right,
|
||||||
|
width_right);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All three centre sections are offset from the middle of the
|
||||||
|
* available space.
|
||||||
|
*/
|
||||||
|
middle = (width_left + ((available - width_right) - width_left) / 2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write centre at
|
||||||
|
* middle - width_list / 2 - width_centre.
|
||||||
|
*/
|
||||||
|
format_draw_put(octx, ocx, ocy, centre, frs,
|
||||||
|
middle - width_list / 2 - width_centre,
|
||||||
|
0,
|
||||||
|
width_centre);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write after at
|
||||||
|
* middle + width_list / 2 - width_centre.
|
||||||
|
*/
|
||||||
|
format_draw_put(octx, ocx, ocy, after, frs,
|
||||||
|
middle + width_list / 2,
|
||||||
|
0,
|
||||||
|
width_after);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The list now goes from
|
||||||
|
* middle - width_list / 2
|
||||||
|
* to
|
||||||
|
* middle + width_list / 2
|
||||||
|
* If there is no focus given, keep the centre in focus.
|
||||||
|
*/
|
||||||
|
if (focus_start == -1 || focus_end == -1)
|
||||||
|
focus_start = focus_end = list->cx / 2;
|
||||||
|
format_draw_put_list(octx, ocx, ocy, middle - width_list / 2,
|
||||||
|
width_list, list, list_left, list_right, focus_start, focus_end,
|
||||||
|
frs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw format with list on the right. */
|
||||||
|
static void
|
||||||
|
format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx,
|
||||||
|
u_int ocy, struct screen *left, struct screen *centre, struct screen *right,
|
||||||
|
struct screen *list, struct screen *list_left, struct screen *list_right,
|
||||||
|
struct screen *after, int focus_start, int focus_end,
|
||||||
|
struct format_ranges *frs)
|
||||||
|
{
|
||||||
|
u_int width_left, width_centre, width_right;
|
||||||
|
u_int width_list, width_after;
|
||||||
|
struct screen_write_ctx ctx;
|
||||||
|
|
||||||
|
width_left = left->cx;
|
||||||
|
width_centre = centre->cx;
|
||||||
|
width_right = right->cx;
|
||||||
|
width_list = list->cx;
|
||||||
|
width_after = after->cx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trim first the centre, then the list, then the right, then
|
||||||
|
* after the list, then the left.
|
||||||
|
*/
|
||||||
|
while (width_left +
|
||||||
|
width_centre +
|
||||||
|
width_right +
|
||||||
|
width_list +
|
||||||
|
width_after > available) {
|
||||||
|
if (width_centre > 0)
|
||||||
|
width_centre--;
|
||||||
|
else if (width_list > 0)
|
||||||
|
width_list--;
|
||||||
|
else if (width_right > 0)
|
||||||
|
width_right--;
|
||||||
|
else if (width_after > 0)
|
||||||
|
width_after--;
|
||||||
|
else
|
||||||
|
width_left--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there is no list left, pass off to the no list function. */
|
||||||
|
if (width_list == 0) {
|
||||||
|
screen_write_start(&ctx, NULL, right);
|
||||||
|
screen_write_fast_copy(&ctx, after, 0, 0, width_after, 1);
|
||||||
|
screen_write_stop(&ctx);
|
||||||
|
|
||||||
|
format_draw_none(octx, available, ocx, ocy, left, centre,
|
||||||
|
right, frs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write left at 0. */
|
||||||
|
format_draw_put(octx, ocx, ocy, left, frs, 0, 0, width_left);
|
||||||
|
|
||||||
|
/* Write after at available - width_after. */
|
||||||
|
format_draw_put(octx, ocx, ocy, after, frs,
|
||||||
|
available - width_after,
|
||||||
|
after->cx - width_after,
|
||||||
|
width_after);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write right at
|
||||||
|
* available - width_right - width_list - width_after.
|
||||||
|
*/
|
||||||
|
format_draw_put(octx, ocx, ocy, right, frs,
|
||||||
|
available - width_right - width_list - width_after,
|
||||||
|
0,
|
||||||
|
width_right);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write centre halfway between
|
||||||
|
* width_left
|
||||||
|
* and
|
||||||
|
* available - width_right - width_list - width_after.
|
||||||
|
*/
|
||||||
|
format_draw_put(octx, ocx, ocy, centre, frs,
|
||||||
|
width_left
|
||||||
|
+ ((available - width_right - width_list - width_after)
|
||||||
|
- width_left) / 2
|
||||||
|
- width_centre / 2,
|
||||||
|
centre->cx / 2 - width_centre / 2,
|
||||||
|
width_centre);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The list now goes from
|
||||||
|
* available - width_list - width_after
|
||||||
|
* to
|
||||||
|
* available - width_after
|
||||||
|
* If there is no focus given, keep the right in focus.
|
||||||
|
*/
|
||||||
|
if (focus_start == -1 || focus_end == -1)
|
||||||
|
focus_start = focus_end = 0;
|
||||||
|
format_draw_put_list(octx, ocx, ocy, available - width_list -
|
||||||
|
width_after, width_list, list, list_left, list_right, focus_start,
|
||||||
|
focus_end, frs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a format to a screen. */
|
||||||
|
void
|
||||||
|
format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
||||||
|
u_int available, const char *expanded, struct style_ranges *srs)
|
||||||
|
{
|
||||||
|
enum { LEFT,
|
||||||
|
CENTRE,
|
||||||
|
RIGHT,
|
||||||
|
LIST,
|
||||||
|
LIST_LEFT,
|
||||||
|
LIST_RIGHT,
|
||||||
|
AFTER,
|
||||||
|
TOTAL } current = LEFT, last = LEFT;
|
||||||
|
const char *names[] = { "LEFT",
|
||||||
|
"CENTRE",
|
||||||
|
"RIGHT",
|
||||||
|
"LIST",
|
||||||
|
"LIST_LEFT",
|
||||||
|
"LIST_RIGHT",
|
||||||
|
"AFTER" };
|
||||||
|
size_t size = strlen(expanded);
|
||||||
|
struct screen *os = octx->s, s[TOTAL];
|
||||||
|
struct screen_write_ctx ctx[TOTAL];
|
||||||
|
u_int ocx = os->cx, ocy = os->cy, i, width[TOTAL];
|
||||||
|
u_int map[] = { LEFT, LEFT, CENTRE, RIGHT };
|
||||||
|
int focus_start = -1, focus_end = -1;
|
||||||
|
int list_state = -1;
|
||||||
|
enum style_align list_align = STYLE_ALIGN_DEFAULT;
|
||||||
|
struct style sy;
|
||||||
|
struct utf8_data *ud = &sy.gc.data;
|
||||||
|
const char *cp, *end;
|
||||||
|
enum utf8_state more;
|
||||||
|
char *tmp;
|
||||||
|
struct format_range *fr = NULL, *fr1;
|
||||||
|
struct format_ranges frs;
|
||||||
|
struct style_range *sr;
|
||||||
|
|
||||||
|
style_set(&sy, base);
|
||||||
|
TAILQ_INIT(&frs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We build three screens for left, right, centre alignment, one for
|
||||||
|
* the list, one for anything after the list and two for the list left
|
||||||
|
* and right markers.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < TOTAL; i++) {
|
||||||
|
screen_init(&s[i], size, 1, 0);
|
||||||
|
screen_write_start(&ctx[i], NULL, &s[i]);
|
||||||
|
screen_write_clearendofline(&ctx[i], base->bg);
|
||||||
|
width[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Walk the string and add to the corresponding screens,
|
||||||
|
* parsing styles as we go.
|
||||||
|
*/
|
||||||
|
cp = expanded;
|
||||||
|
while (*cp != '\0') {
|
||||||
|
if (cp[0] != '#' || cp[1] != '[') {
|
||||||
|
/* See if this is a UTF-8 character. */
|
||||||
|
if ((more = utf8_open(ud, *cp)) == UTF8_MORE) {
|
||||||
|
while (*++cp != '\0' && more == UTF8_MORE)
|
||||||
|
more = utf8_append(ud, *cp);
|
||||||
|
if (more != UTF8_DONE)
|
||||||
|
cp -= ud->have;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not a UTF-8 character - ASCII or not valid. */
|
||||||
|
if (more != UTF8_DONE) {
|
||||||
|
if (*cp < 0x20 || *cp > 0x7e) {
|
||||||
|
/* Ignore nonprintable characters. */
|
||||||
|
cp++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
utf8_set(ud, *cp);
|
||||||
|
cp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw the cell to th current screen. */
|
||||||
|
screen_write_cell(&ctx[current], &sy.gc);
|
||||||
|
width[current] += ud->width;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is a style. Work out where the end is and parse it. */
|
||||||
|
end = format_skip(cp + 2, "]");
|
||||||
|
if (end == NULL)
|
||||||
|
return;
|
||||||
|
tmp = xstrndup(cp + 2, end - (cp + 2));
|
||||||
|
if (style_parse(&sy, base, tmp) != 0) {
|
||||||
|
free(tmp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log_debug("style '%s' -> '%s'", tmp, style_tostring(&sy));
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
/* Check the list state. */
|
||||||
|
switch (sy.list) {
|
||||||
|
case STYLE_LIST_ON:
|
||||||
|
/*
|
||||||
|
* Entering the list, exiting a marker, or exiting the
|
||||||
|
* focus.
|
||||||
|
*/
|
||||||
|
if (list_state != 0) {
|
||||||
|
if (fr != NULL) { /* abort any region */
|
||||||
|
free(fr);
|
||||||
|
fr = NULL;
|
||||||
|
}
|
||||||
|
list_state = 0;
|
||||||
|
list_align = sy.align;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End the focus if started. */
|
||||||
|
if (focus_start != -1 && focus_end == -1)
|
||||||
|
focus_end = s[LIST].cx;
|
||||||
|
|
||||||
|
current = LIST;
|
||||||
|
break;
|
||||||
|
case STYLE_LIST_FOCUS:
|
||||||
|
/* Entering the focus. */
|
||||||
|
if (list_state != 0) /* not inside the list */
|
||||||
|
break;
|
||||||
|
if (focus_start == -1) /* focus already started */
|
||||||
|
focus_start = s[LIST].cx;
|
||||||
|
break;
|
||||||
|
case STYLE_LIST_OFF:
|
||||||
|
/* Exiting or outside the list. */
|
||||||
|
if (list_state == 0) {
|
||||||
|
if (fr != NULL) { /* abort any region */
|
||||||
|
free(fr);
|
||||||
|
fr = NULL;
|
||||||
|
}
|
||||||
|
if (focus_start != -1 && focus_end == -1)
|
||||||
|
focus_end = s[LIST].cx;
|
||||||
|
|
||||||
|
map[list_align] = AFTER;
|
||||||
|
if (list_align == STYLE_ALIGN_LEFT)
|
||||||
|
map[STYLE_ALIGN_DEFAULT] = AFTER;
|
||||||
|
list_state = 1;
|
||||||
|
}
|
||||||
|
current = map[sy.align];
|
||||||
|
break;
|
||||||
|
case STYLE_LIST_LEFT_MARKER:
|
||||||
|
/* Entering left marker. */
|
||||||
|
if (list_state != 0) /* not inside the list */
|
||||||
|
break;
|
||||||
|
if (s[LIST_LEFT].cx != 0) /* already have marker */
|
||||||
|
break;
|
||||||
|
if (fr != NULL) { /* abort any region */
|
||||||
|
free(fr);
|
||||||
|
fr = NULL;
|
||||||
|
}
|
||||||
|
if (focus_start != -1 && focus_end == -1)
|
||||||
|
focus_start = focus_end = -1;
|
||||||
|
current = LIST_LEFT;
|
||||||
|
break;
|
||||||
|
case STYLE_LIST_RIGHT_MARKER:
|
||||||
|
/* Entering right marker. */
|
||||||
|
if (list_state != 0) /* not inside the list */
|
||||||
|
break;
|
||||||
|
if (s[LIST_RIGHT].cx != 0) /* already have marker */
|
||||||
|
break;
|
||||||
|
if (fr != NULL) { /* abort any region */
|
||||||
|
free(fr);
|
||||||
|
fr = NULL;
|
||||||
|
}
|
||||||
|
if (focus_start != -1 && focus_end == -1)
|
||||||
|
focus_start = focus_end = -1;
|
||||||
|
current = LIST_RIGHT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (current != last) {
|
||||||
|
log_debug("%s: change %s -> %s", __func__,
|
||||||
|
names[last], names[current]);
|
||||||
|
last = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the range style has changed and if so end the
|
||||||
|
* current range and start a new one if needed.
|
||||||
|
*/
|
||||||
|
if (srs != NULL) {
|
||||||
|
if (fr != NULL && !format_is_type(fr, &sy)) {
|
||||||
|
if (s[current].cx != fr->start) {
|
||||||
|
fr->end = s[current].cx + 1;
|
||||||
|
TAILQ_INSERT_TAIL(&frs, fr, entry);
|
||||||
|
} else
|
||||||
|
free(fr);
|
||||||
|
fr = NULL;
|
||||||
|
}
|
||||||
|
if (fr == NULL && sy.range_type != STYLE_RANGE_NONE) {
|
||||||
|
fr = xcalloc(1, sizeof *fr);
|
||||||
|
fr->index = current;
|
||||||
|
|
||||||
|
fr->s = &s[current];
|
||||||
|
fr->start = s[current].cx;
|
||||||
|
|
||||||
|
fr->type = sy.range_type;
|
||||||
|
fr->argument = sy.range_argument;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cp = end + 1;
|
||||||
|
}
|
||||||
|
free(fr);
|
||||||
|
|
||||||
|
for (i = 0; i < TOTAL; i++)
|
||||||
|
log_debug("%s: width %s is %u", __func__, names[i], width[i]);
|
||||||
|
if (focus_start != -1 && focus_end != -1)
|
||||||
|
log_debug("focus is %d-%d", focus_start, focus_end);
|
||||||
|
TAILQ_FOREACH(fr, &frs, entry) {
|
||||||
|
log_debug("%s: range %d|%u is %s %u-%u", __func__, fr->type,
|
||||||
|
fr->argument, names[fr->index], fr->start, fr->end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw the screens. How they are arranged depends on where the list
|
||||||
|
* appearsq.
|
||||||
|
*/
|
||||||
|
switch (list_align) {
|
||||||
|
case STYLE_ALIGN_DEFAULT:
|
||||||
|
/* No list. */
|
||||||
|
format_draw_none(octx, available, ocx, ocy, &s[LEFT],
|
||||||
|
&s[CENTRE], &s[RIGHT], &frs);
|
||||||
|
break;
|
||||||
|
case STYLE_ALIGN_LEFT:
|
||||||
|
/* List is part of the left. */
|
||||||
|
format_draw_left(octx, available, ocx, ocy, &s[LEFT],
|
||||||
|
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
|
||||||
|
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
|
||||||
|
break;
|
||||||
|
case STYLE_ALIGN_CENTRE:
|
||||||
|
/* List is part of the centre. */
|
||||||
|
format_draw_centre(octx, available, ocx, ocy, &s[LEFT],
|
||||||
|
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
|
||||||
|
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
|
||||||
|
break;
|
||||||
|
case STYLE_ALIGN_RIGHT:
|
||||||
|
/* List is part of the right. */
|
||||||
|
format_draw_right(octx, available, ocx, ocy, &s[LEFT],
|
||||||
|
&s[CENTRE], &s[RIGHT], &s[LIST], &s[LIST_LEFT],
|
||||||
|
&s[LIST_RIGHT], &s[AFTER], focus_start, focus_end, &frs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create ranges to return. */
|
||||||
|
TAILQ_FOREACH_SAFE(fr, &frs, entry, fr1) {
|
||||||
|
sr = xcalloc(1, sizeof *sr);
|
||||||
|
sr->type = fr->type;
|
||||||
|
sr->argument = fr->argument;
|
||||||
|
sr->start = fr->start;
|
||||||
|
sr->end = fr->end;
|
||||||
|
TAILQ_INSERT_TAIL(srs, sr, entry);
|
||||||
|
|
||||||
|
log_debug("%s: range %d|%u at %u-%u", __func__, sr->type,
|
||||||
|
sr->argument, sr->start, sr->end);
|
||||||
|
|
||||||
|
format_free_range(&frs, fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore the original cursor position. */
|
||||||
|
screen_write_cursormove(octx, ocx, ocy, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get width, taking #[] into account. */
|
||||||
|
u_int
|
||||||
|
format_width(const char *expanded)
|
||||||
|
{
|
||||||
|
const char *cp, *end;
|
||||||
|
u_int width = 0;
|
||||||
|
struct utf8_data ud;
|
||||||
|
enum utf8_state more;
|
||||||
|
|
||||||
|
cp = expanded;
|
||||||
|
while (*cp != '\0') {
|
||||||
|
if (cp[0] == '#' && cp[1] == '[') {
|
||||||
|
end = format_skip(cp + 2, "]");
|
||||||
|
if (end == NULL)
|
||||||
|
return 0;
|
||||||
|
cp = end + 1;
|
||||||
|
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
|
||||||
|
while (*++cp != '\0' && more == UTF8_MORE)
|
||||||
|
more = utf8_append(&ud, *cp);
|
||||||
|
if (more == UTF8_DONE)
|
||||||
|
width += ud.width;
|
||||||
|
else
|
||||||
|
cp -= ud.have;
|
||||||
|
} else if (*cp > 0x1f && *cp < 0x7f) {
|
||||||
|
width++;
|
||||||
|
cp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (width);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trim on the left, taking #[] into account. */
|
||||||
|
char *
|
||||||
|
format_trim_left(const char *expanded, u_int limit)
|
||||||
|
{
|
||||||
|
char *copy, *out;
|
||||||
|
const char *cp = expanded, *end;
|
||||||
|
u_int width = 0;
|
||||||
|
struct utf8_data ud;
|
||||||
|
enum utf8_state more;
|
||||||
|
|
||||||
|
out = copy = xmalloc(strlen(expanded) + 1);
|
||||||
|
while (*cp != '\0') {
|
||||||
|
if (cp[0] == '#' && cp[1] == '[') {
|
||||||
|
end = format_skip(cp + 2, "]");
|
||||||
|
if (end == NULL)
|
||||||
|
break;
|
||||||
|
memcpy(out, cp, end + 1 - cp);
|
||||||
|
out += (end + 1 - cp);
|
||||||
|
cp = end + 1;
|
||||||
|
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
|
||||||
|
while (*++cp != '\0' && more == UTF8_MORE)
|
||||||
|
more = utf8_append(&ud, *cp);
|
||||||
|
if (more == UTF8_DONE) {
|
||||||
|
if (width + ud.width <= limit) {
|
||||||
|
memcpy(out, ud.data, ud.size);
|
||||||
|
out += ud.size;
|
||||||
|
}
|
||||||
|
width += ud.width;
|
||||||
|
} else
|
||||||
|
cp -= ud.have;
|
||||||
|
} else if (*cp > 0x1f && *cp < 0x7f) {
|
||||||
|
if (width + 1 <= limit)
|
||||||
|
*out++ = *cp;
|
||||||
|
width++;
|
||||||
|
cp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*out = '\0';
|
||||||
|
return (copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trim on the right, taking #[] into account. */
|
||||||
|
char *
|
||||||
|
format_trim_right(const char *expanded, u_int limit)
|
||||||
|
{
|
||||||
|
char *copy, *out;
|
||||||
|
const char *cp = expanded, *end;
|
||||||
|
u_int width = 0, total_width, skip;
|
||||||
|
struct utf8_data ud;
|
||||||
|
enum utf8_state more;
|
||||||
|
|
||||||
|
total_width = format_width(expanded);
|
||||||
|
if (total_width <= limit)
|
||||||
|
return (xstrdup(expanded));
|
||||||
|
skip = total_width - limit;
|
||||||
|
|
||||||
|
out = copy = xmalloc(strlen(expanded) + 1);
|
||||||
|
while (*cp != '\0') {
|
||||||
|
if (cp[0] == '#' && cp[1] == '[') {
|
||||||
|
end = format_skip(cp + 2, "]");
|
||||||
|
if (end == NULL)
|
||||||
|
break;
|
||||||
|
memcpy(out, cp, end + 1 - cp);
|
||||||
|
out += (end + 1 - cp);
|
||||||
|
cp = end + 1;
|
||||||
|
} else if ((more = utf8_open(&ud, *cp)) == UTF8_MORE) {
|
||||||
|
while (*++cp != '\0' && more == UTF8_MORE)
|
||||||
|
more = utf8_append(&ud, *cp);
|
||||||
|
if (more == UTF8_DONE) {
|
||||||
|
if (width >= skip) {
|
||||||
|
memcpy(out, ud.data, ud.size);
|
||||||
|
out += ud.size;
|
||||||
|
}
|
||||||
|
width += ud.width;
|
||||||
|
} else
|
||||||
|
cp -= ud.have;
|
||||||
|
} else if (*cp > 0x1f && *cp < 0x7f) {
|
||||||
|
if (width >= skip)
|
||||||
|
*out++ = *cp;
|
||||||
|
width++;
|
||||||
|
cp++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*out = '\0';
|
||||||
|
return (copy);
|
||||||
|
}
|
6
format.c
6
format.c
@ -988,7 +988,7 @@ found:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Skip until end. */
|
/* Skip until end. */
|
||||||
static const char *
|
const char *
|
||||||
format_skip(const char *s, const char *end)
|
format_skip(const char *s, const char *end)
|
||||||
{
|
{
|
||||||
int brackets = 0;
|
int brackets = 0;
|
||||||
@ -1596,12 +1596,12 @@ done:
|
|||||||
|
|
||||||
/* Truncate the value if needed. */
|
/* Truncate the value if needed. */
|
||||||
if (limit > 0) {
|
if (limit > 0) {
|
||||||
new = utf8_trimcstr(value, limit);
|
new = format_trim_left(value, limit);
|
||||||
format_log(ft, "applied length limit %d: %s", limit, new);
|
format_log(ft, "applied length limit %d: %s", limit, new);
|
||||||
free(value);
|
free(value);
|
||||||
value = new;
|
value = new;
|
||||||
} else if (limit < 0) {
|
} else if (limit < 0) {
|
||||||
new = utf8_rtrimcstr(value, -limit);
|
new = format_trim_right(value, -limit);
|
||||||
format_log(ft, "applied length limit %d: %s", limit, new);
|
format_log(ft, "applied length limit %d: %s", limit, new);
|
||||||
free(value);
|
free(value);
|
||||||
value = new;
|
value = new;
|
||||||
|
13
mode-tree.c
13
mode-tree.c
@ -497,7 +497,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
|||||||
struct options *oo = wp->window->options;
|
struct options *oo = wp->window->options;
|
||||||
struct screen_write_ctx ctx;
|
struct screen_write_ctx ctx;
|
||||||
struct grid_cell gc0, gc;
|
struct grid_cell gc0, gc;
|
||||||
u_int w, h, i, j, sy, box_x, box_y;
|
u_int w, h, i, j, sy, box_x, box_y, width;
|
||||||
char *text, *start, key[7];
|
char *text, *start, key[7];
|
||||||
const char *tag, *symbol;
|
const char *tag, *symbol;
|
||||||
size_t size, n;
|
size_t size, n;
|
||||||
@ -572,8 +572,9 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
|||||||
tag = "*";
|
tag = "*";
|
||||||
else
|
else
|
||||||
tag = "";
|
tag = "";
|
||||||
xasprintf(&text, "%-*s%s%s%s: %s", keylen, key, start,
|
xasprintf(&text, "%-*s%s%s%s: ", keylen, key, start, mti->name,
|
||||||
mti->name, tag, mti->text);
|
tag);
|
||||||
|
width = utf8_cstrwidth(text);
|
||||||
free(start);
|
free(start);
|
||||||
|
|
||||||
if (mti->tagged) {
|
if (mti->tagged) {
|
||||||
@ -582,11 +583,13 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i != mtd->current) {
|
if (i != mtd->current) {
|
||||||
screen_write_cnputs(&ctx, w, &gc0, "%s", text);
|
|
||||||
screen_write_clearendofline(&ctx, 8);
|
screen_write_clearendofline(&ctx, 8);
|
||||||
|
screen_write_puts(&ctx, &gc0, "%s", text);
|
||||||
|
format_draw(&ctx, &gc0, w - width, mti->text, NULL);
|
||||||
} else {
|
} else {
|
||||||
screen_write_cnputs(&ctx, w, &gc, "%s", text);
|
|
||||||
screen_write_clearendofline(&ctx, gc.bg);
|
screen_write_clearendofline(&ctx, gc.bg);
|
||||||
|
screen_write_puts(&ctx, &gc, "%s", text);
|
||||||
|
format_draw(&ctx, &gc, w - width, mti->text, NULL);
|
||||||
}
|
}
|
||||||
free(text);
|
free(text);
|
||||||
|
|
||||||
|
@ -38,6 +38,9 @@ static const char *options_table_mode_keys_list[] = {
|
|||||||
static const char *options_table_clock_mode_style_list[] = {
|
static const char *options_table_clock_mode_style_list[] = {
|
||||||
"12", "24", NULL
|
"12", "24", NULL
|
||||||
};
|
};
|
||||||
|
static const char *options_table_status_list[] = {
|
||||||
|
"off", "on", "2", "3", "4", "5", NULL
|
||||||
|
};
|
||||||
static const char *options_table_status_keys_list[] = {
|
static const char *options_table_status_keys_list[] = {
|
||||||
"emacs", "vi", NULL
|
"emacs", "vi", NULL
|
||||||
};
|
};
|
||||||
@ -63,6 +66,46 @@ static const char *options_table_window_size_list[] = {
|
|||||||
"largest", "smallest", "manual", NULL
|
"largest", "smallest", "manual", NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Status line format. */
|
||||||
|
#define OPTIONS_TABLE_STATUS_FORMAT1 \
|
||||||
|
"#[align=left range=left #{status-left-style}]" \
|
||||||
|
"#{T;=/#{status-left-length}:status-left}#[norange default]" \
|
||||||
|
"#[list=on align=#{status-justify}]" \
|
||||||
|
"#[list=left-marker]<#[list=right-marker]>#[list=on]" \
|
||||||
|
"#{W:" \
|
||||||
|
"#[range=window|#{window_index}" \
|
||||||
|
"#{?window_last_flag, #{window-status-last-style},}" \
|
||||||
|
"#{?window_bell_flag," \
|
||||||
|
" #{window-status-bell-style}," \
|
||||||
|
"#{?window_activity_flag," \
|
||||||
|
" #{window-status-activity-style},}" \
|
||||||
|
"}" \
|
||||||
|
"]" \
|
||||||
|
"#{T:window-status-format}" \
|
||||||
|
"#[norange default]" \
|
||||||
|
"#{?window_end_flag,,#{window-status-separator}}" \
|
||||||
|
"," \
|
||||||
|
"#[range=window|#{window_index} list=focus" \
|
||||||
|
"#{?window_last_flag, #{window-status-last-style},}" \
|
||||||
|
"#{?window_bell_flag," \
|
||||||
|
" #{window-status-bell-style}," \
|
||||||
|
"#{?window_activity_flag," \
|
||||||
|
" #{window-status-activity-style},}" \
|
||||||
|
"}" \
|
||||||
|
"]" \
|
||||||
|
"#{T:window-status-current-format}" \
|
||||||
|
"#[norange list=on default]" \
|
||||||
|
"#{?window_end_flag,,#{window-status-separator}}" \
|
||||||
|
"}" \
|
||||||
|
"#[nolist align=right range=right #{status-right-style}]" \
|
||||||
|
"#{T;=/#{status-right-length}:status-right}#[norange default]"
|
||||||
|
#define OPTIONS_TABLE_STATUS_FORMAT2 \
|
||||||
|
"#[align=centre]#{P:#{?pane_active,#[reverse],}" \
|
||||||
|
"#{pane_index}[#{pane_width}x#{pane_height}]#[default] }"
|
||||||
|
static const char *options_table_status_format_default[] = {
|
||||||
|
OPTIONS_TABLE_STATUS_FORMAT1, OPTIONS_TABLE_STATUS_FORMAT2, NULL
|
||||||
|
};
|
||||||
|
|
||||||
/* Top-level options. */
|
/* Top-level options. */
|
||||||
const struct options_table_entry options_table[] = {
|
const struct options_table_entry options_table[] = {
|
||||||
{ .name = "buffer-limit",
|
{ .name = "buffer-limit",
|
||||||
@ -377,8 +420,9 @@ const struct options_table_entry options_table[] = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "status",
|
{ .name = "status",
|
||||||
.type = OPTIONS_TABLE_FLAG,
|
.type = OPTIONS_TABLE_CHOICE,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
|
.choices = options_table_status_list,
|
||||||
.default_num = 1
|
.default_num = 1
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -403,6 +447,12 @@ const struct options_table_entry options_table[] = {
|
|||||||
.style = "status-style"
|
.style = "status-style"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ .name = "status-format",
|
||||||
|
.type = OPTIONS_TABLE_ARRAY,
|
||||||
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
|
.default_arr = options_table_status_format_default,
|
||||||
|
},
|
||||||
|
|
||||||
{ .name = "status-interval",
|
{ .name = "status-interval",
|
||||||
.type = OPTIONS_TABLE_NUMBER,
|
.type = OPTIONS_TABLE_NUMBER,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
|
@ -274,8 +274,8 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
|
|||||||
struct grid_cell gc;
|
struct grid_cell gc;
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
struct format_tree *ft;
|
struct format_tree *ft;
|
||||||
char *out;
|
char *expanded;
|
||||||
size_t outlen;
|
u_int width, i;
|
||||||
struct screen_write_ctx ctx;
|
struct screen_write_ctx ctx;
|
||||||
struct screen old;
|
struct screen old;
|
||||||
|
|
||||||
@ -289,27 +289,27 @@ screen_redraw_make_pane_status(struct client *c, struct window *w,
|
|||||||
ft = format_create(c, NULL, FORMAT_PANE|wp->id, 0);
|
ft = format_create(c, NULL, FORMAT_PANE|wp->id, 0);
|
||||||
format_defaults(ft, c, NULL, NULL, wp);
|
format_defaults(ft, c, NULL, NULL, wp);
|
||||||
|
|
||||||
|
expanded = format_expand_time(ft, fmt);
|
||||||
|
wp->status_size = width = wp->sx - 4;
|
||||||
|
|
||||||
memcpy(&old, &wp->status_screen, sizeof old);
|
memcpy(&old, &wp->status_screen, sizeof old);
|
||||||
screen_init(&wp->status_screen, wp->sx, 1, 0);
|
screen_init(&wp->status_screen, width, 1, 0);
|
||||||
wp->status_screen.mode = 0;
|
wp->status_screen.mode = 0;
|
||||||
|
|
||||||
out = format_expand(ft, fmt);
|
|
||||||
outlen = screen_write_cstrlen("%s", out);
|
|
||||||
if (outlen > wp->sx - 4)
|
|
||||||
outlen = wp->sx - 4;
|
|
||||||
screen_resize(&wp->status_screen, outlen, 1, 0);
|
|
||||||
|
|
||||||
screen_write_start(&ctx, NULL, &wp->status_screen);
|
screen_write_start(&ctx, NULL, &wp->status_screen);
|
||||||
|
|
||||||
|
gc.attr |= GRID_ATTR_CHARSET;
|
||||||
|
for (i = 0; i < width; i++)
|
||||||
|
screen_write_putc(&ctx, &gc, 'q');
|
||||||
|
gc.attr &= ~GRID_ATTR_CHARSET;
|
||||||
|
|
||||||
screen_write_cursormove(&ctx, 0, 0, 0);
|
screen_write_cursormove(&ctx, 0, 0, 0);
|
||||||
screen_write_clearline(&ctx, 8);
|
format_draw(&ctx, &gc, width, expanded, NULL);
|
||||||
screen_write_cnputs(&ctx, outlen, &gc, "%s", out);
|
|
||||||
screen_write_stop(&ctx);
|
screen_write_stop(&ctx);
|
||||||
|
|
||||||
free(out);
|
free(expanded);
|
||||||
format_free(ft);
|
format_free(ft);
|
||||||
|
|
||||||
wp->status_size = outlen;
|
|
||||||
|
|
||||||
if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
|
if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
|
||||||
screen_free(&old);
|
screen_free(&old);
|
||||||
return (0);
|
return (0);
|
||||||
|
107
screen-write.c
107
screen-write.c
@ -169,41 +169,6 @@ screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
|
|||||||
screen_write_cell(ctx, &gc);
|
screen_write_cell(ctx, &gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate string length, with embedded formatting. */
|
|
||||||
size_t
|
|
||||||
screen_write_cstrlen(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
char *msg, *msg2, *ptr, *ptr2;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
xvasprintf(&msg, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
msg2 = xmalloc(strlen(msg) + 1);
|
|
||||||
|
|
||||||
ptr = msg;
|
|
||||||
ptr2 = msg2;
|
|
||||||
while (*ptr != '\0') {
|
|
||||||
if (ptr[0] == '#' && ptr[1] == '[') {
|
|
||||||
while (*ptr != ']' && *ptr != '\0')
|
|
||||||
ptr++;
|
|
||||||
if (*ptr == ']')
|
|
||||||
ptr++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*ptr2++ = *ptr++;
|
|
||||||
}
|
|
||||||
*ptr2 = '\0';
|
|
||||||
|
|
||||||
size = screen_write_strlen("%s", msg2);
|
|
||||||
|
|
||||||
free(msg);
|
|
||||||
free(msg2);
|
|
||||||
|
|
||||||
return (size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate string length. */
|
/* Calculate string length. */
|
||||||
size_t
|
size_t
|
||||||
screen_write_strlen(const char *fmt, ...)
|
screen_write_strlen(const char *fmt, ...)
|
||||||
@ -322,78 +287,6 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
|
|||||||
free(msg);
|
free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write string, similar to nputs, but with embedded formatting (#[]). */
|
|
||||||
void
|
|
||||||
screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
|
|
||||||
const struct grid_cell *gcp, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
struct style sy;
|
|
||||||
struct utf8_data *ud = &sy.gc.data;
|
|
||||||
va_list ap;
|
|
||||||
char *msg;
|
|
||||||
u_char *ptr, *last;
|
|
||||||
size_t left, size = 0;
|
|
||||||
enum utf8_state more;
|
|
||||||
|
|
||||||
style_set(&sy, gcp);
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
xvasprintf(&msg, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
ptr = msg;
|
|
||||||
while (*ptr != '\0') {
|
|
||||||
if (ptr[0] == '#' && ptr[1] == '[') {
|
|
||||||
ptr += 2;
|
|
||||||
last = ptr + strcspn(ptr, "]");
|
|
||||||
if (*last == '\0') {
|
|
||||||
/* No ]. Not much point in doing anything. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*last = '\0';
|
|
||||||
|
|
||||||
style_parse(&sy, gcp, ptr);
|
|
||||||
ptr = last + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
|
|
||||||
ptr++;
|
|
||||||
|
|
||||||
left = strlen(ptr);
|
|
||||||
if (left < (size_t)ud->size - 1)
|
|
||||||
break;
|
|
||||||
while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
|
|
||||||
ptr++;
|
|
||||||
ptr++;
|
|
||||||
|
|
||||||
if (more != UTF8_DONE)
|
|
||||||
continue;
|
|
||||||
if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
|
|
||||||
while (size < (size_t)maxlen) {
|
|
||||||
screen_write_putc(ctx, &sy.gc, ' ');
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
size += ud->width;
|
|
||||||
screen_write_cell(ctx, &sy.gc);
|
|
||||||
} else {
|
|
||||||
if (maxlen > 0 && size + 1 > (size_t)maxlen)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (*ptr == '\001')
|
|
||||||
sy.gc.attr ^= GRID_ATTR_CHARSET;
|
|
||||||
else if (*ptr > 0x1f && *ptr < 0x7f) {
|
|
||||||
size++;
|
|
||||||
screen_write_putc(ctx, &sy.gc, *ptr);
|
|
||||||
}
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy from another screen. Assumes target region is big enough. */
|
/* Copy from another screen. Assumes target region is big enough. */
|
||||||
void
|
void
|
||||||
screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
|
screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px,
|
||||||
|
@ -409,12 +409,13 @@ server_client_check_mouse(struct client *c)
|
|||||||
{
|
{
|
||||||
struct session *s = c->session;
|
struct session *s = c->session;
|
||||||
struct mouse_event *m = &c->tty.mouse;
|
struct mouse_event *m = &c->tty.mouse;
|
||||||
struct window *w;
|
struct winlink *wl;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
u_int x, y, b, sx, sy, px, py;
|
u_int x, y, b, sx, sy, px, py;
|
||||||
int flag;
|
int flag;
|
||||||
key_code key;
|
key_code key;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
struct style_range *sr;
|
||||||
enum { NOTYPE, MOVE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type;
|
enum { NOTYPE, MOVE, DOWN, UP, DRAG, WHEEL, DOUBLE, TRIPLE } type;
|
||||||
enum { NOWHERE, PANE, STATUS, STATUS_LEFT, STATUS_RIGHT, BORDER } where;
|
enum { NOWHERE, PANE, STATUS, STATUS_LEFT, STATUS_RIGHT, BORDER } where;
|
||||||
|
|
||||||
@ -501,17 +502,29 @@ have_event:
|
|||||||
|
|
||||||
/* Is this on the status line? */
|
/* Is this on the status line? */
|
||||||
m->statusat = status_at_line(c);
|
m->statusat = status_at_line(c);
|
||||||
if (m->statusat != -1 && y == (u_int)m->statusat) {
|
if (m->statusat != -1 &&
|
||||||
if (x < c->status.left_size)
|
y >= (u_int)m->statusat &&
|
||||||
|
y < m->statusat + status_line_size(c))
|
||||||
|
sr = status_get_range(c, x, y - m->statusat);
|
||||||
|
else
|
||||||
|
sr = NULL;
|
||||||
|
if (sr != NULL) {
|
||||||
|
switch (sr->type) {
|
||||||
|
case STYLE_RANGE_NONE:
|
||||||
|
break;
|
||||||
|
case STYLE_RANGE_LEFT:
|
||||||
where = STATUS_LEFT;
|
where = STATUS_LEFT;
|
||||||
else if (x > c->tty.sx - c->status.right_size)
|
break;
|
||||||
|
case STYLE_RANGE_RIGHT:
|
||||||
where = STATUS_RIGHT;
|
where = STATUS_RIGHT;
|
||||||
else {
|
break;
|
||||||
w = status_get_window_at(c, x);
|
case STYLE_RANGE_WINDOW:
|
||||||
if (w == NULL)
|
wl = winlink_find_by_index(&s->windows, sr->argument);
|
||||||
return (KEYC_UNKNOWN);
|
if (wl != NULL) {
|
||||||
m->w = w->id;
|
m->w = wl->window->id;
|
||||||
where = STATUS;
|
where = STATUS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
433
status.c
433
status.c
@ -29,14 +29,6 @@
|
|||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
static char *status_redraw_get_left(struct client *, struct grid_cell *,
|
|
||||||
size_t *);
|
|
||||||
static char *status_redraw_get_right(struct client *, struct grid_cell *,
|
|
||||||
size_t *);
|
|
||||||
static char *status_print(struct client *, struct winlink *,
|
|
||||||
struct grid_cell *);
|
|
||||||
static char *status_replace(struct client *, struct winlink *,
|
|
||||||
const char *);
|
|
||||||
static void status_message_callback(int, short, void *);
|
static void status_message_callback(int, short, void *);
|
||||||
static void status_timer_callback(int, short, void *);
|
static void status_timer_callback(int, short, void *);
|
||||||
|
|
||||||
@ -196,7 +188,8 @@ status_timer_start_all(void)
|
|||||||
void
|
void
|
||||||
status_update_cache(struct session *s)
|
status_update_cache(struct session *s)
|
||||||
{
|
{
|
||||||
if (!options_get_number(s->options, "status"))
|
s->statuslines = options_get_number(s->options, "status");
|
||||||
|
if (s->statuslines == 0)
|
||||||
s->statusat = -1;
|
s->statusat = -1;
|
||||||
else if (options_get_number(s->options, "status-position") == 0)
|
else if (options_get_number(s->options, "status-position") == 0)
|
||||||
s->statusat = 0;
|
s->statusat = 0;
|
||||||
@ -225,77 +218,37 @@ status_line_size(struct client *c)
|
|||||||
|
|
||||||
if (c->flags & CLIENT_STATUSOFF)
|
if (c->flags & CLIENT_STATUSOFF)
|
||||||
return (0);
|
return (0);
|
||||||
if (s->statusat == -1)
|
return (s->statuslines);
|
||||||
return (0);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve options for left string. */
|
|
||||||
static char *
|
|
||||||
status_redraw_get_left(struct client *c, struct grid_cell *gc, size_t *size)
|
|
||||||
{
|
|
||||||
struct session *s = c->session;
|
|
||||||
const char *template;
|
|
||||||
char *left;
|
|
||||||
size_t leftlen;
|
|
||||||
|
|
||||||
style_apply_update(gc, s->options, "status-left-style");
|
|
||||||
|
|
||||||
template = options_get_string(s->options, "status-left");
|
|
||||||
left = status_replace(c, NULL, template);
|
|
||||||
|
|
||||||
*size = options_get_number(s->options, "status-left-length");
|
|
||||||
leftlen = screen_write_cstrlen("%s", left);
|
|
||||||
if (leftlen < *size)
|
|
||||||
*size = leftlen;
|
|
||||||
return (left);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Retrieve options for right string. */
|
|
||||||
static char *
|
|
||||||
status_redraw_get_right(struct client *c, struct grid_cell *gc, size_t *size)
|
|
||||||
{
|
|
||||||
struct session *s = c->session;
|
|
||||||
const char *template;
|
|
||||||
char *right;
|
|
||||||
size_t rightlen;
|
|
||||||
|
|
||||||
style_apply_update(gc, s->options, "status-right-style");
|
|
||||||
|
|
||||||
template = options_get_string(s->options, "status-right");
|
|
||||||
right = status_replace(c, NULL, template);
|
|
||||||
|
|
||||||
*size = options_get_number(s->options, "status-right-length");
|
|
||||||
rightlen = screen_write_cstrlen("%s", right);
|
|
||||||
if (rightlen < *size)
|
|
||||||
*size = rightlen;
|
|
||||||
return (right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get window at window list position. */
|
/* Get window at window list position. */
|
||||||
struct window *
|
struct style_range *
|
||||||
status_get_window_at(struct client *c, u_int x)
|
status_get_range(struct client *c, u_int x, u_int y)
|
||||||
{
|
{
|
||||||
struct session *s = c->session;
|
struct status_line *sl = &c->status;
|
||||||
struct winlink *wl;
|
struct style_range *sr;
|
||||||
struct options *oo;
|
|
||||||
const char *sep;
|
|
||||||
size_t seplen;
|
|
||||||
|
|
||||||
x += c->status.window_list_offset;
|
if (y >= nitems(sl->entries))
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
return (NULL);
|
||||||
oo = wl->window->options;
|
TAILQ_FOREACH(sr, &sl->entries[y].ranges, entry) {
|
||||||
|
if (x >= sr->start && x < sr->end)
|
||||||
sep = options_get_string(oo, "window-status-separator");
|
return (sr);
|
||||||
seplen = screen_write_cstrlen("%s", sep);
|
|
||||||
|
|
||||||
if (x < wl->status_width)
|
|
||||||
return (wl->window);
|
|
||||||
x -= wl->status_width + seplen;
|
|
||||||
}
|
}
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free all ranges. */
|
||||||
|
static void
|
||||||
|
status_free_ranges(struct style_ranges *srs)
|
||||||
|
{
|
||||||
|
struct style_range *sr, *sr1;
|
||||||
|
|
||||||
|
TAILQ_FOREACH_SAFE(sr, srs, entry, sr1) {
|
||||||
|
TAILQ_REMOVE(srs, sr, entry);
|
||||||
|
free(sr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Save old status line. */
|
/* Save old status line. */
|
||||||
static void
|
static void
|
||||||
status_push_screen(struct client *c)
|
status_push_screen(struct client *c)
|
||||||
@ -327,6 +280,10 @@ void
|
|||||||
status_init(struct client *c)
|
status_init(struct client *c)
|
||||||
{
|
{
|
||||||
struct status_line *sl = &c->status;
|
struct status_line *sl = &c->status;
|
||||||
|
u_int i;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(sl->entries); i++)
|
||||||
|
TAILQ_INIT(&sl->entries[i].ranges);
|
||||||
|
|
||||||
screen_init(&sl->screen, c->tty.sx, 1, 0);
|
screen_init(&sl->screen, c->tty.sx, 1, 0);
|
||||||
sl->active = &sl->screen;
|
sl->active = &sl->screen;
|
||||||
@ -337,6 +294,12 @@ void
|
|||||||
status_free(struct client *c)
|
status_free(struct client *c)
|
||||||
{
|
{
|
||||||
struct status_line *sl = &c->status;
|
struct status_line *sl = &c->status;
|
||||||
|
u_int i;
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(sl->entries); i++) {
|
||||||
|
status_free_ranges(&sl->entries[i].ranges);
|
||||||
|
free((void *)sl->entries[i].expanded);
|
||||||
|
}
|
||||||
|
|
||||||
if (event_initialized(&sl->timer))
|
if (event_initialized(&sl->timer))
|
||||||
evtimer_del(&sl->timer);
|
evtimer_del(&sl->timer);
|
||||||
@ -352,19 +315,19 @@ status_free(struct client *c)
|
|||||||
int
|
int
|
||||||
status_redraw(struct client *c)
|
status_redraw(struct client *c)
|
||||||
{
|
{
|
||||||
struct status_line *sl = &c->status;
|
struct status_line *sl = &c->status;
|
||||||
struct screen_write_ctx ctx;
|
struct status_line_entry *sle;
|
||||||
struct session *s = c->session;
|
struct session *s = c->session;
|
||||||
struct winlink *wl;
|
struct screen_write_ctx ctx;
|
||||||
struct screen old_screen, window_list;
|
struct grid_cell gc;
|
||||||
struct grid_cell stdgc, lgc, rgc, gc;
|
u_int lines, i, width = c->tty.sx;
|
||||||
struct options *oo;
|
int flags, force = 0, changed = 0;
|
||||||
char *left, *right;
|
struct options_entry *o;
|
||||||
const char *sep;
|
struct format_tree *ft;
|
||||||
u_int offset, needed, lines;
|
const char *fmt;
|
||||||
u_int wlstart, wlwidth, wlavailable, wloffset, wlsize;
|
char *expanded;
|
||||||
size_t llen, rlen, seplen;
|
|
||||||
int larrow, rarrow;
|
log_debug("%s enter", __func__);
|
||||||
|
|
||||||
/* Shouldn't get here if not the active screen. */
|
/* Shouldn't get here if not the active screen. */
|
||||||
if (sl->active != &sl->screen)
|
if (sl->active != &sl->screen)
|
||||||
@ -374,257 +337,71 @@ status_redraw(struct client *c)
|
|||||||
lines = status_line_size(c);
|
lines = status_line_size(c);
|
||||||
if (c->tty.sy == 0 || lines == 0)
|
if (c->tty.sy == 0 || lines == 0)
|
||||||
return (1);
|
return (1);
|
||||||
left = right = NULL;
|
|
||||||
larrow = rarrow = 0;
|
|
||||||
|
|
||||||
/* Set up default colour. */
|
/* Set up default colour. */
|
||||||
style_apply(&stdgc, s->options, "status-style");
|
style_apply(&gc, s->options, "status-style");
|
||||||
|
if (!grid_cells_equal(&gc, &sl->style)) {
|
||||||
/* Create the target screen. */
|
force = 1;
|
||||||
memcpy(&old_screen, sl->active, sizeof old_screen);
|
memcpy(&sl->style, &gc, sizeof sl->style);
|
||||||
screen_init(sl->active, c->tty.sx, lines, 0);
|
|
||||||
screen_write_start(&ctx, NULL, sl->active);
|
|
||||||
for (offset = 0; offset < lines * c->tty.sx; offset++)
|
|
||||||
screen_write_putc(&ctx, &stdgc, ' ');
|
|
||||||
screen_write_stop(&ctx);
|
|
||||||
|
|
||||||
/* If the height is too small, blank status line. */
|
|
||||||
if (c->tty.sy < lines)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* Work out left and right strings. */
|
|
||||||
memcpy(&lgc, &stdgc, sizeof lgc);
|
|
||||||
left = status_redraw_get_left(c, &lgc, &llen);
|
|
||||||
memcpy(&rgc, &stdgc, sizeof rgc);
|
|
||||||
right = status_redraw_get_right(c, &rgc, &rlen);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Figure out how much space we have for the window list. If there
|
|
||||||
* isn't enough space, just show a blank status line.
|
|
||||||
*/
|
|
||||||
needed = 0;
|
|
||||||
if (llen != 0)
|
|
||||||
needed += llen;
|
|
||||||
if (rlen != 0)
|
|
||||||
needed += rlen;
|
|
||||||
if (c->tty.sx == 0 || c->tty.sx <= needed)
|
|
||||||
goto out;
|
|
||||||
wlavailable = c->tty.sx - needed;
|
|
||||||
|
|
||||||
/* Calculate the total size needed for the window list. */
|
|
||||||
wlstart = wloffset = wlwidth = 0;
|
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
|
||||||
free(wl->status_text);
|
|
||||||
memcpy(&wl->status_cell, &stdgc, sizeof wl->status_cell);
|
|
||||||
wl->status_text = status_print(c, wl, &wl->status_cell);
|
|
||||||
wl->status_width = screen_write_cstrlen("%s", wl->status_text);
|
|
||||||
|
|
||||||
if (wl == s->curw)
|
|
||||||
wloffset = wlwidth;
|
|
||||||
|
|
||||||
oo = wl->window->options;
|
|
||||||
sep = options_get_string(oo, "window-status-separator");
|
|
||||||
seplen = screen_write_cstrlen("%s", sep);
|
|
||||||
wlwidth += wl->status_width + seplen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a new screen for the window list. */
|
/* Resize the target screen. */
|
||||||
screen_init(&window_list, wlwidth, 1, 0);
|
if (screen_size_x(&sl->screen) != width ||
|
||||||
|
screen_size_y(&sl->screen) != lines) {
|
||||||
/* And draw the window list into it. */
|
if (screen_size_x(&sl->screen) != width)
|
||||||
screen_write_start(&ctx, NULL, &window_list);
|
force = 1;
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
screen_resize(&sl->screen, width, lines, 0);
|
||||||
screen_write_cnputs(&ctx, -1, &wl->status_cell, "%s",
|
changed = 1;
|
||||||
wl->status_text);
|
|
||||||
|
|
||||||
oo = wl->window->options;
|
|
||||||
sep = options_get_string(oo, "window-status-separator");
|
|
||||||
screen_write_cnputs(&ctx, -1, &stdgc, "%s", sep);
|
|
||||||
}
|
}
|
||||||
screen_write_stop(&ctx);
|
screen_write_start(&ctx, NULL, &sl->screen);
|
||||||
|
|
||||||
/* If there is enough space for the total width, skip to draw now. */
|
/* Create format tree. */
|
||||||
if (wlwidth <= wlavailable)
|
flags = FORMAT_STATUS;
|
||||||
goto draw;
|
|
||||||
|
|
||||||
/* Find size of current window text. */
|
|
||||||
wlsize = s->curw->status_width;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the current window is already on screen, good to draw from the
|
|
||||||
* start and just leave off the end.
|
|
||||||
*/
|
|
||||||
if (wloffset + wlsize < wlavailable) {
|
|
||||||
if (wlavailable > 0) {
|
|
||||||
rarrow = 1;
|
|
||||||
wlavailable--;
|
|
||||||
}
|
|
||||||
wlwidth = wlavailable;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Work out how many characters we need to omit from the
|
|
||||||
* start. There are wlavailable characters to fill, and
|
|
||||||
* wloffset + wlsize must be the last. So, the start character
|
|
||||||
* is wloffset + wlsize - wlavailable.
|
|
||||||
*/
|
|
||||||
if (wlavailable > 0) {
|
|
||||||
larrow = 1;
|
|
||||||
wlavailable--;
|
|
||||||
}
|
|
||||||
|
|
||||||
wlstart = wloffset + wlsize - wlavailable;
|
|
||||||
if (wlavailable > 0 && wlwidth > wlstart + wlavailable + 1) {
|
|
||||||
rarrow = 1;
|
|
||||||
wlstart++;
|
|
||||||
wlavailable--;
|
|
||||||
}
|
|
||||||
wlwidth = wlavailable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bail if anything is now too small too. */
|
|
||||||
if (wlwidth == 0 || wlavailable == 0) {
|
|
||||||
screen_free(&window_list);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now the start position is known, work out the state of the left and
|
|
||||||
* right arrows.
|
|
||||||
*/
|
|
||||||
offset = 0;
|
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
|
||||||
if (wl->flags & WINLINK_ALERTFLAGS &&
|
|
||||||
larrow == 1 && offset < wlstart)
|
|
||||||
larrow = -1;
|
|
||||||
|
|
||||||
offset += wl->status_width;
|
|
||||||
|
|
||||||
if (wl->flags & WINLINK_ALERTFLAGS &&
|
|
||||||
rarrow == 1 && offset > wlstart + wlwidth)
|
|
||||||
rarrow = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw:
|
|
||||||
/* Begin drawing. */
|
|
||||||
screen_write_start(&ctx, NULL, sl->active);
|
|
||||||
|
|
||||||
/* Draw the left string and arrow. */
|
|
||||||
screen_write_cursormove(&ctx, 0, 0, 0);
|
|
||||||
if (llen != 0)
|
|
||||||
screen_write_cnputs(&ctx, llen, &lgc, "%s", left);
|
|
||||||
if (larrow != 0) {
|
|
||||||
memcpy(&gc, &stdgc, sizeof gc);
|
|
||||||
if (larrow == -1)
|
|
||||||
gc.attr ^= GRID_ATTR_REVERSE;
|
|
||||||
screen_write_putc(&ctx, &gc, '<');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Draw the right string and arrow. */
|
|
||||||
if (rarrow != 0) {
|
|
||||||
screen_write_cursormove(&ctx, c->tty.sx - rlen - 1, 0, 0);
|
|
||||||
memcpy(&gc, &stdgc, sizeof gc);
|
|
||||||
if (rarrow == -1)
|
|
||||||
gc.attr ^= GRID_ATTR_REVERSE;
|
|
||||||
screen_write_putc(&ctx, &gc, '>');
|
|
||||||
} else
|
|
||||||
screen_write_cursormove(&ctx, c->tty.sx - rlen, 0, 0);
|
|
||||||
if (rlen != 0)
|
|
||||||
screen_write_cnputs(&ctx, rlen, &rgc, "%s", right);
|
|
||||||
|
|
||||||
/* Figure out the offset for the window list. */
|
|
||||||
if (llen != 0)
|
|
||||||
wloffset = llen;
|
|
||||||
else
|
|
||||||
wloffset = 0;
|
|
||||||
if (wlwidth < wlavailable) {
|
|
||||||
switch (options_get_number(s->options, "status-justify")) {
|
|
||||||
case 1: /* centred */
|
|
||||||
wloffset += (wlavailable - wlwidth) / 2;
|
|
||||||
break;
|
|
||||||
case 2: /* right */
|
|
||||||
wloffset += (wlavailable - wlwidth);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (larrow != 0)
|
|
||||||
wloffset++;
|
|
||||||
|
|
||||||
/* Copy the window list. */
|
|
||||||
sl->window_list_offset = -wloffset + wlstart;
|
|
||||||
screen_write_cursormove(&ctx, wloffset, 0, 0);
|
|
||||||
screen_write_fast_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1);
|
|
||||||
screen_free(&window_list);
|
|
||||||
|
|
||||||
/* Save left and right size. */
|
|
||||||
sl->left_size = llen;
|
|
||||||
sl->right_size = rlen;
|
|
||||||
|
|
||||||
screen_write_stop(&ctx);
|
|
||||||
|
|
||||||
out:
|
|
||||||
free(left);
|
|
||||||
free(right);
|
|
||||||
|
|
||||||
if (grid_compare(sl->active->grid, old_screen.grid) == 0) {
|
|
||||||
screen_free(&old_screen);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
screen_free(&old_screen);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Replace special sequences in fmt. */
|
|
||||||
static char *
|
|
||||||
status_replace(struct client *c, struct winlink *wl, const char *fmt)
|
|
||||||
{
|
|
||||||
struct format_tree *ft;
|
|
||||||
char *expanded;
|
|
||||||
u_int tag;
|
|
||||||
|
|
||||||
if (fmt == NULL)
|
|
||||||
return (xstrdup(""));
|
|
||||||
|
|
||||||
if (wl != NULL)
|
|
||||||
tag = FORMAT_WINDOW|wl->window->id;
|
|
||||||
else
|
|
||||||
tag = FORMAT_NONE;
|
|
||||||
if (c->flags & CLIENT_STATUSFORCE)
|
if (c->flags & CLIENT_STATUSFORCE)
|
||||||
ft = format_create(c, NULL, tag, FORMAT_STATUS|FORMAT_FORCE);
|
flags |= FORMAT_FORCE;
|
||||||
else
|
ft = format_create(c, NULL, FORMAT_NONE, flags);
|
||||||
ft = format_create(c, NULL, tag, FORMAT_STATUS);
|
format_defaults(ft, c, NULL, NULL, NULL);
|
||||||
format_defaults(ft, c, NULL, wl, NULL);
|
|
||||||
|
|
||||||
expanded = format_expand_time(ft, fmt);
|
/* Write the status lines. */
|
||||||
|
o = options_get(s->options, "status-format");
|
||||||
|
if (o == NULL)
|
||||||
|
screen_write_clearscreen(&ctx, gc.bg);
|
||||||
|
else {
|
||||||
|
for (i = 0; i < lines; i++) {
|
||||||
|
screen_write_cursormove(&ctx, 0, i, 0);
|
||||||
|
|
||||||
format_free(ft);
|
fmt = options_array_get(o, i);
|
||||||
return (expanded);
|
if (fmt == NULL) {
|
||||||
}
|
screen_write_clearline(&ctx, gc.bg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sle = &sl->entries[i];
|
||||||
|
|
||||||
/* Return winlink status line entry and adjust gc as necessary. */
|
expanded = format_expand_time(ft, fmt);
|
||||||
static char *
|
if (!force &&
|
||||||
status_print(struct client *c, struct winlink *wl, struct grid_cell *gc)
|
sle->expanded != NULL &&
|
||||||
{
|
strcmp(expanded, sle->expanded) == 0) {
|
||||||
struct options *oo = wl->window->options;
|
free(expanded);
|
||||||
struct session *s = c->session;
|
continue;
|
||||||
const char *fmt;
|
}
|
||||||
char *text;
|
changed = 1;
|
||||||
|
|
||||||
style_apply_update(gc, oo, "window-status-style");
|
screen_write_clearline(&ctx, gc.bg);
|
||||||
fmt = options_get_string(oo, "window-status-format");
|
status_free_ranges(&sle->ranges);
|
||||||
if (wl == s->curw) {
|
format_draw(&ctx, &gc, width, expanded, &sle->ranges);
|
||||||
style_apply_update(gc, oo, "window-status-current-style");
|
|
||||||
fmt = options_get_string(oo, "window-status-current-format");
|
free(sle->expanded);
|
||||||
|
sle->expanded = expanded;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (wl == TAILQ_FIRST(&s->lastw))
|
screen_write_stop(&ctx);
|
||||||
style_apply_update(gc, oo, "window-status-last-style");
|
|
||||||
|
|
||||||
if (wl->flags & WINLINK_BELL)
|
/* Free the format tree. */
|
||||||
style_apply_update(gc, oo, "window-status-bell-style");
|
format_free(ft);
|
||||||
else if (wl->flags & (WINLINK_ACTIVITY|WINLINK_SILENCE))
|
|
||||||
style_apply_update(gc, oo, "window-status-activity-style");
|
|
||||||
|
|
||||||
text = status_replace(c, wl, fmt);
|
/* Return if the status line has changed. */
|
||||||
return (text);
|
log_debug("%s exit: force=%d, changed=%d", __func__, force, changed);
|
||||||
|
return (force || changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set a status line message. */
|
/* Set a status line message. */
|
||||||
@ -713,8 +490,9 @@ status_message_redraw(struct client *c)
|
|||||||
style_apply(&gc, s->options, "message-style");
|
style_apply(&gc, s->options, "message-style");
|
||||||
|
|
||||||
screen_write_start(&ctx, NULL, sl->active);
|
screen_write_start(&ctx, NULL, sl->active);
|
||||||
screen_write_cursormove(&ctx, 0, 0, 0);
|
screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines - 1);
|
||||||
for (offset = 0; offset < lines * c->tty.sx; offset++)
|
screen_write_cursormove(&ctx, 0, lines - 1, 0);
|
||||||
|
for (offset = 0; offset < c->tty.sx; offset++)
|
||||||
screen_write_putc(&ctx, &gc, ' ');
|
screen_write_putc(&ctx, &gc, ' ');
|
||||||
screen_write_cursormove(&ctx, 0, lines - 1, 0);
|
screen_write_cursormove(&ctx, 0, lines - 1, 0);
|
||||||
screen_write_nputs(&ctx, len, &gc, "%s", c->message_string);
|
screen_write_nputs(&ctx, len, &gc, "%s", c->message_string);
|
||||||
@ -864,12 +642,13 @@ status_prompt_redraw(struct client *c)
|
|||||||
start = c->tty.sx;
|
start = c->tty.sx;
|
||||||
|
|
||||||
screen_write_start(&ctx, NULL, sl->active);
|
screen_write_start(&ctx, NULL, sl->active);
|
||||||
screen_write_cursormove(&ctx, 0, 0, 0);
|
screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines - 1);
|
||||||
for (offset = 0; offset < lines * c->tty.sx; offset++)
|
screen_write_cursormove(&ctx, 0, lines - 1, 0);
|
||||||
|
for (offset = 0; offset < c->tty.sx; offset++)
|
||||||
screen_write_putc(&ctx, &gc, ' ');
|
screen_write_putc(&ctx, &gc, ' ');
|
||||||
screen_write_cursormove(&ctx, 0, 0, 0);
|
screen_write_cursormove(&ctx, 0, lines - 1, 0);
|
||||||
screen_write_nputs(&ctx, start, &gc, "%s", c->prompt_string);
|
screen_write_nputs(&ctx, start, &gc, "%s", c->prompt_string);
|
||||||
screen_write_cursormove(&ctx, start, 0, 0);
|
screen_write_cursormove(&ctx, start, lines - 1, 0);
|
||||||
|
|
||||||
left = c->tty.sx - start;
|
left = c->tty.sx - start;
|
||||||
if (left == 0)
|
if (left == 0)
|
||||||
|
111
style.c
111
style.c
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
@ -28,7 +30,12 @@
|
|||||||
|
|
||||||
/* Default style. */
|
/* Default style. */
|
||||||
static struct style style_default = {
|
static struct style style_default = {
|
||||||
{ 0, 0, 8, 8, { { ' ' }, 0, 1, 1 } }
|
{ 0, 0, 8, 8, { { ' ' }, 0, 1, 1 } },
|
||||||
|
|
||||||
|
STYLE_ALIGN_DEFAULT,
|
||||||
|
STYLE_LIST_OFF,
|
||||||
|
|
||||||
|
STYLE_RANGE_NONE, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -40,8 +47,8 @@ int
|
|||||||
style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
||||||
{
|
{
|
||||||
struct style saved;
|
struct style saved;
|
||||||
const char delimiters[] = " ,";
|
const char delimiters[] = " ,", *cp;
|
||||||
char tmp[32];
|
char tmp[256], *found;
|
||||||
int value;
|
int value;
|
||||||
size_t end;
|
size_t end;
|
||||||
|
|
||||||
@ -68,6 +75,60 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
|||||||
sy->gc.bg = base->bg;
|
sy->gc.bg = base->bg;
|
||||||
sy->gc.attr = base->attr;
|
sy->gc.attr = base->attr;
|
||||||
sy->gc.flags = base->flags;
|
sy->gc.flags = base->flags;
|
||||||
|
} else if (strcasecmp(tmp, "nolist") == 0)
|
||||||
|
sy->list = STYLE_LIST_OFF;
|
||||||
|
else if (strncasecmp(tmp, "list=", 5) == 0) {
|
||||||
|
if (strcasecmp(tmp + 5, "on") == 0)
|
||||||
|
sy->list = STYLE_LIST_ON;
|
||||||
|
else if (strcasecmp(tmp + 5, "focus") == 0)
|
||||||
|
sy->list = STYLE_LIST_FOCUS;
|
||||||
|
else if (strcasecmp(tmp + 5, "left-marker") == 0)
|
||||||
|
sy->list = STYLE_LIST_LEFT_MARKER;
|
||||||
|
else if (strcasecmp(tmp + 5, "right-marker") == 0)
|
||||||
|
sy->list = STYLE_LIST_RIGHT_MARKER;
|
||||||
|
else
|
||||||
|
goto error;
|
||||||
|
} else if (strcasecmp(tmp, "norange") == 0) {
|
||||||
|
sy->range_type = style_default.range_type;
|
||||||
|
sy->range_argument = style_default.range_type;
|
||||||
|
} else if (end > 6 && strncasecmp(tmp, "range=", 6) == 0) {
|
||||||
|
found = strchr(tmp + 6, '|');
|
||||||
|
if (found != NULL) {
|
||||||
|
*found++ = '\0';
|
||||||
|
if (*found == '\0')
|
||||||
|
goto error;
|
||||||
|
for (cp = found; *cp != '\0'; cp++) {
|
||||||
|
if (!isdigit((u_char)*cp))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strcasecmp(tmp + 6, "left") == 0) {
|
||||||
|
if (found != NULL)
|
||||||
|
goto error;
|
||||||
|
sy->range_type = STYLE_RANGE_LEFT;
|
||||||
|
sy->range_argument = 0;
|
||||||
|
} else if (strcasecmp(tmp + 6, "right") == 0) {
|
||||||
|
if (found != NULL)
|
||||||
|
goto error;
|
||||||
|
sy->range_type = STYLE_RANGE_RIGHT;
|
||||||
|
sy->range_argument = 0;
|
||||||
|
} else if (strcasecmp(tmp + 6, "window") == 0) {
|
||||||
|
if (found == NULL)
|
||||||
|
goto error;
|
||||||
|
sy->range_type = STYLE_RANGE_WINDOW;
|
||||||
|
sy->range_argument = atoi(found);
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(tmp, "noalign") == 0)
|
||||||
|
sy->align = style_default.align;
|
||||||
|
else if (end > 6 && strncasecmp(tmp, "align=", 6) == 0) {
|
||||||
|
if (strcasecmp(tmp + 6, "left") == 0)
|
||||||
|
sy->align = STYLE_ALIGN_LEFT;
|
||||||
|
else if (strcasecmp(tmp + 6, "centre") == 0)
|
||||||
|
sy->align = STYLE_ALIGN_CENTRE;
|
||||||
|
else if (strcasecmp(tmp + 6, "right") == 0)
|
||||||
|
sy->align = STYLE_ALIGN_RIGHT;
|
||||||
|
else
|
||||||
|
goto error;
|
||||||
} else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
|
} else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
|
||||||
if ((value = colour_fromstring(tmp + 3)) == -1)
|
if ((value = colour_fromstring(tmp + 3)) == -1)
|
||||||
goto error;
|
goto error;
|
||||||
@ -111,11 +172,49 @@ style_tostring(struct style *sy)
|
|||||||
{
|
{
|
||||||
struct grid_cell *gc = &sy->gc;
|
struct grid_cell *gc = &sy->gc;
|
||||||
int off = 0;
|
int off = 0;
|
||||||
const char *comma = "";
|
const char *comma = "", *tmp;
|
||||||
static char s[256];
|
static char s[256];
|
||||||
|
char b[16];
|
||||||
|
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
|
|
||||||
|
if (sy->list != STYLE_LIST_OFF) {
|
||||||
|
if (sy->list == STYLE_LIST_ON)
|
||||||
|
tmp = "on";
|
||||||
|
else if (sy->list == STYLE_LIST_FOCUS)
|
||||||
|
tmp = "focus";
|
||||||
|
else if (sy->list == STYLE_LIST_LEFT_MARKER)
|
||||||
|
tmp = "left-marker";
|
||||||
|
else if (sy->list == STYLE_LIST_RIGHT_MARKER)
|
||||||
|
tmp = "right-marker";
|
||||||
|
off += xsnprintf(s + off, sizeof s - off, "%slist=%s", comma,
|
||||||
|
tmp);
|
||||||
|
comma = ",";
|
||||||
|
}
|
||||||
|
if (sy->range_type != STYLE_RANGE_NONE) {
|
||||||
|
if (sy->range_type == STYLE_RANGE_LEFT)
|
||||||
|
tmp = "left";
|
||||||
|
else if (sy->range_type == STYLE_RANGE_RIGHT)
|
||||||
|
tmp = "right";
|
||||||
|
else if (sy->range_type == STYLE_RANGE_WINDOW) {
|
||||||
|
snprintf(b, sizeof b, "window|%u", sy->range_argument);
|
||||||
|
tmp = b;
|
||||||
|
}
|
||||||
|
off += xsnprintf(s + off, sizeof s - off, "%srange=%s", comma,
|
||||||
|
tmp);
|
||||||
|
comma = ",";
|
||||||
|
}
|
||||||
|
if (sy->align != STYLE_ALIGN_DEFAULT) {
|
||||||
|
if (sy->align == STYLE_ALIGN_LEFT)
|
||||||
|
tmp = "left";
|
||||||
|
else if (sy->align == STYLE_ALIGN_CENTRE)
|
||||||
|
tmp = "centre";
|
||||||
|
else if (sy->align == STYLE_ALIGN_RIGHT)
|
||||||
|
tmp = "right";
|
||||||
|
off += xsnprintf(s + off, sizeof s - off, "%salign=%s", comma,
|
||||||
|
tmp);
|
||||||
|
comma = ",";
|
||||||
|
}
|
||||||
if (gc->fg != 8) {
|
if (gc->fg != 8) {
|
||||||
off += xsnprintf(s + off, sizeof s - off, "%sfg=%s", comma,
|
off += xsnprintf(s + off, sizeof s - off, "%sfg=%s", comma,
|
||||||
colour_tostring(gc->fg));
|
colour_tostring(gc->fg));
|
||||||
@ -180,7 +279,7 @@ style_copy(struct style *dst, struct style *src)
|
|||||||
memcpy(dst, src, sizeof *dst);
|
memcpy(dst, src, sizeof *dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if two styles are the same. */
|
/* Check if two styles are (visibly) the same. */
|
||||||
int
|
int
|
||||||
style_equal(struct style *sy1, struct style *sy2)
|
style_equal(struct style *sy1, struct style *sy2)
|
||||||
{
|
{
|
||||||
@ -193,6 +292,8 @@ style_equal(struct style *sy1, struct style *sy2)
|
|||||||
return (0);
|
return (0);
|
||||||
if ((gc1->attr & STYLE_ATTR_MASK) != (gc2->attr & STYLE_ATTR_MASK))
|
if ((gc1->attr & STYLE_ATTR_MASK) != (gc2->attr & STYLE_ATTR_MASK))
|
||||||
return (0);
|
return (0);
|
||||||
|
if (sy1->align != sy2->align)
|
||||||
|
return (0);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
72
tmux.1
72
tmux.1
@ -255,6 +255,7 @@ client.
|
|||||||
.It !
|
.It !
|
||||||
Break the current pane out of the window.
|
Break the current pane out of the window.
|
||||||
.It \&"
|
.It \&"
|
||||||
|
.\" "
|
||||||
Split the current pane into two, top and bottom.
|
Split the current pane into two, top and bottom.
|
||||||
.It #
|
.It #
|
||||||
List all paste buffers.
|
List all paste buffers.
|
||||||
@ -2925,9 +2926,22 @@ is on.
|
|||||||
The values are the same as those for
|
The values are the same as those for
|
||||||
.Ic activity-action .
|
.Ic activity-action .
|
||||||
.It Xo Ic status
|
.It Xo Ic status
|
||||||
.Op Ic on | off
|
.Op Ic off | on | 2 | 3 | 4 | 5
|
||||||
.Xc
|
.Xc
|
||||||
Show or hide the status line.
|
Show or hide the status line or specify its size.
|
||||||
|
Using
|
||||||
|
.Ic on
|
||||||
|
gives a status line one row in height;
|
||||||
|
.Ic 2 ,
|
||||||
|
.Ic 3 ,
|
||||||
|
.Ic 4
|
||||||
|
or
|
||||||
|
.Ic 5
|
||||||
|
more rows.
|
||||||
|
.It Ic status-format[] Ar format
|
||||||
|
Specify the format to be used for each line of the status line.
|
||||||
|
The default builds the top status line from the various individual status
|
||||||
|
options below.
|
||||||
.It Ic status-interval Ar interval
|
.It Ic status-interval Ar interval
|
||||||
Update the status line every
|
Update the status line every
|
||||||
.Ar interval
|
.Ar interval
|
||||||
@ -3771,6 +3785,7 @@ For example, to get a list of windows formatted like the status line:
|
|||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
#{W:#{E:window-status-format} ,#{E:window-status-current-format} }
|
#{W:#{E:window-status-format} ,#{E:window-status-current-format} }
|
||||||
.Ed
|
.Ed
|
||||||
|
.Pp
|
||||||
A prefix of the form
|
A prefix of the form
|
||||||
.Ql s/foo/bar/:
|
.Ql s/foo/bar/:
|
||||||
will substitute
|
will substitute
|
||||||
@ -3977,8 +3992,9 @@ for the terminal default colour; or a hexadecimal RGB string such as
|
|||||||
Set the background colour.
|
Set the background colour.
|
||||||
.It Ic none
|
.It Ic none
|
||||||
Set no attributes (turn off any active attributes).
|
Set no attributes (turn off any active attributes).
|
||||||
.It Xo Ic bright (or
|
.It Xo Ic bright
|
||||||
.Ic bold )
|
(or
|
||||||
|
.Ic bold ) ,
|
||||||
.Ic dim ,
|
.Ic dim ,
|
||||||
.Ic underscore ,
|
.Ic underscore ,
|
||||||
.Ic blink ,
|
.Ic blink ,
|
||||||
@ -3995,6 +4011,54 @@ Set an attribute.
|
|||||||
Any of the attributes may be prefixed with
|
Any of the attributes may be prefixed with
|
||||||
.Ql no
|
.Ql no
|
||||||
to unset.
|
to unset.
|
||||||
|
.It Xo Ic align=left
|
||||||
|
(or
|
||||||
|
.Ic noalign ) ,
|
||||||
|
.Ic align=centre ,
|
||||||
|
.Ic align=right
|
||||||
|
.Xc
|
||||||
|
Align text to the left, centre or right of the available space if appropriate.
|
||||||
|
.It Xo Ic list=on ,
|
||||||
|
.Ic list=focus ,
|
||||||
|
.Ic list=left-marker ,
|
||||||
|
.Ic list=right=marker ,
|
||||||
|
.Ic nolist
|
||||||
|
.Xc
|
||||||
|
Mark the position of the various window list components in the
|
||||||
|
.Ic status-format
|
||||||
|
option:
|
||||||
|
.Ic list=on
|
||||||
|
marks the start of the list;
|
||||||
|
.Ic list=focus
|
||||||
|
is the part of the list that should be kept in focus if the entire list won't fit
|
||||||
|
in the available space (typically the current window);
|
||||||
|
.Ic list=left-marker
|
||||||
|
and
|
||||||
|
.Ic list=right-marker
|
||||||
|
mark the text to be used to mark that text has been trimmed from the left or
|
||||||
|
right of the list if there is not enough space.
|
||||||
|
.It Xo Ic range=left ,
|
||||||
|
.Ic range=right ,
|
||||||
|
.Ic range=window|X ,
|
||||||
|
.Ic norange
|
||||||
|
.Xc
|
||||||
|
Mark a range in the
|
||||||
|
. Ic status-format
|
||||||
|
option.
|
||||||
|
.Ic range=left
|
||||||
|
and
|
||||||
|
.Ic range=right
|
||||||
|
are the text used for the
|
||||||
|
.Ql StatusLeft
|
||||||
|
and
|
||||||
|
.Ql StatusRight
|
||||||
|
mouse keys.
|
||||||
|
.Ic range=window|X
|
||||||
|
is the range for a window passed to the
|
||||||
|
.Ql Status
|
||||||
|
mouse key, where
|
||||||
|
.Ql X
|
||||||
|
is a window index.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
Examples are:
|
Examples are:
|
||||||
|
85
tmux.h
85
tmux.h
@ -637,9 +637,50 @@ struct grid {
|
|||||||
struct grid_line *linedata;
|
struct grid_line *linedata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Style alignment. */
|
||||||
|
enum style_align {
|
||||||
|
STYLE_ALIGN_DEFAULT,
|
||||||
|
STYLE_ALIGN_LEFT,
|
||||||
|
STYLE_ALIGN_CENTRE,
|
||||||
|
STYLE_ALIGN_RIGHT
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Style list. */
|
||||||
|
enum style_list {
|
||||||
|
STYLE_LIST_OFF,
|
||||||
|
STYLE_LIST_ON,
|
||||||
|
STYLE_LIST_FOCUS,
|
||||||
|
STYLE_LIST_LEFT_MARKER,
|
||||||
|
STYLE_LIST_RIGHT_MARKER,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Style range. */
|
||||||
|
enum style_range_type {
|
||||||
|
STYLE_RANGE_NONE,
|
||||||
|
STYLE_RANGE_LEFT,
|
||||||
|
STYLE_RANGE_RIGHT,
|
||||||
|
STYLE_RANGE_WINDOW
|
||||||
|
};
|
||||||
|
struct style_range {
|
||||||
|
enum style_range_type type;
|
||||||
|
u_int argument;
|
||||||
|
|
||||||
|
u_int start;
|
||||||
|
u_int end; /* not included */
|
||||||
|
|
||||||
|
TAILQ_ENTRY(style_range) entry;
|
||||||
|
};
|
||||||
|
TAILQ_HEAD(style_ranges, style_range);
|
||||||
|
|
||||||
/* Style option. */
|
/* Style option. */
|
||||||
struct style {
|
struct style {
|
||||||
struct grid_cell gc;
|
struct grid_cell gc;
|
||||||
|
|
||||||
|
enum style_align align;
|
||||||
|
enum style_list list;
|
||||||
|
|
||||||
|
enum style_range_type range_type;
|
||||||
|
u_int range_argument;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Hook data structures. */
|
/* Hook data structures. */
|
||||||
@ -871,10 +912,6 @@ struct winlink {
|
|||||||
struct session *session;
|
struct session *session;
|
||||||
struct window *window;
|
struct window *window;
|
||||||
|
|
||||||
size_t status_width;
|
|
||||||
struct grid_cell status_cell;
|
|
||||||
char *status_text;
|
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
#define WINLINK_BELL 0x1
|
#define WINLINK_BELL 0x1
|
||||||
#define WINLINK_ACTIVITY 0x2
|
#define WINLINK_ACTIVITY 0x2
|
||||||
@ -956,6 +993,7 @@ struct session {
|
|||||||
struct winlinks windows;
|
struct winlinks windows;
|
||||||
|
|
||||||
int statusat;
|
int statusat;
|
||||||
|
u_int statuslines;
|
||||||
|
|
||||||
struct hooks *hooks;
|
struct hooks *hooks;
|
||||||
struct options *options;
|
struct options *options;
|
||||||
@ -1000,7 +1038,9 @@ struct mouse_event {
|
|||||||
int valid;
|
int valid;
|
||||||
|
|
||||||
key_code key;
|
key_code key;
|
||||||
|
|
||||||
int statusat;
|
int statusat;
|
||||||
|
u_int statuslines;
|
||||||
|
|
||||||
u_int x;
|
u_int x;
|
||||||
u_int y;
|
u_int y;
|
||||||
@ -1315,17 +1355,20 @@ struct cmd_entry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Status line. */
|
/* Status line. */
|
||||||
|
#define STATUS_LINES_LIMIT 5
|
||||||
|
struct status_line_entry {
|
||||||
|
char *expanded;
|
||||||
|
struct style_ranges ranges;
|
||||||
|
};
|
||||||
struct status_line {
|
struct status_line {
|
||||||
struct event timer;
|
struct event timer;
|
||||||
|
|
||||||
struct screen screen;
|
struct screen screen;
|
||||||
struct screen *active;
|
struct screen *active;
|
||||||
int references;
|
int references;
|
||||||
|
|
||||||
int window_list_offset;
|
struct grid_cell style;
|
||||||
|
struct status_line_entry entries[STATUS_LINES_LIMIT];
|
||||||
u_int left_size;
|
|
||||||
u_int right_size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Client connection. */
|
/* Client connection. */
|
||||||
@ -1584,6 +1627,7 @@ char *paste_make_sample(struct paste_buffer *);
|
|||||||
#define FORMAT_PANE 0x80000000U
|
#define FORMAT_PANE 0x80000000U
|
||||||
#define FORMAT_WINDOW 0x40000000U
|
#define FORMAT_WINDOW 0x40000000U
|
||||||
struct format_tree;
|
struct format_tree;
|
||||||
|
const char *format_skip(const char *s, const char *end);
|
||||||
int format_true(const char *);
|
int format_true(const char *);
|
||||||
struct format_tree *format_create(struct client *, struct cmdq_item *, int,
|
struct format_tree *format_create(struct client *, struct cmdq_item *, int,
|
||||||
int);
|
int);
|
||||||
@ -1606,6 +1650,14 @@ void format_defaults_paste_buffer(struct format_tree *,
|
|||||||
struct paste_buffer *);
|
struct paste_buffer *);
|
||||||
void format_lost_client(struct client *);
|
void format_lost_client(struct client *);
|
||||||
|
|
||||||
|
/* format-draw.c */
|
||||||
|
void format_draw(struct screen_write_ctx *,
|
||||||
|
const struct grid_cell *, u_int, const char *,
|
||||||
|
struct style_ranges *);
|
||||||
|
u_int format_width(const char *);
|
||||||
|
char *format_trim_left(const char *, u_int);
|
||||||
|
char *format_trim_right(const char *, u_int);
|
||||||
|
|
||||||
/* hooks.c */
|
/* hooks.c */
|
||||||
struct hook;
|
struct hook;
|
||||||
struct hooks *hooks_get(struct session *);
|
struct hooks *hooks_get(struct session *);
|
||||||
@ -1981,7 +2033,7 @@ void status_timer_start_all(void);
|
|||||||
void status_update_cache(struct session *);
|
void status_update_cache(struct session *);
|
||||||
int status_at_line(struct client *);
|
int status_at_line(struct client *);
|
||||||
u_int status_line_size(struct client *);
|
u_int status_line_size(struct client *);
|
||||||
struct window *status_get_window_at(struct client *, u_int);
|
struct style_range *status_get_range(struct client *, u_int, u_int);
|
||||||
void status_init(struct client *);
|
void status_init(struct client *);
|
||||||
void status_free(struct client *);
|
void status_free(struct client *);
|
||||||
int status_redraw(struct client *);
|
int status_redraw(struct client *);
|
||||||
@ -2081,9 +2133,6 @@ void screen_write_start(struct screen_write_ctx *, struct window_pane *,
|
|||||||
struct screen *);
|
struct screen *);
|
||||||
void screen_write_stop(struct screen_write_ctx *);
|
void screen_write_stop(struct screen_write_ctx *);
|
||||||
void screen_write_reset(struct screen_write_ctx *);
|
void screen_write_reset(struct screen_write_ctx *);
|
||||||
size_t printflike(1, 2) screen_write_cstrlen(const char *, ...);
|
|
||||||
void printflike(4, 5) screen_write_cnputs(struct screen_write_ctx *,
|
|
||||||
ssize_t, const struct grid_cell *, const char *, ...);
|
|
||||||
size_t printflike(1, 2) screen_write_strlen(const char *, ...);
|
size_t printflike(1, 2) screen_write_strlen(const char *, ...);
|
||||||
void printflike(3, 4) screen_write_puts(struct screen_write_ctx *,
|
void printflike(3, 4) screen_write_puts(struct screen_write_ctx *,
|
||||||
const struct grid_cell *, const char *, ...);
|
const struct grid_cell *, const char *, ...);
|
||||||
@ -2420,8 +2469,6 @@ u_int utf8_strwidth(const struct utf8_data *, ssize_t);
|
|||||||
struct utf8_data *utf8_fromcstr(const char *);
|
struct utf8_data *utf8_fromcstr(const char *);
|
||||||
char *utf8_tocstr(struct utf8_data *);
|
char *utf8_tocstr(struct utf8_data *);
|
||||||
u_int utf8_cstrwidth(const char *);
|
u_int utf8_cstrwidth(const char *);
|
||||||
char *utf8_rtrimcstr(const char *, u_int);
|
|
||||||
char *utf8_trimcstr(const char *, u_int);
|
|
||||||
char *utf8_padcstr(const char *, u_int);
|
char *utf8_padcstr(const char *, u_int);
|
||||||
|
|
||||||
/* osdep-*.c */
|
/* osdep-*.c */
|
||||||
|
60
utf8.c
60
utf8.c
@ -408,66 +408,6 @@ utf8_cstrwidth(const char *s)
|
|||||||
return (width);
|
return (width);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Trim UTF-8 string to width. Caller frees. */
|
|
||||||
char *
|
|
||||||
utf8_trimcstr(const char *s, u_int width)
|
|
||||||
{
|
|
||||||
struct utf8_data *tmp, *next;
|
|
||||||
char *out;
|
|
||||||
u_int at;
|
|
||||||
|
|
||||||
tmp = utf8_fromcstr(s);
|
|
||||||
|
|
||||||
at = 0;
|
|
||||||
for (next = tmp; next->size != 0; next++) {
|
|
||||||
if (at + next->width > width) {
|
|
||||||
next->size = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
at += next->width;
|
|
||||||
}
|
|
||||||
|
|
||||||
out = utf8_tocstr(tmp);
|
|
||||||
free(tmp);
|
|
||||||
return (out);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trim UTF-8 string to width. Caller frees. */
|
|
||||||
char *
|
|
||||||
utf8_rtrimcstr(const char *s, u_int width)
|
|
||||||
{
|
|
||||||
struct utf8_data *tmp, *next, *end;
|
|
||||||
char *out;
|
|
||||||
u_int at;
|
|
||||||
|
|
||||||
tmp = utf8_fromcstr(s);
|
|
||||||
|
|
||||||
for (end = tmp; end->size != 0; end++)
|
|
||||||
/* nothing */;
|
|
||||||
if (end == tmp) {
|
|
||||||
free(tmp);
|
|
||||||
return (xstrdup(""));
|
|
||||||
}
|
|
||||||
next = end - 1;
|
|
||||||
|
|
||||||
at = 0;
|
|
||||||
for (;;) {
|
|
||||||
if (at + next->width > width) {
|
|
||||||
next++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
at += next->width;
|
|
||||||
|
|
||||||
if (next == tmp)
|
|
||||||
break;
|
|
||||||
next--;
|
|
||||||
}
|
|
||||||
|
|
||||||
out = utf8_tocstr(next);
|
|
||||||
free(tmp);
|
|
||||||
return (out);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pad UTF-8 string to width. Caller frees. */
|
/* Pad UTF-8 string to width. Caller frees. */
|
||||||
char *
|
char *
|
||||||
utf8_padcstr(const char *s, u_int width)
|
utf8_padcstr(const char *s, u_int width)
|
||||||
|
@ -217,20 +217,36 @@ window_client_draw(__unused void *modedata, void *itemdata,
|
|||||||
{
|
{
|
||||||
struct window_client_itemdata *item = itemdata;
|
struct window_client_itemdata *item = itemdata;
|
||||||
struct client *c = item->c;
|
struct client *c = item->c;
|
||||||
|
struct screen *s = ctx->s;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
u_int cx = ctx->s->cx, cy = ctx->s->cy;
|
u_int cx = s->cx, cy = s->cy, lines, at;
|
||||||
|
|
||||||
if (c->session == NULL || (c->flags & (CLIENT_DEAD|CLIENT_DETACHING)))
|
if (c->session == NULL || (c->flags & (CLIENT_DEAD|CLIENT_DETACHING)))
|
||||||
return;
|
return;
|
||||||
wp = c->session->curw->window->active;
|
wp = c->session->curw->window->active;
|
||||||
|
|
||||||
screen_write_preview(ctx, &wp->base, sx, sy - 3);
|
lines = status_line_size(c);
|
||||||
|
if (lines >= sy)
|
||||||
|
lines = 0;
|
||||||
|
if (status_at_line(c) == 0)
|
||||||
|
at = lines;
|
||||||
|
else
|
||||||
|
at = 0;
|
||||||
|
|
||||||
screen_write_cursormove(ctx, cx, cy + sy - 2, 0);
|
screen_write_cursormove(ctx, cx, cy + at, 0);
|
||||||
|
screen_write_preview(ctx, &wp->base, sx, sy - 2 - lines);
|
||||||
|
|
||||||
|
if (at != 0)
|
||||||
|
screen_write_cursormove(ctx, cx, cy + 2, 0);
|
||||||
|
else
|
||||||
|
screen_write_cursormove(ctx, cx, cy + sy - 1 - lines, 0);
|
||||||
screen_write_hline(ctx, sx, 0, 0);
|
screen_write_hline(ctx, sx, 0, 0);
|
||||||
|
|
||||||
screen_write_cursormove(ctx, cx, cy + sy - 1, 0);
|
if (at != 0)
|
||||||
screen_write_fast_copy(ctx, &c->status.screen, 0, 0, sx, 1);
|
screen_write_cursormove(ctx, cx, cy, 0);
|
||||||
|
else
|
||||||
|
screen_write_cursormove(ctx, cx, cy + sy - lines, 0);
|
||||||
|
screen_write_fast_copy(ctx, &c->status.screen, 0, 0, sx, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct screen *
|
static struct screen *
|
||||||
|
Loading…
Reference in New Issue
Block a user