Skip to content

feat(examples): add /{r:p}/pol/ packages #4071

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 31 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
502c85b
feat(examples): add 'pol' example page
paulogarithm Apr 7, 2025
f72fd4c
chore: remove the unusep p/pol/gnomining package
paulogarithm Apr 7, 2025
10c4960
feat(gnominers): nerf opal price & spawn rate
paulogarithm Apr 7, 2025
30780d2
Merge branch 'gnolang:master' into master
paulogarithm Apr 8, 2025
d935be7
feat(gnominers): begin dao impl in gnominers
paulogarithm Apr 8, 2025
966de11
fix(gnominers): finish impl dao
paulogarithm Apr 8, 2025
4923018
feat(gnominers): now you can generate a DAO request
paulogarithm Apr 8, 2025
80bf496
fix(gnominers): bad formatting
paulogarithm Apr 8, 2025
20260f7
feat: add uufmt (with printf with flags) + nfmt (number format)
paulogarithm Apr 9, 2025
5455127
Merge branch 'gnolang:master' into master
paulogarithm Apr 9, 2025
5d71b3a
feat: add flag parsing in ufmt.printf
paulogarithm Apr 10, 2025
f396fe4
fix(nfmt): number format fix .2f instead of .1f
paulogarithm Apr 10, 2025
a91aac5
fix(nfmt): number format func name
paulogarithm Apr 10, 2025
efb7a3e
fix(ufmt)!: flag parsing using []rune instead of string
paulogarithm Apr 11, 2025
c5d0400
feat(gnominers): add nfmt to shop
paulogarithm Apr 11, 2025
9451a3b
chore: remove tofix folder remotely
paulogarithm Apr 11, 2025
8289230
fix(#4109): html escape string global realm error
paulogarithm Apr 11, 2025
f2359c8
chore: add some gno-columns everywhere so its cleaner
paulogarithm Apr 11, 2025
ce15ebf
feat(gnominers): add the leaderboard system
paulogarithm Apr 11, 2025
9755a09
feat(ux): improved user experience + use md lib
paulogarithm Apr 14, 2025
6decc3f
feat(gnominers): change everything to use md lib
paulogarithm Apr 14, 2025
6b914d3
feat: add releases to gnominers
paulogarithm Apr 14, 2025
d83de10
feat: implement gnominers releases in home
paulogarithm Apr 14, 2025
6ea1081
chore: fixup render gno unused packages
paulogarithm Apr 14, 2025
76d2680
feat(home): make my home page use md lib
paulogarithm Apr 14, 2025
67b2a21
Merge branch 'master' into master
paulogarithm Apr 14, 2025
d172d78
fix: remove uufmt
paulogarithm Apr 14, 2025
feaffc2
test(ufmt/sprintf): add more tests to printf
paulogarithm Apr 14, 2025
fd9e9fb
feat(ufmt/printf): add %x features for []uint8{}
paulogarithm Apr 14, 2025
9dbcd63
chore: change hof -> hor
paulogarithm Apr 15, 2025
8f2cb72
Merge branch 'gnolang:master' into master
paulogarithm Apr 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 189 additions & 34 deletions examples/gno.land/p/demo/ufmt/ufmt.gno
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would separate this out into a fresh PR :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright i will do it 🫡

Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ package ufmt
import (
"errors"
"io"
"math"
"strconv"
"strings"
"unicode"
"unicode/utf8"
)

Expand All @@ -32,13 +34,120 @@ func (b *buffer) writeRune(r rune) {
*b = utf8.AppendRune(*b, r)
}

// the different flags
const (
flagHashtag uint8 = 1
flagZero uint8 = 1 << 1
flagMinus uint8 = 1 << 2
flagSpace uint8 = 1 << 3
flagPlus uint8 = 1 << 4
)

// the different len modifiers
const (
lenNo uint8 = iota
lenHH
lenH
lenL
lenLL
lenZ
)

type printerMeta struct {
flags uint8
padding uint
length uint8
width uint
precision int
}

// printer holds state for formatting operations.
type printer struct {
buf buffer
buf buffer
meta printerMeta
}

func strtoi(s string) (int, string) {
i := 0
for i < len(s) && unicode.IsDigit(rune(s[i])) {
i++
}
if i == 0 {
return 0, s
}
num, err := strconv.Atoi(s[:i])
if err != nil {
return 0, s
}
return num, s[i:]
}

// parse the flags
// parse the flags
func (p *printer) parse(runes []rune, index *int) {
*index++
if runes[*index] == '#' {
p.meta.flags |= flagHashtag
*index++
}
c2f := map[rune]uint8{
'-': flagMinus,
'+': flagPlus,
' ': flagSpace,
'0': flagZero,
}
stop := false
for {
x, ok := c2f[runes[*index]]
switch {
case ok:
p.meta.flags |= x
*index++
case unicode.IsNumber(runes[*index]):
n, rest := strtoi(string(runes[*index:]))
if rest == string(runes) {
continue
}
p.meta.padding = uint(n)
*index += len(strconv.Itoa(n))
case runes[*index] == '.':
*index++
n, rest := strtoi(string(runes[*index:]))
p.meta.precision = n // 0 by default, not an error
if rest == string(runes[*index:]) {
continue
}
*index += len(strconv.Itoa(n))
default:
stop = true
}
if stop {
break
}
}
for k, v := range map[string]uint8{
"ll": lenLL,
"l": lenL,
"h": lenH,
"hh": lenHH,
"z": lenZ,
} {
if string(runes[*index:*index+len(k)-1]) == k {
p.meta.length = v
*index += len(k)
break
}
}
*index--
}

func newPrinter() *printer {
return &printer{}
return &printer{
buf: buffer{},
meta: printerMeta{
precision: 6,
},
}
}

// Sprint formats using the default formats for its operands and returns the resulting string.
Expand Down Expand Up @@ -110,7 +219,7 @@ func (p *printer) doPrintln(a []any) {
// %G: Formats a float value with %G for large exponents, and %F with full precision for smaller numbers
// %t: Formats a boolean value to "true" or "false".
// %x: Formats an integer value as a hexadecimal string.
// Currently supports only uint8, []uint8, [32]uint8.
// Currently supports only int, uint, uint8, 16, 32, 64 and []uint8.
// %c: Formats a rune value as a string.
// Currently supports only rune, int.
// %q: Formats a string value as a quoted string.
Expand Down Expand Up @@ -142,14 +251,16 @@ func (p *printer) doPrintf(format string, args []any) {
for i := 0; i < end; {
isLast := i == end-1
c := sTor[i]

if isLast || c != '%' {
// we don't check for invalid format like a one ending with "%"
p.buf.writeRune(c)
i++
continue
}

p.parse(sTor, &i)

verb := sTor[i+1]
if verb == '%' {
p.buf.writeRune('%')
Expand All @@ -170,14 +281,14 @@ func (p *printer) doPrintf(format string, args []any) {
writeString(p, verb, arg)
case 'c':
writeChar(p, verb, arg)
case 'd':
case 'd', 'i':
writeInt(p, verb, arg)
case 'e', 'E', 'f', 'F', 'g', 'G':
writeFloat(p, verb, arg)
case 't':
writeBool(p, verb, arg)
case 'x':
writeHex(p, verb, arg)
case 'x', 'X':
writeHex(p, verb, arg, verb == 'X')
case 'q':
writeQuotedString(p, verb, arg)
case 'T':
Expand Down Expand Up @@ -276,53 +387,65 @@ func writeChar(p *printer, verb rune, arg any) {
}
}

// writeInt handles %d formatting
// writeInt handles %d & %i formatting
func writeInt(p *printer, verb rune, arg any) {
var subBuf string
switch v := arg.(type) {
case int:
p.buf.writeString(strconv.Itoa(v))
subBuf = strconv.Itoa(v)
case int8:
p.buf.writeString(strconv.Itoa(int(v)))
subBuf = strconv.Itoa(int(v))
case int16:
p.buf.writeString(strconv.Itoa(int(v)))
subBuf = strconv.Itoa(int(v))
case int32:
p.buf.writeString(strconv.Itoa(int(v)))
subBuf = strconv.Itoa(int(v))
case int64:
p.buf.writeString(strconv.Itoa(int(v)))
subBuf = strconv.Itoa(int(v))
case uint:
p.buf.writeString(strconv.FormatUint(uint64(v), 10))
subBuf = strconv.FormatUint(uint64(v), 10)
case uint8:
p.buf.writeString(strconv.FormatUint(uint64(v), 10))
subBuf = strconv.FormatUint(uint64(v), 10)
case uint16:
p.buf.writeString(strconv.FormatUint(uint64(v), 10))
subBuf = strconv.FormatUint(uint64(v), 10)
case uint32:
p.buf.writeString(strconv.FormatUint(uint64(v), 10))
subBuf = strconv.FormatUint(uint64(v), 10)
case uint64:
p.buf.writeString(strconv.FormatUint(v, 10))
subBuf = strconv.FormatUint(v, 10)
default:
p.buf.writeString(fallback(verb, v))
subBuf = fallback(verb, v)
}
if p.meta.flags&flagSpace != 0 {
subBuf = strings.Repeat(" ", int(math.Max(0, float64(int(p.meta.padding)-len(subBuf))))) + subBuf
} else if p.meta.flags&flagZero != 0 {
subBuf = strings.Repeat("0", int(math.Max(0, float64(int(p.meta.padding)-len(subBuf))))) + subBuf
}
p.buf.writeString(subBuf)
}

// writeFloat handles floating-point formatting verbs
func writeFloat(p *printer, verb rune, arg any) {
var subBuf string
bits := 64
n := 0.
switch v := arg.(type) {
case float64:
switch verb {
case 'e':
p.buf.writeString(strconv.FormatFloat(v, 'e', -1, 64))
case 'E':
p.buf.writeString(strconv.FormatFloat(v, 'E', -1, 64))
case 'f', 'F':
p.buf.writeString(strconv.FormatFloat(v, 'f', 6, 64))
case 'g':
p.buf.writeString(strconv.FormatFloat(v, 'g', -1, 64))
case 'G':
p.buf.writeString(strconv.FormatFloat(v, 'G', -1, 64))
}
bits = 64
n = v
case float32:
bits = 32
n = float64(v)
default:
p.buf.writeString(fallback(verb, v))
return
}
prec := -1
verbChar := byte(verb)
if verbChar == 'f' || verbChar == 'F' {
prec = p.meta.precision
verbChar = 'f'
}
subBuf = strconv.FormatFloat(n, verbChar, prec, bits)
p.buf.writeString(subBuf)
}

// writeBool handles %t formatting
Expand All @@ -339,14 +462,46 @@ func writeBool(p *printer, verb rune, arg any) {
}
}

// writeHex handles %x formatting
func writeHex(p *printer, verb rune, arg any) {
// writeHex handles %x & %X formatting
func writeHex(p *printer, verb rune, arg any, big bool) {
var subBuf string
switch v := arg.(type) {
case int:
subBuf += strconv.FormatUint(uint64(v), 16)
case uint:
subBuf += strconv.FormatUint(uint64(v), 16)
case uint8:
p.buf.writeString(strconv.FormatUint(uint64(v), 16))
subBuf += strconv.FormatUint(uint64(v), 16)
case uint16:
subBuf += strconv.FormatUint(uint64(v), 16)
case uint32:
subBuf += strconv.FormatUint(uint64(v), 16)
case uint64:
subBuf += strconv.FormatUint(v, 16)
case []uint8:
for _, v := range v {
x := strconv.FormatUint(uint64(v), 16)
if len(x) == 1 {
x = "0" + x
}
subBuf += x
}
default:
p.buf.writeString("(unhandled)")
return
}
if p.meta.flags&flagSpace != 0 {
subBuf = strings.Repeat(" ", int(math.Max(0, float64(int(p.meta.padding)-len(subBuf))))) + subBuf
} else if p.meta.flags&flagZero != 0 {
subBuf = strings.Repeat("0", int(math.Max(0, float64(int(p.meta.padding)-len(subBuf))))) + subBuf
}
if p.meta.flags&flagHashtag != 0 {
subBuf = "0x" + subBuf
}
if big {
subBuf = strings.ToUpper(subBuf)
}
p.buf.writeString(subBuf)
}

// writeQuotedString handles %q formatting
Expand Down
27 changes: 27 additions & 0 deletions examples/gno.land/p/demo/ufmt/ufmt_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,28 @@ func TestSprintf(t *testing.T) {
values []any
expectedOutput string
}{
// normal usage
{"hello %s!", []any{"planet"}, "hello planet!"},
{"hello %v!", []any{"planet"}, "hello planet!"},
{"hi %%%s!", []any{"worl%d"}, "hi %worl%d!"},
{"%s %c %d %t", []any{"foo", 'α', 421, true}, "foo α 421 true"},
{"string [%s]", []any{"foo"}, "string [foo]"},

// ints
{"int [%d]", []any{int(42)}, "int [42]"},
{"int [%03d]", []any{int(42)}, "int [042]"},
{"int [%010d]", []any{int(42)}, "int [0000000042]"},
{"int [% 10d]", []any{int(42)}, "int [ 42]"},
{"hex [%x]", []any{int(42)}, "hex [2a]"},
{"hex [%X]", []any{int(42)}, "hex [2A]"},
{"hex [%02x]", []any{int(42)}, "hex [2a]"},
{"hex [%03x]", []any{int(42)}, "hex [02a]"},
{"hex [%#03x]", []any{int(42)}, "hex [0x02a]"},
{"hex [%#03X]", []any{int(42)}, "hex [0X02A]"},
{"hex [%#X]", []any{[]uint8{1, 2, 42}}, "hex [0X01022A]"},
{"hex [%x]", []any{[]uint8("hello")}, "hex [68656c6c6f]"},
{"hex [%x]", []any{[]uint8{0, 0}}, "hex [0000]"},
{"hex [%x]", []any{uint8(0)}, "hex [0]"},
{"int [%v]", []any{int(42)}, "int [42]"},
{"int8 [%d]", []any{int8(8)}, "int8 [8]"},
{"int8 [%v]", []any{int8(8)}, "int8 [8]"},
Expand All @@ -45,16 +61,27 @@ func TestSprintf(t *testing.T) {
{"uint32 [%v]", []any{uint32(32)}, "uint32 [32]"},
{"uint64 [%d]", []any{uint64(64)}, "uint64 [64]"},
{"uint64 [%v]", []any{uint64(64)}, "uint64 [64]"},

// floats
{"float64 [%e]", []any{float64(64.1)}, "float64 [6.41e+01]"},
{"float64 [%E]", []any{float64(64.1)}, "float64 [6.41E+01]"},
{"float64 [%f]", []any{float64(64.1)}, "float64 [64.100000]"},
{"float64 [%.2f]", []any{float64(64.1)}, "float64 [64.10]"},
{"float32 [%.1f]", []any{float32(64.1)}, "float32 [64.1]"},
{"float64 [%.f]", []any{float64(64.1)}, "float64 [64]"},
{"float64 [%.0f]", []any{float64(64.1)}, "float64 [64]"},
{"float64 [%.1f]", []any{float64(64.1)}, "float64 [64.1]"},
{"float64 [%F]", []any{float64(64.1)}, "float64 [64.100000]"},
{"float64 [%g]", []any{float64(64.1)}, "float64 [64.1]"},
{"float64 [%G]", []any{float64(64.1)}, "float64 [64.1]"},

// bool
{"bool [%t]", []any{true}, "bool [true]"},
{"bool [%v]", []any{true}, "bool [true]"},
{"bool [%t]", []any{false}, "bool [false]"},
{"bool [%v]", []any{false}, "bool [false]"},

// errros/special cases
{"no args", nil, "no args"},
{"finish with %", nil, "finish with %"},
{"stringer [%s]", []any{stringer{}}, "stringer [I'm a stringer]"},
Expand Down
Loading