about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--lr.17
-rw-r--r--lr.c43
3 files changed, 49 insertions, 4 deletions
diff --git a/README.md b/README.md
index 38dea16..4833d42 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,7 @@ Over ls:
 
 ## Usage:
 
-	lr [-0|-F|-l [-TA|-TC|-TM]|-S|-f FMT] [-D] [-H|-L] [-1AGQdhsx] [-U|-o ORD] [-t TEST]* PATH...
+	lr [-0|-F|-l [-TA|-TC|-TM]|-S|-f FMT] [-D] [-H|-L] [-1AGQXdhsx] [-U|-o ORD] [-t TEST]* PATH...
 
 The special path argument `-` makes `lr` read file names from standard
 input, instead of traversing path.
@@ -67,6 +67,7 @@ input, instead of traversing path.
 * `-1`: don't go below one level of directories.
 * `-A`: don't list files starting with a dot.
 * `-G`: colorize output to tty.  Use twice to force colorize.
+* `-X`: print OSC 8 hyperlinks to tty.  Use twice to force.
 * `-Q`: shell quote file names (default for output to TTY).
 * `-d`: don't enter directories.
 * `-h`: print human readable size for `-l` (also `%s`).
diff --git a/lr.1 b/lr.1
index d64e42d..75239bb 100644
--- a/lr.1
+++ b/lr.1
@@ -10,7 +10,7 @@
 .br
 .Op Fl D
 .Op Fl H | Fl L
-.Op Fl 1AGQdhsx
+.Op Fl 1AGQXdhsx
 .Op Fl U | Fl o Ar ord
 .br
 .Op Fl t Ar test
@@ -103,6 +103,9 @@ Don't enter directories.
 .It Fl G
 Colorize output to TTY.
 Use twice to force colorized output.
+.It Fl X
+Output OSC 8 hyperlinks to TTY.
+Use twice to force hyperlinks.
 .It Fl h
 Print human readable size for
 .Fl l
@@ -200,7 +203,7 @@ Octal file permissions
 ls-style symbolic file permissions
 .It Ic \&%y
 ls-style symbolic file type
-.Sq Li ( bcdfls )
+.Sq ( Li bcdfls )
 .It Ic \&%g
 Group name
 .It Ic \&%G
diff --git a/lr.c b/lr.c
index 5570b97..daadb3f 100644
--- a/lr.c
+++ b/lr.c
@@ -81,6 +81,7 @@ static int Hflag;
 static int Lflag;
 static int Qflag;
 static int Uflag;
+static int Xflag;
 static int hflag;
 static int lflag;
 static int sflag;
@@ -97,6 +98,7 @@ static size_t prefixl;
 static char input_delim = '\n';
 static int current_color;
 static int status;
+static char *basepath;
 
 static char default_ordering[] = "n";
 static char default_format[] = "%p\\n";
@@ -1558,6 +1560,25 @@ color_name_on(int c, const char *f, mode_t m)
 		fg256(196);
 }
 
+static void
+hyperlink_on(char *fpath)
+{
+	// OSC 8 hyperlink format
+	if (Xflag) {
+		if (*fpath == '/')
+			printf("\033]8;;file://%s\007", fpath);
+		else
+			printf("\033]8;;file://%s/%s\007", basepath, fpath);
+	}
+}
+
+static void
+hyperlink_off()
+{
+	if (Xflag)
+		printf("\033]8;;\007");
+}
+
 // unused format codes: BEHJKLNOQVWXZ achjoqrvwz
 void
 print_format(struct fileinfo *fi)
@@ -1610,17 +1631,21 @@ print_format(struct fileinfo *fi)
 		case 'p':
 			if (!sflag) {
 				color_name_on(fi->color, fi->fpath, fi->sb.st_mode);
+				hyperlink_on(fi->fpath);
 				if (!fi->fpath[0] && S_ISDIR(fi->sb.st_mode))
 					print_shquoted(".");
 				else
 					print_shquoted(fi->fpath);
+				hyperlink_off();
 				fgdefault();
 				break;
 			}
 			/* FALLTHRU */
 		case 'P':
 			color_name_on(fi->color, fi->fpath, fi->sb.st_mode);
+			hyperlink_on(fi->fpath);
 			print_noprefix(fi);
+			hyperlink_off();
 			fgdefault();
 			break;
 		case 'l':
@@ -1645,7 +1670,9 @@ print_format(struct fileinfo *fi)
 					*target = 0;
 				}
 				color_name_on(-1, target, st.st_mode);
+				hyperlink_on(target);
 				print_shquoted(target + j);
+				hyperlink_off();
 				fgdefault();
 			}
 			break;
@@ -1668,7 +1695,9 @@ print_format(struct fileinfo *fi)
 			break;
 		case 'f':
 			color_name_on(fi->color, fi->fpath, fi->sb.st_mode);
+			hyperlink_on(fi->fpath);
 			print_shquoted(basenam(fi->fpath));
+			hyperlink_off();
 			fgdefault();
 			break;
 		case 'A':
@@ -1978,7 +2007,7 @@ main(int argc, char *argv[])
 
 	setlocale(LC_ALL, "");
 
-	while ((c = getopt(argc, argv, "01AC:DFGHLQST:Udf:lho:st:x")) != -1)
+	while ((c = getopt(argc, argv, "01AC:DFGHLQST:UXdf:lho:st:x")) != -1)
 		switch (c) {
 		case '0': format = zero_format; input_delim = 0; Qflag = 0; break;
 		case '1': expr = chain(parse_expr("depth == 0 || prune"), EXPR_AND, expr); break;
@@ -2002,6 +2031,7 @@ main(int argc, char *argv[])
 		case 'S': Qflag++; format = stat_format; break;
 		case 'T': Tflag = timeflag(optarg); break;
 		case 'U': Uflag++; break;
+		case 'X': Xflag++; break;
 		case 'd': expr = chain(parse_expr("type == d && prune || print"), EXPR_AND, expr); break;
 		case 'f': format = optarg; break;
 		case 'h': hflag++; break;
@@ -2022,9 +2052,20 @@ main(int argc, char *argv[])
 	} else {
 		if (Gflag == 1)
 			Gflag = 0;
+		if (Xflag == 1)
+			Xflag = 0;
 	}
 
 	analyze_format();
+	if (Xflag) {
+		basepath = realpath(".", 0);
+		if (!basepath) {
+			fprintf(stderr,
+			    "%s: cannot resolve base path, disabling -X: %s\n",
+			    argv0, strerror(errno));
+			Xflag = 0;
+		}
+	}
 
 	for (i = 0; i < Cflag; i++) {
 		char *r;