diff --git a/command/hook_ui.go b/command/hook_ui.go index 936133551..61bff36b2 100644 --- a/command/hook_ui.go +++ b/command/hook_ui.go @@ -373,7 +373,10 @@ func dropCR(data []byte) []byte { } func truncateId(id string, maxLen int) string { - totalLength := len(id) + // Note that the id may contain multibyte characters. + // We need to truncate it to maxLen characters, not maxLen bytes. + rid := []rune(id) + totalLength := len(rid) if totalLength <= maxLen { return id } @@ -383,11 +386,11 @@ func truncateId(id string, maxLen int) string { maxLen = 5 } - dots := "..." + dots := []rune("...") partLen := maxLen / 2 leftIdx := partLen - 1 - leftPart := id[0:leftIdx] + leftPart := rid[0:leftIdx] rightIdx := totalLength - partLen - 1 @@ -396,7 +399,7 @@ func truncateId(id string, maxLen int) string { rightIdx -= overlap } - rightPart := id[rightIdx:] + rightPart := rid[rightIdx:] - return leftPart + dots + rightPart + return string(leftPart) + string(dots) + string(rightPart) } diff --git a/command/hook_ui_test.go b/command/hook_ui_test.go index 5d4d2814d..03b62add0 100644 --- a/command/hook_ui_test.go +++ b/command/hook_ui_test.go @@ -252,6 +252,51 @@ func TestTruncateId(t *testing.T) { Expected: "Hello world", MaxLen: 12, }, + { + Input: "あいうえおかきくけこさ", + Expected: "あ...さ", + MaxLen: 3, + }, + { + Input: "あいうえおかきくけこさ", + Expected: "あ...さ", + MaxLen: 5, + }, + { + Input: "あいうえおかきくけこさ", + Expected: "あい...さ", + MaxLen: 6, + }, + { + Input: "あいうえおかきくけこさ", + Expected: "あい...こさ", + MaxLen: 7, + }, + { + Input: "あいうえおかきくけこさ", + Expected: "あいう...こさ", + MaxLen: 8, + }, + { + Input: "あいうえおかきくけこさ", + Expected: "あいう...けこさ", + MaxLen: 9, + }, + { + Input: "あいうえおかきくけこさ", + Expected: "あいうえ...けこさ", + MaxLen: 10, + }, + { + Input: "あいうえおかきくけこさ", + Expected: "あいうえおかきくけこさ", + MaxLen: 11, + }, + { + Input: "あいうえおかきくけこさ", + Expected: "あいうえおかきくけこさ", + MaxLen: 12, + }, } for i, tc := range testCases { testName := fmt.Sprintf("%d", i)