mirror of
https://github.com/tmux/tmux.git
synced 2025-03-25 07:18:48 +00:00
Merge branch 'obsd-master'
This commit is contained in:
commit
5e9757b30b
@ -88,7 +88,6 @@ dist_tmux_SOURCES = \
|
|||||||
cmd-list-panes.c \
|
cmd-list-panes.c \
|
||||||
cmd-list-sessions.c \
|
cmd-list-sessions.c \
|
||||||
cmd-list-windows.c \
|
cmd-list-windows.c \
|
||||||
cmd-list.c \
|
|
||||||
cmd-load-buffer.c \
|
cmd-load-buffer.c \
|
||||||
cmd-lock-server.c \
|
cmd-lock-server.c \
|
||||||
cmd-move-window.c \
|
cmd-move-window.c \
|
||||||
@ -152,6 +151,7 @@ dist_tmux_SOURCES = \
|
|||||||
options.c \
|
options.c \
|
||||||
paste.c \
|
paste.c \
|
||||||
proc.c \
|
proc.c \
|
||||||
|
regsub.c \
|
||||||
resize.c \
|
resize.c \
|
||||||
screen-redraw.c \
|
screen-redraw.c \
|
||||||
screen-write.c \
|
screen-write.c \
|
||||||
|
@ -93,7 +93,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_WAIT);
|
return (CMD_RETURN_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
file = server_client_get_path(c, path);
|
file = server_client_get_path(item->client, path);
|
||||||
free(path);
|
free(path);
|
||||||
|
|
||||||
f = fopen(file, "rb");
|
f = fopen(file, "rb");
|
||||||
|
31
cmd-parse.y
31
cmd-parse.y
@ -59,6 +59,7 @@ struct cmd_parse_state {
|
|||||||
size_t len;
|
size_t len;
|
||||||
size_t off;
|
size_t off;
|
||||||
|
|
||||||
|
int condition;
|
||||||
int eol;
|
int eol;
|
||||||
int eof;
|
int eof;
|
||||||
struct cmd_parse_input *input;
|
struct cmd_parse_input *input;
|
||||||
@ -104,7 +105,7 @@ static void cmd_parse_print_commands(struct cmd_parse_input *, u_int,
|
|||||||
%token ENDIF
|
%token ENDIF
|
||||||
%token <token> FORMAT TOKEN EQUALS
|
%token <token> FORMAT TOKEN EQUALS
|
||||||
|
|
||||||
%type <token> argument expanded
|
%type <token> argument expanded format
|
||||||
%type <arguments> arguments
|
%type <arguments> arguments
|
||||||
%type <flag> if_open if_elif
|
%type <flag> if_open if_elif
|
||||||
%type <elif> elif elif1
|
%type <elif> elif elif1
|
||||||
@ -160,7 +161,16 @@ statement : condition
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expanded : FORMAT
|
format : FORMAT
|
||||||
|
{
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
| TOKEN
|
||||||
|
{
|
||||||
|
$$ = $1;
|
||||||
|
}
|
||||||
|
|
||||||
|
expanded : format
|
||||||
{
|
{
|
||||||
struct cmd_parse_state *ps = &parse_state;
|
struct cmd_parse_state *ps = &parse_state;
|
||||||
struct cmd_parse_input *pi = ps->input;
|
struct cmd_parse_input *pi = ps->input;
|
||||||
@ -507,7 +517,10 @@ cmd_parse_print_commands(struct cmd_parse_input *pi, u_int line,
|
|||||||
|
|
||||||
if (pi->item != NULL && (pi->flags & CMD_PARSE_VERBOSE)) {
|
if (pi->item != NULL && (pi->flags & CMD_PARSE_VERBOSE)) {
|
||||||
s = cmd_list_print(cmdlist, 0);
|
s = cmd_list_print(cmdlist, 0);
|
||||||
cmdq_print(pi->item, "%u: %s", line, s);
|
if (pi->file != NULL)
|
||||||
|
cmdq_print(pi->item, "%s:%u: %s", pi->file, line, s);
|
||||||
|
else
|
||||||
|
cmdq_print(pi->item, "%u: %s", line, s);
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -967,12 +980,15 @@ yylex(void)
|
|||||||
{
|
{
|
||||||
struct cmd_parse_state *ps = &parse_state;
|
struct cmd_parse_state *ps = &parse_state;
|
||||||
char *token, *cp;
|
char *token, *cp;
|
||||||
int ch, next;
|
int ch, next, condition;
|
||||||
|
|
||||||
if (ps->eol)
|
if (ps->eol)
|
||||||
ps->input->line++;
|
ps->input->line++;
|
||||||
ps->eol = 0;
|
ps->eol = 0;
|
||||||
|
|
||||||
|
condition = ps->condition;
|
||||||
|
ps->condition = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ch = yylex_getc();
|
ch = yylex_getc();
|
||||||
|
|
||||||
@ -1012,11 +1028,11 @@ yylex(void)
|
|||||||
|
|
||||||
if (ch == '#') {
|
if (ch == '#') {
|
||||||
/*
|
/*
|
||||||
* #{ opens a format; anything else is a comment,
|
* #{ after a condition opens a format; anything else
|
||||||
* ignore up to the end of the line.
|
* is a comment, ignore up to the end of the line.
|
||||||
*/
|
*/
|
||||||
next = yylex_getc();
|
next = yylex_getc();
|
||||||
if (next == '{') {
|
if (condition && next == '{') {
|
||||||
yylval.token = yylex_format();
|
yylval.token = yylex_format();
|
||||||
if (yylval.token == NULL)
|
if (yylval.token == NULL)
|
||||||
return (ERROR);
|
return (ERROR);
|
||||||
@ -1043,6 +1059,7 @@ yylex(void)
|
|||||||
}
|
}
|
||||||
if (*cp == '\0')
|
if (*cp == '\0')
|
||||||
return (TOKEN);
|
return (TOKEN);
|
||||||
|
ps->condition = 1;
|
||||||
if (strcmp(yylval.token, "%if") == 0) {
|
if (strcmp(yylval.token, "%if") == 0) {
|
||||||
free(yylval.token);
|
free(yylval.token);
|
||||||
return (IF);
|
return (IF);
|
||||||
|
@ -104,7 +104,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (args_has(self->args, 'a'))
|
if (args_has(self->args, 'a'))
|
||||||
flags = "ab";
|
flags = "ab";
|
||||||
|
|
||||||
file = server_client_get_path(c, path);
|
file = server_client_get_path(item->client, path);
|
||||||
free(path);
|
free(path);
|
||||||
|
|
||||||
f = fopen(file, flags);
|
f = fopen(file, flags);
|
||||||
|
110
format.c
110
format.c
@ -23,6 +23,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
#include <regex.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -1112,7 +1113,7 @@ format_find(struct format_tree *ft, const char *key, int modifiers)
|
|||||||
envent = environ_find(ft->s->environ, key);
|
envent = environ_find(ft->s->environ, key);
|
||||||
if (envent == NULL)
|
if (envent == NULL)
|
||||||
envent = environ_find(global_environ, key);
|
envent = environ_find(global_environ, key);
|
||||||
if (envent != NULL) {
|
if (envent != NULL && envent->value != NULL) {
|
||||||
found = xstrdup(envent->value);
|
found = xstrdup(envent->value);
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
@ -1263,7 +1264,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
|||||||
cp++;
|
cp++;
|
||||||
|
|
||||||
/* Check single character modifiers with no arguments. */
|
/* Check single character modifiers with no arguments. */
|
||||||
if (strchr("lmCbdtqETSWP<>", cp[0]) != NULL &&
|
if (strchr("lbdtqETSWP<>", cp[0]) != NULL &&
|
||||||
format_is_end(cp[1])) {
|
format_is_end(cp[1])) {
|
||||||
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
||||||
cp++;
|
cp++;
|
||||||
@ -1284,7 +1285,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now try single character with arguments. */
|
/* Now try single character with arguments. */
|
||||||
if (strchr("s=", cp[0]) == NULL)
|
if (strchr("mCs=", cp[0]) == NULL)
|
||||||
break;
|
break;
|
||||||
c = cp[0];
|
c = cp[0];
|
||||||
|
|
||||||
@ -1345,39 +1346,67 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Match against an fnmatch(3) pattern or regular expression. */
|
||||||
|
static char *
|
||||||
|
format_match(struct format_modifier *fm, const char *pattern, const char *text)
|
||||||
|
{
|
||||||
|
const char *s = "";
|
||||||
|
regex_t r;
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
|
if (fm->argc >= 1)
|
||||||
|
s = fm->argv[0];
|
||||||
|
if (strchr(s, 'r') == NULL) {
|
||||||
|
if (strchr(s, 'i') != NULL)
|
||||||
|
flags |= FNM_CASEFOLD;
|
||||||
|
if (fnmatch(pattern, text, flags) != 0)
|
||||||
|
return (xstrdup("0"));
|
||||||
|
} else {
|
||||||
|
flags = REG_EXTENDED|REG_NOSUB;
|
||||||
|
if (strchr(s, 'i') != NULL)
|
||||||
|
flags |= REG_ICASE;
|
||||||
|
if (regcomp(&r, pattern, flags) != 0)
|
||||||
|
return (xstrdup("0"));
|
||||||
|
if (regexec(&r, text, 0, NULL, 0) != 0) {
|
||||||
|
regfree(&r);
|
||||||
|
return (xstrdup("0"));
|
||||||
|
}
|
||||||
|
regfree(&r);
|
||||||
|
}
|
||||||
|
return (xstrdup("1"));
|
||||||
|
}
|
||||||
|
|
||||||
/* Perform substitution in string. */
|
/* Perform substitution in string. */
|
||||||
static char *
|
static char *
|
||||||
format_substitute(const char *source, const char *from, const char *to)
|
format_sub(struct format_modifier *fm, const char *text, const char *pattern,
|
||||||
|
const char *with)
|
||||||
{
|
{
|
||||||
char *copy, *new;
|
char *value;
|
||||||
const char *cp;
|
int flags = REG_EXTENDED;
|
||||||
size_t fromlen, tolen, newlen, used;
|
|
||||||
|
|
||||||
fromlen = strlen(from);
|
if (fm->argc >= 3 && strchr(fm->argv[2], 'i') != NULL)
|
||||||
tolen = strlen(to);
|
flags |= REG_ICASE;
|
||||||
|
value = regsub(pattern, with, text, flags);
|
||||||
|
if (value == NULL)
|
||||||
|
return (xstrdup(text));
|
||||||
|
return (value);
|
||||||
|
}
|
||||||
|
|
||||||
newlen = strlen(source) + 1;
|
/* Search inside pane. */
|
||||||
copy = new = xmalloc(newlen);
|
static char *
|
||||||
|
format_search(struct format_modifier *fm, struct window_pane *wp, const char *s)
|
||||||
|
{
|
||||||
|
int ignore = 0, regex = 0;
|
||||||
|
char *value;
|
||||||
|
|
||||||
for (cp = source; *cp != '\0'; /* nothing */) {
|
if (fm->argc >= 1) {
|
||||||
if (strncmp(cp, from, fromlen) != 0) {
|
if (strchr(fm->argv[0], 'i') != NULL)
|
||||||
*new++ = *cp++;
|
ignore = 1;
|
||||||
continue;
|
if (strchr(fm->argv[0], 'r') != NULL)
|
||||||
}
|
regex = 1;
|
||||||
used = new - copy;
|
|
||||||
|
|
||||||
newlen += tolen;
|
|
||||||
copy = xrealloc(copy, newlen);
|
|
||||||
|
|
||||||
new = copy + used;
|
|
||||||
memcpy(new, to, tolen);
|
|
||||||
|
|
||||||
new += tolen;
|
|
||||||
cp += fromlen;
|
|
||||||
}
|
}
|
||||||
|
xasprintf(&value, "%u", window_pane_search(wp, s, regex, ignore));
|
||||||
*new = '\0';
|
return (value);
|
||||||
return (copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop over sessions. */
|
/* Loop over sessions. */
|
||||||
@ -1522,11 +1551,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
|||||||
char *copy0, *condition, *found, *new;
|
char *copy0, *condition, *found, *new;
|
||||||
char *value, *left, *right;
|
char *value, *left, *right;
|
||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
int modifiers = 0, limit = 0;
|
int modifiers = 0, limit = 0, j;
|
||||||
struct format_modifier *list, *fm, *cmp = NULL, *search = NULL;
|
struct format_modifier *list, *fm, *cmp = NULL, *search = NULL;
|
||||||
struct format_modifier *sub = NULL;
|
struct format_modifier *sub = NULL;
|
||||||
u_int i, count;
|
u_int i, count;
|
||||||
int j;
|
|
||||||
|
|
||||||
/* Make a copy of the key. */
|
/* Make a copy of the key. */
|
||||||
copy = copy0 = xstrndup(key, keylen);
|
copy = copy0 = xstrndup(key, keylen);
|
||||||
@ -1553,18 +1581,18 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
|||||||
search = fm;
|
search = fm;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if (fm->argc != 2)
|
if (fm->argc < 2)
|
||||||
break;
|
break;
|
||||||
sub = fm;
|
sub = fm;
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
if (fm->argc != 1 && fm->argc != 2)
|
if (fm->argc < 1)
|
||||||
break;
|
break;
|
||||||
limit = strtonum(fm->argv[0], INT_MIN, INT_MAX,
|
limit = strtonum(fm->argv[0], INT_MIN, INT_MAX,
|
||||||
&errptr);
|
&errptr);
|
||||||
if (errptr != NULL)
|
if (errptr != NULL)
|
||||||
limit = 0;
|
limit = 0;
|
||||||
if (fm->argc == 2 && fm->argv[1] != NULL)
|
if (fm->argc >= 2 && fm->argv[1] != NULL)
|
||||||
marker = fm->argv[1];
|
marker = fm->argv[1];
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
@ -1635,7 +1663,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
|||||||
value = xstrdup("0");
|
value = xstrdup("0");
|
||||||
} else {
|
} else {
|
||||||
format_log(ft, "search '%s' pane %%%u", copy, wp->id);
|
format_log(ft, "search '%s' pane %%%u", copy, wp->id);
|
||||||
xasprintf(&value, "%u", window_pane_search(wp, copy));
|
value = format_search(fm, wp, copy);
|
||||||
}
|
}
|
||||||
} else if (cmp != NULL) {
|
} else if (cmp != NULL) {
|
||||||
/* Comparison of left and right. */
|
/* Comparison of left and right. */
|
||||||
@ -1687,12 +1715,8 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
|||||||
value = xstrdup("1");
|
value = xstrdup("1");
|
||||||
else
|
else
|
||||||
value = xstrdup("0");
|
value = xstrdup("0");
|
||||||
} else if (strcmp(cmp->modifier, "m") == 0) {
|
} else if (strcmp(cmp->modifier, "m") == 0)
|
||||||
if (fnmatch(left, right, 0) == 0)
|
value = format_match(fm, left, right);
|
||||||
value = xstrdup("1");
|
|
||||||
else
|
|
||||||
value = xstrdup("0");
|
|
||||||
}
|
|
||||||
|
|
||||||
free(right);
|
free(right);
|
||||||
free(left);
|
free(left);
|
||||||
@ -1770,8 +1794,8 @@ done:
|
|||||||
|
|
||||||
/* Perform substitution if any. */
|
/* Perform substitution if any. */
|
||||||
if (sub != NULL) {
|
if (sub != NULL) {
|
||||||
new = format_substitute(value, sub->argv[0], sub->argv[1]);
|
new = format_sub(sub, value, sub->argv[0], sub->argv[1]);
|
||||||
format_log(ft, "substituted '%s' to '%s: %s", sub->argv[0],
|
format_log(ft, "substituted '%s' to '%s': %s", sub->argv[0],
|
||||||
sub->argv[1], new);
|
sub->argv[1], new);
|
||||||
free(value);
|
free(value);
|
||||||
value = new;
|
value = new;
|
||||||
|
98
regsub.c
Normal file
98
regsub.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/* $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 <regex.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tmux.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
regsub_copy(char **buf, size_t *len, const char *text, size_t start,
|
||||||
|
size_t end)
|
||||||
|
{
|
||||||
|
size_t add = end - start;
|
||||||
|
|
||||||
|
*buf = xrealloc(*buf, (*len) + add + 1);
|
||||||
|
memcpy((*buf) + *len, text + start, add);
|
||||||
|
(*len) += add;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
regsub_expand(char **buf, size_t *len, const char *with, const char *text,
|
||||||
|
regmatch_t *m, u_int n)
|
||||||
|
{
|
||||||
|
const char *cp;
|
||||||
|
u_int i;
|
||||||
|
|
||||||
|
for (cp = with; *cp != '\0'; cp++) {
|
||||||
|
if (*cp == '\\') {
|
||||||
|
cp++;
|
||||||
|
if (*cp >= '0' && *cp <= '9') {
|
||||||
|
i = *cp - '0';
|
||||||
|
if (i < n && m[i].rm_so != m[i].rm_eo) {
|
||||||
|
regsub_copy(buf, len, text, m[i].rm_so,
|
||||||
|
m[i].rm_eo);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*buf = xrealloc(*buf, (*len) + 2);
|
||||||
|
(*buf)[(*len)++] = *cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
regsub(const char *pattern, const char *with, const char *text, int flags)
|
||||||
|
{
|
||||||
|
regex_t r;
|
||||||
|
regmatch_t m[10];
|
||||||
|
size_t start, end, len = 0;
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
if (*text == '\0')
|
||||||
|
return (xstrdup(""));
|
||||||
|
if (regcomp(&r, pattern, flags) != 0)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
start = 0;
|
||||||
|
end = strlen(text);
|
||||||
|
|
||||||
|
while (start != end) {
|
||||||
|
m[0].rm_so = start;
|
||||||
|
m[0].rm_eo = end;
|
||||||
|
|
||||||
|
if (regexec(&r, text, nitems(m), m, REG_STARTEND) != 0) {
|
||||||
|
regsub_copy(&buf, &len, text, start, end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (m[0].rm_so == m[0].rm_eo) {
|
||||||
|
regsub_copy(&buf, &len, text, start, end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
regsub_copy(&buf, &len, text, start, m[0].rm_so);
|
||||||
|
regsub_expand(&buf, &len, with, text, m, nitems(m));
|
||||||
|
start = m[0].rm_eo;
|
||||||
|
}
|
||||||
|
buf[len] = '\0';
|
||||||
|
|
||||||
|
regfree(&r);
|
||||||
|
return (buf);
|
||||||
|
}
|
50
tmux.1
50
tmux.1
@ -587,9 +587,9 @@ or
|
|||||||
.Ql %endif .
|
.Ql %endif .
|
||||||
For example:
|
For example:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
%if #{==:#{host},myhost}
|
%if "#{==:#{host},myhost}"
|
||||||
set -g status-style bg=red
|
set -g status-style bg=red
|
||||||
%elif #{==:#{host},myotherhost}
|
%elif "#{==:#{host},myotherhost}"
|
||||||
set -g status-style bg=green
|
set -g status-style bg=green
|
||||||
%else
|
%else
|
||||||
set -g status-style bg=blue
|
set -g status-style bg=blue
|
||||||
@ -4017,25 +4017,45 @@ if running on
|
|||||||
.Ql myhost ,
|
.Ql myhost ,
|
||||||
otherwise by
|
otherwise by
|
||||||
.Ql 0 .
|
.Ql 0 .
|
||||||
An
|
|
||||||
.Ql m
|
|
||||||
specifies an
|
|
||||||
.Xr fnmatch 3
|
|
||||||
comparison where the first argument is the pattern and the second the string to
|
|
||||||
compare, for example
|
|
||||||
.Ql #{m:*foo*,#{host}} .
|
|
||||||
.Ql ||
|
.Ql ||
|
||||||
and
|
and
|
||||||
.Ql &&
|
.Ql &&
|
||||||
evaluate to true if either or both of two comma-separated alternatives are
|
evaluate to true if either or both of two comma-separated alternatives are
|
||||||
true, for example
|
true, for example
|
||||||
.Ql #{||:#{pane_in_mode},#{alternate_on}} .
|
.Ql #{||:#{pane_in_mode},#{alternate_on}} .
|
||||||
|
.Pp
|
||||||
|
An
|
||||||
|
.Ql m
|
||||||
|
specifies an
|
||||||
|
.Xr fnmatch 3
|
||||||
|
or regular expression comparison.
|
||||||
|
The first argument is the pattern and the second the string to compare.
|
||||||
|
An optional third argument specifies flags:
|
||||||
|
.Ql r
|
||||||
|
means the pattern is a regular expression instead of the default
|
||||||
|
.Xr fnmatch 3
|
||||||
|
pattern, and
|
||||||
|
.Ql i
|
||||||
|
means to ignore case.
|
||||||
|
For example:
|
||||||
|
.Ql #{m:*foo*,#{host}}
|
||||||
|
or
|
||||||
|
.Ql #{m/ri:^A,MYVAR} .
|
||||||
A
|
A
|
||||||
.Ql C
|
.Ql C
|
||||||
performs a search for an
|
performs a search for an
|
||||||
.Xr fnmatch 3
|
.Xr fnmatch 3
|
||||||
pattern in the pane content and evaluates to zero if not found, or a line
|
pattern or regular expression in the pane content and evaluates to zero if not
|
||||||
number if found.
|
found, or a line number if found.
|
||||||
|
Like
|
||||||
|
.Ql m ,
|
||||||
|
an
|
||||||
|
.Ql r
|
||||||
|
flag means search for a regular expression and
|
||||||
|
.Ql i
|
||||||
|
ignores case.
|
||||||
|
For example:
|
||||||
|
.Ql #{C/r:^Start}
|
||||||
.Pp
|
.Pp
|
||||||
A limit may be placed on the length of the resultant string by prefixing it
|
A limit may be placed on the length of the resultant string by prefixing it
|
||||||
by an
|
by an
|
||||||
@ -4108,6 +4128,14 @@ will substitute
|
|||||||
with
|
with
|
||||||
.Ql bar
|
.Ql bar
|
||||||
throughout.
|
throughout.
|
||||||
|
The first argument may be an extended regular expression and a final argument may be
|
||||||
|
.Ql i
|
||||||
|
to ignore case, for example
|
||||||
|
.Ql s/a(.)/\e1x/i:
|
||||||
|
would change
|
||||||
|
.Ql abABab
|
||||||
|
into
|
||||||
|
.Ql bxBxbx .
|
||||||
.Pp
|
.Pp
|
||||||
In addition, the first line of a shell command's output may be inserted using
|
In addition, the first line of a shell command's output may be inserted using
|
||||||
.Ql #() .
|
.Ql #() .
|
||||||
|
6
tmux.h
6
tmux.h
@ -2398,7 +2398,8 @@ void window_pane_key(struct window_pane *, struct client *,
|
|||||||
struct session *, struct winlink *, key_code,
|
struct session *, struct winlink *, key_code,
|
||||||
struct mouse_event *);
|
struct mouse_event *);
|
||||||
int window_pane_visible(struct window_pane *);
|
int window_pane_visible(struct window_pane *);
|
||||||
u_int window_pane_search(struct window_pane *, const char *);
|
u_int window_pane_search(struct window_pane *, const char *, int,
|
||||||
|
int);
|
||||||
const char *window_printable_flags(struct winlink *);
|
const char *window_printable_flags(struct winlink *);
|
||||||
struct window_pane *window_pane_find_up(struct window_pane *);
|
struct window_pane *window_pane_find_up(struct window_pane *);
|
||||||
struct window_pane *window_pane_find_down(struct window_pane *);
|
struct window_pane *window_pane_find_down(struct window_pane *);
|
||||||
@ -2635,4 +2636,7 @@ int style_is_default(struct style *);
|
|||||||
struct winlink *spawn_window(struct spawn_context *, char **);
|
struct winlink *spawn_window(struct spawn_context *, char **);
|
||||||
struct window_pane *spawn_pane(struct spawn_context *, char **);
|
struct window_pane *spawn_pane(struct spawn_context *, char **);
|
||||||
|
|
||||||
|
/* regsub.c */
|
||||||
|
char *regsub(const char *, const char *, const char *, int);
|
||||||
|
|
||||||
#endif /* TMUX_H */
|
#endif /* TMUX_H */
|
||||||
|
@ -3027,8 +3027,8 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
|
|||||||
if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
|
if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
|
||||||
window_copy_other_end(wme);
|
window_copy_other_end(wme);
|
||||||
|
|
||||||
data->cx = data->lastcx;
|
|
||||||
if (scroll_only || data->cy == 0) {
|
if (scroll_only || data->cy == 0) {
|
||||||
|
data->cx = data->lastcx;
|
||||||
window_copy_scroll_down(wme, 1);
|
window_copy_scroll_down(wme, 1);
|
||||||
if (scroll_only) {
|
if (scroll_only) {
|
||||||
if (data->cy == screen_size_y(s) - 1)
|
if (data->cy == screen_size_y(s) - 1)
|
||||||
@ -3037,7 +3037,7 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only)
|
|||||||
window_copy_redraw_lines(wme, data->cy, 2);
|
window_copy_redraw_lines(wme, data->cy, 2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
window_copy_update_cursor(wme, data->cx, data->cy - 1);
|
window_copy_update_cursor(wme, data->lastcx, data->cy - 1);
|
||||||
if (window_copy_update_selection(wme, 1)) {
|
if (window_copy_update_selection(wme, 1)) {
|
||||||
if (data->cy == screen_size_y(s) - 1)
|
if (data->cy == screen_size_y(s) - 1)
|
||||||
window_copy_redraw_lines(wme, data->cy, 1);
|
window_copy_redraw_lines(wme, data->cy, 1);
|
||||||
@ -3077,13 +3077,13 @@ window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only)
|
|||||||
if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
|
if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
|
||||||
window_copy_other_end(wme);
|
window_copy_other_end(wme);
|
||||||
|
|
||||||
data->cx = data->lastcx;
|
|
||||||
if (scroll_only || data->cy == screen_size_y(s) - 1) {
|
if (scroll_only || data->cy == screen_size_y(s) - 1) {
|
||||||
|
data->cx = data->lastcx;
|
||||||
window_copy_scroll_up(wme, 1);
|
window_copy_scroll_up(wme, 1);
|
||||||
if (scroll_only && data->cy > 0)
|
if (scroll_only && data->cy > 0)
|
||||||
window_copy_redraw_lines(wme, data->cy - 1, 2);
|
window_copy_redraw_lines(wme, data->cy - 1, 2);
|
||||||
} else {
|
} else {
|
||||||
window_copy_update_cursor(wme, data->cx, data->cy + 1);
|
window_copy_update_cursor(wme, data->lastcx, data->cy + 1);
|
||||||
if (window_copy_update_selection(wme, 1))
|
if (window_copy_update_selection(wme, 1))
|
||||||
window_copy_redraw_lines(wme, data->cy - 1, 2);
|
window_copy_redraw_lines(wme, data->cy - 1, 2);
|
||||||
}
|
}
|
||||||
|
34
window.c
34
window.c
@ -22,6 +22,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
|
#include <regex.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -1207,24 +1208,41 @@ window_pane_visible(struct window_pane *wp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
u_int
|
u_int
|
||||||
window_pane_search(struct window_pane *wp, const char *searchstr)
|
window_pane_search(struct window_pane *wp, const char *term, int regex,
|
||||||
|
int ignore)
|
||||||
{
|
{
|
||||||
struct screen *s = &wp->base;
|
struct screen *s = &wp->base;
|
||||||
char *newsearchstr, *line;
|
regex_t r;
|
||||||
|
char *new = NULL, *line;
|
||||||
u_int i;
|
u_int i;
|
||||||
|
int flags = 0, found;
|
||||||
|
|
||||||
xasprintf(&newsearchstr, "*%s*", searchstr);
|
if (!regex) {
|
||||||
|
if (ignore)
|
||||||
|
flags |= FNM_CASEFOLD;
|
||||||
|
xasprintf(&new, "*%s*", term);
|
||||||
|
} else {
|
||||||
|
if (ignore)
|
||||||
|
flags |= REG_ICASE;
|
||||||
|
if (regcomp(&r, term, flags|REG_EXTENDED) != 0)
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < screen_size_y(s); i++) {
|
for (i = 0; i < screen_size_y(s); i++) {
|
||||||
line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s));
|
line = grid_view_string_cells(s->grid, 0, i, screen_size_x(s));
|
||||||
if (fnmatch(newsearchstr, line, 0) == 0) {
|
if (!regex)
|
||||||
free(line);
|
found = (fnmatch(new, line, 0) == 0);
|
||||||
break;
|
else
|
||||||
}
|
found = (regexec(&r, line, 0, NULL, 0) == 0);
|
||||||
free(line);
|
free(line);
|
||||||
|
if (found)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (!regex)
|
||||||
|
free(new);
|
||||||
|
else
|
||||||
|
regfree(&r);
|
||||||
|
|
||||||
free(newsearchstr);
|
|
||||||
if (i == screen_size_y(s))
|
if (i == screen_size_y(s))
|
||||||
return (0);
|
return (0);
|
||||||
return (i + 1);
|
return (i + 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user