Skip to content

Feature Request: Shared template context between prompts and args sections #106

@davidovich

Description

@davidovich

Problem

Currently, template variables declared in the prompts section (using {{ $var := ... }}) are not accessible in the args section. Each section gets its own template execution context, so computed values must be re-computed or accessed via promptValue/flagValue.

This leads to verbose and repetitive code when you want to compute a value once and use it in multiple places.

Current Workaround

'kv [bucket]':
  flags:
    context:
      effect: "{{ .flag }}"
  prompts: |
    {{ $flagCtx := flagValue "context" }}
    {{ $envCtx := env "NATS_CONTEXT" }}
    {{ if not $flagCtx }}
      {{ if $envCtx }}
        {{ prompt "ctx" "NATS context:" $envCtx }}
      {{ else }}
        {{ $contexts := splitList "\n" (run "bash" `nats context ls`) }}
        {{ prompt "ctx" "NATS context:" $contexts }}
      {{ end }}
    {{ end }}
    {{ $ctx := or $flagCtx (promptValue "ctx") }}  # Can't use this in args!
    {{ prompt "search" "Search:" "" }}
    {{ $keys := run "bash" (printf "nats --context=%s kv ls %s" $ctx (arg 0)) }}
    {{ prompt "key" "Select key:" (splitList "\n" $keys) }}
  args:
    - |
      # Must re-compute $ctx here because template variables don't persist
      CTX="{{ or (flagValue "context") (promptValue "ctx") }}"
      KEY="{{ promptValue "key" }}"
      nats --context="$CTX" kv get bucket "$KEY"

Proposed Solution

Add set and get template functions that store/retrieve values in a shared context that persists across prompts, args, and cmd sections.

Example Usage

'kv [bucket]':
  flags:
    context:
      effect: "{{ .flag }}"
  prompts: |
    {{ $flagCtx := flagValue "context" }}
    {{ $envCtx := env "NATS_CONTEXT" }}
    {{ if $flagCtx }}
      {{ set "ctx" $flagCtx }}
    {{ else if $envCtx }}
      {{ set "ctx" (prompt "ctx" "NATS context:" $envCtx) }}
    {{ else }}
      {{ $contexts := splitList "\n" (run "bash" `nats context ls`) }}
      {{ set "ctx" (prompt "ctx" "NATS context:" $contexts) }}
    {{ end }}
    {{ prompt "search" "Search:" "" }}
    {{ $keys := run "bash" (printf "nats --context=%s kv ls %s" (get "ctx") (arg 0)) }}
    {{ prompt "key" "Select key:" (splitList "\n" $keys) }}
  args:
    - |
      CTX="{{ get "ctx" }}"
      KEY="{{ promptValue "key" }}"
      nats --context="$CTX" kv get bucket "$KEY"

Implementation Suggestion

In pkg/summon/driver.go, add a shared state map:

type Driver struct {
    // ... existing fields
    templateState map[string]interface{}  // NEW: shared state across template renders
}

In pkg/summon/template.go, add the functions:

func summonFuncMap(d *Driver) template.FuncMap {
    return template.FuncMap{
        // ... existing functions
        "set": func(key string, value interface{}) string {
            if d.templateState == nil {
                d.templateState = make(map[string]interface{})
            }
            d.templateState[key] = value
            return ""  // Return empty string so it doesn't output anything
        },
        "get": func(key string) interface{} {
            if d.templateState == nil {
                return ""
            }
            return d.templateState[key]
        },
    }
}

Benefits

  1. DRY: Compute values once, use everywhere
  2. Cleaner templates: Less repetition of or (flagValue "x") (promptValue "x") patterns
  3. Preamble pattern: Could enable a preamble section for setup logic that runs before prompts
  4. Backward compatible: Existing configs continue to work unchanged

Alternatives Considered

  1. Merge prompts and args into single template execution: Would break existing behavior where prompts run interactively before args are rendered.

  2. Use promptValue for everything: Works but requires calling prompt even when you don't want user interaction, and doesn't work when the value comes from a flag.

Related

This would complement the existing promptValue function which already provides a form of shared state (but only for prompt results).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions