Add themes to js version

This commit is contained in:
Anton Medvedev 2023-09-24 14:22:50 +02:00
parent a7249fea5a
commit 289165d553
No known key found for this signature in database
3 changed files with 109 additions and 63 deletions

View File

@ -57,6 +57,9 @@ func main() {
case "--themes": case "--themes":
themeTester() themeTester()
return return
case "--export-themes":
exportThemes()
return
default: default:
args = append(args, arg) args = append(args, arg)
} }

View File

@ -18,6 +18,7 @@ void async function main() {
} }
if (flagHelp || (args.length === 0 && process.stdin.isTTY)) if (flagHelp || (args.length === 0 && process.stdin.isTTY))
return printUsage() return printUsage()
const theme = themes(process.stdout.isTTY ? (process.env.FX_THEME || '1') : '0')
await importFxrc(process.cwd()) await importFxrc(process.cwd())
await importFxrc(os.homedir()) await importFxrc(os.homedir())
let fd = 0 // stdin let fd = 0 // stdin
@ -35,17 +36,17 @@ void async function main() {
for (const json of input) { for (const json of input) {
array.push(json) array.push(json)
} }
await runTransforms(array, args) await runTransforms(array, args, theme)
} else { } else {
for (const json of input) { for (const json of input) {
await runTransforms(json, args) await runTransforms(json, args, theme)
} }
} }
}() }()
const skip = Symbol('skip') const skip = Symbol('skip')
async function runTransforms(json, args) { async function runTransforms(json, args, theme) {
const process = await import('node:process') const process = await import('node:process')
let i, code, output = json let i, code, output = json
for ([i, code] of args.entries()) try { for ([i, code] of args.entries()) try {
@ -62,7 +63,7 @@ async function runTransforms(json, args) {
else if (output === skip) else if (output === skip)
return return
else else
console.log(stringify(output, process.stdout.isTTY)) console.log(stringify(output, theme))
function printErr(err) { function printErr(err) {
let pre = args.slice(0, i).join(' ') let pre = args.slice(0, i).join(' ')
@ -520,14 +521,10 @@ function* parseJson(gen) {
} }
} }
function stringify(value, isPretty = false) { function stringify(value, theme) {
const colors = { function color(id, str) {
key: isPretty ? '\x1b[1;34m' : '', if (theme[id] === '') return str
string: isPretty ? '\x1b[32m' : '', return `\x1b[${theme[id]}m${str}\x1b[0m`
number: isPretty ? '\x1b[36m' : '',
boolean: isPretty ? '\x1b[35m' : '',
null: isPretty ? '\x1b[38;5;243m' : '',
reset: isPretty ? '\x1b[0m' : '',
} }
function getIndent(level) { function getIndent(level) {
@ -536,38 +533,35 @@ function stringify(value, isPretty = false) {
function stringifyValue(value, level = 0) { function stringifyValue(value, level = 0) {
if (typeof value === 'string') { if (typeof value === 'string') {
return `${colors.string}${JSON.stringify(value)}${colors.reset}` return color(2, JSON.stringify(value))
} else if (typeof value === 'number') { } else if (typeof value === 'number') {
return `${colors.number}${value}${colors.reset}` return color(3, `${value}`)
} else if (typeof value === 'bigint') { } else if (typeof value === 'bigint') {
return `${colors.number}${value}${colors.reset}` return color(3, `${value}`)
} else if (typeof value === 'boolean') { } else if (typeof value === 'boolean') {
return `${colors.boolean}${value}${colors.reset}` return color(4, `${value}`)
} else if (value === null || typeof value === 'undefined') { } else if (value === null || typeof value === 'undefined') {
return `${colors.null}null${colors.reset}` return color(5, `null`)
} else if (Array.isArray(value)) { } else if (Array.isArray(value)) {
if (value.length === 0) { if (value.length === 0) {
return `[]` return color(0, `[]`)
} }
const items = value const items = value
.map((v) => `${getIndent(level + 1)}${stringifyValue(v, level + 1)}`) .map((v) => getIndent(level + 1) + stringifyValue(v, level + 1))
.join(',\n') .join(color(0, ',') + '\n')
return `[\n${items}\n${getIndent(level)}]` return color(0, '[') + '\n' + items + '\n' + getIndent(level) + color(0, ']')
} else if (typeof value === 'object') { } else if (typeof value === 'object') {
const keys = Object.keys(value) const keys = Object.keys(value)
if (keys.length === 0) { if (keys.length === 0) {
return `{}` return color(0, '{}')
} }
const entries = keys const entries = keys
.map( .map((key) =>
(key) => getIndent(level + 1) + color(1, `"${key}"`) + color(0, ': ') +
`${getIndent(level + 1)}${colors.key}"${key}"${colors.reset}: ${stringifyValue( stringifyValue(value[key], level + 1),
value[key],
level + 1,
)}`,
) )
.join(',\n') .join(color(0, ',') + '\n')
return `{\n${entries}\n${getIndent(level)}}` return color(0, '{') + '\n' + entries + '\n' + getIndent(level) + color(0, '}')
} }
throw new Error(`Unsupported value type: ${typeof value}`) throw new Error(`Unsupported value type: ${typeof value}`)
} }
@ -575,6 +569,23 @@ function stringify(value, isPretty = false) {
return stringifyValue(value) return stringifyValue(value)
} }
function themes(id) {
const themes = {
'0': ['', '', '', '', '', ''],
'1': ['', '1;34', '32', '36', '35', '38;5;243'],
'2': ['', '32', '34', '36', '35', '38;5;243'],
'3': ['', '95', '93', '96', '31', '38;5;243'],
'4': ['', '38;5;50', '38;5;39', '38;5;98', '38;5;205', '38;5;243'],
'5': ['', '38;5;230', '38;5;221', '38;5;209', '38;5;209', '38;5;243'],
'6': ['', '38;5;69', '38;5;78', '38;5;221', '38;5;203', '38;5;243'],
'7': ['', '1;38;5;42', '1;38;5;213', '1;38;5;201', '1;38;5;201', '38;5;243'],
'8': ['', '1;38;5;51', '38;5;195', '38;5;123', '38;5;50', '38;5;243'],
'🔵': ['1;38;5;33', '38;5;33', '', '', '', ''],
'🥝': ['38;5;179', '1;38;5;154', '38;5;82', '38;5;226', '38;5;226', '38;5;230'],
}
return themes[id] || themes['1']
}
async function importFxrc(path) { async function importFxrc(path) {
const {join} = await import('node:path') const {join} = await import('node:path')
const {pathToFileURL} = await import('node:url') const {pathToFileURL} = await import('node:url')

View File

@ -1,8 +1,10 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"regexp"
"sort" "sort"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
@ -24,6 +26,30 @@ type theme struct {
type color func(s []byte) []byte type color func(s []byte) []byte
func valueStyle(b []byte, selected, chunk bool) color {
if selected {
return currentTheme.Cursor
} else if chunk {
return currentTheme.String
} else {
switch b[0] {
case '"':
return currentTheme.String
case 't', 'f':
return currentTheme.Boolean
case 'n':
return currentTheme.Null
case '{', '[', '}', ']':
return currentTheme.Syntax
default:
if isDigit(b[0]) || b[0] == '-' {
return currentTheme.Number
}
return noColor
}
}
}
func init() { func init() {
themeNames = make([]string, 0, len(themes)) themeNames = make([]string, 0, len(themes))
for name := range themes { for name := range themes {
@ -234,60 +260,66 @@ func boldFg(color string) color {
func themeTester() { func themeTester() {
title := lipgloss.NewStyle().Bold(true) title := lipgloss.NewStyle().Bold(true)
for _, name := range themeNames { for _, name := range themeNames {
theme := themes[name] t := themes[name]
comma := string(theme.Syntax([]byte{','})) comma := string(t.Syntax([]byte{','}))
colon := string(theme.Syntax([]byte{':'})) colon := string(t.Syntax([]byte{':'}))
fmt.Println(title.Render(fmt.Sprintf("Theme %q", name))) fmt.Println(title.Render(fmt.Sprintf("Theme %q", name)))
fmt.Println(string(theme.Syntax([]byte("{")))) fmt.Println(string(t.Syntax([]byte("{"))))
fmt.Printf(" %v%v %v%v\n", fmt.Printf(" %v%v %v%v\n",
string(theme.Key([]byte("\"string\""))), string(t.Key([]byte("\"string\""))),
colon, colon,
string(theme.String([]byte("\"Fox jumps over the lazy dog\""))), string(t.String([]byte("\"Fox jumps over the lazy dog\""))),
comma) comma)
fmt.Printf(" %v%v %v%v\n", fmt.Printf(" %v%v %v%v\n",
string(theme.Key([]byte("\"number\""))), string(t.Key([]byte("\"number\""))),
colon, colon,
string(theme.Number([]byte("1234567890"))), string(t.Number([]byte("1234567890"))),
comma) comma)
fmt.Printf(" %v%v %v%v\n", fmt.Printf(" %v%v %v%v\n",
string(theme.Key([]byte("\"boolean\""))), string(t.Key([]byte("\"boolean\""))),
colon, colon,
string(theme.Boolean([]byte("true"))), string(t.Boolean([]byte("true"))),
comma) comma)
fmt.Printf(" %v%v %v%v\n", fmt.Printf(" %v%v %v%v\n",
string(theme.Key([]byte("\"null\""))), string(t.Key([]byte("\"null\""))),
colon, colon,
string(theme.Null([]byte("null"))), string(t.Null([]byte("null"))),
comma) comma)
fmt.Println(string(theme.Syntax([]byte("}")))) fmt.Println(string(t.Syntax([]byte("}"))))
println() println()
} }
} }
func valueStyle(b []byte, selected, chunk bool) color { func exportThemes() {
if selected { lipgloss.SetColorProfile(termenv.ANSI256) // Export in Terminal.app compatible colors
return currentTheme.Cursor placeholder := []byte{'_'}
} else if chunk { extract := func(b []byte) string {
return currentTheme.String matches := regexp.
} else { MustCompile(`^\x1b\[(.+)m_`).
switch b[0] { FindStringSubmatch(string(b))
case '"': if len(matches) == 0 {
return currentTheme.String return ""
case 't', 'f': } else {
return currentTheme.Boolean return matches[1]
case 'n':
return currentTheme.Null
case '{', '[', '}', ']':
return currentTheme.Syntax
default:
if isDigit(b[0]) || b[0] == '-' {
return currentTheme.Number
}
return noColor
} }
} }
var export = map[string][]string{}
for _, name := range themeNames {
t := themes[name]
export[name] = append(export[name], extract(t.Syntax(placeholder)))
export[name] = append(export[name], extract(t.Key(placeholder)))
export[name] = append(export[name], extract(t.String(placeholder)))
export[name] = append(export[name], extract(t.Number(placeholder)))
export[name] = append(export[name], extract(t.Boolean(placeholder)))
export[name] = append(export[name], extract(t.Null(placeholder)))
}
data, err := json.Marshal(export)
if err != nil {
panic(err)
}
fmt.Println(string(data))
} }