From 498e5d8782361476fe1ccb95cdc164a197aac48e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20F=2E=20R=C3=B8dseth?= Date: Wed, 26 Jun 2024 12:40:50 +0200 Subject: [PATCH] Use a text template when printing a "pretty error" --- engine/prettyerror.go | 144 +++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/engine/prettyerror.go b/engine/prettyerror.go index 905cd6fd7..0c6df60de 100644 --- a/engine/prettyerror.go +++ b/engine/prettyerror.go @@ -5,15 +5,58 @@ import ( "net/http" "strconv" "strings" + "text/template" ) const ( // Highlight of errors in the code preHighlight = "" postHighlight = "" + + // HTML template for the error page + htmlTemplate = ` + + + {{.Title}} + + + +
{{.Title}}
+ Contents of {{.Filename}}: +
+
{{.Code}}
+
+ Error message: +
+
{{.ErrorMessage}}
+
+ + +` ) -// Given a lowercase string for the language, return an approprite error page title +// Given a lowercase string for the language, return an appropriate error page title func errorPageTitle(lang string) string { switch lang { case "": @@ -27,24 +70,19 @@ func errorPageTitle(lang string) string { 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 ) @@ -54,32 +92,25 @@ func (ac *Config) PrettyError(w http.ResponseWriter, req *http.Request, filename 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 } @@ -87,79 +118,48 @@ func (ac *Config) PrettyError(w http.ResponseWriter, req *http.Request, filename } } - // 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" + data := struct { + Title string + Filename string + Code string + ErrorMessage string + VersionString string + }{ + Title: title, + Filename: filename, + Code: code, + ErrorMessage: strings.TrimSpace(errormessage), + VersionString: ac.versionString, } - // Highlighting for the error message - errorclass := "json" // "nohighlight" - - // Inform the user of the error - htmldata := []byte(` - - - ` + title + ` - - - -
` + title + `
- Contents of ` + filename + `: -
-
` + code + `
-
- Error message: -
-
` + strings.TrimSpace(errormessage) + `
-
- -`) + tmpl, err := template.New("errorPage").Parse(htmlTemplate) + if err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } if ac.autoRefresh { - // Insert JavaScript for refreshing the page into the generated HTML - htmldata = ac.InsertAutoRefresh(req, htmldata) + var htmlbuf bytes.Buffer + if err := tmpl.Execute(&htmlbuf, data); err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + w.Write(ac.InsertAutoRefresh(req, htmlbuf.Bytes())) + return } - w.Write(htmldata) + if err := tmpl.Execute(w, data); err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } }