gitlab.com/greut/eclint@v0.5.2-0.20240402114752-14681fe6e0bf/definition.go (about) 1 package eclint 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 9 "github.com/editorconfig/editorconfig-core-go/v2" 10 ) 11 12 // ErrNotImplemented represents a missing feature. 13 var ErrNotImplemented = errors.New("not implemented yet, PRs are welcome") 14 15 // definition contains the fields that aren't native to EditorConfig.Definition. 16 type definition struct { 17 editorconfig.Definition 18 BlockCommentStart []byte 19 BlockComment []byte 20 BlockCommentEnd []byte 21 MaxLength int 22 TabWidth int 23 IndentSize int 24 LastLine []byte 25 LastIndex int 26 InsideBlockComment bool 27 } 28 29 func newDefinition(d *editorconfig.Definition) (*definition, error) { //nolint:cyclop 30 def := &definition{ 31 Definition: *d, 32 TabWidth: d.TabWidth, 33 } 34 35 // Backward compatibility with buggy core. 36 if def.Charset == "utf-8 bom" { 37 def.Charset = "utf-8-bom" 38 } 39 40 if d.IndentSize != "" && d.IndentSize != UnsetValue { 41 is, err := strconv.Atoi(d.IndentSize) 42 if err != nil { 43 return nil, fmt.Errorf("cannot convert indentsize %q to int: %w", d.IndentSize, err) 44 } 45 46 def.IndentSize = is 47 } 48 49 if def.IndentStyle != "" && def.IndentStyle != UnsetValue { //nolint:nestif 50 bs, ok := def.Raw["block_comment_start"] 51 if ok && bs != "" && bs != UnsetValue { 52 def.BlockCommentStart = []byte(bs) 53 bc, ok := def.Raw["block_comment"] 54 55 if ok && bc != "" && bs != UnsetValue { 56 def.BlockComment = []byte(bc) 57 } 58 59 be, ok := def.Raw["block_comment_end"] 60 if !ok || be == "" || be == UnsetValue { 61 return nil, fmt.Errorf( 62 "%w: .editorconfig: block_comment_end was expected, none were found", 63 ErrConfiguration, 64 ) 65 } 66 67 def.BlockCommentEnd = []byte(be) 68 } 69 } 70 71 if mll, ok := def.Raw["max_line_length"]; ok && mll != "off" && mll != UnsetValue { 72 ml, er := strconv.Atoi(mll) 73 if er != nil || ml < 0 { 74 return nil, fmt.Errorf( 75 "%w: .editorconfig: max_line_length expected a non-negative number, got %q", 76 ErrConfiguration, 77 mll, 78 ) 79 } 80 81 def.MaxLength = ml 82 83 if def.TabWidth <= 0 { 84 def.TabWidth = DefaultTabWidth 85 } 86 } 87 88 return def, nil 89 } 90 91 // EOL returns the byte value of the given definition. 92 func (def *definition) EOL() ([]byte, error) { 93 switch def.EndOfLine { 94 case editorconfig.EndOfLineCr: 95 return []byte{cr}, nil 96 case editorconfig.EndOfLineCrLf: 97 return []byte{cr, lf}, nil 98 case editorconfig.EndOfLineLf: 99 return []byte{lf}, nil 100 default: 101 return nil, fmt.Errorf("%w: unsupported EndOfLine value %s", ErrConfiguration, def.EndOfLine) 102 } 103 } 104 105 // OverrideDefinitionUsingPrefix is an helper that takes the prefixed values. 106 // 107 // It replaces those values into the nominal ones. That way a tool could a 108 // different set of definition than the real editor would. 109 func OverrideDefinitionUsingPrefix(def *editorconfig.Definition, prefix string) error { 110 for k, v := range def.Raw { 111 if strings.HasPrefix(k, prefix) { 112 nk := k[len(prefix):] 113 def.Raw[nk] = v 114 115 switch nk { 116 case "indent_style": 117 def.IndentStyle = v 118 case "indent_size": 119 def.IndentSize = v 120 case "charset": 121 def.Charset = v 122 case "end_of_line": 123 def.EndOfLine = v 124 case "tab_width": 125 i, err := strconv.Atoi(v) 126 if err != nil { 127 return fmt.Errorf("tab_width cannot be set. %w", err) 128 } 129 130 def.TabWidth = i 131 case "trim_trailing_whitespace": 132 return fmt.Errorf("%v cannot be overridden: %w", nk, ErrNotImplemented) 133 case "insert_final_newline": 134 return fmt.Errorf("%v cannot be overridden: %w", nk, ErrNotImplemented) 135 } 136 } 137 } 138 139 return nil 140 }