github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/parse/error.go (about)

     1  package parse
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/markusbkk/elvish/pkg/diag"
     8  )
     9  
    10  const parseErrorType = "parse error"
    11  
    12  // Error stores multiple underlying parse errors, and can pretty print them.
    13  type Error struct {
    14  	Entries []*diag.Error
    15  }
    16  
    17  var _ diag.Shower = &Error{}
    18  
    19  // GetError returns an *Error if the given error has dynamic type *Error, i.e.
    20  // is returned by one of the Parse functions. Otherwise it returns nil.
    21  func GetError(e error) *Error {
    22  	if er, ok := e.(*Error); ok {
    23  		return er
    24  	}
    25  	return nil
    26  }
    27  
    28  func (er *Error) add(msg string, ctx *diag.Context) {
    29  	err := &diag.Error{Type: parseErrorType, Message: msg, Context: *ctx}
    30  	er.Entries = append(er.Entries, err)
    31  }
    32  
    33  // Error returns a string representation of the error.
    34  func (er *Error) Error() string {
    35  	switch len(er.Entries) {
    36  	case 0:
    37  		return "no parse error"
    38  	case 1:
    39  		return er.Entries[0].Error()
    40  	default:
    41  		sb := new(strings.Builder)
    42  		// Contexts of parse error entries all have the same name
    43  		fmt.Fprintf(sb, "multiple parse errors in %s: ", er.Entries[0].Context.Name)
    44  		for i, e := range er.Entries {
    45  			if i > 0 {
    46  				fmt.Fprint(sb, "; ")
    47  			}
    48  			fmt.Fprintf(sb, "%d-%d: %s", e.Context.From, e.Context.To, e.Message)
    49  		}
    50  		return sb.String()
    51  	}
    52  }
    53  
    54  // Show shows the error.
    55  func (er *Error) Show(indent string) string {
    56  	switch len(er.Entries) {
    57  	case 0:
    58  		return "no parse error"
    59  	case 1:
    60  		return er.Entries[0].Show(indent)
    61  	default:
    62  		sb := new(strings.Builder)
    63  		fmt.Fprint(sb, "Multiple parse errors:")
    64  		for _, e := range er.Entries {
    65  			sb.WriteString("\n" + indent + "  ")
    66  			fmt.Fprintf(sb, "\033[31;1m%s\033[m\n", e.Message)
    67  			sb.WriteString(indent + "    ")
    68  			sb.WriteString(e.Context.Show(indent + "      "))
    69  		}
    70  		return sb.String()
    71  	}
    72  }