123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- package engine
- import (
- "bytes"
- "net/http"
- "strconv"
- "strings"
- )
- const (
- // Highlight of errors in the code
- preHighlight = "<font style='color: red !important'>"
- postHighlight = "</font>"
- )
- // Given a lowercase string for the language, return an approprite error page title
- func errorPageTitle(lang string) string {
- switch lang {
- case "":
- return "Error"
- case "css":
- return "CSS Error"
- case "gcss":
- return "GCSS Error"
- case "html":
- return "HTML Error"
- case "jsx":
- return "JSX Error"
- default:
- // string.Title(lang) was used here before, but staticcheck recommends against it
- return lang + " Error"
- }
- }
- // PrettyError serves an informative error page to the user
- // Takes a ResponseWriter, title (can be empty), filename, filebytes, errormessage and
- // programming/scripting/template language (i.e. "lua". Can be empty).
- func (ac *Config) PrettyError(w http.ResponseWriter, req *http.Request, filename string, filebytes []byte, errormessage, lang string) {
- // HTTP status
- // w.WriteHeader(http.StatusInternalServerError)
- w.WriteHeader(http.StatusOK)
- // HTTP content type
- w.Header().Add("Content-Type", "text/html;charset=utf-8")
- var (
- // If there is code to be displayed
- code string
- err error
- )
- // The line that the error refers to, for the case of Lua
- linenr := -1
- if len(filebytes) > 0 {
- if lang == "lua" {
- // If the first line of the error message has two colons, see if the second field is a number
- fields := strings.SplitN(errormessage, ":", 3)
- if len(fields) > 2 {
- // Extract the line number from the error message, if possible
- numberfield := fields[1]
- if strings.Contains(numberfield, "(") {
- numberfield = strings.Split(numberfield, "(")[0]
- }
- linenr, err = strconv.Atoi(numberfield)
- // Subtract one to make it a slice index instead of human-friendly line number
- linenr--
- // Set linenumber to -1 if the conversion failed
- if err != nil {
- linenr = -1
- }
- }
- } else if lang == "amber" {
- // If the error contains "- Line: ", extract the line number
- if strings.Contains(errormessage, "- Line: ") {
- fields := strings.SplitN(errormessage, "- Line: ", 2)
- if strings.Contains(fields[1], ",") {
- numberfields := strings.SplitN(fields[1], ",", 2)
- linenr, err = strconv.Atoi(strings.TrimSpace(numberfields[0]))
- // Subtract one to make it a slice index instead of human-friendly line number
- linenr--
- // Set linenumber to -1 if the conversion failed
- if err != nil {
- linenr = -1
- }
- }
- }
- }
- // Escape any HTML in the code, so that the pretty printer is not confused
- filebytes = bytes.ReplaceAll(filebytes, []byte("<"), []byte("<"))
- // Modify the line that is to be highlighted
- bytelines := bytes.Split(filebytes, []byte("\n"))
- if (linenr >= 0) && (linenr < len(bytelines)) {
- bytelines[linenr] = []byte(preHighlight + string(bytelines[linenr]) + postHighlight)
- }
- // Build a string from the bytelines slice
- code = string(bytes.Join(bytelines, []byte("\n")))
- }
- // Set an appropriate title
- title := errorPageTitle(lang)
- // Set the highlight class
- langclass := lang
- // Turn off highlighting for some languages
- switch lang {
- case "", "amber", "gcss":
- langclass = "nohighlight"
- }
- // Highlighting for the error message
- errorclass := "json" // "nohighlight"
- // Inform the user of the error
- htmldata := []byte(`<!doctype html>
- <html>
- <head>
- <title>` + title + `</title>
- <style>
- body {
- background-color: #f0f0f0;
- color: #0b0b0b;
- font-family: Lato,'Trebuchet MS',Helvetica,sans-serif;
- font-weight: 300;
- margin: 3.5em;
- font-size: 1.3em;
- }
- h1 {
- color: #101010;
- }
- div {
- margin-bottom: 35pt;
- }
- #right {
- text-align: right;
- }
- #wrap {
- white-space: pre-wrap;
- }
- </style>
- </head>
- <body>
- <div style="font-size: 3em; font-weight: bold;">` + title + `</div>
- Contents of ` + filename + `:
- <div>
- <pre><code class="` + langclass + `">` + code + `</code></pre>
- </div>
- Error message:
- <div>
- <pre id="wrap"><code style="color: #A00000;" class="` + errorclass + `">` + strings.TrimSpace(errormessage) + `</code></pre>
- </div>
- <div id="right">` + ac.versionString + `</div>
- `)
- if ac.autoRefresh {
- // Insert JavaScript for refreshing the page into the generated HTML
- htmldata = ac.InsertAutoRefresh(req, htmldata)
- }
- w.Write(htmldata)
- }
|