mirror of
https://salsa.debian.org/dskoll/remind.git
synced 2026-04-16 06:18:47 +02:00
Add $TerminalHyperlinks system variable.
This lets you turn any reminder with an INFO "Url: ..." string into a hyperlink on the terminal.
This commit is contained in:
@@ -3488,6 +3488,13 @@ to be "dark" if the average of the red, green and blue components is
|
||||
at most 85 out of 255, and if the maximum of any component is at most
|
||||
128 out of 255.
|
||||
.TP
|
||||
.B $TerminalHyperlinks (INT type)
|
||||
If your terminal supports escape sequences to allow HTML-like
|
||||
anchors around text (see https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda), then you can set this variable to 1. \fBRemind\fR will then
|
||||
make any reminder with a "Url:" info string into a hyperlink in your
|
||||
terminal. By default, \fB$TerminalHyperlinks\fR is set to zero because
|
||||
not all terminals support this feature.
|
||||
.TP
|
||||
.B $WarningLevel (STRING type)
|
||||
As new versions of \fBRemind\fR are released, new warnings may be added.
|
||||
If your formerly-fine scripts suddenly start issuing warnings when you
|
||||
|
||||
@@ -95,9 +95,6 @@ static struct line_drawing UTF8Drawing = {
|
||||
"\xe2\x94\x80"
|
||||
};
|
||||
|
||||
static char const *start_link = "\x1B]8;;";
|
||||
static char const *end_link = "\x1B]8;;\x1B\\";
|
||||
|
||||
static char *VT100Colors[2][2][2][2] /* [Br][R][G][B] */ = {
|
||||
{
|
||||
/*** DIM COLORS ***/
|
||||
@@ -1578,8 +1575,7 @@ static int WriteOneColLine(int col)
|
||||
}
|
||||
|
||||
if (url) {
|
||||
printf("%s", start_link);
|
||||
printf("%s\x1B\\", url);
|
||||
printf("\x1B]8;;%s\x1B\\", url);
|
||||
}
|
||||
/* If we couldn't find a space char, print what we have. */
|
||||
if (!wspace) {
|
||||
@@ -1616,7 +1612,7 @@ static int WriteOneColLine(int col)
|
||||
}
|
||||
|
||||
if (url) {
|
||||
printf("%s", end_link);
|
||||
printf("\x1B]8;;\x1B\\");
|
||||
}
|
||||
/* Decolorize reminder if necessary, but keep any SHADE */
|
||||
if (UseVTColors && e->is_color) {
|
||||
@@ -2445,7 +2441,7 @@ get_url(TrigInfo *infos)
|
||||
{
|
||||
TrigInfo *ti = infos;
|
||||
char const *url;
|
||||
if (!LinksInTerminal) {
|
||||
if (!TerminalHyperlinks) {
|
||||
/* Nope, not doing links in terminal */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
20
src/dorem.c
20
src/dorem.c
@@ -1555,6 +1555,7 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
|
||||
DynamicBuffer pre_buf;
|
||||
char const *s;
|
||||
char const *msg_command = NULL;
|
||||
char const *url;
|
||||
Value v;
|
||||
|
||||
if (MsgCommand) {
|
||||
@@ -1830,9 +1831,16 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
|
||||
}
|
||||
}
|
||||
|
||||
/* If we are sorting, just queue it up in the sort buffer */
|
||||
/* Get the url if terminal hyperlinks are enabled */
|
||||
if (TerminalHyperlinks) {
|
||||
url = FindTrigInfo(t, "url");
|
||||
} else {
|
||||
url = NULL;
|
||||
}
|
||||
|
||||
/* If we are sorting, just queue it up in the sort buffer */
|
||||
if (SortByDate) {
|
||||
if (InsertIntoSortBuffer(dse, tim->ttime, DBufValue(&buf),
|
||||
if (InsertIntoSortBuffer(dse, tim->ttime, url, DBufValue(&buf),
|
||||
t->typ, t->priority) == OK) {
|
||||
DBufFree(&buf);
|
||||
NumTriggered++;
|
||||
@@ -1855,14 +1863,20 @@ int TriggerReminder(ParsePtr p, Trigger *t, TimeTrig const *tim, int dse, int is
|
||||
if (IsServerMode() && !strncmp(DBufValue(&buf), "NOTE endreminder", 16)) {
|
||||
printf(" %s", DBufValue(&buf));
|
||||
} else {
|
||||
if (url) {
|
||||
printf("\x1B]8;;%s\x1B\\", url);
|
||||
}
|
||||
printf("%s", DBufValue(&buf));
|
||||
if (url) {
|
||||
printf("\x1B]8;;\x1B\\");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MSF_TYPE:
|
||||
FillParagraph(DBufValue(&buf), output);
|
||||
FillParagraph(url, DBufValue(&buf), output);
|
||||
break;
|
||||
|
||||
case RUN_TYPE:
|
||||
|
||||
@@ -106,7 +106,6 @@ EXTERN INIT( int DefaultPrio, NO_PRIORITY);
|
||||
EXTERN INIT( int SysTime, -1);
|
||||
EXTERN INIT( int LocalSysTime, -1);
|
||||
EXTERN INIT( int ParseUntriggered, 0);
|
||||
EXTERN INIT( int LinksInTerminal, 0);
|
||||
|
||||
EXTERN char const *InitialFile;
|
||||
EXTERN char const *LocalTimeZone;
|
||||
@@ -171,6 +170,10 @@ EXTERN INIT( double Latitude, DEFAULT_LATITUDE);
|
||||
|
||||
EXTERN INIT( char *Location, LOCATION);
|
||||
|
||||
/* Support hyperlinks in terminal emulators?
|
||||
https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
|
||||
*/
|
||||
EXTERN INIT( int TerminalHyperlinks, 0);
|
||||
/* UTC calculation stuff */
|
||||
EXTERN INIT( int MinsFromUTC, 0);
|
||||
EXTERN INIT( int CalculateUTC, 1);
|
||||
|
||||
@@ -519,11 +519,6 @@ void InitRemind(int argc, char const *argv[])
|
||||
arg++;
|
||||
continue;
|
||||
}
|
||||
if (*arg == 'z' || *arg == 'Z') {
|
||||
LinksInTerminal = 1;
|
||||
arg++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (weeks) {
|
||||
|
||||
15
src/main.c
15
src/main.c
@@ -1866,7 +1866,7 @@ FillParagraphWC(char const *s, DynamicBuffer *output)
|
||||
/* A macro safe ONLY if used with arg with no side effects! */
|
||||
#define ISBLANK(c) (isspace(c) && (c) != '\n')
|
||||
|
||||
void FillParagraph(char const *s, DynamicBuffer *output)
|
||||
void FillParagraph(char const *url, char const *s, DynamicBuffer *output)
|
||||
{
|
||||
|
||||
int line = 0;
|
||||
@@ -1883,7 +1883,14 @@ void FillParagraph(char const *s, DynamicBuffer *output)
|
||||
while(ISBLANK(*s)) s++;
|
||||
if (!*s) return;
|
||||
|
||||
if (url) {
|
||||
printf("\x1B]8;;%s\x1B\\", url);
|
||||
}
|
||||
|
||||
if (FillParagraphWC(s, output) == OK) {
|
||||
if (url) {
|
||||
printf("\x1B]8;;\x1B\\");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1899,6 +1906,9 @@ void FillParagraph(char const *s, DynamicBuffer *output)
|
||||
continue;
|
||||
}
|
||||
if (!*s) {
|
||||
if (url) {
|
||||
printf("\x1B]8;;\x1B\\");
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* Over here, we're at the beginning of a line. Emit the correct
|
||||
@@ -1933,6 +1943,9 @@ void FillParagraph(char const *s, DynamicBuffer *output)
|
||||
len++;
|
||||
}
|
||||
if (s == t) {
|
||||
if (url) {
|
||||
printf("\x1B]8;;\x1B\\");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!pendspace || len+pendspace <= roomleft) {
|
||||
|
||||
@@ -144,7 +144,7 @@ int ParseNonSpaceChar (ParsePtr p, int *err, int peek);
|
||||
unsigned int HashVal_preservecase(char const *str);
|
||||
int DateOK (int y, int m, int d);
|
||||
BuiltinFunc *FindBuiltinFunc (char const *name);
|
||||
int InsertIntoSortBuffer (int dse, int tim, char const *body, int typ, int prio);
|
||||
int InsertIntoSortBuffer (int dse, int tim, char const *url, char const *body, int typ, int prio);
|
||||
void IssueSortedReminders (void);
|
||||
UserFunc *FindUserFunc(char const *name);
|
||||
int UserFuncExists (char const *fn);
|
||||
@@ -160,7 +160,7 @@ int GetSysVar (char const *name, Value *val);
|
||||
int SetSysVar (char const *name, Value *val);
|
||||
void DumpSysVarByName (char const *name);
|
||||
int CalcMinsFromUTC (int dse, int tim, int *mins, int *isdst);
|
||||
void FillParagraph (char const *s, DynamicBuffer *output);
|
||||
void FillParagraph (char const *url, char const *s, DynamicBuffer *output);
|
||||
void LocalToUTC (int locdate, int loctime, int *utcdate, int *utctime);
|
||||
void UTCToLocal (int utcdate, int utctime, int *locdate, int *loctime);
|
||||
int MoonPhase (int date, int time);
|
||||
|
||||
11
src/queue.c
11
src/queue.c
@@ -140,7 +140,7 @@ int QueueReminder(ParsePtr p, Trigger *trig,
|
||||
TimeTrig const *tim, char const *sched)
|
||||
{
|
||||
QueuedRem *qelem;
|
||||
|
||||
TrigInfo *ti;
|
||||
if (DontQueue ||
|
||||
trig->noqueue ||
|
||||
tim->ttime == NO_TIME ||
|
||||
@@ -169,8 +169,13 @@ int QueueReminder(ParsePtr p, Trigger *trig,
|
||||
qelem->tt = *tim;
|
||||
qelem->t = *trig;
|
||||
|
||||
/* Take over infos */
|
||||
trig->infos = NULL;
|
||||
/* Copy infos */
|
||||
qelem->t.infos = NULL;
|
||||
ti = trig->infos;
|
||||
while(ti) {
|
||||
(void) AppendTrigInfo(&qelem->t, ti->info);
|
||||
ti = ti->next;
|
||||
}
|
||||
|
||||
DBufInit(&(qelem->t.tags));
|
||||
DBufPuts(&(qelem->t.tags), DBufValue(&(trig->tags)));
|
||||
|
||||
75
src/sort.c
75
src/sort.c
@@ -25,6 +25,7 @@
|
||||
typedef struct sortrem {
|
||||
struct sortrem *next;
|
||||
char const *text;
|
||||
char const *url;
|
||||
int trigdate;
|
||||
int trigtime;
|
||||
int typ;
|
||||
@@ -34,7 +35,7 @@ typedef struct sortrem {
|
||||
/* The sorted reminder queue */
|
||||
static Sortrem *SortedQueue = (Sortrem *) NULL;
|
||||
|
||||
static Sortrem *MakeSortRem (int dse, int tim, char const *body, int typ, int prio);
|
||||
static Sortrem *MakeSortRem (int dse, int tim, char const *url, char const *body, int typ, int prio);
|
||||
static void IssueSortBanner (int dse);
|
||||
|
||||
/***************************************************************/
|
||||
@@ -44,23 +45,33 @@ static void IssueSortBanner (int dse);
|
||||
/* Create a new Sortrem entry - return NULL on failure. */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
static Sortrem *MakeSortRem(int dse, int tim, char const *body, int typ, int prio)
|
||||
static Sortrem *MakeSortRem(int dse, int tim, char const *url, char const *body, int typ, int prio)
|
||||
{
|
||||
Sortrem *new = NEW(Sortrem);
|
||||
if (!new) return NULL;
|
||||
Sortrem *srem = NEW(Sortrem);
|
||||
if (!srem) return NULL;
|
||||
|
||||
new->text = strdup(body);
|
||||
if (!new->text) {
|
||||
free(new);
|
||||
srem->text = strdup(body);
|
||||
if (!srem->text) {
|
||||
free(srem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new->trigdate = dse;
|
||||
new->trigtime = tim;
|
||||
new->typ = typ;
|
||||
new->priority = prio;
|
||||
new->next = NULL;
|
||||
return new;
|
||||
if (url) {
|
||||
srem->url = strdup(url);
|
||||
if (!srem->url) {
|
||||
free((char *) srem->text);
|
||||
free(srem);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
srem->url = NULL;
|
||||
}
|
||||
|
||||
srem->trigdate = dse;
|
||||
srem->trigtime = tim;
|
||||
srem->typ = typ;
|
||||
srem->priority = prio;
|
||||
srem->next = NULL;
|
||||
return srem;
|
||||
}
|
||||
|
||||
/***************************************************************/
|
||||
@@ -70,13 +81,13 @@ static Sortrem *MakeSortRem(int dse, int tim, char const *body, int typ, int pri
|
||||
/* Insert a reminder into the sort buffer */
|
||||
/* */
|
||||
/***************************************************************/
|
||||
int InsertIntoSortBuffer(int dse, int tim, char const *body, int typ, int prio)
|
||||
int InsertIntoSortBuffer(int dse, int tim, char const *url, char const *body, int typ, int prio)
|
||||
{
|
||||
Sortrem *new = MakeSortRem(dse, tim, body, typ, prio);
|
||||
Sortrem *srem = MakeSortRem(dse, tim, url, body, typ, prio);
|
||||
Sortrem *cur = SortedQueue, *prev = NULL;
|
||||
int ShouldGoAfter;
|
||||
|
||||
if (!new) {
|
||||
if (!srem) {
|
||||
Eprint("%s", GetErr(E_NO_MEM));
|
||||
IssueSortedReminders();
|
||||
SortByDate = 0;
|
||||
@@ -88,11 +99,11 @@ int InsertIntoSortBuffer(int dse, int tim, char const *body, int typ, int prio)
|
||||
|
||||
/* Find the correct place in the sorted list */
|
||||
if (!SortedQueue) {
|
||||
SortedQueue = new;
|
||||
SortedQueue = srem;
|
||||
return OK;
|
||||
}
|
||||
while (cur) {
|
||||
ShouldGoAfter = CompareRems(new->trigdate, new->trigtime, new->priority,
|
||||
ShouldGoAfter = CompareRems(srem->trigdate, srem->trigtime, srem->priority,
|
||||
cur->trigdate, cur->trigtime, cur->priority,
|
||||
SortByDate, SortByTime, SortByPrio, UntimedBeforeTimed);
|
||||
|
||||
@@ -101,22 +112,21 @@ int InsertIntoSortBuffer(int dse, int tim, char const *body, int typ, int prio)
|
||||
cur = cur->next;
|
||||
} else {
|
||||
if (prev) {
|
||||
prev->next = new;
|
||||
new->next = cur;
|
||||
prev->next = srem;
|
||||
srem->next = cur;
|
||||
} else {
|
||||
SortedQueue = new;
|
||||
new->next = cur;
|
||||
SortedQueue = srem;
|
||||
srem->next = cur;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
prev->next = new;
|
||||
new->next = cur; /* For safety - actually redundant */
|
||||
prev->next = srem;
|
||||
srem->next = cur; /* For safety - actually redundant */
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************/
|
||||
/* */
|
||||
/* IssueSortedReminders */
|
||||
@@ -141,7 +151,13 @@ void IssueSortedReminders(void)
|
||||
IssueSortBanner(cur->trigdate);
|
||||
olddate = cur->trigdate;
|
||||
}
|
||||
if (cur->url) {
|
||||
printf("\x1B]8;;%s\x1B\\", cur->url);
|
||||
}
|
||||
printf("%s", cur->text);
|
||||
if (cur->url) {
|
||||
printf("\x1B]8;;\x1B\\");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -150,7 +166,7 @@ void IssueSortedReminders(void)
|
||||
IssueSortBanner(cur->trigdate);
|
||||
olddate = cur->trigdate;
|
||||
}
|
||||
FillParagraph(cur->text, NULL);
|
||||
FillParagraph(cur->url, cur->text, NULL);
|
||||
break;
|
||||
|
||||
case RUN_TYPE:
|
||||
@@ -159,6 +175,9 @@ void IssueSortedReminders(void)
|
||||
}
|
||||
|
||||
free((char *) cur->text);
|
||||
if (cur->url) {
|
||||
free((char *) cur->url);
|
||||
}
|
||||
free(cur);
|
||||
cur = next;
|
||||
}
|
||||
|
||||
@@ -1109,6 +1109,7 @@ static SysVar SysVarArr[] = {
|
||||
{"Tb", 0, SPECIAL_TYPE, trig_base_func, 0, 0 },
|
||||
{"Td", 0, SPECIAL_TYPE, trig_day_func, 0, 0 },
|
||||
{"TerminalBackground", 0, SPECIAL_TYPE, terminal_bg_func, 0, 0 },
|
||||
{"TerminalHyperlinks", 1, INT_TYPE, &TerminalHyperlinks, 0, 1 },
|
||||
{"Thursday", 1, TRANS_TYPE, "Thursday", 0, 0 },
|
||||
{"TimeSep", 1, SPECIAL_TYPE, time_sep_func, 0, 0 },
|
||||
{"TimetIs64bit", 0, SPECIAL_TYPE, timet_is_64_func, 0, 0 },
|
||||
|
||||
@@ -402,6 +402,7 @@ Tcl
|
||||
Td
|
||||
Terbeck
|
||||
TerminalBackground
|
||||
TerminalHyperlinks
|
||||
Thronicke
|
||||
TimeSep
|
||||
TimetIs64bit
|
||||
|
||||
@@ -961,6 +961,14 @@ SET $ParseUntriggered 1
|
||||
REM 1 Jan 1994 MSG 1/0 = [1/0]
|
||||
EOF
|
||||
|
||||
# Calendars with hyperlinks
|
||||
$REMIND -w,0,0 -@2 -c - 1 Jan 2020 <<'EOF' >> $OUT 2>&1
|
||||
SET $TerminalHyperlinks 1
|
||||
REM 15 INFO "Url: https://dianne.skoll.ca" MSG Hello, linky!
|
||||
REM 16 INFO "Url: https://dianne.skoll.ca" MSF Hello, linky!
|
||||
REM 17 INFO "Url: https://dianne.skoll.ca" CAL Hello, linky!
|
||||
REM 18 INFO "Url: https://dianne.skoll.ca" SPECIAL COLOR 255 0 0 Hello, linky!
|
||||
EOF
|
||||
cmp -s $OUT $CMP
|
||||
if [ "$?" = "0" ]; then
|
||||
echo "Remind: Acceptance tests ${GRN}PASSED${NRM}"
|
||||
|
||||
@@ -16759,7 +16759,10 @@ mbpad("
|
||||
bad => "ÿ"
|
||||
mbpad("ÿ", "bar", 8, 1) => Invalid multibyte sequence
|
||||
../tests/test.rem(1891): mbpad(): Invalid multibyte sequence
|
||||
DynBuf Mallocs: 1114 mallocs; 31872128 bytes
|
||||
]8;;https://dianne.skoll.ca\Hello, linky!
|
||||
]8;;\]8;;https://dianne.skoll.ca\Hello, linky!
|
||||
]8;;\]8;;https://dianne.skoll.ca\Hello, linky!
|
||||
]8;;\DynBuf Mallocs: 1120 mallocs; 31872640 bytes
|
||||
Variable hash table statistics:
|
||||
Entries: 100146; Buckets: 87719; Non-empty Buckets: 66303
|
||||
Maxlen: 5; Minlen: 0; Avglen: 1.142; Stddev: 0.878; Avg nonempty len: 1.510
|
||||
@@ -16781,7 +16784,7 @@ Expression nodes high-water: 302076
|
||||
Expression nodes leaked: 0
|
||||
Parse level high-water: 34
|
||||
Max expr node evaluations per line: 2001
|
||||
Total expression node evaluations: 106732
|
||||
Total expression node evaluations: 106733
|
||||
|
||||
Test 2
|
||||
|
||||
@@ -24950,6 +24953,7 @@ $T
|
||||
$Tb
|
||||
$Td
|
||||
$TerminalBackground
|
||||
$TerminalHyperlinks
|
||||
$Thursday
|
||||
$TimeSep
|
||||
$TimetIs64bit
|
||||
@@ -40154,3 +40158,21 @@ February 28
|
||||
-stdin-(2): `/': Division by zero
|
||||
-stdin-(2): `/': Division by zero
|
||||
# rem2ps end
|
||||
+----------------------------------------------------------------------------+
|
||||
| January 2020 |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
| Sunday | Monday | Tuesday |Wednesday | Thursday | Friday | Saturday |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
| | | |1 |2 |3 |4 |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
|5 |6 |7 |8 |9 |10 |11 |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
|12 |13 |14 |15 |16 |17 |18 |
|
||||
| | | |]8;;https://dianne.skoll.ca\Hello,]8;;\ |]8;;https://dianne.skoll.ca\Hello,]8;;\ |]8;;https://dianne.skoll.ca\Hello,]8;;\ |[38;2;255;0;0m]8;;https://dianne.skoll.ca\Hello,]8;;\[0m |
|
||||
| | | |]8;;https://dianne.skoll.ca\linky!]8;;\ |]8;;https://dianne.skoll.ca\linky!]8;;\ |]8;;https://dianne.skoll.ca\linky!]8;;\ |[38;2;255;0;0m]8;;https://dianne.skoll.ca\linky!]8;;\[0m |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
|19 |20 |21 |22 |23 |24 |25 |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
|26 |27 |28 |29 |30 |31 | |
|
||||
+----------+----------+----------+----------+----------+----------+----------+
|
||||
|
||||
@@ -1891,6 +1891,11 @@ set a mbpad(bad, "bar", 8)
|
||||
set a mbpad(bad, "bar", 8, 1)
|
||||
|
||||
DEBUG -x
|
||||
SET $TerminalHyperlinks 1
|
||||
REM INFO "Url: https://dianne.skoll.ca" MSG Hello, linky!
|
||||
REM INFO "Url: https://dianne.skoll.ca" MSF Hello, linky!
|
||||
REM INFO "Url: https://dianne.skoll.ca" SPECIAL COLOR 255 0 0 Hello, linky!
|
||||
|
||||
# Don't want Remind to queue reminders
|
||||
EXIT
|
||||
|
||||
|
||||
Reference in New Issue
Block a user