-
Notifications
You must be signed in to change notification settings - Fork 440
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7bf3320
commit 0e14cb7
Showing
7 changed files
with
332 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/*"] |