-/* $Id: tag.c,v 1.33 2020/04/07 22:56:02 schwarze Exp $ */
+/* $Id: tag.c,v 1.36 2020/04/19 16:36:16 schwarze Exp $ */
/*
* Copyright (c) 2015,2016,2018,2019,2020 Ingo Schwarze <schwarze@openbsd.org>
*
#include "mandoc_ohash.h"
#include "roff.h"
#include "mdoc.h"
+#include "roff_int.h"
#include "tag.h"
struct tag_entry {
char s[];
};
+static void tag_move_href(struct roff_man *,
+ struct roff_node *, const char *);
static void tag_move_id(struct roff_node *);
static struct ohash tag_data;
tag_put(const char *s, int prio, struct roff_node *n)
{
struct tag_entry *entry;
+ struct roff_node *nold;
const char *se;
size_t len;
unsigned int slot;
*/
else if (entry->prio > prio || prio == TAG_FALLBACK) {
- while (entry->nnodes > 0)
- entry->nodes[--entry->nnodes]->flags &= ~NODE_ID;
-
+ while (entry->nnodes > 0) {
+ nold = entry->nodes[--entry->nnodes];
+ nold->flags &= ~NODE_ID;
+ free(nold->tag);
+ nold->tag = NULL;
+ }
if (prio == TAG_FALLBACK) {
entry->prio = TAG_DELETE;
return;
entry->prio = prio;
n->flags |= NODE_ID;
if (n->child == NULL || n->child->string != s || *se != '\0') {
- assert(n->string == NULL);
- n->string = mandoc_strndup(s, len);
+ assert(n->tag == NULL);
+ n->tag = mandoc_strndup(s, len);
}
}
}
/* FALLTHROUGH */
case MDOC_Pp: /* Target the ROFFT_ELEM = <p>. */
- if (np->string == NULL) {
- np->string = mandoc_strdup(n->string == NULL ?
- n->child->string : n->string);
+ if (np->tag == NULL) {
+ np->tag = mandoc_strdup(n->tag == NULL ?
+ n->child->string : n->tag);
np->flags |= NODE_ID;
n->flags &= ~NODE_ID;
}
}
}
+/*
+ * When a paragraph is tagged and starts with text,
+ * move the permalink to the first few words.
+ */
+static void
+tag_move_href(struct roff_man *man, struct roff_node *n, const char *tag)
+{
+ char *cp;
+
+ if (n == NULL || n->type != ROFFT_TEXT ||
+ *n->string == '\0' || *n->string == ' ')
+ return;
+
+ cp = n->string;
+ while (cp != NULL && cp - n->string < 5)
+ cp = strchr(cp + 1, ' ');
+
+ /* If the first text node is longer, split it. */
+
+ if (cp != NULL && cp[1] != '\0') {
+ man->last = n;
+ man->next = ROFF_NEXT_SIBLING;
+ roff_word_alloc(man, n->line,
+ n->pos + (cp - n->string), cp + 1);
+ man->last->flags = n->flags & ~NODE_LINE;
+ *cp = '\0';
+ }
+
+ assert(n->tag == NULL);
+ n->tag = mandoc_strdup(tag);
+ n->flags |= NODE_HREF;
+}
+
/*
* When all tags have been set, decide where to put
* the associated permalinks, and maybe move some tags
* to the beginning of the respective paragraphs.
*/
void
-tag_postprocess(struct roff_node *n)
+tag_postprocess(struct roff_man *man, struct roff_node *n)
{
if (n->flags & NODE_ID) {
switch (n->tok) {
+ case MDOC_Pp:
+ tag_move_href(man, n->next, n->tag);
+ break;
case MDOC_Bd:
+ case MDOC_D1:
+ case MDOC_Dl:
+ tag_move_href(man, n->child, n->tag);
+ break;
case MDOC_Bl:
- case MDOC_Pp:
/* XXX No permalink for now. */
break;
default:
tag_move_id(n);
if (n->tok != MDOC_Tg)
n->flags |= NODE_HREF;
- else if ((n->flags & NODE_ID) == 0)
+ else if ((n->flags & NODE_ID) == 0) {
n->flags |= NODE_NOPRT;
+ free(n->tag);
+ n->tag = NULL;
+ }
break;
}
}
for (n = n->child; n != NULL; n = n->next)
- tag_postprocess(n);
+ tag_postprocess(man, n);
}