contract.gno
2.50 Kb · 81 lines
1// Package importdemo shows a realm importing and composing packages from
2// ANOTHER namespace — the whole point of the demo.
3//
4// v2 imported gno.land/p/archive/dom, which is published on no chain we target
5// (absent on both sapphire and pearl), so it type-checked locally but could
6// never be deployed: `addpkg` failed with
7// `could not import gno.land/p/archive/dom (unknown import path)`. v2 is
8// archived (`ignore = true`); this version rebuilds the same thread-of-posts
9// idea on foreign packages that are actually on chain — `p/nt/avl/v0` for
10// ordered storage and `p/nt/ufmt/v0` for formatting.
11//
12// Deliberately keeps no realm state: Render builds the thread on each call, so
13// output depends only on the code and the demo is reproducible.
14package importdemo
15
16import (
17 "strconv"
18 "strings"
19
20 "gno.land/p/nt/avl/v0"
21 "gno.land/p/nt/ufmt/v0"
22)
23
24// thread is a titled list of posts, kept in an avl.Tree so iteration is ordered
25// by key rather than by insertion — the same guarantee the realm needs for a
26// stable Render.
27type thread struct {
28 name string
29 posts *avl.Tree // zero-padded index -> *post
30 n int
31}
32
33type post struct {
34 title string
35 body string
36}
37
38func newThread(name string) *thread {
39 return &thread{name: name, posts: avl.NewTree()}
40}
41
42// addPost appends a post. The key is zero-padded so avl's lexicographic order
43// matches insertion order past 9 entries ("10" would otherwise sort before "9").
44func (t *thread) addPost(title, body string) {
45 t.posts.Set(padIdx(t.n), &post{title: title, body: body})
46 t.n++
47}
48
49// padIdx renders i as a fixed-width, zero-padded key.
50//
51// Done by hand on purpose: gno's ufmt supports NO width or padding flags, so
52// ufmt.Sprintf("%03d", 7) yields "7", not "007" — silently, with no error. Keys
53// built that way sort as "0","1","10","11","2", which quietly reorders every
54// thread past nine posts (TestOrderSurvivesPastNinePosts covers exactly this).
55func padIdx(i int) string {
56 s := strconv.Itoa(i)
57 for len(s) < 3 {
58 s = "0" + s
59 }
60 return s
61}
62
63// String renders the thread as Markdown.
64func (t *thread) String() string {
65 var b strings.Builder
66 b.WriteString(ufmt.Sprintf("# [thread] %s\n\n", t.name))
67 t.posts.Iterate("", "", func(_ string, v any) bool {
68 p := v.(*post)
69 b.WriteString(ufmt.Sprintf("## %s\n%s\n", p.title, p.body))
70 return false
71 })
72 return b.String()
73}
74
75// Render renders the demo thread for gnoweb.
76func Render(path string) string {
77 t := newThread("Hello!")
78 t.addPost("Foo", "foo foo foo")
79 t.addPost("Bar", "bar bar bar")
80 return t.String()
81}