Skip to content

Commit

Permalink
adjust indent position
Browse files Browse the repository at this point in the history
  • Loading branch information
notJoon committed Sep 27, 2024
1 parent 64fa7f8 commit 3b69244
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 36 deletions.
62 changes: 46 additions & 16 deletions formatter/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ var (

// IssueFormatter is the interface that wraps the Format method.
// Implementations of this interface are responsible for formatting specific types of lint issues.
//
// ! TODO: Use template to format issue
type IssueFormatter interface {
Format(issue tt.Issue, snippet *internal.SourceCode) string
}
Expand Down Expand Up @@ -128,17 +130,24 @@ func (b *IssueFormatterBuilder) AddCodeSnippet() *IssueFormatterBuilder {
endLine := b.issue.End.Line
maxLineNumWidth := calculateMaxLineNumWidth(endLine)

var commonIndent string
if startLine-1 < 0 || endLine > len(b.snippet.Lines) || startLine > endLine {
commonIndent = ""
} else {
commonIndent = findCommonIndent(b.snippet.Lines[startLine-1 : endLine])
}

// add separator
padding := strings.Repeat(" ", maxLineNumWidth+1)
b.result.WriteString(lineStyle.Sprintf("%s|\n", padding))

for i := startLine; i <= endLine; i++ {
// check that the line number does not go out of range of snippet.Lines
if i-1 < 0 || i-1 >= len(b.snippet.Lines) {
continue
}

line := expandTabs(b.snippet.Lines[i-1])
line = strings.TrimPrefix(line, commonIndent)
lineNum := fmt.Sprintf("%*d", maxLineNumWidth, i)

b.result.WriteString(lineStyle.Sprintf("%s | ", lineNum))
Expand All @@ -156,14 +165,22 @@ func (b *IssueFormatterBuilder) AddUnderlineAndMessage() *IssueFormatterBuilder

b.result.WriteString(lineStyle.Sprintf("%s| ", padding))

if startLine <= 0 || startLine > len(b.snippet.Lines) || endLine <= 0 || endLine > len(b.snippet.Lines) {
if startLine <= 0 || startLine > len(b.snippet.Lines) || endLine <= 0 || endLine > len(b.snippet.Lines) || startLine > endLine {
b.result.WriteString(messageStyle.Sprintf("%s\n\n", b.issue.Message))
return b
}

// draw underline from start column to end column
underlineStart := calculateVisualColumn(b.snippet.Lines[startLine-1], b.issue.Start.Column)
underlineEnd := calculateVisualColumn(b.snippet.Lines[endLine-1], b.issue.End.Column)
commonIndent := findCommonIndent(b.snippet.Lines[startLine-1 : endLine])
commonIndentWidth := calculateVisualColumn(commonIndent, len(commonIndent)+1)

// calculate underline start position
underlineStart := calculateVisualColumn(b.snippet.Lines[startLine-1], b.issue.Start.Column) - commonIndentWidth
if underlineStart < 0 {
underlineStart = 0
}

// calculate underline end position
underlineEnd := calculateVisualColumn(b.snippet.Lines[endLine-1], b.issue.End.Column) - commonIndentWidth
underlineLength := underlineEnd - underlineStart + 1

b.result.WriteString(strings.Repeat(" ", underlineStart))
Expand Down Expand Up @@ -219,17 +236,6 @@ func (b *IssueFormatterBuilder) AddNote() *IssueFormatterBuilder {

type BaseFormatter struct{}

func (f *BaseFormatter) Format(issue tt.Issue, snippet *internal.SourceCode) string {
builder := NewIssueFormatterBuilder(issue, snippet)
return builder.
AddHeader(warningHeader).
AddCodeSnippet().
AddUnderlineAndMessage().
AddSuggestion().
AddNote().
Build()
}

func (b *IssueFormatterBuilder) Build() string {
return b.result.String()
}
Expand Down Expand Up @@ -272,3 +278,27 @@ func calculateVisualColumn(line string, column int) int {
}
return visualColumn
}

func findCommonIndent(lines []string) string {
if len(lines) == 0 {
return ""
}

commonIndentPrefix := strings.TrimLeft(lines[0], " \t")
commonIndentPrefix = lines[0][:len(lines[0])-len(commonIndentPrefix)]

for _, line := range lines[1:] {
if strings.TrimSpace(line) == "" {
continue // ignore empty lines
}

for !strings.HasPrefix(line, commonIndentPrefix) {
commonIndentPrefix = commonIndentPrefix[:len(commonIndentPrefix)-1]
if len(commonIndentPrefix) == 0 {
return ""
}
}
}

return commonIndentPrefix
}
111 changes: 95 additions & 16 deletions formatter/formatter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ func TestFormatIssuesWithArrows(t *testing.T) {
expected := `error: unused-variable
--> test.go
|
4 | x := 1
| ~~
4 | x := 1
| ~~
| x declared but not used
error: empty-if
--> test.go
|
5 | if true {}
| ~~~~~~~~~
5 | if true {}
| ~~~~~~~~~
| empty branch
`
Expand All @@ -74,15 +74,15 @@ error: empty-if
expectedWithTabs := `error: unused-variable
--> test.go
|
4 | x := 1
| ~~
4 | x := 1
| ~~
| x declared but not used
error: empty-if
--> test.go
|
5 | if true {}
| ~~~~~~~~~
5 | if true {}
| ~~~~~~~~~
| empty branch
`
Expand Down Expand Up @@ -136,22 +136,22 @@ func TestFormatIssuesWithArrows_MultipleDigitsLineNumbers(t *testing.T) {
expected := `error: unused-variable
--> test.go
|
4 | x := 1 // unused variable
| ~~
4 | x := 1 // unused variable
| ~~
| x declared but not used
error: empty-if
--> test.go
|
5 | if true {} // empty if statement
| ~~~~~~~~~
5 | if true {} // empty if statement
| ~~~~~~~~~
| empty branch
error: example
--> test.go
|
10 | println("end")
| ~~~~~~~~
10 | println("end")
| ~~~~~~~~
| example issue
`
Expand Down Expand Up @@ -244,8 +244,8 @@ func TestUnnecessaryTypeConversionFormatter(t *testing.T) {
expected := `error: unnecessary-type-conversion
--> test.go
|
5 | result := int(myInt)
| ~~~~~~~~~~~
5 | result := int(myInt)
| ~~~~~~~~~~~
| unnecessary type conversion
Suggestion:
Expand All @@ -261,3 +261,82 @@ Note: Unnecessary type conversions can make the code less readable and may sligh

assert.Equal(t, expected, result, "Formatted output should match expected output")
}

func TestFindCommonIndent(t *testing.T) {
tests := []struct {
name string
lines []string
expected string
}{
{
name: "whitespace indent",
lines: []string{
" if foo {",
" println()",
" }",
},
expected: " ",
},
{
name: "tab indent",
lines: []string{
"\tif foo {",
"\t\tprintln()",
"\t}",
},
expected: "\t",
},
{
name: "mixed indent (space and tab)",
lines: []string{
"\t if foo {",
"\t \tprintln()",
"\t }",
},
expected: "\t ",
},
{
name: "no indent",
lines: []string{
"if foo {",
"println()",
"}",
},
expected: "",
},
{
name: "empty line",
lines: []string{
" if foo {",
"",
" println()",
" }",
},
expected: " ",
},
{
name: "various indent levels",
lines: []string{
" if foo {",
" bar()",
" baz()",
" }",
},
expected: " ",
},
{
name: "empty input",
lines: []string{},
expected: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := findCommonIndent(tt.lines)
if result != tt.expected {
t.Errorf("findCommonIndent() = %q, want %q", result, tt.expected)
}
})
}
}
8 changes: 4 additions & 4 deletions internal/fixer/fixer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,10 @@ func main() {
}`,
issues: []tt.Issue{
{
Rule: "emit-format",
Message: "Consider formatting std.Emit call for better readability",
Start: token.Position{Line: 8, Column: 5},
End: token.Position{Line: 9, Column: 44},
Rule: "emit-format",
Message: "Consider formatting std.Emit call for better readability",
Start: token.Position{Line: 8, Column: 5},
End: token.Position{Line: 9, Column: 44},
Suggestion: `std.Emit(
"OwnershipChange",
"newOwner", newOwner,
Expand Down

0 comments on commit 3b69244

Please sign in to comment.