loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add `DumpVar` helper function to help debugging templates (#24262)

I guess many contributors might agree that it's really difficult to
write Golang template. The dot syntax `.` confuses everyone: what
variable it is ....

So, we can use a `{{DumpVar .ContextUser}}` to look into every variable
now.


![image](https://user-images.githubusercontent.com/2114189/233692383-f3c8f24d-4465-45f8-839b-b63e00731559.png)


And it can even dump the whole `ctx.Data` by `{{DumpVar .}}`:

```
dumpVar: templates.Vars
{
"AllLangs": [
{
"Lang": "id-ID",
"Name": "Bahasa Indonesia"
},
...
"Context": "[dumped]",
"ContextUser": {
"AllowCreateOrganization": true,
"AllowGitHook": false,
"AllowImportLocal": false,
...
"TemplateLoadTimes": "[func() string]",
"TemplateName": "user/profile",
"Title": "Full'\u003cspan\u003e Name",
"Total": 7,
"UnitActionsGlobalDisabled": false,
"UnitIssuesGlobalDisabled": false,
"UnitProjectsGlobalDisabled": false,
"UnitPullsGlobalDisabled": false,
"UnitWikiGlobalDisabled": false,
"locale": {
"Lang": "en-US",
"LangName": "English",
"Locale": {}
}
...

---------

Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: silverwind <me@silverwind.io>

authored by

wxiaoguang
delvh
silverwind
and committed by
GitHub
c0d10560 3cc87370

+75
+1
modules/templates/helper.go
··· 74 74 "DotEscape": DotEscape, 75 75 "HasPrefix": strings.HasPrefix, 76 76 "EllipsisString": base.EllipsisString, 77 + "DumpVar": dumpVar, 77 78 78 79 "Json": func(in interface{}) string { 79 80 out, err := json.Marshal(in)
+74
modules/templates/util.go
··· 5 5 6 6 import ( 7 7 "fmt" 8 + "html" 9 + "html/template" 8 10 "reflect" 11 + 12 + "code.gitea.io/gitea/modules/json" 13 + "code.gitea.io/gitea/modules/setting" 9 14 ) 10 15 11 16 func dictMerge(base map[string]any, arg any) bool { ··· 45 50 } 46 51 return m, nil 47 52 } 53 + 54 + func dumpVarMarshalable(v any, dumped map[uintptr]bool) (ret any, ok bool) { 55 + if v == nil { 56 + return nil, true 57 + } 58 + e := reflect.ValueOf(v) 59 + for e.Kind() == reflect.Pointer { 60 + e = e.Elem() 61 + } 62 + if e.CanAddr() { 63 + addr := e.UnsafeAddr() 64 + if dumped[addr] { 65 + return "[dumped]", false 66 + } 67 + dumped[addr] = true 68 + defer delete(dumped, addr) 69 + } 70 + switch e.Kind() { 71 + case reflect.Bool, reflect.String, 72 + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 73 + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 74 + reflect.Float32, reflect.Float64: 75 + return e.Interface(), true 76 + case reflect.Struct: 77 + m := map[string]any{} 78 + for i := 0; i < e.NumField(); i++ { 79 + k := e.Type().Field(i).Name 80 + if !e.Type().Field(i).IsExported() { 81 + continue 82 + } 83 + v := e.Field(i).Interface() 84 + m[k], _ = dumpVarMarshalable(v, dumped) 85 + } 86 + return m, true 87 + case reflect.Map: 88 + m := map[string]any{} 89 + for _, k := range e.MapKeys() { 90 + m[k.String()], _ = dumpVarMarshalable(e.MapIndex(k).Interface(), dumped) 91 + } 92 + return m, true 93 + case reflect.Array, reflect.Slice: 94 + var m []any 95 + for i := 0; i < e.Len(); i++ { 96 + v, _ := dumpVarMarshalable(e.Index(i).Interface(), dumped) 97 + m = append(m, v) 98 + } 99 + return m, true 100 + default: 101 + return "[" + reflect.TypeOf(v).String() + "]", false 102 + } 103 + } 104 + 105 + // dumpVar helps to dump a variable in a template, to help debugging and development. 106 + func dumpVar(v any) template.HTML { 107 + if setting.IsProd { 108 + return "<pre>dumpVar: only available in dev mode</pre>" 109 + } 110 + m, ok := dumpVarMarshalable(v, map[uintptr]bool{}) 111 + dumpStr := "" 112 + jsonBytes, err := json.MarshalIndent(m, "", " ") 113 + if err != nil { 114 + dumpStr = fmt.Sprintf("dumpVar: unable to marshal %T: %v", v, err) 115 + } else if ok { 116 + dumpStr = fmt.Sprintf("dumpVar: %T\n%s", v, string(jsonBytes)) 117 + } else { 118 + dumpStr = fmt.Sprintf("dumpVar: unmarshalable %T\n%s", v, string(jsonBytes)) 119 + } 120 + return template.HTML("<pre>" + html.EscapeString(dumpStr) + "</pre>") 121 + }