Make stylistic sets able to specify variants only enabled under Oblique

This commit is contained in:
be5invis 2020-10-27 21:16:05 -07:00
parent 2e601b641c
commit e719992f2c
11 changed files with 67 additions and 201 deletions

181
README.md
View file

@ -1,5 +1,5 @@
# Iosevka ![Version](https://img.shields.io/github/release/be5invis/Iosevka.svg) # Iosevka ![Version](https://img.shields.io/github/release/be5invis/Iosevka.svg)
Coders typeface, built from code. **Iosevka** is an *open-source*, *sans-serif* + *slab-serif*, *monospace* + *quasiproportional* typeface family, designed for *writing code*, using in *terminals*, and preparing *technical documents*.
![](images/preview-all.png) ![](images/preview-all.png)
@ -7,10 +7,16 @@ Coders typeface, built from code.
Quit your editor/program. Unzip and open the folder. Quit your editor/program. Unzip and open the folder.
* **Instructions for Windows**: Download the fonts from the [Releases](https://github.com/be5invis/Iosevka/releases), select the font files and right click, then hit "Install". * **Windows**: Download the fonts from the [Releases](https://github.com/be5invis/Iosevka/releases), select the font files and right click, then hit “Install”.
* On Windows 10 1809 or newer the default font installation is per-user, and it may cause compatibility issues for some applications, mostly written in Java. To cope with this, right click and select "Install for all users" instead. [Ref.](https://youtrack.jetbrains.com/issue/JRE-1166?p=IDEA-200145)
* **[Instructions for macOS](http://support.apple.com/kb/HT2509)** * On Windows 10 1809 or newer the default font installation is per-user, and it may cause compatibility issues for some applications, mostly written in Java. To cope with this, right click and select “Install for all users” instead. [Ref.](https://youtrack.jetbrains.com/issue/JRE-1166?p=IDEA-200145)
* Standard distribution in Homebrew: `brew tap homebrew/cask-fonts && brew cask install font-iosevka && brew cask install font-iosevka-slab`. Search for other variants using `brew search font-iosevka` and install what you want. * **[macOS](http://support.apple.com/kb/HT2509)**
* Standard distribution in Homebrew:
```bash
brew tap homebrew/cask-fonts
brew cask install font-iosevka
```
* Search for other variants using `brew search font-iosevka` and install what you want.
* Customizable install using Homebrew: see [robertgzr/homebrew-tap](https://github.com/robertgzr/homebrew-tap). * Customizable install using Homebrew: see [robertgzr/homebrew-tap](https://github.com/robertgzr/homebrew-tap).
* **Linux** : Copy the TTF files to your fonts directory → Run `sudo fc-cache`. * **Linux** : Copy the TTF files to your fonts directory → Run `sudo fc-cache`.
- Arch Linux users can install the font from the AUR [here](https://aur.archlinux.org/packages/ttf-iosevka) using an AUR wrapper or by doing it manually. [All variants](https://aur.archlinux.org/packages/?O=0&SeB=nd&K=ttf-iosevka&SB=n&SO=a&PP=50&do_Search=Go). - Arch Linux users can install the font from the AUR [here](https://aur.archlinux.org/packages/ttf-iosevka) using an AUR wrapper or by doing it manually. [All variants](https://aur.archlinux.org/packages/?O=0&SeB=nd&K=ttf-iosevka&SB=n&SO=a&PP=50&do_Search=Go).
@ -18,9 +24,9 @@ Quit your editor/program. Unzip and open the folder.
* **FreeBSD**: The font can be installed with `pkg install iosevka`. * **FreeBSD**: The font can be installed with `pkg install iosevka`.
* **OpenBSD**: Run `pkg_info -Q iosevka` to see which Iosevka packages are available. Use `pkg_add` to install the chosen package(s). * **OpenBSD**: Run `pkg_info -Q iosevka` to see which Iosevka packages are available. Use `pkg_add` to install the chosen package(s).
## Weights, Variants and OpenType features ## Features
The typeface contains 9 weights (Thin to Heavy) alongside with both italic and oblique versions, with the same metrics as the regular one. In the official package, Iosevka provides 6 monospace subfamilies and 3 quasi-proportional subfamilies. In all the monospace subfamilies, 9 weights (Thin to Heavy), 2 widths (Normal and Extended), and 3 slopes (Upright, Italic and Oblique) are included. In the quasi-proportional subfamilies, the quantity of widths is reduced to 1.
![Weights sample](images/weights.png) ![Weights sample](images/weights.png)
@ -67,7 +73,7 @@ You will find TTFs, as well as WOFF(2) web fonts and one Webfont CSS in the `dis
Refer to these [instructions.](https://github.com/ejuarezg/containers/tree/master/iosevka_font#container-method) Refer to these [instructions.](https://github.com/ejuarezg/containers/tree/master/iosevka_font#container-method)
## Build Your Own Style ## Customized Build
To create a custom build, you need: To create a custom build, you need:
@ -200,7 +206,7 @@ Subsection `variants` is used to configure character variants in the font. Prope
<!-- BEGIN Section-Cherry-Picking-Styles --> <!-- BEGIN Section-Cherry-Picking-Styles -->
<!-- THIS SECTION IS AUTOMATICALLY GENERATED. DO NOT EDIT. --> <!-- THIS SECTION IS AUTOMATICALLY GENERATED. DO NOT EDIT. -->
* `design`, `upright` and `italic`: Optional, Dictionary, defines styles for individual characters. The choices are organized in key-value pairs, assigning a variant to a character group. Alternatively, you could assign numbers to `cv##` tags, like what you did when using OpenType in CSS.The valid combinations include: * `design`, `upright`, `italic`, and `oblique`: Optional, Dictionary, defines styles for individual characters. The choices are organized in key-value pairs, assigning a variant to a character group. Alternatively, you could assign numbers to `cv##` tags, like what you did when using OpenType in CSS. Assignments under `design` will be applied to all the slopes, and `upright`, `italic`, and `oblique` will apply to corresponded slopes. The valid combinations include:
- Styles for `A`, `Λ`, `Δ`: - Styles for `A`, `Λ`, `Δ`:
+ `turn-v = 'straight'`, `cv01 = 1`: Standard, straight `A`, `Λ`, `Δ` (default). + `turn-v = 'straight'`, `cv01 = 1`: Standard, straight `A`, `Λ`, `Δ` (default).
@ -526,162 +532,7 @@ sequence = '<*>'
#### Sample Configuration #### Sample Configuration
A sample configuration could be found at [private-build-plans.sample.toml](private-build-plans.sample.toml): A sample configuration could be found at [private-build-plans.sample.toml](private-build-plans.sample.toml).
<!-- BEGIN Section-Private-Build-Plan-Sample -->
<!-- THIS SECTION IS AUTOMATICALLY GENERATED. DO NOT EDIT. -->
```toml
[buildPlans.iosevka-custom] # <iosevka-custom> is your plan name
family = "Iosevka Custom" # Font menu family name
spacing = "normal" # Optional; Values: `normal`, `term`, `fontconfig-mono`, or `fixed`
serifs = "sans" # Optional; Values: `sans` or `slab`
digit-form = "lining" # Optional; Values `lining` or `old-style`
###################################################################################################
# Configure variants
# Optional; Whether to inherit a `ss##` variant
[buildPlans.iosevka-custom.variants]
inherits = "ss01"
# Optional; Configure single character's variant
[buildPlans.iosevka-custom.variants.design]
g = 'singlestorey'
# Optional; Configure single character's variant for Upright and Oblique; Overrides [design]
[buildPlans.iosevka-custom.variants.upright]
i = 'zshaped'
l = 'zshaped'
# Optional; Configure single character's variant for Italic only; Overrides [design]
[buildPlans.iosevka-custom.variants.italic]
i = 'italic'
l = 'italic'
# End variant section
###################################################################################################
###################################################################################################
# Configure ligations
[buildPlans.iosevka-custom.ligations]
inherits = "calt" # Optional; inherits an existing ligation set
disables = [] # Optional; disable specific ligation groups, overrides inherited ligation set
enables = [] # Optional; enable specific ligation groups, overrides inherited ligation set
# End ligation section
###################################################################################################
###################################################################################################
# Override default building weights
# When buildPlans.<plan name>.weights is absent, all weights would built and mapped to
# default values.
# IMPORTANT : Currently "menu" and "css" property only support numbers between 0 and 1000.
# and "shape" properly only supports number between 100 and 900 (inclusive).
# If you decide to use custom weights you have to define all the weights you
# plan to use otherwise they will not be built.
[buildPlans.iosevka-custom.weights.regular]
shape = 400 # Weight for glyph shapes.
menu = 400 # Weight for the font's names.
css = 400 # Weight for webfont CSS.
[buildPlans.iosevka-custom.weights.book]
shape = 450
menu = 450 # Use 450 here to name the font's weight "Book"
css = 450
[buildPlans.iosevka-custom.weights.bold]
shape = 700
menu = 700
css = 700
# End weight section
###################################################################################################
###################################################################################################
# Override default building slope sets
# Format: <upright|italic|oblique> = <"normal"|"italic"|"oblique">
# When this section is absent, all slopes would be built.
[buildPlans.iosevka-custom.slopes]
upright = "normal"
italic = "italic"
oblique = "oblique"
# End slope section
###################################################################################################
###################################################################################################
# Override default building widths
# When buildPlans.<plan name>.widths is absent, all widths would built and mapped to
# default values.
# IMPORTANT : Currently "shape" property only supports numbers between 434 and 664 (inclusive),
# while "menu" only supports integers between 1 and 9 (inclusive).
# The "shape" parameter specifies the unit width, measured in 1/1000 em. The glyphs'
# width are equal to, or a simple multiple of the unit width.
# If you decide to use custom widths you have to define all the widths you plan to use,
# otherwise they will not be built.
[buildPlans.iosevka-custom.widths.normal]
shape = 500 # Unit Width, measured in 1/1000 em.
menu = 5 # Width grade for the font's names.
css = "normal" # "font-stretch' property of webfont CSS.
[buildPlans.iosevka-custom.widths.extended]
shape = 576
menu = 7
css = "expanded"
# End width section
###################################################################################################
###################################################################################################
# Character Exclusion
# Specify character ranges in the section below to exclude certain characters from the font being
# built. Remove this section when this feature is not needed.
[buildPlans.iosevka-custom.exclude-chars]
ranges = [[10003, 10008]]
# End character exclusion
###################################################################################################
###################################################################################################
# Compatibility Ligatures
# Certain applications like Emacs does not support proper programming liagtures provided by
# OpenType, but can support ligatures provided by PUA codepoints. Therefore you can edit the
# following section to build PUA characters that are generated from the OpenType ligatures.
# Remove this section when compatibility ligatures are not needed.
[[buildPlans.iosevka-custom.compatibility-ligatures]]
unicode = 57600 # 0xE100
featureTag = 'calt'
sequence = '<*>'
# End compatibility ligatures section
###################################################################################################
###################################################################################################
# Metric overrides
# Certain metrics like line height (leading) could be overridden in your build plan file.
# Edit the values to change the metrics. Remove this section when overriding is not needed.
[buildPlans.iosevka-custom.metric-override]
leading = 1250
winMetricAscenderPad = 0
winMetricDescenderPad = 0
powerlineScaleY = 1
powerlineScaleX = 1
powerlineShiftY = 0
powerlineShiftX = 0
# End metric override section
###################################################################################################
```
<!-- END Section-Private-Build-Plan-Sample -->
## For Chinese and Japanese users... ## For Chinese and Japanese users...

View file

@ -73,12 +73,18 @@ class Composite {
this.description = cfg.description; this.description = cfg.description;
this.inherits = cfg.inherits; this.inherits = cfg.inherits;
this.design = cfg.design; this.design = cfg.design;
this.upright = cfg.upright; this.upright = cfg.upright || cfg["upright-oblique"];
this.oblique = cfg.oblique || cfg["upright-oblique"];
this.italic = cfg.italic; this.italic = cfg.italic;
} }
decompose(para, selTree) { decompose(para, selTree) {
const ans = []; const ans = [];
const cfg = Object.assign({}, this.design, para.isItalic ? this.italic : this.upright); const cfg = Object.assign(
{},
this.design,
para.isItalic ? this.italic : para.isOblique ? this.oblique : this.upright
);
for (const [k, v] of Object.entries(cfg)) { for (const [k, v] of Object.entries(cfg)) {
const pv = selTree.get(k, v); const pv = selTree.get(k, v);
if (!pv) throw new Error(`Composite ${this.key} cannot be resolved: ${[k, v]}.`); if (!pv) throw new Error(`Composite ${this.key} cannot be resolved: ${[k, v]}.`);

View file

@ -1717,7 +1717,7 @@ h = 'straight'
m = 'normal' m = 'normal'
n = 'straight' n = 'straight'
[default.upright] [default.upright-oblique]
a = 'doublestorey' a = 'doublestorey'
d = 'toothed' d = 'toothed'
f = 'straight' f = 'straight'
@ -1814,7 +1814,7 @@ one = 'base'
six = 'open-contour' six = 'open-contour'
nine = 'open-contour' nine = 'open-contour'
[composite.ss03.upright] [composite.ss03.upright-oblique]
g = 'doublestorey' g = 'doublestorey'
y = 'straight-turn' y = 'straight-turn'
@ -1940,7 +1940,7 @@ ampersand = 'upper-open'
six = 'closed-contour' six = 'closed-contour'
nine = 'closed-contour' nine = 'closed-contour'
[composite.ss08.upright] [composite.ss08.upright-oblique]
g = 'doublestorey' g = 'doublestorey'
[composite.ss08.italic] [composite.ss08.italic]
@ -1965,7 +1965,7 @@ one = 'base'
six = 'closed-contour' six = 'closed-contour'
nine = 'closed-contour' nine = 'closed-contour'
[composite.ss09.upright] [composite.ss09.upright-oblique]
i = 'hooky' i = 'hooky'
g = 'doublestorey' g = 'doublestorey'
@ -2090,7 +2090,7 @@ lambda = 'curly'
six = 'open-contour' six = 'open-contour'
nine = 'open-contour' nine = 'open-contour'
[composite.ss20.upright] [composite.ss20.upright-oblique]
k = 'curly' k = 'curly'
y = 'curly' y = 'curly'

View file

@ -0,0 +1 @@
* `design`, `upright`, `italic`, and `oblique`: Optional, Dictionary, defines styles for individual characters. The choices are organized in key-value pairs, assigning a variant to a character group. Alternatively, you could assign numbers to `cv##` tags, like what you did when using OpenType in CSS. Assignments under `design` will be applied to all the slopes, and `upright`, `italic`, and `oblique` will apply to corresponded slopes. The valid combinations include:

View file

@ -0,0 +1 @@
* `disables` and `enables`: Optional, String Array, Cherry-picking ligation groups to be disabled or enabled. Valid values include:

View file

@ -0,0 +1 @@
* `inherits`: Optional, String, defines the inherited ligation set. When absent, the ligation set will not inherit any other sets. Valid values are:

View file

@ -0,0 +1 @@
* `inherits`: Optional, String, defines the inherited stylistic set. Valid options include:

View file

@ -2,7 +2,7 @@
const fs = require("fs-extra"); const fs = require("fs-extra");
const path = require("path"); const path = require("path");
const parseVariantsData = require("../export-data/parse-variants-data"); const parseVariantsData = require("../export-data/variants-data");
const parseLigationData = require("../export-data/ligation-data"); const parseLigationData = require("../export-data/ligation-data");
const getCharMapAndSupportedLanguageList = require("../export-data/supported-languages"); const getCharMapAndSupportedLanguageList = require("../export-data/supported-languages");
const execMain = require("../shared/execMain"); const execMain = require("../shared/execMain");
@ -29,10 +29,8 @@ async function main() {
async function processSs() { async function processSs() {
const variantsData = await parseVariantsData(); const variantsData = await parseVariantsData();
const md = new MdCol("Section-Stylistic-Sets"); const md = new MdCol("Section-Stylistic-Sets");
md.log( const headerPath = path.resolve(__dirname, "fragments/description-stylistic-sets.md");
`* \`inherits\`: Optional, String, defines the inherited stylistic set. ` + md.log(await fs.readFile(headerPath, "utf-8"));
`Valid options include:\n`
);
for (const gr of variantsData.ssData) { for (const gr of variantsData.ssData) {
if (!gr.effective) continue; if (!gr.effective) continue;
md.log(` - \`${gr.tag}\`: Set character variant to “${gr.description}”.`); md.log(` - \`${gr.tag}\`: Set character variant to “${gr.description}”.`);
@ -42,15 +40,10 @@ async function processSs() {
async function processCv() { async function processCv() {
const variantsData = await parseVariantsData(); const variantsData = await parseVariantsData();
const md = new MdCol("Section-Cherry-Picking-Styles"); const md = new MdCol("Section-Cherry-Picking-Styles");
md.log(
`* \`design\`, \`upright\` and \`italic\`: Optional, Dictionary, ` + const headerPath = path.resolve(__dirname, "fragments/description-cheery-picking-styles.md");
`defines styles for individual characters. ` + md.log(await fs.readFile(headerPath, "utf-8"));
`The choices are organized in key-value pairs, ` +
`assigning a variant to a character group. ` +
`Alternatively, you could assign numbers to \`cv##\` tags, ` +
`like what you did when using OpenType in CSS.` +
`The valid combinations include:\n`
);
for (const gr of variantsData.cvData) { for (const gr of variantsData.cvData) {
const sampleText = gr.descSampleText const sampleText = gr.descSampleText
.map(c => (c === "`" ? "`` ` ``" : `\`${c}\``)) .map(c => (c === "`" ? "`` ` ``" : `\`${c}\``))
@ -160,11 +153,12 @@ function figureOutDefaults(variantsData, gr) {
async function processLigSetCherryPicking() { async function processLigSetCherryPicking() {
const ligData = await parseLigationData(); const ligData = await parseLigationData();
const md = new MdCol("Section-Cherry-Picking-Ligation-Sets"); const md = new MdCol("Section-Cherry-Picking-Ligation-Sets");
md.log( const headerPath = path.resolve(
`* \`disables\` and \`enables\`: Optional, String Array, ` + __dirname,
`Cherry-picking ligation groups to be disabled or enabled. ` + "fragments/description-cherry-picking-ligation-sets.md"
`Valid values include:\n`
); );
md.log(await fs.readFile(headerPath, "utf-8"));
for (const gr in ligData.cherry) { for (const gr in ligData.cherry) {
md.log(` - \`${gr}\`: ${ligData.cherry[gr].desc}.`); md.log(` - \`${gr}\`: ${ligData.cherry[gr].desc}.`);
} }
@ -174,11 +168,8 @@ async function processLigSetCherryPicking() {
async function processLigSetPreDef() { async function processLigSetPreDef() {
const ligData = await parseLigationData(); const ligData = await parseLigationData();
const md = new MdCol("Section-Predefined-Ligation-Sets"); const md = new MdCol("Section-Predefined-Ligation-Sets");
md.log( const headerPath = path.resolve(__dirname, "fragments/description-predefined-ligation-sets.md");
`* \`inherits\`: Optional, String, defines the inherited ligation set. ` + md.log(await fs.readFile(headerPath, "utf-8"));
`When absent, the ligation set will not inherit any other sets. ` +
`Valid values are:\n`
);
for (const gr in ligData.rawSets) { for (const gr in ligData.rawSets) {
if (ligData.rawSets[gr].isOptOut) continue; if (ligData.rawSets[gr].isOptOut) continue;
const longDesc = const longDesc =

View file

@ -1,7 +1,7 @@
"use strict"; "use strict";
const fs = require("fs-extra"); const fs = require("fs-extra");
const parseVariantsData = require("./parse-variants-data"); const parseVariantsData = require("./variants-data");
const parseLigationData = require("./ligation-data"); const parseLigationData = require("./ligation-data");
const getCharMapAndSupportedLanguageList = require("./supported-languages"); const getCharMapAndSupportedLanguageList = require("./supported-languages");
const execMain = require("../shared/execMain"); const execMain = require("../shared/execMain");

View file

@ -57,7 +57,8 @@ function getCvData(parsed) {
return Array.from(samplerGroups.values()); return Array.from(samplerGroups.values());
} }
const UPRIGHT = { isItalic: false }; const UPRIGHT = {};
const OBLIQUE = { isOblique: true };
const ITALIC = { isItalic: true }; const ITALIC = { isItalic: true };
function getSsData(variants) { function getSsData(variants) {
@ -68,16 +69,20 @@ function getSsData(variants) {
description: "Default", description: "Default",
uprightComposition: [], uprightComposition: [],
italicComposition: [], italicComposition: [],
obliqueComposition: [],
hotCharSetUpright: [], hotCharSetUpright: [],
hotCharSetItalic: [] hotCharSetItalic: [],
hotCharSetOblique: []
} }
]; ];
const defaultUpright = buildupComposite(variants, UPRIGHT, variants.defaultComposite); const defaultUpright = buildupComposite(variants, UPRIGHT, variants.defaultComposite);
const defaultOblique = buildupComposite(variants, OBLIQUE, variants.defaultComposite);
const defaultItalic = buildupComposite(variants, ITALIC, variants.defaultComposite); const defaultItalic = buildupComposite(variants, ITALIC, variants.defaultComposite);
for (const [key, composite] of variants.composites) { for (const [key, composite] of variants.composites) {
if (!composite.tag) continue; if (!composite.tag) continue;
const upright = buildupComposite(variants, UPRIGHT, composite); const upright = buildupComposite(variants, UPRIGHT, composite);
const oblique = buildupComposite(variants, OBLIQUE, composite);
const italic = buildupComposite(variants, ITALIC, composite); const italic = buildupComposite(variants, ITALIC, composite);
result.push({ result.push({
@ -86,8 +91,10 @@ function getSsData(variants) {
description: composite.description, description: composite.description,
uprightComposition: upright.composition, uprightComposition: upright.composition,
italicComposition: italic.composition, italicComposition: italic.composition,
obliqueComposition: oblique.composition,
hotCharSetUpright: Array.from(uniqueHotChars(defaultUpright, upright.hotChars)), hotCharSetUpright: Array.from(uniqueHotChars(defaultUpright, upright.hotChars)),
hotCharSetItalic: Array.from(uniqueHotChars(defaultItalic, italic.hotChars)) hotCharSetItalic: Array.from(uniqueHotChars(defaultItalic, italic.hotChars)),
hotCharSetOblique: Array.from(uniqueHotChars(defaultOblique, oblique.hotChars))
}); });
} }
return result; return result;
@ -97,6 +104,7 @@ function getDefaultCompData(variants) {
return { return {
sansUpright: buildupComposite(variants, UPRIGHT, variants.defaultComposite), sansUpright: buildupComposite(variants, UPRIGHT, variants.defaultComposite),
sansItalic: buildupComposite(variants, ITALIC, variants.defaultComposite), sansItalic: buildupComposite(variants, ITALIC, variants.defaultComposite),
sansOblique: buildupComposite(variants, OBLIQUE, variants.defaultComposite),
slabUpright: buildupComposite( slabUpright: buildupComposite(
variants, variants,
UPRIGHT, UPRIGHT,
@ -108,6 +116,12 @@ function getDefaultCompData(variants) {
ITALIC, ITALIC,
variants.defaultComposite, variants.defaultComposite,
variants.composites.get("slab") variants.composites.get("slab")
),
slabOblique: buildupComposite(
variants,
OBLIQUE,
variants.defaultComposite,
variants.composites.get("slab")
) )
}; };
} }

View file

@ -3,7 +3,7 @@
const ejs = require("ejs"); const ejs = require("ejs");
const fs = require("fs-extra"); const fs = require("fs-extra");
const path = require("path"); const path = require("path");
const parseVariantsData = require("../export-data/parse-variants-data"); const parseVariantsData = require("../export-data/variants-data");
const getLigationData = require("../export-data/ligation-data"); const getLigationData = require("../export-data/ligation-data");
const execMain = require("../shared/execMain"); const execMain = require("../shared/execMain");