decasify 0.8.0__tar.gz → 0.9.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {decasify-0.8.0 → decasify-0.9.1}/Cargo.lock +31 -1
- {decasify-0.8.0 → decasify-0.9.1}/Cargo.toml +89 -53
- {decasify-0.8.0 → decasify-0.9.1}/PKG-INFO +20 -6
- {decasify-0.8.0 → decasify-0.9.1}/README.md +18 -4
- {decasify-0.8.0 → decasify-0.9.1}/src/content.rs +74 -12
- {decasify-0.8.0 → decasify-0.9.1}/src/en.rs +35 -35
- {decasify-0.8.0 → decasify-0.9.1}/src/tr.rs +25 -25
- {decasify-0.8.0 → decasify-0.9.1}/src/types.rs +23 -2
- {decasify-0.8.0 → decasify-0.9.1}/tests/lib.rs +18 -0
- {decasify-0.8.0 → decasify-0.9.1}/build-aux/build.rs +0 -0
- {decasify-0.8.0 → decasify-0.9.1}/pyproject.toml +0 -0
- {decasify-0.8.0 → decasify-0.9.1}/src/bin/decasify.rs +0 -0
- {decasify-0.8.0 → decasify-0.9.1}/src/cli.rs +0 -0
- {decasify-0.8.0 → decasify-0.9.1}/src/lib.rs +0 -0
- {decasify-0.8.0 → decasify-0.9.1}/src/lua.rs +0 -0
- {decasify-0.8.0 → decasify-0.9.1}/src/python.rs +0 -0
- {decasify-0.8.0 → decasify-0.9.1}/src/traits.rs +0 -0
- {decasify-0.8.0 → decasify-0.9.1}/src/wasm.rs +0 -0
- {decasify-0.8.0 → decasify-0.9.1}/tests/cli.rs +0 -0
|
@@ -306,7 +306,7 @@ dependencies = [
|
|
|
306
306
|
|
|
307
307
|
[[package]]
|
|
308
308
|
name = "decasify"
|
|
309
|
-
version = "0.
|
|
309
|
+
version = "0.9.1"
|
|
310
310
|
dependencies = [
|
|
311
311
|
"anyhow",
|
|
312
312
|
"assert_cmd",
|
|
@@ -1691,6 +1691,15 @@ dependencies = [
|
|
|
1691
1691
|
"regex",
|
|
1692
1692
|
]
|
|
1693
1693
|
|
|
1694
|
+
[[package]]
|
|
1695
|
+
name = "typst"
|
|
1696
|
+
version = "0.9.1"
|
|
1697
|
+
dependencies = [
|
|
1698
|
+
"anyhow",
|
|
1699
|
+
"decasify",
|
|
1700
|
+
"wasm-minimal-protocol",
|
|
1701
|
+
]
|
|
1702
|
+
|
|
1694
1703
|
[[package]]
|
|
1695
1704
|
name = "unicode-bidi"
|
|
1696
1705
|
version = "0.3.17"
|
|
@@ -1747,6 +1756,16 @@ version = "0.2.2"
|
|
|
1747
1756
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1748
1757
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|
1749
1758
|
|
|
1759
|
+
[[package]]
|
|
1760
|
+
name = "venial"
|
|
1761
|
+
version = "0.5.0"
|
|
1762
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1763
|
+
checksum = "61584a325b16f97b5b25fcc852eb9550843a251057a5e3e5992d2376f3df4bb2"
|
|
1764
|
+
dependencies = [
|
|
1765
|
+
"proc-macro2",
|
|
1766
|
+
"quote",
|
|
1767
|
+
]
|
|
1768
|
+
|
|
1750
1769
|
[[package]]
|
|
1751
1770
|
name = "vergen"
|
|
1752
1771
|
version = "9.0.1"
|
|
@@ -1869,6 +1888,17 @@ version = "0.2.95"
|
|
|
1869
1888
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1870
1889
|
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
|
1871
1890
|
|
|
1891
|
+
[[package]]
|
|
1892
|
+
name = "wasm-minimal-protocol"
|
|
1893
|
+
version = "0.1.0"
|
|
1894
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1895
|
+
checksum = "264a7e0acbdd292aca03fee87eaea5a07647394c8985b19be27e950bde57930a"
|
|
1896
|
+
dependencies = [
|
|
1897
|
+
"proc-macro2",
|
|
1898
|
+
"quote",
|
|
1899
|
+
"venial",
|
|
1900
|
+
]
|
|
1901
|
+
|
|
1872
1902
|
[[package]]
|
|
1873
1903
|
name = "winapi-util"
|
|
1874
1904
|
version = "0.1.9"
|
|
@@ -1,28 +1,49 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "decasify"
|
|
3
|
-
version = "0.
|
|
4
|
-
authors = ["Caleb Maclennan <caleb@alerque.com>"]
|
|
5
|
-
edition = "2021"
|
|
6
|
-
rust-version = "1.73.0"
|
|
3
|
+
version = "0.9.1"
|
|
7
4
|
description = "A CLI utility and library to cast strings to title-case according to locale specific style guides including Turkish support"
|
|
8
5
|
readme = "README.md"
|
|
6
|
+
build = "build-aux/build.rs"
|
|
7
|
+
include = ["*.rs"]
|
|
8
|
+
edition.workspace = true
|
|
9
|
+
rust-version.workspace = true
|
|
10
|
+
authors.workspace = true
|
|
11
|
+
homepage.workspace = true
|
|
12
|
+
repository.workspace = true
|
|
13
|
+
license.workspace = true
|
|
14
|
+
|
|
15
|
+
[workspace.package]
|
|
16
|
+
version = "0.9.1"
|
|
17
|
+
authors = ["Caleb Maclennan <caleb@alerque.com>"]
|
|
9
18
|
homepage = "https://github.com/alerque/decasify"
|
|
10
19
|
repository = "https://github.com/alerque/decasify"
|
|
11
20
|
license = "LGPL-3.0-only"
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
edition = "2021"
|
|
22
|
+
rust-version = "1.73.0"
|
|
14
23
|
|
|
15
|
-
[
|
|
16
|
-
|
|
17
|
-
crate-type = ["rlib", "cdylib"]
|
|
24
|
+
[workspace]
|
|
25
|
+
resolver = "2"
|
|
18
26
|
|
|
19
27
|
[[bin]]
|
|
20
28
|
name = "decasify"
|
|
21
29
|
required-features = ["cli"]
|
|
22
30
|
|
|
31
|
+
[lib]
|
|
32
|
+
name = "decasify"
|
|
33
|
+
crate-type = ["rlib", "cdylib"]
|
|
34
|
+
|
|
35
|
+
[profile.release]
|
|
36
|
+
lto = true
|
|
37
|
+
|
|
38
|
+
[profile.typst]
|
|
39
|
+
inherits = "release"
|
|
40
|
+
opt-level = "z"
|
|
41
|
+
strip = true
|
|
42
|
+
|
|
23
43
|
[features]
|
|
24
44
|
default = []
|
|
25
45
|
full = ["cli", "bash", "elvish", "fish", "manpage", "powershell", "zsh"]
|
|
46
|
+
modules = ["luamodule", "pythonmodule", "wasm"]
|
|
26
47
|
completions = ["cli", "dep:clap_complete"]
|
|
27
48
|
cli = ["dep:clap"]
|
|
28
49
|
bash = ["completions"]
|
|
@@ -31,7 +52,7 @@ fish = ["completions"]
|
|
|
31
52
|
manpage = ["dep:clap_mangen"]
|
|
32
53
|
powershell = ["completions"]
|
|
33
54
|
zsh = ["completions"]
|
|
34
|
-
luamodule = []
|
|
55
|
+
luamodule = ["mlua"]
|
|
35
56
|
lua54 = ["luamodule", "mlua/lua54"]
|
|
36
57
|
lua53 = ["luamodule", "mlua/lua53"]
|
|
37
58
|
lua52 = ["luamodule", "mlua/lua52"]
|
|
@@ -41,8 +62,9 @@ pythonmodule = ["dep:pyo3"]
|
|
|
41
62
|
unstable-trait = []
|
|
42
63
|
wasm = ["dep:wasm-bindgen"]
|
|
43
64
|
|
|
44
|
-
[
|
|
45
|
-
|
|
65
|
+
[workspace.dependencies.decasify]
|
|
66
|
+
path = "."
|
|
67
|
+
version = "0.9.1"
|
|
46
68
|
|
|
47
69
|
[dependencies]
|
|
48
70
|
regex = "1.11"
|
|
@@ -51,54 +73,54 @@ strum = "0.26"
|
|
|
51
73
|
strum_macros = "0.26"
|
|
52
74
|
unicode_titlecase = "2.4"
|
|
53
75
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
[dependencies.clap]
|
|
77
|
+
version = "4.5"
|
|
78
|
+
optional = true
|
|
79
|
+
features = ["derive", "wrap_help"]
|
|
58
80
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
81
|
+
[dependencies.mlua]
|
|
82
|
+
version = "0.10.0"
|
|
83
|
+
optional = true
|
|
84
|
+
features = ["module"]
|
|
63
85
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
86
|
+
[dependencies.pyo3]
|
|
87
|
+
version = "0.22"
|
|
88
|
+
optional = true
|
|
89
|
+
features = ["extension-module"]
|
|
68
90
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
91
|
+
[dependencies.titlecase]
|
|
92
|
+
version = "3.3"
|
|
93
|
+
features = ["perf"]
|
|
72
94
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
95
|
+
[dependencies.wasm-bindgen]
|
|
96
|
+
version = "0.2"
|
|
97
|
+
optional = true
|
|
76
98
|
|
|
77
99
|
[build-dependencies]
|
|
78
100
|
snafu = "0.8"
|
|
79
101
|
strum = "0.26"
|
|
80
102
|
strum_macros = "0.26"
|
|
81
103
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
104
|
+
[build-dependencies.clap_complete]
|
|
105
|
+
version = "4.5"
|
|
106
|
+
optional = true
|
|
85
107
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
108
|
+
[build-dependencies.clap_mangen]
|
|
109
|
+
version = "0.2"
|
|
110
|
+
optional = true
|
|
89
111
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
112
|
+
[build-dependencies.clap]
|
|
113
|
+
version = "4.5"
|
|
114
|
+
optional = true
|
|
115
|
+
features = ["derive"]
|
|
94
116
|
|
|
95
|
-
|
|
96
|
-
|
|
117
|
+
[build-dependencies.anyhow]
|
|
118
|
+
version = "1.0"
|
|
97
119
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
120
|
+
[build-dependencies.vergen-gix]
|
|
121
|
+
version = "1.0"
|
|
122
|
+
default-features = false
|
|
123
|
+
features = ["build", "cargo", "rustc"]
|
|
102
124
|
|
|
103
125
|
[dev-dependencies]
|
|
104
126
|
assert_cmd = "2.0"
|
|
@@ -107,6 +129,22 @@ predicates = "3.1"
|
|
|
107
129
|
[lints.rust]
|
|
108
130
|
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(build)'] }
|
|
109
131
|
|
|
132
|
+
[package.metadata.bacon]
|
|
133
|
+
default_job = "build"
|
|
134
|
+
|
|
135
|
+
[package.metadata.bacon.jobs.build]
|
|
136
|
+
command = ["cargo", "build", "--features", "full", "--color", "always"]
|
|
137
|
+
|
|
138
|
+
[package.metadata.bacon.jobs.build-modules]
|
|
139
|
+
command = [
|
|
140
|
+
"cargo",
|
|
141
|
+
"build",
|
|
142
|
+
"--features",
|
|
143
|
+
"modules,luajit",
|
|
144
|
+
"--color",
|
|
145
|
+
"always",
|
|
146
|
+
]
|
|
147
|
+
|
|
110
148
|
[package.metadata.docs.rs]
|
|
111
149
|
features = ["luamodule", "luajit", "pythonmodule", "wasm", "unstable-trait"]
|
|
112
150
|
rustdoc-args = ["--cfg", "docsrs"]
|
|
@@ -114,10 +152,10 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|
|
114
152
|
[package.metadata.git-cliff.git]
|
|
115
153
|
protect_breaking_commits = true
|
|
116
154
|
commit_parsers = [
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
155
|
+
{ message = "^feat", group = "<!-- 0 -->Features" },
|
|
156
|
+
{ message = "^fix", group = "<!-- 1 -->Bug Fixes" },
|
|
157
|
+
{ message = "^perf", group = "<!-- 2 -->Performance" },
|
|
158
|
+
{ message = ".*", skip = true },
|
|
121
159
|
]
|
|
122
160
|
commit_preprocessors = [
|
|
123
161
|
{ pattern = '.*', replace_command = 'typos --quiet --write-changes -' },
|
|
@@ -125,9 +163,7 @@ commit_preprocessors = [
|
|
|
125
163
|
|
|
126
164
|
[package.metadata.typos.default]
|
|
127
165
|
locale = "en-us"
|
|
128
|
-
extend-ignore-identifiers-re = [
|
|
129
|
-
"[bB][aA][zZ]"
|
|
130
|
-
]
|
|
166
|
+
extend-ignore-identifiers-re = ["[bB][aA][zZ]"]
|
|
131
167
|
|
|
132
168
|
[package.metadata.typos.default.extend-words]
|
|
133
169
|
runing = "running"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: decasify
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.1
|
|
4
4
|
Classifier: Development Status :: 5 - Production/Stable
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: Natural Language :: English
|
|
@@ -33,7 +33,7 @@ Project-URL: Source Code, https://github.com/alerque/decasify
|
|
|
33
33
|
[](https://pypi.org/project/decasify)
|
|
34
34
|
[](https://www.npmjs.com/package/decasify)
|
|
35
35
|
|
|
36
|
-
A CLI utility, Rust crate, Lua rock, Python module, JavaScript module, Neovim plugin, and
|
|
36
|
+
A CLI utility, Rust crate, Lua rock, Python module, JavaScript module, Neovim plugin, SILE package, and Typst package to cast strings to title-case (and other cases) according to locale specific style guides including Turkish support.
|
|
37
37
|
|
|
38
38
|
This project was born out of frustration with authors and editors leaving ALL CAPS TITLES in Markdown sources.
|
|
39
39
|
No tooling I could find properly supported casting these to title-cased strings (which are more versatile for typesetting purposes).
|
|
@@ -47,7 +47,7 @@ Where possible the APIs currently default to English rules and (for English) the
|
|
|
47
47
|
|
|
48
48
|
The Turkish style follows the Turkish Language Institute's [guidelines][tdk].
|
|
49
49
|
|
|
50
|
-
For English, three style guides are known: Associated Press (AP), Chicago Manual of Style (CMOS), and John
|
|
50
|
+
For English, three style guides are known: Associated Press (AP), Chicago Manual of Style (CMOS), and John Gruber's Daring Fireball (Gruber).
|
|
51
51
|
The Gruber style is by far the most complete, being implemented by the [titlecase crate][titlecase_crate].
|
|
52
52
|
The CMOS style handles a number of parts of speech but has punctuation related issues.
|
|
53
53
|
The AP style is largely unimplemented.
|
|
@@ -77,7 +77,8 @@ Foo BAR and Baz: An Alter Ego
|
|
|
77
77
|
|
|
78
78
|
### Installation
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
<a href="https://repology.org/project/decasify/versions"><img src="https://repology.org/badge/vertical-allrepos/decasify.svg" align="right" alt="Packaging status"></a>
|
|
81
|
+
To install, first check your distro for packages, e.g. for [Arch Linux](https://archlinux.org/packages/extra/x86_64/decasify/) just install via `pacman -S decasify` or for [Homebrew](https://formulae.brew.sh/formula/decasify) via `brew install decasify`.
|
|
81
82
|
|
|
82
83
|
Otherwise for many platforms you can run it directly or install it to a shell using Nix Flakes:
|
|
83
84
|
|
|
@@ -113,7 +114,7 @@ In your `Cargo.toml` file.
|
|
|
113
114
|
|
|
114
115
|
```toml
|
|
115
116
|
[dependencies]
|
|
116
|
-
decasify = "0.
|
|
117
|
+
decasify = "0.9"
|
|
117
118
|
```
|
|
118
119
|
|
|
119
120
|
Then use the crate functions and types in your project something like this:
|
|
@@ -236,6 +237,19 @@ Loading it in a SILE document uses the usual `\use[module=package.decasify]` (se
|
|
|
236
237
|
Once loaded the package exposes a `\decasify{}` function that can take any combination of `case`, `locale`, and `style` settings and applies the appropriate transformation to the content.
|
|
237
238
|
By default it will track the language of the document content.
|
|
238
239
|
|
|
240
|
+
## Use as a Typst package
|
|
241
|
+
|
|
242
|
+
[Typst](https://typst.app/) has its own [package registry](https://typst.app/universe/).
|
|
243
|
+
The [decasify](https://typst.app/universe/package/decasify) package can be added to your project with an import line.
|
|
244
|
+
The exact version must be specified explicitly:
|
|
245
|
+
|
|
246
|
+
```typst
|
|
247
|
+
#import "@preview/decasify:0.8.0": *
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Specific functions for each case should be available throughout the document.
|
|
251
|
+
See the Typst package [readme](typst/README.md) or the [package listing on Typst universe](https://typst.app/universe/package/decasify) for more details.
|
|
252
|
+
|
|
239
253
|
[rock]: http://luarocks.org/modules/alerque/decasify
|
|
240
254
|
[rock.sile]: http://luarocks.org/modules/alerque/decasify.sile
|
|
241
255
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
[](https://pypi.org/project/decasify)
|
|
12
12
|
[](https://www.npmjs.com/package/decasify)
|
|
13
13
|
|
|
14
|
-
A CLI utility, Rust crate, Lua rock, Python module, JavaScript module, Neovim plugin, and
|
|
14
|
+
A CLI utility, Rust crate, Lua rock, Python module, JavaScript module, Neovim plugin, SILE package, and Typst package to cast strings to title-case (and other cases) according to locale specific style guides including Turkish support.
|
|
15
15
|
|
|
16
16
|
This project was born out of frustration with authors and editors leaving ALL CAPS TITLES in Markdown sources.
|
|
17
17
|
No tooling I could find properly supported casting these to title-cased strings (which are more versatile for typesetting purposes).
|
|
@@ -25,7 +25,7 @@ Where possible the APIs currently default to English rules and (for English) the
|
|
|
25
25
|
|
|
26
26
|
The Turkish style follows the Turkish Language Institute's [guidelines][tdk].
|
|
27
27
|
|
|
28
|
-
For English, three style guides are known: Associated Press (AP), Chicago Manual of Style (CMOS), and John
|
|
28
|
+
For English, three style guides are known: Associated Press (AP), Chicago Manual of Style (CMOS), and John Gruber's Daring Fireball (Gruber).
|
|
29
29
|
The Gruber style is by far the most complete, being implemented by the [titlecase crate][titlecase_crate].
|
|
30
30
|
The CMOS style handles a number of parts of speech but has punctuation related issues.
|
|
31
31
|
The AP style is largely unimplemented.
|
|
@@ -55,7 +55,8 @@ Foo BAR and Baz: An Alter Ego
|
|
|
55
55
|
|
|
56
56
|
### Installation
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
<a href="https://repology.org/project/decasify/versions"><img src="https://repology.org/badge/vertical-allrepos/decasify.svg" align="right" alt="Packaging status"></a>
|
|
59
|
+
To install, first check your distro for packages, e.g. for [Arch Linux](https://archlinux.org/packages/extra/x86_64/decasify/) just install via `pacman -S decasify` or for [Homebrew](https://formulae.brew.sh/formula/decasify) via `brew install decasify`.
|
|
59
60
|
|
|
60
61
|
Otherwise for many platforms you can run it directly or install it to a shell using Nix Flakes:
|
|
61
62
|
|
|
@@ -91,7 +92,7 @@ In your `Cargo.toml` file.
|
|
|
91
92
|
|
|
92
93
|
```toml
|
|
93
94
|
[dependencies]
|
|
94
|
-
decasify = "0.
|
|
95
|
+
decasify = "0.9"
|
|
95
96
|
```
|
|
96
97
|
|
|
97
98
|
Then use the crate functions and types in your project something like this:
|
|
@@ -214,5 +215,18 @@ Loading it in a SILE document uses the usual `\use[module=package.decasify]` (se
|
|
|
214
215
|
Once loaded the package exposes a `\decasify{}` function that can take any combination of `case`, `locale`, and `style` settings and applies the appropriate transformation to the content.
|
|
215
216
|
By default it will track the language of the document content.
|
|
216
217
|
|
|
218
|
+
## Use as a Typst package
|
|
219
|
+
|
|
220
|
+
[Typst](https://typst.app/) has its own [package registry](https://typst.app/universe/).
|
|
221
|
+
The [decasify](https://typst.app/universe/package/decasify) package can be added to your project with an import line.
|
|
222
|
+
The exact version must be specified explicitly:
|
|
223
|
+
|
|
224
|
+
```typst
|
|
225
|
+
#import "@preview/decasify:0.8.0": *
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Specific functions for each case should be available throughout the document.
|
|
229
|
+
See the Typst package [readme](typst/README.md) or the [package listing on Typst universe](https://typst.app/universe/package/decasify) for more details.
|
|
230
|
+
|
|
217
231
|
[rock]: http://luarocks.org/modules/alerque/decasify
|
|
218
232
|
[rock.sile]: http://luarocks.org/modules/alerque/decasify.sile
|
|
@@ -3,20 +3,27 @@
|
|
|
3
3
|
|
|
4
4
|
use regex::Regex;
|
|
5
5
|
use std::{borrow::Cow, fmt, fmt::Display, str::FromStr};
|
|
6
|
+
use unicode_titlecase::StrTitleCase;
|
|
6
7
|
|
|
7
8
|
use snafu::prelude::*;
|
|
8
9
|
|
|
10
|
+
#[derive(Clone, Debug)]
|
|
11
|
+
#[non_exhaustive]
|
|
12
|
+
pub struct Chunk {
|
|
13
|
+
pub segments: Vec<Segment>,
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
#[derive(Clone, Debug, PartialEq)]
|
|
10
17
|
#[non_exhaustive]
|
|
11
18
|
pub enum Segment {
|
|
12
19
|
Separator(String),
|
|
13
|
-
Word(
|
|
20
|
+
Word(Word),
|
|
14
21
|
}
|
|
15
22
|
|
|
16
|
-
#[derive(Clone, Debug)]
|
|
23
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
17
24
|
#[non_exhaustive]
|
|
18
|
-
pub struct
|
|
19
|
-
pub
|
|
25
|
+
pub struct Word {
|
|
26
|
+
pub word: String,
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
#[derive(Snafu)]
|
|
@@ -42,7 +49,9 @@ fn split_chunk(s: &str) -> Chunk {
|
|
|
42
49
|
if let Some(m) = capture.name("separator") {
|
|
43
50
|
segments.push(Segment::Separator(m.as_str().to_string()));
|
|
44
51
|
} else if let Some(m) = capture.name("word") {
|
|
45
|
-
segments.push(Segment::Word(
|
|
52
|
+
segments.push(Segment::Word(Word {
|
|
53
|
+
word: m.as_str().to_owned(),
|
|
54
|
+
}));
|
|
46
55
|
}
|
|
47
56
|
}
|
|
48
57
|
Chunk { segments }
|
|
@@ -79,13 +88,13 @@ impl FromStr for Chunk {
|
|
|
79
88
|
}
|
|
80
89
|
}
|
|
81
90
|
|
|
82
|
-
impl
|
|
83
|
-
fn
|
|
84
|
-
let
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
91
|
+
impl From<Chunk> for String {
|
|
92
|
+
fn from(c: Chunk) -> Self {
|
|
93
|
+
let mut s = String::new();
|
|
94
|
+
for segment in c.segments {
|
|
95
|
+
s.push_str(segment.to_string().as_ref());
|
|
96
|
+
}
|
|
97
|
+
s
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
|
|
@@ -97,3 +106,56 @@ impl Display for Chunk {
|
|
|
97
106
|
Ok(())
|
|
98
107
|
}
|
|
99
108
|
}
|
|
109
|
+
|
|
110
|
+
impl Display for Segment {
|
|
111
|
+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
112
|
+
match self {
|
|
113
|
+
Segment::Separator(string) => fmt.write_str(string)?,
|
|
114
|
+
Segment::Word(word) => fmt.write_str(word.to_string().as_ref())?,
|
|
115
|
+
};
|
|
116
|
+
Ok(())
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
impl Word {
|
|
121
|
+
pub fn to_lowercase(&self) -> String {
|
|
122
|
+
self.word.to_lowercase()
|
|
123
|
+
}
|
|
124
|
+
pub fn to_uppercase(&self) -> String {
|
|
125
|
+
self.word.to_uppercase()
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
impl From<String> for Word {
|
|
130
|
+
fn from(word: String) -> Self {
|
|
131
|
+
Self { word }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
impl StrTitleCase for Word {
|
|
136
|
+
fn to_titlecase(&self) -> String {
|
|
137
|
+
self.word.to_titlecase()
|
|
138
|
+
}
|
|
139
|
+
fn to_titlecase_lower_rest(&self) -> String {
|
|
140
|
+
self.word.to_titlecase_lower_rest()
|
|
141
|
+
}
|
|
142
|
+
fn to_titlecase_tr_or_az(&self) -> String {
|
|
143
|
+
self.word.to_titlecase_tr_or_az()
|
|
144
|
+
}
|
|
145
|
+
fn to_titlecase_tr_or_az_lower_rest(&self) -> String {
|
|
146
|
+
self.word.to_titlecase_tr_or_az_lower_rest()
|
|
147
|
+
}
|
|
148
|
+
fn starts_titlecase(&self) -> bool {
|
|
149
|
+
self.word.starts_titlecase()
|
|
150
|
+
}
|
|
151
|
+
fn starts_titlecase_rest_lower(&self) -> bool {
|
|
152
|
+
self.word.starts_titlecase_rest_lower()
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
impl Display for Word {
|
|
157
|
+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
158
|
+
fmt.write_str(self.word.as_ref())?;
|
|
159
|
+
Ok(())
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2023 Caleb Maclennan <caleb@alerque.com>
|
|
2
2
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
3
3
|
|
|
4
|
-
use crate::content::{Chunk, Segment};
|
|
4
|
+
use crate::content::{Chunk, Segment, Word};
|
|
5
5
|
use crate::types::StyleGuide;
|
|
6
6
|
|
|
7
7
|
use regex::Regex;
|
|
@@ -20,32 +20,32 @@ pub fn titlecase(chunk: Chunk, style: StyleGuide) -> String {
|
|
|
20
20
|
|
|
21
21
|
fn titlecase_ap(chunk: Chunk) -> String {
|
|
22
22
|
eprintln!("AP style guide not implemented, string returned as-is!");
|
|
23
|
-
chunk.
|
|
23
|
+
chunk.into()
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
fn titlecase_cmos(chunk: Chunk) -> String {
|
|
27
|
-
let mut done_first = false;
|
|
28
27
|
let mut chunk = chunk.clone();
|
|
29
|
-
let mut
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
28
|
+
let mut words = chunk
|
|
29
|
+
.segments
|
|
30
|
+
.iter_mut()
|
|
31
|
+
.filter_map(|segment| match segment {
|
|
32
|
+
Segment::Word(word) => Some(word),
|
|
33
|
+
_ => None,
|
|
34
|
+
})
|
|
35
|
+
.peekable();
|
|
36
|
+
if let Some(word) = words.next() {
|
|
37
|
+
word.word = word.to_titlecase_lower_rest();
|
|
38
|
+
}
|
|
39
|
+
while let Some(word) = words.next() {
|
|
40
|
+
word.word = match words.peek().is_none() {
|
|
41
|
+
true => word.to_titlecase_lower_rest(),
|
|
42
|
+
false => match is_reserved(word) {
|
|
43
|
+
true => word.to_lowercase(),
|
|
44
|
+
false => word.to_titlecase_lower_rest(),
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
47
|
}
|
|
48
|
-
chunk.
|
|
48
|
+
chunk.into()
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
fn titlecase_gruber(chunk: Chunk) -> String {
|
|
@@ -61,11 +61,11 @@ fn titlecase_gruber(chunk: Chunk) -> String {
|
|
|
61
61
|
} else {
|
|
62
62
|
String::from("")
|
|
63
63
|
};
|
|
64
|
-
let titilized = gruber_titlecase(
|
|
64
|
+
let titilized = gruber_titlecase(chunk.to_string().as_ref());
|
|
65
65
|
format!("{}{}{}", leading_trivia, titilized, trailing_trivia)
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
fn is_reserved(word:
|
|
68
|
+
fn is_reserved(word: &Word) -> bool {
|
|
69
69
|
let word = word.to_lowercase();
|
|
70
70
|
let word = word.as_str();
|
|
71
71
|
let article = Regex::new(r"^(a|an|the)$").unwrap();
|
|
@@ -77,35 +77,35 @@ fn is_reserved(word: String) -> bool {
|
|
|
77
77
|
pub fn lowercase(chunk: Chunk) -> String {
|
|
78
78
|
let mut chunk = chunk.clone();
|
|
79
79
|
chunk.segments.iter_mut().for_each(|segment| {
|
|
80
|
-
if let Segment::Word(
|
|
81
|
-
|
|
80
|
+
if let Segment::Word(word) = segment {
|
|
81
|
+
word.word = word.to_lowercase()
|
|
82
82
|
}
|
|
83
83
|
});
|
|
84
|
-
chunk.
|
|
84
|
+
chunk.into()
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
pub fn uppercase(chunk: Chunk) -> String {
|
|
88
88
|
let mut chunk = chunk.clone();
|
|
89
89
|
chunk.segments.iter_mut().for_each(|segment| {
|
|
90
|
-
if let Segment::Word(
|
|
91
|
-
|
|
90
|
+
if let Segment::Word(word) = segment {
|
|
91
|
+
word.word = word.to_uppercase()
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
|
-
chunk.
|
|
94
|
+
chunk.into()
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
pub fn sentencecase(chunk: Chunk) -> String {
|
|
98
98
|
let mut chunk = chunk.clone();
|
|
99
99
|
let mut done_first = false;
|
|
100
100
|
chunk.segments.iter_mut().for_each(|segment| {
|
|
101
|
-
if let Segment::Word(
|
|
102
|
-
|
|
101
|
+
if let Segment::Word(word) = segment {
|
|
102
|
+
word.word = if !done_first {
|
|
103
103
|
done_first = true;
|
|
104
|
-
|
|
104
|
+
word.to_titlecase_lower_rest()
|
|
105
105
|
} else {
|
|
106
|
-
|
|
106
|
+
word.to_lowercase()
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
|
-
chunk.
|
|
110
|
+
chunk.into()
|
|
111
111
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: © 2023 Caleb Maclennan <caleb@alerque.com>
|
|
2
2
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
3
3
|
|
|
4
|
-
use crate::content::{Chunk, Segment};
|
|
4
|
+
use crate::content::{Chunk, Segment, Word};
|
|
5
5
|
use crate::types::StyleGuide;
|
|
6
6
|
|
|
7
7
|
use regex::Regex;
|
|
@@ -20,63 +20,63 @@ fn titlecase_tdk(chunk: Chunk) -> String {
|
|
|
20
20
|
let mut chunk = chunk.clone();
|
|
21
21
|
let mut done_first = false;
|
|
22
22
|
chunk.segments.iter_mut().for_each(|segment| {
|
|
23
|
-
if let Segment::Word(
|
|
24
|
-
|
|
23
|
+
if let Segment::Word(word) = segment {
|
|
24
|
+
word.word = if !done_first {
|
|
25
25
|
done_first = true;
|
|
26
|
-
|
|
26
|
+
word.to_titlecase_tr_or_az_lower_rest()
|
|
27
27
|
} else {
|
|
28
|
-
match is_reserved(
|
|
29
|
-
true =>
|
|
30
|
-
false =>
|
|
28
|
+
match is_reserved(word) {
|
|
29
|
+
true => word.word.to_lowercase_tr_az(),
|
|
30
|
+
false => word.word.to_titlecase_tr_or_az_lower_rest(),
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
|
-
chunk.
|
|
35
|
+
chunk.into()
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
fn is_reserved(word:
|
|
39
|
-
let
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
fn is_reserved(word: &Word) -> bool {
|
|
39
|
+
let word = word.to_string();
|
|
40
|
+
let word = word.as_ref();
|
|
41
|
+
let baglac =
|
|
42
|
+
Regex::new(r"^([Vv][Ee]|[İi][Ll][Ee]|[Yy][Aa]|[Yy][Aa][Hh][Uu][Tt]|[Kk][İi]|[Dd][AaEe])$")
|
|
43
|
+
.unwrap();
|
|
43
44
|
let soruek = Regex::new(r"^([Mm][İiIıUuÜü])([Dd][İiIıUuÜü][Rr]([Ll][AaEe][Rr])?|[Ss][İiIıUuÜü][Nn]|[Yy][İiIıUuÜü][Zz]|[Ss][İiIıUuÜü][Nn][İiIıUuÜü][Zz]|[Ll][AaEe][Rr])?$").unwrap();
|
|
44
|
-
let word = word.as_str();
|
|
45
45
|
baglac.is_match(word) || soruek.is_match(word)
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
pub fn lowercase(chunk: Chunk) -> String {
|
|
49
49
|
let mut chunk = chunk.clone();
|
|
50
50
|
chunk.segments.iter_mut().for_each(|segment| {
|
|
51
|
-
if let Segment::Word(
|
|
52
|
-
|
|
51
|
+
if let Segment::Word(word) = segment {
|
|
52
|
+
word.word = word.word.to_lowercase_tr_az()
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
|
-
chunk.
|
|
55
|
+
chunk.into()
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
pub fn uppercase(chunk: Chunk) -> String {
|
|
59
59
|
let mut chunk = chunk.clone();
|
|
60
60
|
chunk.segments.iter_mut().for_each(|segment| {
|
|
61
|
-
if let Segment::Word(
|
|
62
|
-
|
|
61
|
+
if let Segment::Word(word) = segment {
|
|
62
|
+
word.word = word.word.to_uppercase_tr_az()
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
|
-
chunk.
|
|
65
|
+
chunk.into()
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
pub fn sentencecase(chunk: Chunk) -> String {
|
|
69
69
|
let mut chunk = chunk.clone();
|
|
70
70
|
let mut done_first = false;
|
|
71
71
|
chunk.segments.iter_mut().for_each(|segment| {
|
|
72
|
-
if let Segment::Word(
|
|
73
|
-
|
|
72
|
+
if let Segment::Word(word) = segment {
|
|
73
|
+
word.word = if !done_first {
|
|
74
74
|
done_first = true;
|
|
75
|
-
|
|
75
|
+
word.word.to_titlecase_tr_or_az_lower_rest()
|
|
76
76
|
} else {
|
|
77
|
-
|
|
77
|
+
word.word.to_lowercase_tr_az()
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
});
|
|
81
|
-
chunk.
|
|
81
|
+
chunk.into()
|
|
82
82
|
}
|
|
@@ -84,8 +84,8 @@ impl FromStr for Locale {
|
|
|
84
84
|
type Err = Error;
|
|
85
85
|
fn from_str(s: &str) -> Result<Self> {
|
|
86
86
|
match s.to_ascii_lowercase().as_str() {
|
|
87
|
-
"en" | "
|
|
88
|
-
"tr" | "
|
|
87
|
+
"en" | "english" | "en_en" => Ok(Locale::EN),
|
|
88
|
+
"tr" | "turkish" | "tr_tr" | "türkçe" => Ok(Locale::TR),
|
|
89
89
|
input => LocaleSnafu { input }.fail()?,
|
|
90
90
|
}
|
|
91
91
|
}
|
|
@@ -109,6 +109,13 @@ impl From<&String> for Locale {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
impl From<&[u8]> for Locale {
|
|
113
|
+
fn from(s: &[u8]) -> Self {
|
|
114
|
+
let s = String::from_utf8(s.to_vec()).unwrap();
|
|
115
|
+
Self::from_str(s.as_ref()).unwrap()
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
112
119
|
impl FromStr for Case {
|
|
113
120
|
type Err = Error;
|
|
114
121
|
fn from_str(s: &str) -> Result<Self> {
|
|
@@ -140,6 +147,13 @@ impl From<&String> for Case {
|
|
|
140
147
|
}
|
|
141
148
|
}
|
|
142
149
|
|
|
150
|
+
impl From<&[u8]> for Case {
|
|
151
|
+
fn from(s: &[u8]) -> Self {
|
|
152
|
+
let s = String::from_utf8(s.to_vec()).unwrap();
|
|
153
|
+
Self::from_str(s.as_ref()).unwrap()
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
143
157
|
impl FromStr for StyleGuide {
|
|
144
158
|
type Err = Error;
|
|
145
159
|
fn from_str(s: &str) -> Result<Self> {
|
|
@@ -174,6 +188,13 @@ impl From<&String> for StyleGuide {
|
|
|
174
188
|
}
|
|
175
189
|
}
|
|
176
190
|
|
|
191
|
+
impl From<&[u8]> for StyleGuide {
|
|
192
|
+
fn from(s: &[u8]) -> Self {
|
|
193
|
+
let s = String::from_utf8(s.to_vec()).unwrap();
|
|
194
|
+
Self::from_str(s.as_ref()).unwrap()
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
177
198
|
impl From<Option<StyleGuide>> for StyleGuide {
|
|
178
199
|
fn from(style: Option<StyleGuide>) -> Self {
|
|
179
200
|
match style {
|
|
@@ -65,6 +65,24 @@ case!(
|
|
|
65
65
|
"a b c"
|
|
66
66
|
);
|
|
67
67
|
|
|
68
|
+
case!(
|
|
69
|
+
trivia_en,
|
|
70
|
+
Case::Title,
|
|
71
|
+
Locale::EN,
|
|
72
|
+
StyleGuide::LanguageDefault,
|
|
73
|
+
" foo bar ",
|
|
74
|
+
" Foo Bar "
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
case!(
|
|
78
|
+
trivia_tr,
|
|
79
|
+
Case::Title,
|
|
80
|
+
Locale::TR,
|
|
81
|
+
StyleGuide::LanguageDefault,
|
|
82
|
+
" foo bar ",
|
|
83
|
+
" Foo Bar "
|
|
84
|
+
);
|
|
85
|
+
|
|
68
86
|
macro_rules! titlecase {
|
|
69
87
|
($name:ident, $locale:expr, $style:expr, $input:expr, $expected:expr) => {
|
|
70
88
|
#[test]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|