|
diff --git Makefile.am Makefile.am |
|
index 8b39ccf..711231f 100644 |
|
--- Makefile.am |
|
+++ Makefile.am |
|
@@ -139,6 +139,7 @@ dist_tmux_SOURCES = \ |
|
grid-cell.c \ |
|
grid-view.c \ |
|
grid.c \ |
|
+ highlight.c \ |
|
input-keys.c \ |
|
input.c \ |
|
job.c \ |
|
diff --git cmd-set-option.c cmd-set-option.c |
|
index e0b07ed..8476fc3 100644 |
|
--- cmd-set-option.c |
|
+++ cmd-set-option.c |
|
@@ -63,10 +63,13 @@ struct options_entry *cmd_set_option_choice(struct cmd *, struct cmd_q *, |
|
struct options_entry *cmd_set_option_style(struct cmd *, struct cmd_q *, |
|
const struct options_table_entry *, struct options *, |
|
const char *); |
|
+struct options_entry *cmd_set_highlight(struct cmd *, struct cmd_q *, |
|
+ const struct options_table_entry *, struct options *, |
|
+ const char *); |
|
|
|
const struct cmd_entry cmd_set_option_entry = { |
|
"set-option", "set", |
|
- "agoqst:uw", 1, 2, |
|
+ "agoqst:uw", 1, 4, |
|
"[-agosquw] [-t target-session|target-window] option [value]", |
|
0, |
|
cmd_set_option_exec |
|
@@ -342,6 +345,10 @@ cmd_set_option_set(struct cmd *self, struct cmd_q *cmdq, |
|
case OPTIONS_TABLE_STYLE: |
|
o = cmd_set_option_style(self, cmdq, oe, oo, value); |
|
break; |
|
+ case OPTIONS_TABLE_HIGHLIGHT: |
|
+ o = cmd_set_highlight(self, cmdq, oe, oo, value); |
|
+ break; |
|
+ |
|
} |
|
if (o == NULL) |
|
return (-1); |
|
@@ -404,6 +411,25 @@ cmd_set_option_key(unused struct cmd *self, struct cmd_q *cmdq, |
|
return (options_set_number(oo, oe->name, key)); |
|
} |
|
|
|
+/* Set a highlight option. */ |
|
+struct options_entry * |
|
+cmd_set_highlight(unused struct cmd *self, struct cmd_q *cmdq, |
|
+ const struct options_table_entry *oe, struct options *oo, |
|
+ const char *value) |
|
+{ |
|
+ int fg, ignorecase; |
|
+ |
|
+ if (self->args->argc < 4) { |
|
+ cmdq_error(cmdq, "bad argument count : %d", self->args->argc); |
|
+ return (NULL); |
|
+ } |
|
+ |
|
+ fg = colour_fromstring(self->args->argv[2]); |
|
+ ignorecase = atoi(self->args->argv[3]); |
|
+ add_highlight(value,fg, ignorecase); |
|
+ return (options_set_number(oo,oe->name,fg)); |
|
+} |
|
+ |
|
/* Set a colour option. */ |
|
struct options_entry * |
|
cmd_set_option_colour(unused struct cmd *self, struct cmd_q *cmdq, |
|
diff --git highlight.c highlight.c |
|
new file mode 100644 |
|
index 0000000..c297833 |
|
--- /dev/null |
|
+++ highlight.c |
|
@@ -0,0 +1,69 @@ |
|
+#include <stdlib.h> |
|
+#include <string.h> |
|
+#include <regex.h> |
|
+ |
|
+#include "tmux.h" |
|
+ |
|
+struct highlightlist all_highlights = LIST_HEAD_INITIALIZER(all_highlights); |
|
+ |
|
+int add_highlight(const char *regstr, int fg, int ignorecase){ |
|
+ struct highlight *tmp_highlight, *new_highlight; |
|
+ int flags=REG_EXTENDED | REG_NEWLINE; |
|
+ |
|
+ LIST_FOREACH(tmp_highlight, &all_highlights, lentry) { |
|
+ if (strcmp(tmp_highlight->regstr, regstr) == 0 && tmp_highlight->ignorecase == ignorecase) { |
|
+ free(tmp_highlight->regstr); |
|
+ regfree(&tmp_highlight->reg); |
|
+ tmp_highlight->regstr = xmalloc(sizeof(char)*strlen(regstr)); |
|
+ strcpy(tmp_highlight->regstr, regstr); |
|
+ tmp_highlight->fg = fg; |
|
+ tmp_highlight->ignorecase = ignorecase; |
|
+ if(tmp_highlight->ignorecase){ |
|
+ flags |= REG_ICASE; |
|
+ } |
|
+ if (regcomp(&tmp_highlight->reg, tmp_highlight->regstr, flags) != 0) { |
|
+ fprintf(stderr, "regex compile failed"); |
|
+ return 1; |
|
+ } |
|
+ return 0; |
|
+ } |
|
+ } |
|
+ new_highlight = xmalloc(sizeof(struct highlight)); |
|
+ new_highlight->regstr = xmalloc(sizeof(char)*strlen(regstr)); |
|
+ strcpy(new_highlight->regstr, regstr); |
|
+ new_highlight->fg = fg; |
|
+ new_highlight->ignorecase = ignorecase; |
|
+ if (new_highlight->ignorecase) { |
|
+ flags |= REG_ICASE; |
|
+ } |
|
+ if (regcomp(&new_highlight->reg, new_highlight->regstr, flags) != 0) { |
|
+ fprintf(stderr, "regex compile failed"); |
|
+ return 1; |
|
+ } |
|
+ |
|
+ LIST_INSERT_HEAD(&all_highlights, new_highlight, lentry); |
|
+ return 0; |
|
+} |
|
+ |
|
+struct highlight_search_result find_highlight_target(const u_char *target){ |
|
+ struct highlight *tmp_highlight; |
|
+ struct highlight_search_result res = {.find = 0, .start = 0, .end = 0}; |
|
+ regmatch_t patternMatch; |
|
+ |
|
+ LIST_FOREACH(tmp_highlight, &all_highlights, lentry) { |
|
+ if (regexec(&tmp_highlight->reg, target, 1, &patternMatch, 0) == 0){ |
|
+ regoff_t tmp_startIndex = patternMatch.rm_so; |
|
+ regoff_t tmp_endIndex = patternMatch.rm_eo; |
|
+ if (tmp_startIndex == -1 || tmp_endIndex == -1) { |
|
+ continue; |
|
+ } |
|
+ if (res.find == 0 || tmp_startIndex < res.start) { |
|
+ res.start = tmp_startIndex; |
|
+ res.end = tmp_endIndex; |
|
+ res.fg = tmp_highlight->fg; |
|
+ } |
|
+ res.find = 1; |
|
+ } |
|
+ } |
|
+ return res; |
|
+} |
|
diff --git input.c input.c |
|
index ab56fc3..a45212c 100644 |
|
--- input.c |
|
+++ input.c |
|
@@ -47,6 +47,9 @@ |
|
* be passed to the underlying terminals. |
|
*/ |
|
|
|
+/* To restore the original fg after the highlighting */ |
|
+int original_fg = -1; |
|
+ |
|
/* Input parser cell. */ |
|
struct input_cell { |
|
struct grid_cell cell; |
|
@@ -840,6 +843,9 @@ input_parse(struct window_pane *wp) |
|
struct evbuffer *evb = wp->event->input; |
|
u_char *buf; |
|
size_t len, off; |
|
+ struct highlight_search_result search_res = {.find = 0}; |
|
+ size_t startIndex = 0; |
|
+ size_t endIndex = 0; |
|
|
|
if (EVBUFFER_LENGTH(evb) == 0) |
|
return; |
|
@@ -869,6 +875,26 @@ input_parse(struct window_pane *wp) |
|
while (off < len) { |
|
ictx->ch = buf[off++]; |
|
|
|
+ if (off > endIndex) { |
|
+ if (original_fg >= 0) { |
|
+ ictx->cell.cell.fg = original_fg; |
|
+ original_fg = -1; |
|
+ } |
|
+ |
|
+ search_res = find_highlight_target((u_char*)((unsigned long)buf+endIndex)); |
|
+ if (search_res.find) { |
|
+ startIndex = endIndex + search_res.start; |
|
+ endIndex = endIndex + search_res.end; |
|
+ } |
|
+ } |
|
+ |
|
+ if (search_res.find && startIndex < off && off <= endIndex) { |
|
+ if (original_fg == -1) { |
|
+ original_fg = ictx->cell.cell.fg; |
|
+ } |
|
+ ictx->cell.cell.fg = search_res.fg; |
|
+ } |
|
+ |
|
/* Find the transition. */ |
|
itr = ictx->state->transitions; |
|
while (itr->first != -1 && itr->last != -1) { |
|
diff --git options-table.c options-table.c |
|
index e901e24..cbb826f 100644 |
|
--- options-table.c |
|
+++ options-table.c |
|
@@ -782,6 +782,10 @@ const struct options_table_entry window_options_table[] = { |
|
.type = OPTIONS_TABLE_FLAG, |
|
.default_num = 0 |
|
}, |
|
+ { .name = "trigger-highlight", |
|
+ .type = OPTIONS_TABLE_HIGHLIGHT, |
|
+ .default_num = -1 |
|
+ }, |
|
|
|
{ .name = NULL } |
|
}; |
|
diff --git tmux.h tmux.h |
|
index 4d19a5a..a466240 100644 |
|
--- tmux.h |
|
+++ tmux.h |
|
@@ -29,6 +29,7 @@ |
|
#include <stdarg.h> |
|
#include <stdio.h> |
|
#include <termios.h> |
|
+#include <regex.h> |
|
|
|
#ifdef HAVE_UTEMPTER |
|
#include <utempter.h> |
|
@@ -710,6 +711,22 @@ struct job { |
|
}; |
|
LIST_HEAD(joblist, job); |
|
|
|
+struct highlight{ |
|
+ char *regstr; |
|
+ regex_t reg; |
|
+ int fg; |
|
+ int ignorecase; |
|
+ LIST_ENTRY(highlight) lentry; |
|
+}; |
|
+ |
|
+struct highlight_search_result{ |
|
+ int find; |
|
+ off_t start; |
|
+ off_t end; |
|
+ int fg; |
|
+}; |
|
+LIST_HEAD(highlightlist, highlight); |
|
+ |
|
/* Screen selection. */ |
|
struct screen_sel { |
|
int flag; |
|
@@ -1376,7 +1393,8 @@ enum options_table_type { |
|
OPTIONS_TABLE_ATTRIBUTES, |
|
OPTIONS_TABLE_FLAG, |
|
OPTIONS_TABLE_CHOICE, |
|
- OPTIONS_TABLE_STYLE |
|
+ OPTIONS_TABLE_STYLE, |
|
+ OPTIONS_TABLE_HIGHLIGHT |
|
}; |
|
|
|
struct options_table_entry { |
|
@@ -1532,6 +1550,11 @@ struct job *job_run(const char *, struct session *, int, |
|
void job_free(struct job *); |
|
void job_died(struct job *, int); |
|
|
|
+/* highlight.c */ |
|
+extern struct highlightlist all_highlights; |
|
+int add_highlight(const char *, int, int); |
|
+struct highlight_search_result find_highlight_target(const u_char *); |
|
+ |
|
/* environ.c */ |
|
int environ_cmp(struct environ_entry *, struct environ_entry *); |
|
RB_PROTOTYPE(environ, environ_entry, entry, environ_cmp); |