Skip to content

Commit

Permalink
chore: In gnoweb, use vm/qdoc to show func comments. See the PR
Browse files Browse the repository at this point in the history
Signed-off-by: Jeff Thompson <jeff@thefirst.org>
  • Loading branch information
jefft0 committed Feb 28, 2025
1 parent f4324fb commit c89cb03
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 39 deletions.
13 changes: 7 additions & 6 deletions gno.land/pkg/gnoweb/components/ui/help_function.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{{ define "ui/help_function" }}
{{ $data := . }}
{{ range .Functions }}
<article class="bg-gray-100 rounded p-4 mb-3" data-func="{{ .FuncName }}">
<h2 id="func-{{ .FuncName }}" class="text-gray-600 font-semibold text-200 mb-3 leading-tight">{{ .FuncName }}</h2>
<article class="bg-gray-100 rounded p-4 mb-3" data-func="{{ .Name }}">
<h2 id="func-{{ .Name }}" class="text-gray-600 font-semibold text-200 mb-3 leading-tight">{{ .Name }}</h2>
<h3 class="text-gray-600 text-50 mb-1">{{ .Doc }}</h3>
<div class="mb-1">
<div class="flex flex-col gap-1 items-stretch text-gray-400">
<h3 class="mr-10 text-50">Params</h3>
<form class="w-full text-100">
{{ $funcName := .FuncName }} {{ range .Params }}
{{ $funcName := .Name }} {{ range .Params }}
<div class="flex flex-col gap-3 items-stretch text-gray-400 mb-2">
<div class="group relative overflow-hidden flex w-full border rounded-sm has-[:focus]:border-gray-300 hover:border-gray-300">
<label for="func-{{ $funcName }}-param-{{ .Name }}" class="flex gap-3 items-center bg-gray-50 px-4 font-semibold text-gray-600 text-100">{{ .Name }}</label>
Expand All @@ -29,11 +30,11 @@ <h3 class="mr-10 text-50">Params</h3>
<div>
<h3 class="text-gray-400 text-50 mb-1">Command</h3>
<div class="relative rounded-sm text-100 bg-light">
<button class="js-copy-btn w-5 h-5 absolute top-2 right-2 text-gray-400 hover:text-gray-600" aria-label="Copy Command" data-copy-btn="help-cmd-{{ .FuncName }}">{{ template "ui/copy" }}</button>
<button class="js-copy-btn w-5 h-5 absolute top-2 right-2 text-gray-400 hover:text-gray-600" aria-label="Copy Command" data-copy-btn="help-cmd-{{ .Name }}">{{ template "ui/copy" }}</button>
<pre
class="font-mono text-gray-600 p-4 pr-10 whitespace-pre-wrap"
><code><span data-code-mode="fast" class="inline" data-copy-content="help-cmd-{{ .FuncName }}">gnokey maketx call -pkgpath "{{ $.PkgPath }}" -func "{{ .FuncName }}"{{ range .Params }} -args "<span data-role="help-code-args" data-arg="{{ .Name }}" data-copy-content=""></span>"{{ end }} -gas-fee 1000000ugnot -gas-wanted 5000000 -broadcast -chainid "{{ $.ChainId }}" -remote "{{ $.Remote }}" <span data-role="help-code-address">ADDRESS</span></span><span data-code-mode="secure" class="hidden">gnokey query -remote "{{ $.Remote }}" auth/accounts/<span data-role="help-code-address">ADDRESS</span>
gnokey maketx call -pkgpath "{{ $.PkgPath }}" -func "{{ .FuncName }}"{{ range .Params }} -args "<span data-role="help-code-args" data-arg="{{ .Name }}"></span>"{{ end }} -gas-fee 1000000ugnot -gas-wanted 5000000 -send "" <span data-role="help-code-address">ADDRESS</span> > call.tx
><code><span data-code-mode="fast" class="inline" data-copy-content="help-cmd-{{ .Name }}">gnokey maketx call -pkgpath "{{ $.PkgPath }}" -func "{{ .Name }}"{{ range .Params }} -args "<span data-role="help-code-args" data-arg="{{ .Name }}" data-copy-content=""></span>"{{ end }} -gas-fee 1000000ugnot -gas-wanted 5000000 -broadcast -chainid "{{ $.ChainId }}" -remote "{{ $.Remote }}" <span data-role="help-code-address">ADDRESS</span></span><span data-code-mode="secure" class="hidden">gnokey query -remote "{{ $.Remote }}" auth/accounts/<span data-role="help-code-address">ADDRESS</span>
gnokey maketx call -pkgpath "{{ $.PkgPath }}" -func "{{ .Name }}"{{ range .Params }} -args "<span data-role="help-code-args" data-arg="{{ .Name }}"></span>"{{ end }} -gas-fee 1000000ugnot -gas-wanted 5000000 -send "" <span data-role="help-code-address">ADDRESS</span> > call.tx
gnokey sign -tx-path call.tx -chainid "{{ $.ChainId }}" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER <span data-role="help-code-address">ADDRESS</span>
gnokey broadcast -remote "{{ $.Remote }}" call.tx</span></code></pre>
</div>
Expand Down
11 changes: 6 additions & 5 deletions gno.land/pkg/gnoweb/components/view_help.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package components
import (
"html/template"

"github.com/gnolang/gno/gno.land/pkg/sdk/vm" // for error types
// for error types
"github.com/gnolang/gno/gnovm/pkg/doc"
)

