iTerm2 presets and VS Code themes

Prompt, in five grounds

A palette built so that nothing on screen falls below readable, including the two-pane vimdiff that iTerm2’s Diff tab runs. Every variant below is the real preset, shown against one very small project. Switch tabs, or pick a file from the open list. Flip the toggle to see what vim’s own defaults do to the same hunk.

The same five palettes ship as VS Code themes, so the editor, the terminal and the editor’s own terminal all agree. Both install from one make command.

Vim diff highlights

Prompt Dark

dark

Blue-tinted charcoal. The default: most contrast headroom for long sessions.

tally — iTerm2
package.json
HEAD
@@ -1,9 +1,11 @@ package.json
{
"name": "tally",
"version": "0.1.2",
"description": "Count lines by extension",
 
"main": "src/index.js",
+-- 4 lines: "scripts": { "test": "node --test" },
"license": "GPL-3.0-or-later"
}
~
{
"name": "tally",
"version": "0.2.0",
"description": "Count lines by extension",
"bin": { "tally": "src/index.js" },
"main": "src/index.js",
+-- 4 lines: "scripts": { "test": "node --test" },
"license": "GPL-3.0-or-later"
}
~
@@ -1,12 +1,13 @@ README.md
# tally
 
A very small command line tool. No dependencies.
 
## Usage
 
tally src/
 
 
+-- 5 lines: ## Options -----------------------------
## Licence
GPL-3.0-or-later.
~
# tally - count lines by extension
 
A very small command line tool. No dependencies.
 
## Usage
 
tally src/
tally src/ --min 10
 
+-- 5 lines: ## Options -----------------------------
## Licence
GPL-3.0-or-later.
~
@@ -1,14 +1,15 @@ src/index.js
// Entry point. Parses argv, then hands off to count().
import { count } from './count.js';
 
