mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-04 00:45:35 +00:00
widget: test and document clusterIndexFor
This commit adds documentation and tests for the clusterIndexFor helper, making it easier to understand what it does and how to use it safely. Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit is contained in:
+10
-1
@@ -1049,7 +1049,16 @@ func positionGreaterOrEqual(lines []text.Line, p1, p2 combinedPos) bool {
|
|||||||
// at the given position within the line. As a special case, if the rune is one
|
// at the given position within the line. As a special case, if the rune is one
|
||||||
// beyond the final rune of the line, it returns the length of the line's clusters
|
// beyond the final rune of the line, it returns the length of the line's clusters
|
||||||
// slice. Otherwise, it panics if given a rune beyond the
|
// slice. Otherwise, it panics if given a rune beyond the
|
||||||
// dimensions of the line.
|
// dimensions of the line. The startIdx must be known to be at or before
|
||||||
|
// the real index of the cluster. This means that this function is
|
||||||
|
// only useful for searching forward through text, not backward.
|
||||||
|
// Passing a startIdx after the cluster corresponding to the runeIdx
|
||||||
|
// will trigger a panic.
|
||||||
|
//
|
||||||
|
// All indices are relative to the content in the line. The runeIdx 0
|
||||||
|
// refers to the first rune on the line, regardless of the line's
|
||||||
|
// rune offset. Similarly, the provided and returned glyph cluster
|
||||||
|
// indices are relative to the line's cluster slice.
|
||||||
func clusterIndexFor(line text.Line, runeIdx, startIdx int) int {
|
func clusterIndexFor(line text.Line, runeIdx, startIdx int) int {
|
||||||
if runeIdx == line.Layout.Runes.Count {
|
if runeIdx == line.Layout.Runes.Count {
|
||||||
return len(line.Layout.Clusters)
|
return len(line.Layout.Clusters)
|
||||||
|
|||||||
@@ -244,3 +244,114 @@ func TestIncrementPosition(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClusterIndexFor(t *testing.T) {
|
||||||
|
fontSize := 16
|
||||||
|
lineWidth := fontSize * 3
|
||||||
|
ltrText, rtlText := makeTestText(fontSize, lineWidth)
|
||||||
|
type input struct {
|
||||||
|
runeIdx int
|
||||||
|
clusterStartIdx int
|
||||||
|
expected int
|
||||||
|
panics bool
|
||||||
|
}
|
||||||
|
type testcase struct {
|
||||||
|
name string
|
||||||
|
line text.Line
|
||||||
|
inputs []input
|
||||||
|
}
|
||||||
|
for _, tc := range []testcase{
|
||||||
|
{
|
||||||
|
name: "ltr",
|
||||||
|
line: ltrText[0],
|
||||||
|
inputs: []input{
|
||||||
|
{runeIdx: 0, clusterStartIdx: 0, expected: 0},
|
||||||
|
{runeIdx: 1, clusterStartIdx: 0, expected: 1},
|
||||||
|
{runeIdx: 1, clusterStartIdx: 1, expected: 1},
|
||||||
|
{runeIdx: 1, clusterStartIdx: 2, panics: true},
|
||||||
|
{runeIdx: 2, clusterStartIdx: 0, expected: 2},
|
||||||
|
{runeIdx: 2, clusterStartIdx: 1, expected: 2},
|
||||||
|
{runeIdx: 2, clusterStartIdx: 2, expected: 2},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 0, expected: 3},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 1, expected: 3},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 2, expected: 3},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 3, expected: 3},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 0, expected: 4},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 1, expected: 4},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 2, expected: 4},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 3, expected: 4},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 4, expected: 4},
|
||||||
|
{runeIdx: 5, panics: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rtl",
|
||||||
|
line: rtlText[0],
|
||||||
|
inputs: []input{
|
||||||
|
{runeIdx: 0, clusterStartIdx: 0, expected: 0},
|
||||||
|
{runeIdx: 1, clusterStartIdx: 0, expected: 1},
|
||||||
|
{runeIdx: 1, clusterStartIdx: 1, expected: 1},
|
||||||
|
{runeIdx: 1, clusterStartIdx: 2, panics: true},
|
||||||
|
{runeIdx: 2, clusterStartIdx: 0, expected: 2},
|
||||||
|
{runeIdx: 2, clusterStartIdx: 1, expected: 2},
|
||||||
|
{runeIdx: 2, clusterStartIdx: 2, expected: 2},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 0, expected: 3},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 1, expected: 3},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 2, expected: 3},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 3, expected: 3},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 0, expected: 4},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 1, expected: 4},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 2, expected: 4},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 3, expected: 4},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 4, expected: 4},
|
||||||
|
{runeIdx: 5, clusterStartIdx: 0, expected: 5},
|
||||||
|
{runeIdx: 6, panics: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rtl-ligatures",
|
||||||
|
line: rtlText[4],
|
||||||
|
inputs: []input{
|
||||||
|
{runeIdx: 0, clusterStartIdx: 0, expected: 0},
|
||||||
|
{runeIdx: 1, clusterStartIdx: 0, expected: 1},
|
||||||
|
{runeIdx: 1, clusterStartIdx: 1, expected: 1},
|
||||||
|
{runeIdx: 2, clusterStartIdx: 0, expected: 1},
|
||||||
|
{runeIdx: 2, clusterStartIdx: 1, expected: 1},
|
||||||
|
{runeIdx: 2, clusterStartIdx: 2, panics: true},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 0, expected: 2},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 1, expected: 2},
|
||||||
|
{runeIdx: 3, clusterStartIdx: 2, expected: 2},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 0, expected: 3},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 1, expected: 3},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 2, expected: 3},
|
||||||
|
{runeIdx: 4, clusterStartIdx: 3, expected: 3},
|
||||||
|
{runeIdx: 5, clusterStartIdx: 0, expected: 3},
|
||||||
|
{runeIdx: 5, clusterStartIdx: 1, expected: 3},
|
||||||
|
{runeIdx: 5, clusterStartIdx: 2, expected: 3},
|
||||||
|
{runeIdx: 5, clusterStartIdx: 3, expected: 3},
|
||||||
|
{runeIdx: 6, clusterStartIdx: 0, expected: 4},
|
||||||
|
{runeIdx: 6, clusterStartIdx: 1, expected: 4},
|
||||||
|
{runeIdx: 6, clusterStartIdx: 2, expected: 4},
|
||||||
|
{runeIdx: 6, clusterStartIdx: 3, expected: 4},
|
||||||
|
{runeIdx: 6, clusterStartIdx: 4, expected: 4},
|
||||||
|
{runeIdx: 7, clusterStartIdx: 0, expected: 5},
|
||||||
|
{runeIdx: 8, panics: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
for i, input := range tc.inputs {
|
||||||
|
t.Run(tc.name+strconv.Itoa(i), func(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
err := recover()
|
||||||
|
if err != nil != input.panics {
|
||||||
|
t.Errorf("panic state mismatch")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
actual := clusterIndexFor(tc.line, input.runeIdx, input.clusterStartIdx)
|
||||||
|
if actual != input.expected {
|
||||||
|
t.Errorf("input[%d]: expected %d, got %d", i, input.expected, actual)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user