const HelpViewType ViewType = "help-view"
Expand All @@ -14,7 +15,7 @@ type HelpData struct {
SelectedArgs map[string]string

RealmName string
Functions []vm.FunctionSignature
Functions []*doc.JSONFunc
ChainId string
Remote string
PkgPath string
Expand All @@ -37,7 +38,7 @@ type helpViewParams struct {
}

func registerHelpFuncs(funcs template.FuncMap) {
funcs["getSelectedArgValue"] = func(data HelpData, param vm.NamedType) (string, error) {
funcs["getSelectedArgValue"] = func(data HelpData, param *doc.JSONField) (string, error) {
if data.SelectedArgs == nil {
return "", nil
}
Expand All @@ -53,7 +54,7 @@ func HelpView(data HelpData) *View {
}

for i, fn := range data.Functions {
sig := fn.FuncName + "("
sig := fn.Name + "("
for j, param := range fn.Params {
if j > 0 {
sig += ", "
Expand All @@ -63,7 +64,7 @@ func HelpView(data HelpData) *View {
sig += ")"

tocData.Items[i] = HelpTocItem{
Link: "#func-" + fn.FuncName,
Link: "#func-" + fn.Name,
Text: sig,
}
}
Expand Down
24 changes: 19 additions & 5 deletions gno.land/pkg/gnoweb/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

"github.com/gnolang/gno/gno.land/pkg/gnoweb/components"
"github.com/gnolang/gno/gno.land/pkg/gnoweb/weburl"
"github.com/gnolang/gno/gno.land/pkg/sdk/vm" // For error types
"github.com/gnolang/gno/gnovm/pkg/doc"
)

// StaticMetadata holds static configuration for a web handler.
Expand Down Expand Up @@ -196,30 +196,44 @@ func (h *WebHandler) GetRealmView(gnourl *weburl.GnoURL, indexData *components.I
}

func (h *WebHandler) GetHelpView(gnourl *weburl.GnoURL, indexData *components.IndexData) (int, *components.View) {
fsigs, err := h.Client.Functions(gnourl.Path)
jdoc, err := h.Client.Doc(gnourl.Path)
if err != nil {
h.Logger.Error("unable to fetch path functions", "error", err)
h.Logger.Error("unable to fetch qdoc", "error", err)

Check warning on line 201 in gno.land/pkg/gnoweb/handler.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoweb/handler.go#L201

Added line #L201 was not covered by tests
return GetClientErrorStatusPage(gnourl, err)
}

// HTML Head metadata
indexData.HeadData.Title = h.Static.Domain + " - " + gnourl.Path + " docs and realm interactions"
indexData.Description = "Read the Realm " + gnourl.Path + " functions an interact with them from " + h.Static.Domain + "."

// Get public non-method funcs
fsigs := []*doc.JSONFunc{}
for _, fun := range jdoc.Funcs {
if fun.Type != "" {
continue

Check warning on line 213 in gno.land/pkg/gnoweb/handler.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoweb/handler.go#L213

Added line #L213 was not covered by tests
}
first := fun.Name[0:1]
if strings.ToUpper(first) != first {
continue
}

fsigs = append(fsigs, fun)
}

// Get selected function
selArgs := make(map[string]string)
selFn := gnourl.WebQuery.Get("func")
if selFn != "" {
for _, fn := range fsigs {
if selFn != fn.FuncName {
if selFn != fn.Name {
continue
}

for _, param := range fn.Params {
selArgs[param.Name] = gnourl.WebQuery.Get(param.Name)
}

fsigs = []vm.FunctionSignature{fn}
fsigs = []*doc.JSONFunc{fn}
break
}
}
Expand Down
10 changes: 5 additions & 5 deletions gno.land/pkg/gnoweb/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"testing"

"github.com/gnolang/gno/gno.land/pkg/gnoweb"
"github.com/gnolang/gno/gno.land/pkg/sdk/vm"
"github.com/gnolang/gno/gnovm/pkg/doc"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand All @@ -34,13 +34,13 @@ func TestWebHandler_Get(t *testing.T) {
"gno.mod": `module example.com/r/mock/path`,
"LicEnse": `my super license`,
},
Functions: []vm.FunctionSignature{
{FuncName: "SuperRenderFunction", Params: []vm.NamedType{
Functions: []*doc.JSONFunc{
{Name: "SuperRenderFunction", Params: []*doc.JSONField{
{Name: "my_super_arg", Type: "string"},
}},
{
FuncName: "Render", Params: []vm.NamedType{{Name: "path", Type: "string"}},
Results: []vm.NamedType{{Name: "", Type: "string"}},
Name: "Render", Params: []*doc.JSONField{{Name: "path", Type: "string"}},
Results: []*doc.JSONField{{Name: "", Type: "string"}},
},
},
}
Expand Down
6 changes: 3 additions & 3 deletions gno.land/pkg/gnoweb/webclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"io"

md "github.com/gnolang/gno/gno.land/pkg/gnoweb/markdown"
"github.com/gnolang/gno/gno.land/pkg/sdk/vm"
"github.com/gnolang/gno/gnovm/pkg/doc"
)

var (
Expand Down Expand Up @@ -43,9 +43,9 @@ type WebClient interface {
// file's content is safely handled and formatted.
SourceFile(w io.Writer, pkgPath, fileName string) (*FileMeta, error)

// Functions retrieves a list of function signatures from a
// Doc retrieves the JSON doc suitable for printing from a
// specified package path.
Functions(path string) ([]vm.FunctionSignature, error)
Doc(path string) (*doc.JSONDocumentation, error)

// Sources lists all source files available in a specified
// package path.
Expand Down
19 changes: 10 additions & 9 deletions gno.land/pkg/gnoweb/webclient_html.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/alecthomas/chroma/v2/styles"
md "github.com/gnolang/gno/gno.land/pkg/gnoweb/markdown"
"github.com/gnolang/gno/gno.land/pkg/sdk/vm" // for error types
"github.com/gnolang/gno/gnovm/pkg/doc"
"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/bft/rpc/client"
"github.com/yuin/goldmark"
Expand Down Expand Up @@ -90,24 +91,24 @@ func NewHTMLClient(log *slog.Logger, cfg *HTMLWebClientConfig) *HTMLWebClient {
}
}

// Functions retrieves a list of function signatures from a
// Doc retrieves the JSON doc suitable for printing from a
// specified package path.
func (s *HTMLWebClient) Functions(pkgPath string) ([]vm.FunctionSignature, error) {
const qpath = "vm/qfuncs"
func (s *HTMLWebClient) Doc(pkgPath string) (*doc.JSONDocumentation, error) {
const qpath = "vm/qdoc"

args := fmt.Sprintf("%s/%s", s.domain, strings.Trim(pkgPath, "/"))
res, err := s.query(qpath, []byte(args))
if err != nil {
return nil, fmt.Errorf("unable to query func list: %w", err)
return nil, fmt.Errorf("unable to query qdoc: %w", err)

Check warning on line 102 in gno.land/pkg/gnoweb/webclient_html.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoweb/webclient_html.go#L102

Added line #L102 was not covered by tests
}

var fsigs vm.FunctionSignatures
if err := amino.UnmarshalJSON(res, &fsigs); err != nil {
s.logger.Warn("unable to unmarshal function signatures, client is probably outdated")
return nil, fmt.Errorf("unable to unmarshal function signatures: %w", err)
jdoc := &doc.JSONDocumentation{}
if err := amino.UnmarshalJSON(res, jdoc); err != nil {
s.logger.Warn("unable to unmarshal qdoc, client is probably outdated")
return nil, fmt.Errorf("unable to unmarshal qdoc: %w", err)

Check warning on line 108 in gno.land/pkg/gnoweb/webclient_html.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoweb/webclient_html.go#L107-L108

Added lines #L107 - L108 were not covered by tests
}

return fsigs, nil
return jdoc, nil
}

// SourceFile fetches and writes the source file from a given
Expand Down
12 changes: 6 additions & 6 deletions gno.land/pkg/gnoweb/webclient_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import (
"io"
"sort"

"github.com/gnolang/gno/gno.land/pkg/sdk/vm"
"github.com/gnolang/gno/gnovm/pkg/doc"
)

// MockPackage represents a mock package with files and function signatures.
type MockPackage struct {
Path string
Domain string
Files map[string]string // filename -> body
Functions []vm.FunctionSignature
Functions []*doc.JSONFunc
}

// MockWebClient is a mock implementation of the Client interface.
Expand Down Expand Up @@ -67,14 +67,14 @@ func (m *MockWebClient) SourceFile(w io.Writer, pkgPath, fileName string) (*File
return nil, ErrClientPathNotFound
}

// Functions simulates retrieving function signatures from a package.
func (m *MockWebClient) Functions(path string) ([]vm.FunctionSignature, error) {
// Doc simulates retrieving function docs from a package.
func (m *MockWebClient) Doc(path string) (*doc.JSONDocumentation, error) {
pkg, exists := m.Packages[path]
if !exists {
return nil, ErrClientPathNotFound
}

return pkg.Functions, nil
return &doc.JSONDocumentation{Funcs: pkg.Functions}, nil
}

// Sources simulates listing all source files in a package.
Expand All @@ -101,7 +101,7 @@ func pkgHasRender(pkg *MockPackage) bool {
}

for _, fn := range pkg.Functions {
if fn.FuncName == "Render" &&
if fn.Name == "Render" &&
len(fn.Params) == 1 &&
len(fn.Results) == 1 &&
fn.Params[0].Type == "string" &&
Expand Down

0 comments on commit c89cb03

Please sign in to comment.