const dir = process.argv[2] ?? '.';
 
 
const totals = count(dir);
+-- 6 lines: for (const [ext, lines] of totals) { ------
console.log(`${totals.size} extensions`);
~
// Entry point. Parses argv, then hands off to count().
import { count } from './count.js';
 
const dir = process.argv[2] ?? 'src';
const min = Number(process.argv[3] ?? 0);
 
const totals = count(dir, min);
+-- 6 lines: for (const [ext, lines] of totals) { ------
console.log(`${totals.size} extensions`);
~
@@ -3,13 +3,14 @@ src/count.js
export function count(dir, min = 0) {
const totals = new Map();
+-- 7 lines: for (const entry of readdirSync(dir)) { ----
// off by one: the header line was counted twice
totals.set(ext, lines + 1);
}
 
 
return totals;
}
~
export function count(dir, min = 0) {
const totals = new Map();
+-- 7 lines: for (const entry of readdirSync(dir)) { ----
 
totals.set(ext, lines);
}
 
return new Map([...totals].filter(([, n]) => n >= min));
 
}
~
why does tally report one extra line per file?
 
Looking at src/count.js.
 
Read(src/count.js) 13 lines
Grep(lines \+ 1) 1 match
 
The header line is counted twice. Line 7 adds one
to a total that already includes it:
 
7 totals.set(ext, lines + 1);
 
Dropping the + 1 fixes it. Want me to make
the change and add a test?
 
yes, and run the tests
Reviewing 4 files against HEAD · 2 findings
 
high src/count.js:7
Off by one. The header line is already in lines,
so + 1 counts it twice. A one line file reports 2.
 
low src/index.js:5
min is parsed with Number() and never checked.
tally src --min abc filters everything out.
 
ok package.json no findings
ok README.md no findings
 
Fix the first and re-run? [y/N]
package.json [RO] diff 1,1 All

Diff groups slot 0 as the text on each, WCAG AAA needs 7:1

DiffAdd slot 10 · 10.33:1 DiffChange slot 12 · 8.49:1 DiffText slot 11 · 10.99:1 DiffDelete slot 0 · no bar

ANSI slots contrast against this variant’s background

0 black near-bg#22232f1.10:1
1 red#e8795a5.95:1
2 green#3cd9a09.46:1
3 yellow#e6a93a8.22:1
4 blue#4f9cf56.03:1
5 magenta#d0669e4.95:1
6 cyan#7adbe810.68:1
7 white#c8ccd410.62:1
8 br black#7c84994.57:1
9 br red#f5957a7.70:1
10 br green#6ee8bd11.35:1
11 br yellow#f5d76e12.07:1
12 br blue#8cc4ff9.32:1
13 br magenta#e28fbf7.26:1
14 br cyan#a4e9f312.64:1
15 br white#f2f4f815.52:1

Prompt Midnight

dark

Near-black for OLED panels. Deeper chroma so the colours do not glare.

tally — iTerm2
package.json
HEAD
@@ -1,9 +1,11 @@ package.json
{
"name": "tally",
"version": "0.1.2",
"description": "Count lines by extension",
 
"main": "src/index.js",
+-- 4 lines: "scripts": { "test": "node --test" },
"license": "GPL-3.0-or-later"
}
~
{
"name": "tally",
"version": "0.2.0",
"description": "Count lines by extension",
"bin": { "tally": "src/index.js" },
"main": "src/index.js",
+-- 4 lines: "scripts": { "test": "node --test" },
"license": "GPL-3.0-or-later"
}
~
@@ -1,12 +1,13 @@ README.md
# tally
 
A very small command line tool. No dependencies.
 
## Usage
 
tally src/
 
 
+-- 5 lines: ## Options -----------------------------
## Licence
GPL-3.0-or-later.
~
# tally - count lines by extension
 
A very small command line tool. No dependencies.
 
## Usage
 
tally src/
tally src/ --min 10
 
+-- 5 lines: ## Options -----------------------------
## Licence
GPL-3.0-or-later.
~
@@ -1,14 +1,15 @@ src/index.js
// Entry point. Parses argv, then hands off to count().
import { count } from './count.js';
 
const dir = process.argv[2] ?? '.';
 
 
const totals = count(dir);
+-- 6 lines: for (const [ext, lines] of totals) { ------
console.log(`${totals.size} extensions`);
~
// Entry point. Parses argv, then hands off to count().
import { count } from './count.js';
 
const dir = process.argv[2] ?? 'src';
const min = Number(process.argv[3] ?? 0);
 
const totals = count(dir, min);
+-- 6 lines: for (const [ext, lines] of totals) { ------
console.log(`${totals.size} extensions`);
~
@@ -3,13 +3,14 @@ src/count.js
export function count(dir, min = 0) {
const totals = new Map();
+-- 7 lines: for (const entry of readdirSync(dir)) { ----
// off by one: the header line was counted twice
totals.set(ext, lines + 1);
}
 
 
return totals;
}
~
export function count(dir, min = 0) {
const totals = new Map();
+-- 7 lines: for (const entry of readdirSync(dir)) { ----
 
totals.set(ext, lines);
}
 
return new Map([...totals].filter(([, n]) => n >= min));
 
}
~
why does tally report one extra line per file?
 
Looking at src/count.js.
 
Read(src/count.js) 13 lines
Grep(lines \+ 1) 1 match
 
The header line is counted twice. Line 7 adds one
to a total that already includes it:
 
7 totals.set(ext, lines + 1);
 
Dropping the + 1 fixes it. Want me to make
the change and add a test?
 
yes, and run the tests
Reviewing 4 files against HEAD · 2 findings
 
high src/count.js:7
Off by one. The header line is already in lines,
so + 1 counts it twice. A one line file reports 2.
 
low src/index.js:5
min is parsed with Number() and never checked.
tally src --min abc filters everything out.
 
ok package.json no findings
ok README.md no findings
 
Fix the first and re-run? [y/N]
package.json [RO] diff 1,1 All

Diff groups slot 0 as the text on each, WCAG AAA needs 7:1

DiffAdd slot 10 · 11.00:1 DiffChange slot 12 · 8.99:1 DiffText slot 11 · 11.59:1 DiffDelete slot 0 · no bar

ANSI slots contrast against this variant’s background

0 black near-bg#191b241.14:1
1 red#e5714f6.33:1
2 green#2fd19b9.97:1
3 yellow#e2a42f8.92:1
4 blue#4596f26.42:1
5 magenta#cc5f995.27:1
6 cyan#6fd7e511.65:1
7 white#c6cad311.90:1
8 br black#767e934.82:1
9 br red#f28f728.32:1
10 br green#63e5bb12.52:1
11 br yellow#f2d26413.19:1
12 br blue#86c0ff10.23:1
13 br magenta#e089bd7.89:1
14 br cyan#9ee6f214.01:1
15 br white#f0f2f717.44:1

Prompt Twilight

dark

Dusk indigo. A violet-leaning ground that stays cool without going black.

tally — iTerm2
package.json
HEAD
@@ -1,9 +1,11 @@ package.json
{
"name": "tally",
"version": "0.1.2",
"description": "Count lines by extension",
 
"main": "src/index.js",
+-- 4 lines: "scripts": { "test": "node --test" },
"license": "GPL-3.0-or-later"
}
~
{
"name": "tally",
"version": "0.2.0",
"description": "Count lines by extension",
"bin": { "tally": "src/index.js" },
"main": "src/index.js",
+-- 4 lines: "scripts": { "test": "node --test" },
"license": "GPL-3.0-or-later"
}
~
@@ -1,12 +1,13 @@ README.md
# tally
 
A very small command line tool. No dependencies.
 
## Usage
 
tally src/
 
 
+-- 5 lines: ## Options -----------------------------
## Licence
GPL-3.0-or-later.
~
# tally - count lines by extension
 
A very small command line tool. No dependencies.
 
## Usage
 
tally src/
tally src/ --min 10
 
+-- 5 lines: ## Options -----------------------------
## Licence
GPL-3.0-or-later.
~
@@ -1,14 +1,15 @@ src/index.js
// Entry point. Parses argv, then hands off to count().
import { count } from './count.js';
 
const dir = process.argv[2] ?? '.';
 
 
const totals = count(dir);
+-- 6 lines: for (const [ext, lines] of totals) { ------
console.log(`${totals.size} extensions`);
~
// Entry point. Parses argv, then hands off to count().
import { count } from './count.js';
 
const dir = process.argv[2] ?? 'src';
const min = Number(process.argv[3] ?? 0);
 
const totals = count(dir, min);
+-- 6 lines: for (const [ext, lines] of totals) { ------
console.log(`${totals.size} extensions`);
~
@@ -3,13 +3,14 @@ src/count.js
export function count(dir, min = 0) {
const totals = new Map();
+-- 7 lines: for (const entry of readdirSync(dir)) { ----
// off by one: the header line was counted twice
totals.set(ext, lines + 1);
}
 
 
return totals;
}
~
export function count(dir, min = 0) {
const totals = new Map();
+-- 7 lines: for (const entry of readdirSync(dir)) { ----
 
totals.set(ext, lines);
}
 
return new Map([...totals].filter(([, n]) => n >= min));
 
}
~
why does tally report one extra line per file?
 
Looking at src/count.js.
 
Read(src/count.js) 13 lines
Grep(lines \+ 1) 1 match
 
The header line is counted twice. Line 7 adds one
to a total that already includes it:
 
7 totals.set(ext, lines + 1);
 
Dropping the + 1 fixes it. Want me to make
the change and add a test?
 
yes, and run the tests
Reviewing 4 files against HEAD · 2 findings
 
high src/count.js:7
Off by one. The header line is already in lines,
so + 1 counts it twice. A one line file reports 2.
 
low src/index.js:5
min is parsed with Number() and never checked.
tally src --min abc filters everything out.
 
ok package.json no findings
ok README.md no findings
 
Fix the first and re-run? [y/N]
package.json [RO] diff 1,1 All

Diff groups slot 0 as the text on each, WCAG AAA needs 7:1

DiffAdd slot 10 · 10.45:1 DiffChange slot 12 · 8.78:1 DiffText slot 11 · 11.07:1 DiffDelete slot 0 · no bar

ANSI slots contrast against this variant’s background

0 black near-bg#241f3d1.11:1
1 red#ec7a636.23:1
2 green#3ed2a49.06:1
3 yellow#e7ab4a8.54:1
4 blue#6a9cf76.38:1
5 magenta#c95e9f4.62:1
6 cyan#79d9ea10.69:1
7 white#cfcbe010.98:1
8 br black#8781a44.72:1
9 br red#f798818.07:1
10 br green#6fe8c011.56:1
11 br yellow#f6d67a12.25:1
12 br blue#9cc4ff9.72:1
13 br magenta#cd84b06.22:1
14 br cyan#a6e8f512.80:1
15 br white#f3f1fa15.53:1

Prompt Light

light

Paper white with an inverted grey ramp, so every ANSI slot reads on the page.

tally — iTerm2
package.json
HEAD
@@ -1,9 +1,11 @@ package.json
{
"name": "tally",
"version": "0.1.2",
"description": "Count lines by extension",
 
"main": "src/index.js",
+-- 4 lines: "scripts": { "test": "node --test" },
"license": "GPL-3.0-or-later"
}
~
{
"name": "tally",
"version": "0.2.0",
"description": "Count lines by extension",
"bin": { "tally": "src/index.js" },
"main": "src/index.js",
+-- 4 lines: "scripts": { "test": "node --test" },
"license": "GPL-3.0-or-later"
}
~
@@ -1,12 +1,13 @@ README.md
# tally
 
A very small command line tool. No dependencies.
 
## Usage
 
tally src/
 
 
+-- 5 lines: ## Options -----------------------------
## Licence
GPL-3.0-or-later.
~
# tally - count lines by extension
 
A very small command line tool. No dependencies.
 
## Usage
 
tally src/
tally src/ --min 10
 
+-- 5 lines: ## Options -----------------------------
## Licence
GPL-3.0-or-later.
~
@@ -1,14 +1,15 @@ src/index.js
// Entry point. Parses argv, then hands off to count().
import { count } from './count.js';
 
const dir = process.argv[2] ?? '.';
 
 
const totals = count(dir);
+-- 6 lines: for (const [ext, lines] of totals) { ------
console.log(`${totals.size} extensions`);
~
// Entry point. Parses argv, then hands off to count().
import { count } from './count.js';
 
const dir = process.argv[2] ?? 'src';
const min = Number(process.argv[3] ?? 0);
 
const totals = count(dir, min);
+-- 6 lines: for (const [ext, lines] of totals) { ------
console.log(`${totals.size} extensions`);
~
@@ -3,13 +3,14 @@ src/count.js
export function count(dir, min = 0) {
const totals = new Map();
+-- 7 lines: for (const entry of readdirSync(dir)) { ----
// off by one: the header line was counted twice
totals.set(ext, lines + 1);
}
 
 
return totals;
}
~
export function count(dir, min = 0) {
const totals = new Map();
+-- 7 lines: for (const entry of readdirSync(dir)) { ----
 
totals.set(ext, lines);
}
 
return new Map([...totals].filter(([, n]) => n >= min));
 
}
~
why does tally report one extra line per file?
 
Looking at src/count.js.
 
Read(src/count.js) 13 lines
Grep(lines \+ 1) 1 match
 
The header line is counted twice. Line 7 adds one
to a total that already includes it:
 
7 totals.set(ext, lines + 1);
 
Dropping the + 1 fixes it. Want me to make
the change and add a test?
 
yes, and run the tests
Reviewing 4 files against HEAD · 2 findings
 
high src/count.js:7
Off by one. The header line is already in lines,
so + 1 counts it twice. A one line file reports 2.
 
low src/index.js:5
min is parsed with Number() and never checked.
tally src --min abc filters everything out.
 
ok package.json no findings
ok README.md no findings
 
Fix the first and re-run? [y/N]
package.json [RO] diff 1,1 All

Diff groups slot 0 as the text on each, WCAG AAA needs 7:1

DiffAdd slot 10 · 7.20:1 DiffChange slot 12 · 8.13:1 DiffText slot 11 · 7.23:1 DiffDelete slot 0 · no bar

ANSI slots contrast against this variant’s background

0 black near-bg#eeede71.11:1
1 red#872a228.36:1
2 green#127d564.87:1
3 yellow#9664084.84:1
4 blue#0a4ec26.92:1
5 magenta#cc008f5.03:1
6 cyan#0551668.40:1
7 white#3f434d9.40:1
8 br black#6269775.24:1
9 br red#67241e10.79:1
10 br green#0059398.02:1
11 br yellow#6b45008.05:1
12 br blue#083f9c9.06:1
13 br magenta#9c006d7.57:1
14 br cyan#0c3c4911.34:1
15 br white#22242a14.73:1

Prompt Dawn

light

Warm paper. The light ground for rooms with warm light, with the same inverted grey ramp.

tally — iTerm2
package.json
HEAD
@@ -1,9 +1,11 @@ package.json
{
"name": "tally",
"version": "0.1.2",
"description": "Count lines by extension",
 
"main": "src/index.js",
+-- 4 lines: "scripts": { "test": "node --test" },
"license": "GPL-3.0-or-later"
}
~
{
"name": "tally",
"version": "0.2.0",
"description": "Count lines by extension",
"bin": { "tally": "src/index.js" },
"main": "src/index.js",
+-- 4 lines: "scripts": { "test": "node --test" },
"license": "GPL-3.0-or-later"
}
~
@@ -1,12 +1,13 @@ README.md
# tally
 
A very small command line tool. No dependencies.
 
## Usage
 
tally src/
 
 
+-- 5 lines: ## Options -----------------------------
## Licence
GPL-3.0-or-later.
~
# tally - count lines by extension
 
A very small command line tool. No dependencies.
 
## Usage
 
tally src/
tally src/ --min 10
 
+-- 5 lines: ## Options -----------------------------
## Licence
GPL-3.0-or-later.
~
@@ -1,14 +1,15 @@ src/index.js
// Entry point. Parses argv, then hands off to count().
import { count } from './count.js';
 
const dir = process.argv[2] ?? '.';
 
 
const totals = count(dir);
+-- 6 lines: for (const [ext, lines] of totals) { ------
console.log(`${totals.size} extensions`);
~
// Entry point. Parses argv, then hands off to count().
import { count } from './count.js';
 
const dir = process.argv[2] ?? 'src';
const min = Number(process.argv[3] ?? 0);
 
const totals = count(dir, min);
+-- 6 lines: for (const [ext, lines] of totals) { ------
console.log(`${totals.size} extensions`);
~
@@ -3,13 +3,14 @@ src/count.js
export function count(dir, min = 0) {
const totals = new Map();
+-- 7 lines: for (const entry of readdirSync(dir)) { ----
// off by one: the header line was counted twice
totals.set(ext, lines + 1);
}
 
 
return totals;
}
~
export function count(dir, min = 0) {
const totals = new Map();
+-- 7 lines: for (const entry of readdirSync(dir)) { ----
 
totals.set(ext, lines);
}
 
return new Map([...totals].filter(([, n]) => n >= min));
 
}
~
why does tally report one extra line per file?
 
Looking at src/count.js.
 
Read(src/count.js) 13 lines
Grep(lines \+ 1) 1 match
 
The header line is counted twice. Line 7 adds one
to a total that already includes it:
 
7 totals.set(ext, lines + 1);
 
Dropping the + 1 fixes it. Want me to make
the change and add a test?
 
yes, and run the tests
Reviewing 4 files against HEAD · 2 findings
 
high src/count.js:7
Off by one. The header line is already in lines,
so + 1 counts it twice. A one line file reports 2.
 
low src/index.js:5
min is parsed with Number() and never checked.
tally src --min abc filters everything out.
 
ok package.json no findings
ok README.md no findings
 
Fix the first and re-run? [y/N]
package.json [RO] diff 1,1 All

Diff groups slot 0 as the text on each, WCAG AAA needs 7:1

DiffAdd slot 10 · 7.18:1 DiffChange slot 12 · 7.47:1 DiffText slot 11 · 7.25:1 DiffDelete slot 0 · no bar

ANSI slots contrast against this variant’s background

0 black near-bg#f2e9da1.12:1
1 red#7538158.39:1
2 green#0e815e4.53:1
3 yellow#a362004.55:1
4 blue#0039d67.66:1
5 magenta#cb10b24.60:1
6 cyan#05505c8.48:1
7 white#4a42389.20:1
8 br black#6b61555.65:1
9 br red#592d1310.82:1
10 br green#00573c8.06:1
11 br yellow#6d41008.13:1
12 br blue#0035c78.38:1
13 br magenta#9d00887.02:1
14 br cyan#0a3b4211.40:1
15 br white#2a251e14.16:1

Measured

Every figure computed by tools/build.py, which fails the build if any variant slips below the constraints.
VariantBackground Lowest text contrastLowest diff-text contrast Grey ramp
Prompt Dark #1a1b264.57:18.49:1 normal
Prompt Midnight #0b0c114.82:18.99:1 normal
Prompt Twilight #1a17304.62:18.78:1 normal
Prompt Light #faf9f64.84:17.20:1 inverted
Prompt Dawn #fdf6ec4.53:17.18:1 inverted

Install

Import the preset, then select it under Settings → Profiles → Colors → Color Presets. The second command symlinks the vim highlights and adds one source line to your ~/.vimrc; make uninstall reverses it.

make import-iterm2
make install
make verify        # re-check every variant

Neovim needs nothing: its default scheme already puts dark text on those lines.