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:
Dianne Skoll
2026-01-08 14:13:34 -05:00
parent 3e6233b6f0
commit f6253d0fca
14 changed files with 141 additions and 52 deletions

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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)));

View File

@@ -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;
}

View File

@@ -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 },