context.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package pongo2
  2. import (
  3. "fmt"
  4. "regexp"
  5. "errors"
  6. )
  7. var reIdentifiers = regexp.MustCompile("^[a-zA-Z0-9_]+$")
  8. var autoescape = true
  9. func SetAutoescape(newValue bool) {
  10. autoescape = newValue
  11. }
  12. // A Context type provides constants, variables, instances or functions to a template.
  13. //
  14. // pongo2 automatically provides meta-information or functions through the "pongo2"-key.
  15. // Currently, context["pongo2"] contains the following keys:
  16. // 1. version: returns the version string
  17. //
  18. // Template examples for accessing items from your context:
  19. // {{ myconstant }}
  20. // {{ myfunc("test", 42) }}
  21. // {{ user.name }}
  22. // {{ pongo2.version }}
  23. type Context map[string]interface{}
  24. func (c Context) checkForValidIdentifiers() *Error {
  25. for k, v := range c {
  26. if !reIdentifiers.MatchString(k) {
  27. return &Error{
  28. Sender: "checkForValidIdentifiers",
  29. OrigError: fmt.Errorf("context-key '%s' (value: '%+v') is not a valid identifier", k, v),
  30. }
  31. }
  32. }
  33. return nil
  34. }
  35. // Update updates this context with the key/value-pairs from another context.
  36. func (c Context) Update(other Context) Context {
  37. for k, v := range other {
  38. c[k] = v
  39. }
  40. return c
  41. }
  42. // ExecutionContext contains all data important for the current rendering state.
  43. //
  44. // If you're writing a custom tag, your tag's Execute()-function will
  45. // have access to the ExecutionContext. This struct stores anything
  46. // about the current rendering process's Context including
  47. // the Context provided by the user (field Public).
  48. // You can safely use the Private context to provide data to the user's
  49. // template (like a 'forloop'-information). The Shared-context is used
  50. // to share data between tags. All ExecutionContexts share this context.
  51. //
  52. // Please be careful when accessing the Public data.
  53. // PLEASE DO NOT MODIFY THE PUBLIC CONTEXT (read-only).
  54. //
  55. // To create your own execution context within tags, use the
  56. // NewChildExecutionContext(parent) function.
  57. type ExecutionContext struct {
  58. template *Template
  59. Autoescape bool
  60. Public Context
  61. Private Context
  62. Shared Context
  63. }
  64. var pongo2MetaContext = Context{
  65. "version": Version,
  66. }
  67. func newExecutionContext(tpl *Template, ctx Context) *ExecutionContext {
  68. privateCtx := make(Context)
  69. // Make the pongo2-related funcs/vars available to the context
  70. privateCtx["pongo2"] = pongo2MetaContext
  71. return &ExecutionContext{
  72. template: tpl,
  73. Public: ctx,
  74. Private: privateCtx,
  75. Autoescape: autoescape,
  76. }
  77. }
  78. func NewChildExecutionContext(parent *ExecutionContext) *ExecutionContext {
  79. newctx := &ExecutionContext{
  80. template: parent.template,
  81. Public: parent.Public,
  82. Private: make(Context),
  83. Autoescape: parent.Autoescape,
  84. }
  85. newctx.Shared = parent.Shared
  86. // Copy all existing private items
  87. newctx.Private.Update(parent.Private)
  88. return newctx
  89. }
  90. func (ctx *ExecutionContext) Error(msg string, token *Token) *Error {
  91. return ctx.OrigError(errors.New(msg), token)
  92. }
  93. func (ctx *ExecutionContext) OrigError(err error, token *Token) *Error {
  94. filename := ctx.template.name
  95. var line, col int
  96. if token != nil {
  97. // No tokens available
  98. // TODO: Add location (from where?)
  99. filename = token.Filename
  100. line = token.Line
  101. col = token.Col
  102. }
  103. return &Error{
  104. Template: ctx.template,
  105. Filename: filename,
  106. Line: line,
  107. Column: col,
  108. Token: token,
  109. Sender: "execution",
  110. OrigError: err,
  111. }
  112. }
  113. func (ctx *ExecutionContext) Logf(format string, args ...interface{}) {
  114. ctx.template.set.logf(format, args...)
  115. }