github.com/goradd/got@v1.1.1/README.md (about) 1 [![Go Reference](https://pkg.go.dev/badge/github.com/goradd/got.svg)](https://pkg.go.dev/github.com/goradd/got) 2 ![Build Status](https://img.shields.io/github/actions/workflow/status/goradd/got/go.yml?branch=main) 3 [![codecov](https://codecov.io/gh/goradd/got/branch/main/graph/badge.svg?token=FHU0NR2N1V)](https://codecov.io/gh/goradd/got) 4 [![Go Report Card](https://goreportcard.com/badge/github.com/goradd/got)](https://goreportcard.com/report/github.com/goradd/got) 5 [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go#template-engines) 6 # GoT 7 8 GoT (short for Go Templates) is a flexible template engine that generates Go code. 9 10 This approach creates extremely fast templates. It also gives you much more freedom than Go's template 11 engine, since at any time you can just switch to Go code to do what you want. 12 13 GoT has: 14 - Mustache-like syntax similar to Go's built-in template engine 15 - The ability to define new tags, so you can create your own template syntax 16 - Include files, so you can create a library of tags and templates 17 18 The GoT syntax is easy to learn. Get started in minutes. 19 20 - [Features](#features) 21 - [Installation](#installation) 22 - [Command Line Usage](#command-line-usage) 23 - [Basic Syntax](#basic-syntax) 24 - [Template Syntax](#template-syntax) 25 - [License](#license) 26 - [Acknowledgements](#acknowledgements) 27 28 ## Features 29 30 - **High performance**. Since the resulting template is go code, your template will be compiled to fast 31 machine code. 32 - **Easy to use**. The templates themselves are embedded into your go code. The template language is pretty 33 simple and you can do a lot with only a few tags. You can switch into and out of go code at will. Tags are 34 Mustache-like, so similar to Go's template engine. 35 - **Flexible**. The template language makes very few assumptions about the go environment it is in. Most other 36 template engines require you to call the template with a specific function signature. **GoT** gives you the 37 freedom to call your templates how you want. 38 - **Translation Support**. You can specify that you want to send your strings to a translator before 39 output. 40 - **Error Support**. You can call into go code that returns errors, and have the template stop at that 41 point and return an error to your wrapper function. The template will output its text up to that point, 42 allowing you to easily see where in the template the error occurred. 43 - **Include Files**. Templates can include other templates. You can specify 44 a list of search directories for the include files, allowing you to put include files in a variety of 45 locations, and have include files in one directory that override another directory. 46 - **Custom Tags**. You can define named fragments that you can include at will, 47 and you can define these fragments in include files. To use these fragments, you just 48 use the name of the fragment as the tag. This essentially gives you the ability to create your own template 49 language. When you use a custom tag, you can also include parameters that will 50 replace placeholders in your fragment, giving you even more power to your custom tags. 51 - **Error Reporting**. Errors in your template files are identified by line and character 52 number. No need to guess where the error is. 53 54 Using other go libraries, you can have your templates compile when they are changed, 55 use buffer pools to increase performance, and more. Since the 56 templates become go code, you can do what you want. 57 58 59 ## Installation 60 61 ```shell 62 go install github.com/goradd/got/got@latest 63 ``` 64 65 We also recommend installing `goimports` 66 and passing GoT the -i flag on the command line. That will format your Go code and 67 fix up the import lines of any generated go files. 68 ```shell 69 go install golang.org/x/tools/cmd/goimports@latest 70 ``` 71 72 ## Command Line Usage 73 74 ```shell 75 got [options] [files] 76 77 options: 78 - o: The output directory. If not specified, files will be output at the same 79 location as the corresponding template. 80 - t fileType: If set, will process all files in the current directory with this suffix. 81 If not set, you must specify the files at the end of the command line. 82 - i: Run `goimports` on the output files, rather than `go fmt` 83 - I directories and/or files: A list of directories and/or files. 84 If a directory, it is used as the search path for include files. 85 If a file, it is automatically added to the front of every file that is processed. 86 Directories are searched in the order specified and first matching file will be used. 87 It will always look in the current directory last unless the current directory 88 is specified in the list in another location. Relative paths must start with a dot (.) 89 or double-dot (..). Directories can start with a module name, and based on the 90 current directory, the correct go.mod file will be searched to know where to look 91 for include files. 92 - d directory: When using the -t option, will specify a directory to search. 93 - v verbose: Prints information about files being processed 94 - r recursive: Recursively processes directories. Used with the -t option and possibley -d. 95 - f force: Output files are normally not over-written if they are newer than the input file. 96 This otpion will force all input files to over-write the output files. 97 ``` 98 If a path described above starts with a module path, the actual disk location 99 will be substituted. 100 101 examples: 102 ```shell 103 got -t got -i -o ../templates 104 got -I .;../tmpl;example.com/projectTemplates file1.tmpl file2.tmpl 105 ``` 106 107 ## Basic Syntax 108 Template tags start with `{{` and end with `}}`. 109 110 A template starts in go mode. To send simple text or html to output, surround the text with `{{` and `}}` tags 111 with a space or newline separating the tags from the surrounding text. Inside the brackets you will be in 112 text mode. 113 114 In the resulting Go code, text will get written to output by calling: 115 116 ```_, err = io.WriteString(_w, <text>)``` 117 118 GoT assumes that the `_w` variable 119 is available and satisfies the io.Writer interface 120 and optionally the io.StringWriter interface. 121 Usually you would do this by declaring a function at the top of your template that looks like this: 122 123 ``` func f(_w io.Writer) (err error) ``` 124 125 After compiling the template output together with your program, you call 126 this function to get the template output. 127 128 At a minimum, you will need to import the "io" package into the file with your template function. 129 Depending on what tags you use, you might need to add 130 additional items to your import list. Those are mentioned below with each tag. 131 132 ### Example 133 Here is how you might create a very basic template. For purposes of this example, we will call the file 134 `example.got` and put it in the `template` package, but you can name the file and package whatever you want. 135 ``` 136 package template 137 138 import "io" 139 140 func OutTemplate(_w io.Writer) (err error) { 141 var world string = "World" 142 {{ 143 <p> 144 Hello {{world}}! 145 </p> 146 }} 147 return // make sure the error gets returned 148 } 149 ``` 150 151 To compile this template, call GoT: 152 ```shell 153 got example.got 154 ``` 155 156 This will create an `example.go` file, which you include in your program. You then can call the function 157 you declared: 158 ```go 159 package main 160 161 import ( 162 "io" 163 "os" 164 "mypath/template" 165 ) 166 167 func main() { 168 _ = template.OutTemplate(os.Stdout) 169 } 170 ``` 171 172 This simple example shows a mix of go code and template syntax in the same file. Using GoT's include files, 173 you can separate your go code from template code. 174 175 ## Template Syntax 176 177 The following describes how the various open tags work. Most tags end with a ` }}`, unless otherwise indicated. 178 Many tags have a short and a long form. Using the long form does not impact performance, its just there 179 to help your templates have some human readable context to them. 180 181 ### Static Text 182 {{<space or newline> Begin to output text as written. 183 {{! or {{esc Html escape the text. Html reserved characters, like < or > are 184 turned into html entities first. This happens when the template is 185 compiled, so that when the template runs, the string will already 186 be escaped. 187 {{h or {{html Html escape and html format double-newlines into <p> tags. 188 {{t or {{translate Send the text to a translator 189 190 191 The `{{!` tag requires you to import the standard html package. `{{h` requires both the html and strings packages. 192 193 `{{t` will wrap the static text with a call to t.Translate(). Its up to you to define this object and make it available to the template. The 194 translation will happen during runtime of your program. We hope that a future implementation of GoT could 195 have an option to send these strings to an i18n file to make it easy to send these to a translation service. 196 197 #### Example 198 In this example file, note that we start in Go mode, copying the text verbatim to the template file. 199 ``` 200 package test 201 202 import ( 203 "io" 204 "fmt" 205 ) 206 207 type Translater interface { 208 Translate(string) string 209 } 210 211 func staticTest(_w io.Writer) { 212 {{ 213 <p> 214 {{! Escaped html < }} 215 </p> 216 }} 217 218 {{h 219 This is text that is both escaped. 220 221 And has html paragraphs inserted. 222 }} 223 224 } 225 226 func translateTest(t Translater, buf *bytes.Buffer) { 227 228 {{t Translate me to some language }} 229 230 {{!t Translate & escape me > }} 231 232 } 233 ``` 234 235 ### Switching Between Go Mode and Template Mode 236 From within any static text context described above you can switch into go context by using: 237 238 {{g or {{go Change to straight go code. 239 240 Go code is copied verbatim to the final template. Use it to set up loops, call special processing functions, etc. 241 End go mode using the `}}` closing tag. You can also include any other GoT tag inside of Go mode, 242 meaning you can nest Go mode and all the other template tags. 243 244 #### Example 245 ``` 246 // We start a template in Go mode. The next tag switches to text mode, and then nests 247 // switching back to go mode. 248 {{ Here 249 {{go 250 io.WriteString(_w, "is") 251 }} some code wrapping text escaping to go. }} 252 ``` 253 254 ### Dynamic Text 255 The following tags are designed to surround go code that returns a go value. The value will be 256 converted to a string and sent to the buf. The go code could be a static value, or a function 257 that returns a value. 258 259 Tag Description Example 260 261 {{=, {{s, or {{string Send a go string to output {{= fmt.Sprintf("I am %s", sVar) }} 262 {{i or {{int Send an int to output {{ The value is: {{i iVar }} }} 263 {{u or {{uint Send an unsigned Integer {{ The value is: {{u uVar }} }} 264 {{f or {{float Send a floating point number {{ The value is: {{f fVar }} }} 265 {{b or {{bool A boolean ("true" or "false") {{ The value is: {{b bVar }} }} 266 {{w or {{bytes A byte slice {{ The value is: {{w byteSliceVar }} }} 267 {{v or {{stringer or Send any value that implements {{ The value is: {{objVar}} }} 268 {{goIdentifier}} the Stringer interface. 269 270 271 This last tag can be slower than the other tags since it uses fmt.Sprint() internally, 272 so if this is a heavily used template, avoid it. Usually you will not notice a speed difference though, 273 and the third option can be very convenient. This third option is simply any go variable surrounded by mustaches 274 with no spaces. 275 276 The i, u, and f tags use the strconv package, so be sure to include that in your template. 277 278 #### Escaping Dynamic Text 279 280 Some value types potentially could produce html reserved characters. The following tags will html escape 281 the output. 282 283 {{!=, {{!s or {{!string HTML escape a go string 284 {{!w or {{!bytes HTML escape a byte slice 285 {{!v or {{!stringer HTML escape a Stringer 286 {{!h Escape a go string and html format breaks and newlines 287 288 These tags require you to import the "html" package. The `{{!h` tag also requires the "strings" package. 289 290 #### Capturing Errors 291 292 These tags will receive two results, the first a value to send to output, and the second an error 293 type. If the error is not nil, processing will stop and the error will be returned by the template function. Therefore, these 294 tags expect to be included in a function that returns an error. Any template text 295 processed so far will still be sent to the output buffer. 296 297 {{=e, {{se, {{string,err Output a go string, capturing an error 298 {{!=e, {{!se, {{!string,err HTML escape a go string and capture an error 299 {{ie or {{int,err Output a go int and capture an error 300 {{ue or {{uint,err Output a go uint and capture an error 301 {{fe or {{float,err Output a go float64 and capture an error 302 {{be or {{bool,err Output a bool ("true" or "false") and capture an error 303 {{we, {{bytes,err Output a byte slice and capture an error 304 {{!we or {{!bytes,err HTML escape a byte slice and capture an error 305 {{ve, {{stringer,err Output a Stringer and capture an error 306 {{!ve or {{!stringer,err HTML escape a Stringer and capture an error 307 {{e, or {{err Execute go code that returns an error, and stop if the error is not nil 308 309 ##### Example 310 ```go 311 func Tester(s string) (out string, err error) { 312 if s == "bad" { 313 err = errors.New("This is bad.") 314 } 315 return s 316 } 317 318 func OutTemplate(toPrint string, buf bytes.Buffer) error { 319 {{=e Tester(toPrint) }} 320 } 321 ``` 322 323 ### Include Files 324 #### Include a GoT source file 325 326 {{: "fileName" }} or 327 {{include "fileName" }} Inserts the given file name into the template. 328 329 The included file will start in whatever mode the receiving template is in, as if the text was inserted 330 at that spot, so if the include tags are put inside of go code, the included file will start in go mode. 331 The file will then be processed like any other GoT file. Include files can refer to other include files, 332 and so are recursive. 333 334 Include files are searched for in the current directory, and in the list of include directories provided 335 on the command line by the -I option. 336 337 Example: `{{: "myTemplate.inc" }}` 338 339 #### Include a text file 340 341 {{:! "fileName" }} or Inserts the given file name into the template 342 {{includeEscaped "fileName" }} and html escapes it. 343 {{:h "fileName" }} or Inserts the given file name into the template, 344 {{includeAsHtml "fileName" }} html escapes it, and converts newlines into html breaks. 345 346 Use `{{:!` to include a file that you surround with a `<pre>` tag to include a text file 347 and have it appear in an html document looking the same. Use `{{:h` to include a file 348 without the `<pre>` tags, but if the file uses extra spaces for indent, those spaces will 349 not indent in the html. These kinds of include files will not be searched for GoT commands. 350 351 ### Defined Fragments 352 353 Defined fragments start a block of text that can be included later in a template. The included text will 354 be sent as is, and then processed in whatever mode the template processor is in, as if that text was simply 355 inserted into the template at that spot. You can include the `{{` or `{{g` tags inside of the fragment to 356 force the processor into the text or go modes if needed. The fragment can be defined 357 any time before it is included, including being defined in other include files. 358 359 You can add optional parameters 360 to a fragment that will be substituted for placeholders when the fragment is used. You can have up to 9 361 placeholders ($1 - $9). Parameters should be separated by commas, and can be surrounded by quotes if needed 362 to have a parameter that has a quote or comma in it. 363 364 {{< fragName }} or {{define fragName }} Start a block called "fragName". 365 {{< fragName <count>}} or Start a block called "fragName" that will 366 {{define fragName <count>}} have <count> parameters. 367 {{> fragName param1,param2,...}} or Substitute this tag for the given defined fragment. 368 {{put fragName param1,param2,...}} or 369 {{fragName param1,param2,...}} 370 {{>? fragName param1,param2,...}} or Substitute this tag for the given defined fragment, 371 {{put? fragName param1,param2,...}} but if the fragment is not defined, leave blank. 372 373 374 If you attempt to use a fragment that was not previously defined, GoT will panic and stop compiling, 375 unless you use {{>? or {{put? to include the fragment. 376 377 param1, param2, ... are optional parameters that will be substituted for $1, $2, ... in the defined fragment. 378 If a parameter is not included when using a fragment, an empty value will be substituted for the parameter in the fragment. 379 380 The fragment name is NOT surrounded by quotes, and cannot contain any whitespace in the name. Blocks are ended with a 381 `{{end fragName}}` tag. The end tag must be just like that, with no spaces after the fragName. 382 383 The following fragments are predefined: 384 * `{{templatePath}}` is the full path of the template file being processed 385 * `{{templateName}}` is the base name of the template file being processed, including any extensions 386 * `{{templateRoot}}` is the base name of the template file being processed without any extensions 387 * `{{templateParent}}` is the directory name of the template file being processed, without the preceeding path 388 * `{{outPath}}` is the full path of the output file being written 389 * `{{outName}}` is the base name of the output file being written, including any extensions 390 * `{{outRoot}}` is the base name of the output file being written without any extensions 391 * `{{outParent}}` is the directory name of the output file being written, without the preceeding path 392 393 Note that if you are using these in an included file, these will refer to the parent file. Multiple 394 levels of includes will return the information for the top level file being processed. 395 396 #### Example 397 ``` 398 399 {{< hFrag }} 400 <p> 401 This is my html body. 402 </p> 403 {{end hFrag}} 404 405 {{< writeMe 2}} 406 {{// The g tag here forces us to process the text as go code, 407 no matter where the fragment is included }} 408 {{g 409 if "$2" != "" { 410 io.WriteString(_w, "$1") 411 } 412 }} 413 {{end writeMe}} 414 415 416 func OutTemplate(_w io.Writer) (err error) { 417 {{ 418 <html> 419 <body> 420 {{> hFrag }} 421 </body> 422 </html> 423 }} 424 425 {{writeMe "Help Me!", a}} 426 {{writeMe "Help Me!", }} 427 return 428 } 429 ``` 430 431 ### Comment Tags 432 433 {{# or {{// Comment the template. This is removed from the compiled template. 434 435 These tags and anything enclosed in them is removed from the compiled template. 436 437 ### Go Block Tags 438 439 {{if <go condition>}}<text block>{{if}} 440 A convenience tag for surrounding text with a go "if" statement. 441 {{if <go condition>}}<text block>{{else}}<text block>{{if}} 442 Go "if" and "else" statement. 443 {{if <go condition>}}<text block>{{elseif <go condition>}}<text block>{{if}} 444 Go "if" and "else if" statement. 445 {{for <go condition and optional range statement>}}<text block>{{for}} 446 A convenience tag for surrounding text with a go "for" statement. 447 448 These tags are substitutes for switching into GO mode and using a `for` or `if` statements. 449 `<text block>` will be in text mode to begin with, so that whatever you put there 450 will be output, but you can switch to go mode if needed. 451 452 ####Example 453 454 ``` 455 {{ 456 {{for num,item := range items }} 457 <p>Item {{num}} is {{item}}</p> 458 {{for}} 459 }} 460 ``` 461 ### Join Tags 462 463 {{join <slice>, <string>}}<text block>{{join}} Joins the items of a slice with a string. 464 465 Join will output the `<text block>` for each item of `<slice>`. Within `<text block>` the variable 466 `_i` will be an integer representing the index of the slice item, and `_j` will be the 467 item itself. `<text block>` starts in text mode, but you can put GoT commands in it. `<string>` will be output 468 between the output of each item, creating an effect similar to joining a slice of strings. 469 470 471 ####Example 472 473 ``` 474 {{g 475 items := []string{"a", "b", "c"} 476 }} 477 {{join items,", "}} 478 {{ {{_i}} = {{_j}} }} 479 {{join}} 480 ``` 481 482 483 ### Strict Text Block Tag 484 485 From within most of the GoT tags, you can insert another GoT tag. GoT will be looking for these 486 as it processes text. If you would like to turn off GoT's processing to output text 487 that is not processed by GoT, you can use: 488 489 {{begin *endTag*}} Starts a strict text block and turns off the GoT parser. 490 491 One thing this is useful for is to use GoT to generate GoT code. 492 End the block with a `{{end *endTag*}}` tag, where `*endTag*` is whatever you specified in the begin tag. 493 There can be no space between the endTag and the final brackets 494 The following example will output the entire second line of code with no changes, 495 including all brackets: 496 497 ``` 498 {{begin mystrict}} 499 {{! This is verbatim code }} 500 {{< all included}} 501 {{end mystrict}} 502 ``` 503 504 ## Bigger Example 505 506 In this example, we will combine multiple files. One, a traditional html template with a place to fill in 507 some body text. Another, a go function declaration that we will use when we want to draw the template. 508 The function will use a traditional web server io.Writer pattern, including the use of a context parameter. 509 Finally, there is an example main.go illustrating how our template function would be called. 510 511 ### index.html 512 513 ```html 514 <!DOCTYPE html> 515 <html> 516 <head> 517 <meta charset="utf-8"> 518 </head> 519 520 <body> 521 {{# The tag below declares that we want to substitute a named 522 fragment that is declared elsewhere }} 523 {{put body }} 524 </body> 525 </html> 526 ``` 527 528 ### template.got 529 530 ``` 531 package main 532 533 import { 534 "context" 535 "bytes" 536 } 537 538 539 func writeTemplate(ctx context.Context, buf *bytes.Buffer) { 540 541 {{# Define the body that will be inserted into the template }} 542 {{< body }} 543 <p> 544 The caller is: {{=s ctx.Value("caller") }} 545 </p> 546 {{end body}} 547 548 {{# include the html template. Since the template is html, 549 we need to enter static text mode first }} 550 {{ 551 {{include "index.html"}} 552 }} 553 554 } 555 ``` 556 557 ### main.go 558 559 ```html 560 type myHandler struct {} 561 562 func (h myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 563 ctx := context.WithValue(r.Context(), "caller", r.Referer()) 564 writeTemplate(ctx, w) // call the GoT template 565 } 566 567 568 func main() { 569 var r myHandler 570 var err error 571 572 *local = "0.0.0.0:8000" 573 574 err = http.ListenAndServe(*local, r) 575 576 if err != nil { 577 fmt.Println(err) 578 } 579 } 580 ``` 581 582 To compile the template: 583 584 ```shell 585 got template.got 586 ``` 587 588 Build your application and go to `http://localhost:8000` in your browser, to see your results 589 590 ## License 591 GoT is licensed under the MIT License. 592 593 ## Acknowldgements 594 595 GoT was influenced by: 596 597 - [hero](https://github.com/shiyanhui/hero) 598 - [fasttemplate](https://github.com/valyala/fasttemplate) 599 - [Rob Pike's Lexing/Parsing Talk](https://www.youtube.com/watch?v=HxaD_trXwRE) 600 601 ## Syntax Changes 602 603 ###v0.10.0 604 This was a major rewrite with the following changes: 605 - defined fragments end with {{end fragName}} tags, rather than {{end}} tags 606 - {{else if ...}} is now {{elseif ...}} 607 - {{join }} tag will join items with a string 608 - The backup tag {{- has been removed 609 - Reorganized the lexer and parser to be easier to debug 610 - Added many more unit tests. Code coverage > 90%. 611 - The output is sent to an io.Writer called _w. This allows more flexible use of the templates, and the ability to wrap them with middleware