diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fc90d2..0f5708b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # [unreleased](https://github.com/tingerrr/hydra/releases/tags/) ## Added +- `use-last` parameter on `hydra` for a more LaTeX style heading look up, thanks @freundTech! + - `hydra` now has a new `use-last` parameter + - `context` now has a new `use-last` field + - **BREAKING CHANGE** `candidates` now has a new `last` field containiing a suitable match for the last primary candidate on this page ## Removed diff --git a/doc/chapters/3-reference.typ b/doc/chapters/3-reference.typ index 4201e04..08276ee 100644 --- a/doc/chapters/3-reference.typ +++ b/doc/chapters/3-reference.typ @@ -46,7 +46,7 @@ Defines the candidates that have been found in a specific context. ```typc ( - primary: (prev: content | none, next: content | none), + primary: (prev: content | none, next: content | none, last: content | none), ancestor: (prev: content | none, next: content | none), ) ``` @@ -61,6 +61,7 @@ displaying. next-filter: (context, candidates) => bool, display: (context, content) => content, skip-starting: bool, + use-last: bool, book: bool, anchor: label | none, anchor-loc: location, diff --git a/doc/manual.pdf b/doc/manual.pdf index 0d8ee98..b0c205b 100644 Binary files a/doc/manual.pdf and b/doc/manual.pdf differ diff --git a/src/core.typ b/src/core.typ index 7c3b2f4..f2e5816 100644 --- a/src/core.typ +++ b/src/core.typ @@ -84,43 +84,48 @@ #let get-candidates(ctx, scope-prev: true, scope-next: true) = { let look-prev = selector(ctx.primary.target).before(ctx.anchor-loc) let look-next = selector(ctx.primary.target).after(ctx.anchor-loc) + let look-last = look-next let prev-ancestor = none let next-ancestor = none if ctx.ancestors != none { - let prev = query(selector(ctx.ancestors.target).before(ctx.anchor-loc)) - let next = query(selector(ctx.ancestors.target).after(ctx.anchor-loc)) + let prev-ancestors = query(selector(ctx.ancestors.target).before(ctx.anchor-loc)) + let next-ancestors = query(selector(ctx.ancestors.target).after(ctx.anchor-loc)) if ctx.ancestors.filter != none { - prev = prev.filter(x => (ctx.ancestors.filter)(ctx, x)) - next = next.filter(x => (ctx.ancestors.filter)(ctx, x)) + prev-ancestors = prev-ancestors.filter(x => (ctx.ancestors.filter)(ctx, x)) + next-ancestors = next-ancestors.filter(x => (ctx.ancestors.filter)(ctx, x)) } - if scope-prev and prev != () { - prev-ancestor = prev.last() + if scope-prev and prev-ancestors != () { + prev-ancestor = prev-ancestors.last() look-prev = look-prev.after(prev-ancestor.location()) } - if scope-next and next != () { - next-ancestor = next.first() + if scope-next and next-ancestors != () { + next-ancestor = next-ancestors.first() look-next = look-next.before(next-ancestor.location()) } } - let prev = query(look-prev) - let next = query(look-next) + let prev-targets = query(look-prev) + let next-targets = query(look-next) + let last-targets = query(look-last) if ctx.primary.filter != none { - prev = prev.filter(x => (ctx.primary.filter)(ctx, x)) - next = next.filter(x => (ctx.primary.filter)(ctx, x)) + prev-targets = prev-targets.filter(x => (ctx.primary.filter)(ctx, x)) + next-targets = next-targets.filter(x => (ctx.primary.filter)(ctx, x)) + last-targets = last-targets.filter(x => (ctx.primary.filter)(ctx, x)) } + last-targets = last-targets.filter(x => x.location().page() == ctx.anchor-loc.page()) - let prev = if prev != () { prev.last() } - let next = if next != () { next.first() } + let prev = if prev-targets != () { prev-targets.last() } + let next = if next-targets != () { next-targets.first() } + let last = if last-targets != () { last-targets.last() } ( - primary: (prev: prev, next: next), + primary: (prev: prev, next: next, last: last), ancestor: (prev: prev-ancestor, next: next-ancestor), ) } @@ -231,11 +236,18 @@ let candidates = get-candidates(ctx) let prev-eligible = candidates.primary.prev != none and (ctx.prev-filter)(ctx, candidates) let next-eligible = candidates.primary.next != none and (ctx.next-filter)(ctx, candidates) + let last-eligible = candidates.primary.last != none and (ctx.next-filter)(ctx, candidates) let active-redundant = is-active-redundant(ctx, candidates) - if prev-eligible and not active-redundant { + if active-redundant and ctx.skip-starting { + return + } + + if ctx.use-last and last-eligible { + (ctx.display)(ctx, candidates.primary.last) + } else if prev-eligible and not active-redundant { (ctx.display)(ctx, candidates.primary.prev) - } else if next-eligible and not ctx.skip-starting { + } else if next-eligible { (ctx.display)(ctx, candidates.primary.next) } } diff --git a/src/lib.typ b/src/lib.typ index 52ead0b..c1b0f68 100644 --- a/src/lib.typ +++ b/src/lib.typ @@ -28,6 +28,8 @@ /// display. If this is `auto`, the default implementaion will be used. /// - skip-starting (bool): Whether `hydra` should show the current candidate even if it's on top of /// the current page. +/// - use-last (bool): If hydra should show the name of the first or last candidate on the page. +// Defaults to false. /// - dir (direction, auto): The reading direction of the document. If this is `auto`, the text /// direction is used. Be cautious about leaving this option on `auto` if you switch text /// direction mid-page and use hydra outside of footers or headers. @@ -47,6 +49,7 @@ next-filter: auto, display: auto, skip-starting: true, + use-last: false, dir: auto, binding: auto, book: false, @@ -57,6 +60,7 @@ util.assert.types("next-filter", next-filter, function, auto) util.assert.types("display", display, function, auto) util.assert.types("skip-starting", skip-starting, bool) + util.assert.types("use-last", use-last, bool) util.assert.enum("dir", dir, ltr, rtl, auto) util.assert.enum("binding", binding, left, right, auto) util.assert.types("book", book, bool) @@ -78,6 +82,7 @@ next-filter: util.auto-or(next-filter, () => default-filter), display: util.auto-or(display, () => core.display), skip-starting: skip-starting, + use-last: use-last, dir: dir, binding: binding, book: book, diff --git a/tests/features/use-last/.gitignore b/tests/features/use-last/.gitignore new file mode 100644 index 0000000..7ecdc7c --- /dev/null +++ b/tests/features/use-last/.gitignore @@ -0,0 +1 @@ +# added by typst-test diff --git a/tests/features/use-last/basic/ref/1.png b/tests/features/use-last/basic/ref/1.png new file mode 100644 index 0000000..c8770cb Binary files /dev/null and b/tests/features/use-last/basic/ref/1.png differ diff --git a/tests/features/use-last/basic/ref/2.png b/tests/features/use-last/basic/ref/2.png new file mode 100644 index 0000000..02af2f7 Binary files /dev/null and b/tests/features/use-last/basic/ref/2.png differ diff --git a/tests/features/use-last/basic/ref/3.png b/tests/features/use-last/basic/ref/3.png new file mode 100644 index 0000000..ba9c2db Binary files /dev/null and b/tests/features/use-last/basic/ref/3.png differ diff --git a/tests/features/use-last/basic/ref/4.png b/tests/features/use-last/basic/ref/4.png new file mode 100644 index 0000000..66eca06 Binary files /dev/null and b/tests/features/use-last/basic/ref/4.png differ diff --git a/tests/features/use-last/basic/ref/5.png b/tests/features/use-last/basic/ref/5.png new file mode 100644 index 0000000..c3a5566 Binary files /dev/null and b/tests/features/use-last/basic/ref/5.png differ diff --git a/tests/features/use-last/basic/ref/6.png b/tests/features/use-last/basic/ref/6.png new file mode 100644 index 0000000..64692ca Binary files /dev/null and b/tests/features/use-last/basic/ref/6.png differ diff --git a/tests/features/use-last/basic/ref/7.png b/tests/features/use-last/basic/ref/7.png new file mode 100644 index 0000000..b359eee Binary files /dev/null and b/tests/features/use-last/basic/ref/7.png differ diff --git a/tests/features/use-last/basic/test.typ b/tests/features/use-last/basic/test.typ new file mode 100644 index 0000000..8fda5f8 --- /dev/null +++ b/tests/features/use-last/basic/test.typ @@ -0,0 +1,23 @@ +// Synopsis: +// - Setting use-last to true makes hydra use show the last candidate on a page instead of the first + +#import "/src/lib.typ": hydra + +#set page( + paper: "a7", + header: context hydra(use-last: true), +) +#set heading(numbering: "1.1") +#show heading.where(level: 1): it => pagebreak(weak: true) + it +#set par(justify: true) + += Introduction +#lorem(200) + += Content +== First Section +#lorem(50) +== Second Section +#lorem(100) +== Third section +#lorem(100) diff --git a/tests/features/use-last/multiple-ancestors/ref/1.png b/tests/features/use-last/multiple-ancestors/ref/1.png new file mode 100644 index 0000000..ac0d011 Binary files /dev/null and b/tests/features/use-last/multiple-ancestors/ref/1.png differ diff --git a/tests/features/use-last/multiple-ancestors/ref/2.png b/tests/features/use-last/multiple-ancestors/ref/2.png new file mode 100644 index 0000000..9bc160e Binary files /dev/null and b/tests/features/use-last/multiple-ancestors/ref/2.png differ diff --git a/tests/features/use-last/multiple-ancestors/ref/3.png b/tests/features/use-last/multiple-ancestors/ref/3.png new file mode 100644 index 0000000..5cdc048 Binary files /dev/null and b/tests/features/use-last/multiple-ancestors/ref/3.png differ diff --git a/tests/features/use-last/multiple-ancestors/ref/4.png b/tests/features/use-last/multiple-ancestors/ref/4.png new file mode 100644 index 0000000..225b216 Binary files /dev/null and b/tests/features/use-last/multiple-ancestors/ref/4.png differ diff --git a/tests/features/use-last/multiple-ancestors/test.typ b/tests/features/use-last/multiple-ancestors/test.typ new file mode 100644 index 0000000..e72ed2b --- /dev/null +++ b/tests/features/use-last/multiple-ancestors/test.typ @@ -0,0 +1,29 @@ +// Synopsis: +// - When there are multiple ancestors on one page hydra should still show the last heading + +#import "/src/lib.typ": hydra + +#set page( + paper: "a7", + header: context hydra(2, use-last: true), +) +#set heading(numbering: "1.1") +#set par(justify: true) + + += Introduction +== First Section +#lorem(50) +== Second Section +#lorem(100) +== Third section +#lorem(50) + += Other +#lorem(10) +== test +#lorem(10) += More +#lorem(5) +== more tests +#lorem(10)