summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--bin/hi.c50
-rw-r--r--bin/man1/hi.139
2 files changed, 73 insertions, 16 deletions
diff --git a/bin/hi.c b/bin/hi.c
index fdf14532..8a8b3f04 100644
--- a/bin/hi.c
+++ b/bin/hi.c
@@ -1,3 +1,4 @@
+/* vim: set foldmethod=marker foldlevel=0: */
 /* Copyright (C) 2019  June McEnroe <june@causal.agency>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -167,6 +168,54 @@ static const struct Syntax MdocSyntax[] = {
 };
 // }}}
 
+// sh syntax {{{
+static const struct Syntax ShSyntax[] = {
+	{ Keyword, .subexp = 2, .pattern =
+		WB "("
+		"!|case|do|done|elif|else|esac|fi|for|if|in|then|until|while"
+		")" WB
+	},
+	{ Keyword, .subexp = 2, .pattern =
+		WB "("
+		"alias|bg|cd|command|false|fc|fg|getopts|jobs|kill|newgrp|pwd|read"
+		"|true|umask|unalias|wait"
+		")" WB
+	},
+	{ Keyword, .subexp = 2, .pattern =
+		WB "("
+		"[.:]|break|continue|eval|exec|exit|export|local|readonly|return|set"
+		"|shift|times|trap|unset"
+		")" WB
+	},
+	{ String,
+		.pattern = PATTERN_DQ },
+	{ String, .subexp = 1,
+		.pattern = "<<-?" WS "EOF.*(\n)",
+		.pattend = "^\t*EOF$" },
+	{ Escape, .parent = SET(String),
+		.pattern = "[\\][\"$\\`]" },
+	{ String, .parent = ~SET(Escape),
+		.pattern = "[\\]." },
+	{ Interp, .parent = ~SET(Escape),
+		.pattern = "[$]([!#$*-?@]|[_[:alnum:]]+)" },
+	{ Interp, .parent = ~SET(Escape),
+		.pattern = "[$][{][^}]*[}]" },
+	{ Interp, .parent = ~SET(Escape),
+		.pattern = "[$][(][^)]*[)]" "|" "`[^`]*`" },
+	{ String,
+		.pattern = "'[^']*'" },
+	{ String, .subexp = 1,
+		.pattern = "<<-?" WS "'EOF'.*(\n)",
+		.pattend = "^\t*EOF$" },
+	{ Normal, .parent = SET(String),
+		.pattern = "^\t*EOF$" },
+	{ Comment, .parent = ~SET(String), .subexp = 2,
+		.pattern = "(^|" WS ")" "(#.*)" },
+	{ Todo, .parent = SET(Comment),
+		.pattern = PATTERN_TODO },
+};
+// }}}
+
 static const struct Language {
 	const char *name;
 	const char *pattern;
@@ -176,6 +225,7 @@ static const struct Language {
 	{ "c",    "[.][ch]$", CSyntax, ARRAY_LEN(CSyntax) },
 	{ "make", "[.]mk$|^Makefile$", MakeSyntax, ARRAY_LEN(MakeSyntax) },
 	{ "mdoc", "[.][1-9]$", MdocSyntax, ARRAY_LEN(MdocSyntax) },
+	{ "sh",   "[.]sh$", ShSyntax, ARRAY_LEN(ShSyntax) },
 };
 
 static regex_t compile(const char *pattern, int flags) {
diff --git a/bin/man1/hi.1 b/bin/man1/hi.1
index ad3957f1..77bb1c46 100644
--- a/bin/man1/hi.1
+++ b/bin/man1/hi.1
@@ -27,30 +27,22 @@ is read from standard input.
 .
 .Pp
 The arguments are as follows:
-.Bl -tag -width Ds
+.Bl -tag -width "-f format"
 .It Fl c
 Compile all regular expressions and exit.
 .It Fl f Ar format
 Set the output format.
-The default
-.Ar format
-is
-.Cm ansi .
 .It Fl l Ar lang
 Set the input language.
-If a
-.Ar file
-is provided,
-the input language
-may be inferred from its name.
 .It Fl n Ar name
 Override the name used
 to infer the input language.
 .El
 .
-.Pp
-The output formats are as follows:
-.Bl -tag -offset indent -width "html-document"
+.Ss Output Formats
+The default output format is
+.Cm ansi .
+.Bl -tag -width "html-document"
 .It Cm ansi
 ANSI terminal escape codes.
 .It Cm irc
@@ -61,9 +53,15 @@ HTML fragment.
 HTML document.
 .El
 .
-.Pp
-The languages are as follows:
-.Bl -tag -offset indent -width "make"
+.Ss Input Languages
+If no input language is set with
+.Fl l ,
+it may be inferred from the name set by
+.Fl n
+or from the provided
+.Ar file
+name.
+.Bl -tag -width "make"
 .It Cm c
 The C11 language.
 .It Cm make
@@ -75,4 +73,13 @@ one level of nesting with the same delimiter.
 The
 .Xr mdoc 7
 language.
+.It Cm sh
+The POSIX
+.Xr sh 1
+language.
+Here-documents are correctly highlighted
+only with a delimiter of
+.Ql EOF .
+Arbitrarily nested strings and command substitutions
+are not highlighted correctly.
 .El