mirror of
https://github.com/charmbracelet/lipgloss.git
synced 2024-08-17 01:40:36 +03:00
feat: convert tabs to spaces with Style.TabWidth(int)
(#204)
* feat: convert tabs to spaces with Style.TabWidth(int) By default tabs will be converted to 4 spaces. To disable tab conversion set Style.TabWidth(NoTabConversion).
This commit is contained in:
parent
233079e2d9
commit
df8b3fa1f2
6
get.go
6
get.go
@ -370,6 +370,12 @@ func (s Style) GetMaxHeight() int {
|
||||
return s.getAsInt(maxHeightKey)
|
||||
}
|
||||
|
||||
// GetTabWidth returns the style's tab width setting. If no value is set 4 is
|
||||
// returned which is the implicit default.
|
||||
func (s Style) GetTabWidth() int {
|
||||
return s.getAsInt(tabWidthKey)
|
||||
}
|
||||
|
||||
// GetUnderlineSpaces returns whether or not the style is set to underline
|
||||
// spaces. If not value is set false is returned.
|
||||
func (s Style) GetUnderlineSpaces() bool {
|
||||
|
28
set.go
28
set.go
@ -14,7 +14,14 @@ func (s *Style) set(key propKey, value interface{}) {
|
||||
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
// We don't allow negative integers on any of our values, so just keep
|
||||
// TabWidth is the only property that may have a negative value (and
|
||||
// that negative value can be no less than -1).
|
||||
if key == tabWidthKey {
|
||||
s.rules[key] = v
|
||||
break
|
||||
}
|
||||
|
||||
// We don't allow negative integers on any of our other values, so just keep
|
||||
// them at zero or above. We could use uints instead, but the
|
||||
// conversions are a little tedious, so we're sticking with ints for
|
||||
// sake of usability.
|
||||
@ -497,13 +504,30 @@ func (s Style) MaxWidth(n int) Style {
|
||||
// styles.
|
||||
//
|
||||
// Because this in intended to be used at the time of render, this method will
|
||||
// not mutate the style and instead return a copy.
|
||||
// not mutate the style and instead returns a copy.
|
||||
func (s Style) MaxHeight(n int) Style {
|
||||
o := s.Copy()
|
||||
o.set(maxHeightKey, n)
|
||||
return o
|
||||
}
|
||||
|
||||
// NoTabConversion can be passed to [Style.TabWidth] to disable the replacement
|
||||
// of tabs with spaces at render time.
|
||||
const NoTabConversion = -1
|
||||
|
||||
// TabWidth sets the number of spaces that a tab (/t) should be rendered as.
|
||||
// When set to 0, tabs will be removed. To disable the replacement of tabs with
|
||||
// spaces entirely, set this to [NoTabConversion].
|
||||
//
|
||||
// By default, tabs will be replaced with 4 spaces.
|
||||
func (s Style) TabWidth(n int) Style {
|
||||
if n <= -1 {
|
||||
n = -1
|
||||
}
|
||||
s.set(tabWidthKey, n)
|
||||
return s
|
||||
}
|
||||
|
||||
// UnderlineSpaces determines whether to underline spaces between words. By
|
||||
// default, this is true. Spaces can also be underlined without underlining the
|
||||
// text itself.
|
||||
|
23
style.go
23
style.go
@ -10,6 +10,8 @@ import (
|
||||
"github.com/muesli/termenv"
|
||||
)
|
||||
|
||||
const tabWidthDefault = 4
|
||||
|
||||
// Property for a key.
|
||||
type propKey int
|
||||
|
||||
@ -68,6 +70,7 @@ const (
|
||||
inlineKey
|
||||
maxWidthKey
|
||||
maxHeightKey
|
||||
tabWidthKey
|
||||
underlineSpacesKey
|
||||
strikethroughSpacesKey
|
||||
)
|
||||
@ -224,7 +227,7 @@ func (s Style) Render(strs ...string) string {
|
||||
)
|
||||
|
||||
if len(s.rules) == 0 {
|
||||
return str
|
||||
return s.maybeConvertTabs(str)
|
||||
}
|
||||
|
||||
// Enable support for ANSI on the legacy Windows cmd.exe console. This is a
|
||||
@ -287,6 +290,9 @@ func (s Style) Render(strs ...string) string {
|
||||
teSpace = teSpace.CrossOut()
|
||||
}
|
||||
|
||||
// Potentially convert tabs to spaces
|
||||
str = s.maybeConvertTabs(str)
|
||||
|
||||
// Strip newlines in single line mode
|
||||
if inline {
|
||||
str = strings.ReplaceAll(str, "\n", "")
|
||||
@ -397,6 +403,21 @@ func (s Style) Render(strs ...string) string {
|
||||
return str
|
||||
}
|
||||
|
||||
func (s Style) maybeConvertTabs(str string) string {
|
||||
tw := tabWidthDefault
|
||||
if s.isSet(tabWidthKey) {
|
||||
tw = s.getAsInt(tabWidthKey)
|
||||
}
|
||||
switch tw {
|
||||
case -1:
|
||||
return str
|
||||
case 0:
|
||||
return strings.ReplaceAll(str, "\t", "")
|
||||
default:
|
||||
return strings.ReplaceAll(str, "\t", strings.Repeat(" ", tw))
|
||||
}
|
||||
}
|
||||
|
||||
func (s Style) applyMargins(str string, inline bool) string {
|
||||
var (
|
||||
topMargin = s.getAsInt(marginTopKey)
|
||||
|
@ -181,7 +181,8 @@ func TestStyleCopy(t *testing.T) {
|
||||
Foreground(Color("#ffffff")).
|
||||
Background(Color("#111111")).
|
||||
Margin(1, 1, 1, 1).
|
||||
Padding(1, 1, 1, 1)
|
||||
Padding(1, 1, 1, 1).
|
||||
TabWidth(2)
|
||||
|
||||
i := s.Copy()
|
||||
|
||||
@ -202,6 +203,7 @@ func TestStyleCopy(t *testing.T) {
|
||||
requireEqual(t, s.GetPaddingRight(), i.GetPaddingRight())
|
||||
requireEqual(t, s.GetPaddingTop(), i.GetPaddingTop())
|
||||
requireEqual(t, s.GetPaddingBottom(), i.GetPaddingBottom())
|
||||
requireEqual(t, s.GetTabWidth(), i.GetTabWidth())
|
||||
}
|
||||
|
||||
func TestStyleUnset(t *testing.T) {
|
||||
@ -312,6 +314,12 @@ func TestStyleUnset(t *testing.T) {
|
||||
requireTrue(t, s.GetBorderLeft())
|
||||
s.UnsetBorderLeft()
|
||||
requireFalse(t, s.GetBorderLeft())
|
||||
|
||||
// tab width
|
||||
s = NewStyle().TabWidth(2)
|
||||
requireEqual(t, s.GetTabWidth(), 2)
|
||||
s.UnsetTabWidth()
|
||||
requireNotEqual(t, s.GetTabWidth(), 4)
|
||||
}
|
||||
|
||||
func TestStyleValue(t *testing.T) {
|
||||
@ -352,7 +360,17 @@ func TestStyleValue(t *testing.T) {
|
||||
res, formatEscapes(res))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTabConversion(t *testing.T) {
|
||||
s := NewStyle()
|
||||
requireEqual(t, "[ ]", s.Render("[\t]"))
|
||||
s = NewStyle().TabWidth(2)
|
||||
requireEqual(t, "[ ]", s.Render("[\t]"))
|
||||
s = NewStyle().TabWidth(0)
|
||||
requireEqual(t, "[]", s.Render("[\t]"))
|
||||
s = NewStyle().TabWidth(-1)
|
||||
requireEqual(t, "[\t]", s.Render("[\t]"))
|
||||
}
|
||||
|
||||
func BenchmarkStyleRender(b *testing.B) {
|
||||
|
6
unset.go
6
unset.go
@ -287,6 +287,12 @@ func (s Style) UnsetMaxHeight() Style {
|
||||
return s
|
||||
}
|
||||
|
||||
// UnsetMaxHeight removes the max height style rule, if set.
|
||||
func (s Style) UnsetTabWidth() Style {
|
||||
delete(s.rules, tabWidthKey)
|
||||
return s
|
||||
}
|
||||
|
||||
// UnsetUnderlineSpaces removes the value set by UnderlineSpaces.
|
||||
func (s Style) UnsetUnderlineSpaces() Style {
|
||||
delete(s.rules, underlineSpacesKey)
|
||||
|
Loading…
Reference in New Issue
Block a user