diff --git a/src/hammer.h b/src/hammer.h
index 5774b2dd7ed022d0297b3f22903c73ea6281490b..d983f2c5bc231eeda7928ece341f31720668876e 100644
--- a/src/hammer.h
+++ b/src/hammer.h
@@ -728,10 +728,22 @@ HAMMER_FN_DECL(void, h_parse_result_free, HParseResult *result);
  */
 char* h_write_result_unamb(const HParsedToken* tok);
 /**
- * Format token to the given output stream. Indent starting at
- * [indent] spaces, with [delta] spaces between levels.
+ * Format token to the given output stream. Indent starting at [indent] spaces,
+ * with [delta] spaces between levels.
+ *
+ * Note: This function does not print a trailing newline. It also does not
+ * print any spaces to indent the initial line of output. This makes it
+ * suitable for recursive use in the condensed output of larger structures.
  */
 void h_pprint(FILE* stream, const HParsedToken* tok, int indent, int delta);
+/**
+ * Format token to the given output. Print a trailing newline.
+ *
+ * This function assumes an initial indentation of 0 and uses 2 spaces between
+ * indentation levels. It is equivalent to 'h_pprint(stream, tok, 0, 2)'
+ * followed by 'fputc('\n', stream)' and is provided for convenience.
+ */
+void h_pprintln(FILE* stream, const HParsedToken* tok);
 
 /**
  * Build parse tables for the given parser backend. See the
diff --git a/src/pprint.c b/src/pprint.c
index 6747a2a8f7d6cef2bc1b352563e56380b7c0a3b5..85a9f7db8e6ba186bd3d69ee73aa3528e6588573 100644
--- a/src/pprint.c
+++ b/src/pprint.c
@@ -32,9 +32,8 @@ typedef struct pp_state {
 } pp_state_t;
 
 void h_pprint(FILE* stream, const HParsedToken* tok, int indent, int delta) {
-  fprintf(stream, "%*s", indent, ""); 
   if (tok == NULL) {
-    fprintf(stream, "(null)\n");
+    fprintf(stream, "(null)");
     return;
   }
   switch (tok->token_type) {
@@ -54,21 +53,26 @@ void h_pprint(FILE* stream, const HParsedToken* tok, int indent, int delta) {
     break;
   case TT_SINT:
     if (tok->sint < 0)
-      fprintf(stream, "s -%#" PRIx64, -tok->sint);
+      fprintf(stream, "-%#" PRIx64, -tok->sint);
     else
-      fprintf(stream, "s %#" PRIx64, tok->sint);
+      fprintf(stream, "+%#" PRIx64, tok->sint);
     break;
   case TT_UINT:
-    fprintf(stream, "u %#" PRIx64, tok->uint);
+    fprintf(stream, "%#" PRIx64, tok->uint);
     break;
   case TT_SEQUENCE:
     if (tok->seq->used == 0)
-      fprintf(stream, "[]");
+      fprintf(stream, "[ ]");
     else {
-      fprintf(stream, "[\n");
-      for (size_t i = 0; i < tok->seq->used; i++)
+      fprintf(stream, "[%*s", delta - 1, "");
+      for (size_t i = 0; i < tok->seq->used; i++) {
+	if (i > 0) fprintf(stream, "\n%*s,%*s", indent, "", delta - 1, "");
         h_pprint(stream, tok->seq->elements[i], indent + delta, delta);
-      fprintf(stream, "%*s]", indent, "");
+      }
+      if (tok->seq->used > 2)
+        fprintf(stream, "\n%*s]", indent, "");
+      else
+        fprintf(stream, " ]");
     }
     break;
   default:
@@ -76,11 +80,15 @@ void h_pprint(FILE* stream, const HParsedToken* tok, int indent, int delta) {
       const HTTEntry *e = h_get_token_type_entry(tok->token_type);
       fprintf(stream, "USER %d (%s) ", e->value - TT_USER, e->name);
       if (e->pprint)
-        e->pprint(stream, tok, indent + delta, delta);
+        e->pprint(stream, tok, indent, delta);
     } else {
       assert_message(0, "Should not reach here.");
     }
   }
+}
+
+void h_pprintln(FILE* stream, const HParsedToken* tok) {
+  h_pprint(stream, tok, 0, 2);
   fputc('\n', stream);
 }