diff --git a/common/formatting/formatting.go b/common/formatting/formatting.go new file mode 100644 index 0000000..3400aaf --- /dev/null +++ b/common/formatting/formatting.go @@ -0,0 +1,69 @@ +package formatting + +import ( + "fmt" + "strings" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +type FormatTemplate string + +func (f FormatTemplate) Format( + options protocol.FormattingOptions, + a ...any, +) string { + trimTrailingSpace := true + + if shouldTrim, found := options["trimTrailingWhitespace"]; found { + trimTrailingSpace = shouldTrim.(bool) + } + + value := "" + value = fmt.Sprintf( + string( + f.replace("/t", getTab(options)), + ), + a..., + ) + + if trimTrailingSpace { + value = strings.TrimRight(value, " ") + value = strings.TrimRight(value, "\t") + } + + return value +} + +func (f FormatTemplate) replace(format string, replacement string) FormatTemplate { + value := string(f) + currentIndex := 0 + + for { + position := strings.Index(value[currentIndex:], format) + + if position == -1 { + break + } + + position = position + currentIndex + currentIndex = position + + if position == 0 || value[position-1] != '\\' { + value = value[:position] + replacement + value[position+len(format):] + } + } + + return FormatTemplate(value) +} + +func getTab(options protocol.FormattingOptions) string { + tabSize := options["tabSize"].(float64) + insertSpace := options["insertSpaces"].(bool) + + if insertSpace { + return strings.Repeat(" ", int(tabSize)) + } else { + return "\t" + } +} diff --git a/common/formatting/formatting_test.go b/common/formatting/formatting_test.go new file mode 100644 index 0000000..290d41f --- /dev/null +++ b/common/formatting/formatting_test.go @@ -0,0 +1,81 @@ +package formatting + +import ( + "testing" + + protocol "github.com/tliron/glsp/protocol_3_16" +) + +func TestSimpleTabExampleWithTabOptions( + t *testing.T, +) { + template := FormatTemplate("%s/t%s") + + options := protocol.FormattingOptions{ + "tabSize": float64(4), + "insertSpaces": false, + } + + result := template.Format(options, "PermitRootLogin", "yes") + expected := "PermitRootLogin\tyes" + + if result != expected { + t.Errorf("Expected %q but got %q", expected, result) + } +} + +func TestSimpleTabExampleWithSpaceOptions( + t *testing.T, +) { + template := FormatTemplate("%s/t%s") + + options := protocol.FormattingOptions{ + "tabSize": float64(4), + "insertSpaces": true, + } + + result := template.Format(options, "PermitRootLogin", "yes") + expected := "PermitRootLogin yes" + + if result != expected { + t.Errorf("Expected %q but got %q", expected, result) + } +} + +func TestSimpleExampleWhiteSpaceAtEndShouldTrim( + t *testing.T, +) { + template := FormatTemplate("%s/t%s") + + options := protocol.FormattingOptions{ + "tabSize": float64(4), + "insertSpaces": false, + "trimTrailingWhitespace": true, + } + + result := template.Format(options, "PermitRootLogin", "yes ") + expected := "PermitRootLogin\tyes" + + if result != expected { + t.Errorf("Expected %q but got %q", expected, result) + } +} + +func TestSimpleExampleWhiteSpaceAtEndShouldNOTTrim( + t *testing.T, +) { + template := FormatTemplate("%s/t%s") + + options := protocol.FormattingOptions{ + "tabSize": float64(4), + "insertSpaces": false, + "trimTrailingWhitespace": false, + } + + result := template.Format(options, "PermitRootLogin", "yes ") + expected := "PermitRootLogin\tyes " + + if result != expected { + t.Errorf("Expected %q but got %q", expected, result) + } +}