Skip to content

Commit

Permalink
Override grapheme cluster width
Browse files Browse the repository at this point in the history
Add functionality to override the grapheme cluster width. This is
useful when dealing with terminals that do not confirm to the Unicode
specification and display a grapheme cluster with the incorrect width.

By having uniseg report back the same response as the terminal, this
allows for the terminal to match cursor positioning with the
application. While the results are incorrect, this still provides a
better user experience.

Signed-off-by: Michael Lorant <[email protected]>
  • Loading branch information
mikelorant committed Mar 3, 2024
1 parent 03509a9 commit 27c8665
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 6 deletions.
12 changes: 6 additions & 6 deletions grapheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, new
} else {
prop = state >> shiftGraphemePropState
}
return b, nil, runeWidth(r, prop), grAny | (prop << shiftGraphemePropState)
return b, nil, overrideWidth(string(b), runeWidth(r, prop)), grAny | (prop << shiftGraphemePropState)
}

// If we don't know the state, determine it now.
Expand All @@ -250,7 +250,7 @@ func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, new
state, prop, boundary = transitionGraphemeState(state&maskGraphemeState, r)

if boundary {
return b[:length], b[length:], width, state | (prop << shiftGraphemePropState)
return b[:length], b[length:], overrideWidth(string(b[:length]), width), state | (prop << shiftGraphemePropState)
}

if firstProp == prExtendedPictographic {
Expand All @@ -265,7 +265,7 @@ func FirstGraphemeCluster(b []byte, state int) (cluster, rest []byte, width, new

length += l
if len(b) <= length {
return b, nil, width, grAny | (prop << shiftGraphemePropState)
return b, nil, overrideWidth(string(b), width), grAny | (prop << shiftGraphemePropState)
}
}
}
Expand All @@ -287,7 +287,7 @@ func FirstGraphemeClusterInString(str string, state int) (cluster, rest string,
} else {
prop = state >> shiftGraphemePropState
}
return str, "", runeWidth(r, prop), grAny | (prop << shiftGraphemePropState)
return str, "", overrideWidth(str, runeWidth(r, prop)), grAny | (prop << shiftGraphemePropState)
}

// If we don't know the state, determine it now.
Expand All @@ -310,7 +310,7 @@ func FirstGraphemeClusterInString(str string, state int) (cluster, rest string,
state, prop, boundary = transitionGraphemeState(state&maskGraphemeState, r)

if boundary {
return str[:length], str[length:], width, state | (prop << shiftGraphemePropState)
return str[:length], str[length:], overrideWidth(str[:length], width), state | (prop << shiftGraphemePropState)
}

if firstProp == prExtendedPictographic {
Expand All @@ -325,7 +325,7 @@ func FirstGraphemeClusterInString(str string, state int) (cluster, rest string,

length += l
if len(str) <= length {
return str, "", width, grAny | (prop << shiftGraphemePropState)
return str, "", overrideWidth(str, width), grAny | (prop << shiftGraphemePropState)
}
}
}
15 changes: 15 additions & 0 deletions graphemeoverrides.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package uniseg

var GraphemeClusterWidthOverrides map[string]int

func overrideWidth(gc string, w int) int {
if len(GraphemeClusterWidthOverrides) == 0 {
return w
}

if width, ok := GraphemeClusterWidthOverrides[gc]; ok {
return width
}

return w
}

0 comments on commit 27c8665

Please sign in to comment.