Skip to content

Commit

Permalink
ctheorems:1.1.0 (#222)
Browse files Browse the repository at this point in the history
  • Loading branch information
sahasatvik authored Nov 6, 2023
1 parent 7bf3320 commit 0e14cb7
Show file tree
Hide file tree
Showing 7 changed files with 332 additions and 0 deletions.
21 changes: 21 additions & 0 deletions packages/preview/ctheorems/1.1.0/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 Satvik Saha, DVDTSB

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
107 changes: 107 additions & 0 deletions packages/preview/ctheorems/1.1.0/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# ctheorems

An implementation of numbered theorem environments in
[typst](https://github.com/typst/typst). Import using
```typst
#import "@preview/ctheorems:1.1.0": *
#show: thmrules
```

### Features
- Numbered theorem environments can be created and customized.
- Environments can share the same counter, via same `identifier`s.
- Environment counters can be _attached_ (just as subheadings are attached to headings) to other environments, headings, or keep a global count via `base`.
- The depth of a counter can be manually set, via `base_level`.
- Environments can be `<label>`'d and `@reference`'d.
- Awesome presets (coming soon!)

## Manual and Examples
Get acquainted with `ctheorems` by checking out the minimal example below!

You can read the [manual](assets/manual.pdf) for a full walkthrough of functionality offered by this module; flick through [manual_examples](assets/manual_examples.pdf) to just see the examples.

![basic example](assets/basic.png)

### Preamble
```typst
#import "@preview/ctheorems:1.1.0": *
#show: thmrules
#set page(width: 16cm, height: auto, margin: 1.5cm)
#set heading(numbering: "1.1.")
#let theorem = thmbox("theorem", "Theorem", fill: rgb("#eeffee"))
#let corollary = thmplain(
"corollary",
"Corollary",
base: "theorem",
titlefmt: strong
)
#let definition = thmbox("definition", "Definition", inset: (x: 1.2em, top: 1em))
#let example = thmplain("example", "Example").with(numbering: none)
#let proof = thmplain(
"proof",
"Proof",
base: "theorem",
bodyfmt: body => [#body #h(1fr) $square$]
).with(numbering: none)
```

### Document
```typst
= Prime numbers
#definition[
A natural number is called a #highlight[_prime number_] if it is greater
than 1 and cannot be written as the product of two smaller natural numbers.
]
#example[
The numbers $2$, $3$, and $17$ are prime.
@cor_largest_prime shows that this list is not exhaustive!
]
#theorem("Euclid")[
There are infinitely many primes.
]
#proof[
Suppose to the contrary that $p_1, p_2, dots, p_n$ is a finite enumeration
of all primes. Set $P = p_1 p_2 dots p_n$. Since $P + 1$ is not in our list,
it cannot be prime. Thus, some prime factor $p_j$ divides $P + 1$. Since
$p_j$ also divides $P$, it must divide the difference $(P + 1) - P = 1$, a
contradiction.
]
#corollary[
There is no largest prime number.
] <cor_largest_prime>
#corollary[
There are infinitely many composite numbers.
]
```


## Changelog

### v1.1.0

- The `supplement` (for references) is no longer set in `thmenv`. It can be passed to the theorem environment directly, along with `refnumbering` to control the appearance of `@reference`s.
- Extra named arguments given to `thmbox` are passed to `block`.
- Fixed spacing bug for unnumbered environments.
- Replaced dummy figure with labelled metadata.

### v1.0.0

- Extra named arguments given to a theorem environment are passed to its formatting function `fmt`.
- Removed `thmref`, introduced normal `<label>`s and `@reference`s.
- Import must be followed by `show: thmrules`.
- Removed `name: ...` from theorem environments; use `#theorem("Euclid")[]` instead of `#theorem(name: "Euclid")[]`.
- Theorems are now wrapped in `figure`s.


## Credits

- [sahasatvik (Satvik Saha)](https://github.com/sahasatvik)
- [MJHutchinson (Michael Hutchinson)](https://github.com/MJHutchinson)
- [rmolinari (Rory Molinari)](https://github.com/rmolinari)
- [DVDTSB](https://github.com/DVDTSB)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
190 changes: 190 additions & 0 deletions packages/preview/ctheorems/1.1.0/lib.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Store theorem environment numbering

#let thmcounters = state("thm",
(
"counters": ("heading": ()),
"latest": ()
)
)


#let thmenv(identifier, base, base_level, fmt) = {

let global_numbering = numbering

return (
..args,
body,
number: auto,
numbering: "1.1",
refnumbering: auto,
supplement: identifier,
base: base,
base_level: base_level
) => {
let name = none
if args != none and args.pos().len() > 0 {
name = args.pos().first()
}
if refnumbering == auto {
refnumbering = numbering
}
let result = none
if number == auto and numbering == none {
number = none
}
if number == auto and numbering != none {
result = locate(loc => {
return thmcounters.update(thmpair => {
let counters = thmpair.at("counters")
// Manually update heading counter
counters.at("heading") = counter(heading).at(loc)
if not identifier in counters.keys() {
counters.insert(identifier, (0, ))
}

let tc = counters.at(identifier)
if base != none {
let bc = counters.at(base)

// Pad or chop the base count
if base_level != none {
if bc.len() < base_level {
bc = bc + (0,) * (base_level - bc.len())
} else if bc.len() > base_level{
bc = bc.slice(0, base_level)
}
}

// Reset counter if the base counter has updated
if tc.slice(0, -1) == bc {
counters.at(identifier) = (..bc, tc.last() + 1)
} else {
counters.at(identifier) = (..bc, 1)
}
} else {
// If we have no base counter, just count one level
counters.at(identifier) = (tc.last() + 1,)
let latest = counters.at(identifier)
}

let latest = counters.at(identifier)
return (
"counters": counters,
"latest": latest
)
})
})

number = thmcounters.display(x => {
return global_numbering(numbering, ..x.at("latest"))
})
}

return figure(
result + // hacky!
fmt(name, number, body, ..args.named()) +
[#metadata(identifier) <meta:thmenvcounter>],
kind: "thmenv",
outlined: false,
caption: name,
supplement: supplement,
numbering: refnumbering,
)
}
}


#let thmbox(
identifier,
head,
..blockargs,
supplement: auto,
padding: (top: 0.5em, bottom: 0.5em),
namefmt: x => [(#x)],
titlefmt: strong,
bodyfmt: x => x,
separator: [#h(0.1em):#h(0.2em)],
base: "heading",
base_level: none,
) = {
if supplement == auto {
supplement = head
}
let boxfmt(name, number, body, title: auto) = {
if not name == none {
name = [ #namefmt(name)]
} else {
name = []
}
if title == auto {
title = head
}
if not number == none {
title += " " + number
}
title = titlefmt(title)
body = bodyfmt(body)
pad(
..padding,
block(
width: 100%,
inset: 1.2em,
radius: 0.3em,
breakable: false,
..blockargs.named(),
[#title#name#separator#body]
)
)
}
return thmenv(
identifier,
base,
base_level,
boxfmt
).with(
supplement: supplement,
)
}


#let thmplain = thmbox.with(
padding: (top: 0em, bottom: 0em),
breakable: true,
inset: (top: 0em, left: 1.2em, right: 1.2em),
namefmt: name => emph([(#name)]),
titlefmt: emph,
)



#let thmrules(doc) = {
show figure.where(kind: "thmenv"): it => it.body

show ref: it => {
if it.element == none {
return it
}
if it.element.func() != figure {
return it
}
if it.element.kind != "thmenv" {
return it
}

let supplement = it.element.supplement
if it.citation.supplement != none {
supplement = it.citation.supplement
}

let loc = it.element.location()
let thms = query(selector(<meta:thmenvcounter>).after(loc), loc)
let number = thmcounters.at(thms.first().location()).at("latest")
return link(
it.target,
[#supplement~#numbering(it.element.numbering, ..number)]
)
}

doc
}
14 changes: 14 additions & 0 deletions packages/preview/ctheorems/1.1.0/typst.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "ctheorems"
version = "1.1.0"
entrypoint = "lib.typ"
authors = [
"sahasatvik (Satvik Saha)",
"rmolinari (Rory Molinari)",
"MJHutchinson (Michael Hutchinson)",
"DVDTSB",
]
license = "MIT"
description = "Numbered theorem environments for typst."
repository = "https://github.com/sahasatvik/typst-theorems"
exclude = ["/assets/*"]

0 comments on commit 0e14cb7

Please sign in to comment.