[GH-ISSUE #101] missing character in thai #81

Closed
opened 2026-03-04 01:01:44 +03:00 by kerem · 10 comments
Owner

Originally created by @prasertwi on GitHub (Apr 17, 2018).
Original GitHub issue: https://github.com/rivo/tview/issues/101

i test textview code from wiki but can't display correct thai character
tview

and then i test with tcell code is correct

tcell

how to coding for solve problem ? Please suggestion for me
thank you .

tview code
`package main

import (
"fmt"
"strconv"
"strings"
"time"

"github.com/gdamore/tcell"
"github.com/rivo/tview"

)

const corporate = เป็นมนุษย์ สุดประเสริฐ เลิศคุณค่า กว่าบรรดา ฝูงสัตว์ เดรัจฉาน จงฝ่าฟัน พัฒนา วิชาการ อย่าล้างผลาญ ฤๅเข่นฆ่า บีฑาใคร ไม่ถือโทษ โกรธแช่งซัด ฮึดฮัดด่า หัดอภัยเหมือน กีฬา อัชฌาสัย ปฏิบัติ ประพฤติกฎ กำหนดใจ พูดจาให้จ๊ะ ๆ จ๋า ๆ น่าฟังเอยฯ

func main() {
app := tview.NewApplication()
textView := tview.NewTextView().
SetDynamicColors(true).
SetRegions(true).
SetChangedFunc(func() {
app.Draw()
})
numSelections := 0
go func() {
for _, word := range strings.Split(corporate, " ") {
if word == "the" {
word = "[red]the[white]"
}
if word == "to" {
word = fmt.Sprintf(["%d"]to[""], numSelections)
numSelections++
}
fmt.Fprintf(textView, "%s ", word)
time.Sleep(200 * time.Millisecond)
}
}()
textView.SetDoneFunc(func(key tcell.Key) {
currentSelection := textView.GetHighlights()
if key == tcell.KeyEnter {
if len(currentSelection) > 0 {
textView.Highlight()
} else {
textView.Highlight("0").ScrollToHighlight()
}
} else if len(currentSelection) > 0 {
index, _ := strconv.Atoi(currentSelection[0])
if key == tcell.KeyTab {
index = (index + 1) % numSelections
} else if key == tcell.KeyBacktab {
index = (index - 1 + numSelections) % numSelections
} else {
return
}
textView.Highlight(strconv.Itoa(index)).ScrollToHighlight()
}
})
textView.SetBorder(true)
if err := app.SetRoot(textView, true).SetFocus(textView).Run(); err != nil {
panic(err)
}
}
**tcell code**package main

import (
"fmt"
"os"

"github.com/gdamore/tcell"
"github.com/gdamore/tcell/encoding"
"github.com/mattn/go-runewidth"

)

var row = 0
var style = tcell.StyleDefault

func putln(s tcell.Screen, str string) {

puts(s, style, 1, row, str)
row++

}

func puts(s tcell.Screen, style tcell.Style, x, y int, str string) {
i := 0
var deferred []rune
dwidth := 0
for _, r := range str {
switch runewidth.RuneWidth(r) {
case 0:
if len(deferred) == 0 {
deferred = append(deferred, ' ')
dwidth = 1
}
case 1:
if len(deferred) != 0 {
s.SetContent(x+i, y, deferred[0], deferred[1:], style)
i += dwidth
}
deferred = nil
dwidth = 1
case 2:
if len(deferred) != 0 {
s.SetContent(x+i, y, deferred[0], deferred[1:], style)
i += dwidth
}
deferred = nil
dwidth = 2
}
deferred = append(deferred, r)
}
if len(deferred) != 0 {
s.SetContent(x+i, y, deferred[0], deferred[1:], style)
i += dwidth
}
}

func main() {

s, e := tcell.NewScreen()
if e != nil {
	fmt.Fprintf(os.Stderr, "%v\n", e)
	os.Exit(1)
}

encoding.Register()

if e = s.Init(); e != nil {
	fmt.Fprintf(os.Stderr, "%v\n", e)
	os.Exit(1)
}

plain := tcell.StyleDefault
bold := style.Bold(true)

s.SetStyle(tcell.StyleDefault.
	Foreground(tcell.ColorBlack).
	Background(tcell.ColorWhite))
s.Clear()

quit := make(chan struct{})

style = bold
putln(s, "Press ESC to Exit")
putln(s, "Character set: "+s.CharacterSet())
style = plain
putln(s, "Thai:เป็นมนุษย์ สุดประเสริฐ เลิศคุณค่า กว่าบรรดา ฝูงสัตว์ เดรัจฉาน")
putln(s, "English:   October")
putln(s, "Icelandic: október")
putln(s, "Arabic:    أكتوبر")
putln(s, "Russian:   октября")
putln(s, "Greek:     Οκτωβρίου")
putln(s, "Chinese:   十月 (note, two double wide characters)")
putln(s, "Combining: A\u030a (should look like Angstrom)")
putln(s, "Emoticon:  \U0001f618 (blowing a kiss)")
putln(s, "Airplane:  \u2708 (fly away)")
putln(s, "Command:   \u2318 (mac clover key)")
putln(s, "Enclose:   !\u20e3 (should be enclosed exclamation)")
putln(s, "")
putln(s, "Box:")
putln(s, string([]rune{
	tcell.RuneULCorner,
	tcell.RuneHLine,
	tcell.RuneTTee,
	tcell.RuneHLine,
	tcell.RuneURCorner,
}))
putln(s, string([]rune{
	tcell.RuneVLine,
	tcell.RuneBullet,
	tcell.RuneVLine,
	tcell.RuneLantern,
	tcell.RuneVLine,
})+"  (bullet, lantern/section)")
putln(s, string([]rune{
	tcell.RuneLTee,
	tcell.RuneHLine,
	tcell.RunePlus,
	tcell.RuneHLine,
	tcell.RuneRTee,
}))
putln(s, string([]rune{
	tcell.RuneVLine,
	tcell.RuneDiamond,
	tcell.RuneVLine,
	tcell.RuneUArrow,
	tcell.RuneVLine,
})+"  (diamond, up arrow)")
putln(s, string([]rune{
	tcell.RuneLLCorner,
	tcell.RuneHLine,
	tcell.RuneBTee,
	tcell.RuneHLine,
	tcell.RuneLRCorner,
}))

s.Show()
go func() {
	for {
		ev := s.PollEvent()
		switch ev := ev.(type) {
		case *tcell.EventKey:
			switch ev.Key() {
			case tcell.KeyEscape, tcell.KeyEnter:
				close(quit)
				return
			case tcell.KeyCtrlL:
				s.Sync()
			}
		case *tcell.EventResize:
			s.Sync()
		}
	}
}()

<-quit

s.Fini()

}
`

Originally created by @prasertwi on GitHub (Apr 17, 2018). Original GitHub issue: https://github.com/rivo/tview/issues/101 i test textview code from wiki but can't display correct thai character ![tview](https://user-images.githubusercontent.com/1924296/38845962-246b6682-4224-11e8-9fb0-40bc45b1f1f4.png) and then i test with tcell code is correct ![tcell](https://user-images.githubusercontent.com/1924296/38845985-3c5220ba-4224-11e8-99d3-f30c74b85786.png) how to coding for solve problem ? Please suggestion for me thank you . **tview code** `package main import ( "fmt" "strconv" "strings" "time" "github.com/gdamore/tcell" "github.com/rivo/tview" ) const corporate = `เป็นมนุษย์ สุดประเสริฐ เลิศคุณค่า กว่าบรรดา ฝูงสัตว์ เดรัจฉาน จงฝ่าฟัน พัฒนา วิชาการ อย่าล้างผลาญ ฤๅเข่นฆ่า บีฑาใคร ไม่ถือโทษ โกรธแช่งซัด ฮึดฮัดด่า หัดอภัยเหมือน กีฬา อัชฌาสัย ปฏิบัติ ประพฤติกฎ กำหนดใจ พูดจาให้จ๊ะ ๆ จ๋า ๆ น่าฟังเอยฯ` func main() { app := tview.NewApplication() textView := tview.NewTextView(). SetDynamicColors(true). SetRegions(true). SetChangedFunc(func() { app.Draw() }) numSelections := 0 go func() { for _, word := range strings.Split(corporate, " ") { if word == "the" { word = "[red]the[white]" } if word == "to" { word = fmt.Sprintf(`["%d"]to[""]`, numSelections) numSelections++ } fmt.Fprintf(textView, "%s ", word) time.Sleep(200 * time.Millisecond) } }() textView.SetDoneFunc(func(key tcell.Key) { currentSelection := textView.GetHighlights() if key == tcell.KeyEnter { if len(currentSelection) > 0 { textView.Highlight() } else { textView.Highlight("0").ScrollToHighlight() } } else if len(currentSelection) > 0 { index, _ := strconv.Atoi(currentSelection[0]) if key == tcell.KeyTab { index = (index + 1) % numSelections } else if key == tcell.KeyBacktab { index = (index - 1 + numSelections) % numSelections } else { return } textView.Highlight(strconv.Itoa(index)).ScrollToHighlight() } }) textView.SetBorder(true) if err := app.SetRoot(textView, true).SetFocus(textView).Run(); err != nil { panic(err) } } ` **tcell code** `package main import ( "fmt" "os" "github.com/gdamore/tcell" "github.com/gdamore/tcell/encoding" "github.com/mattn/go-runewidth" ) var row = 0 var style = tcell.StyleDefault func putln(s tcell.Screen, str string) { puts(s, style, 1, row, str) row++ } func puts(s tcell.Screen, style tcell.Style, x, y int, str string) { i := 0 var deferred []rune dwidth := 0 for _, r := range str { switch runewidth.RuneWidth(r) { case 0: if len(deferred) == 0 { deferred = append(deferred, ' ') dwidth = 1 } case 1: if len(deferred) != 0 { s.SetContent(x+i, y, deferred[0], deferred[1:], style) i += dwidth } deferred = nil dwidth = 1 case 2: if len(deferred) != 0 { s.SetContent(x+i, y, deferred[0], deferred[1:], style) i += dwidth } deferred = nil dwidth = 2 } deferred = append(deferred, r) } if len(deferred) != 0 { s.SetContent(x+i, y, deferred[0], deferred[1:], style) i += dwidth } } func main() { s, e := tcell.NewScreen() if e != nil { fmt.Fprintf(os.Stderr, "%v\n", e) os.Exit(1) } encoding.Register() if e = s.Init(); e != nil { fmt.Fprintf(os.Stderr, "%v\n", e) os.Exit(1) } plain := tcell.StyleDefault bold := style.Bold(true) s.SetStyle(tcell.StyleDefault. Foreground(tcell.ColorBlack). Background(tcell.ColorWhite)) s.Clear() quit := make(chan struct{}) style = bold putln(s, "Press ESC to Exit") putln(s, "Character set: "+s.CharacterSet()) style = plain putln(s, "Thai:เป็นมนุษย์ สุดประเสริฐ เลิศคุณค่า กว่าบรรดา ฝูงสัตว์ เดรัจฉาน") putln(s, "English: October") putln(s, "Icelandic: október") putln(s, "Arabic: أكتوبر") putln(s, "Russian: октября") putln(s, "Greek: Οκτωβρίου") putln(s, "Chinese: 十月 (note, two double wide characters)") putln(s, "Combining: A\u030a (should look like Angstrom)") putln(s, "Emoticon: \U0001f618 (blowing a kiss)") putln(s, "Airplane: \u2708 (fly away)") putln(s, "Command: \u2318 (mac clover key)") putln(s, "Enclose: !\u20e3 (should be enclosed exclamation)") putln(s, "") putln(s, "Box:") putln(s, string([]rune{ tcell.RuneULCorner, tcell.RuneHLine, tcell.RuneTTee, tcell.RuneHLine, tcell.RuneURCorner, })) putln(s, string([]rune{ tcell.RuneVLine, tcell.RuneBullet, tcell.RuneVLine, tcell.RuneLantern, tcell.RuneVLine, })+" (bullet, lantern/section)") putln(s, string([]rune{ tcell.RuneLTee, tcell.RuneHLine, tcell.RunePlus, tcell.RuneHLine, tcell.RuneRTee, })) putln(s, string([]rune{ tcell.RuneVLine, tcell.RuneDiamond, tcell.RuneVLine, tcell.RuneUArrow, tcell.RuneVLine, })+" (diamond, up arrow)") putln(s, string([]rune{ tcell.RuneLLCorner, tcell.RuneHLine, tcell.RuneBTee, tcell.RuneHLine, tcell.RuneLRCorner, })) s.Show() go func() { for { ev := s.PollEvent() switch ev := ev.(type) { case *tcell.EventKey: switch ev.Key() { case tcell.KeyEscape, tcell.KeyEnter: close(quit) return case tcell.KeyCtrlL: s.Sync() } case *tcell.EventResize: s.Sync() } } }() <-quit s.Fini() } `
kerem closed this issue 2026-03-04 01:01:44 +03:00
Author
Owner

@rivo commented on GitHub (Apr 19, 2018):

For someone who does not read Thai, can you explain what exactly is not correct?

<!-- gh-comment-id:382848333 --> @rivo commented on GitHub (Apr 19, 2018): For someone who does not read Thai, can you explain what exactly is not correct?
Author
Owner

@rivo commented on GitHub (Apr 27, 2018):

I'll reopen when there is more information.

<!-- gh-comment-id:384886725 --> @rivo commented on GitHub (Apr 27, 2018): I'll reopen when there is more information.
Author
Owner

@prasertwi commented on GitHub (Apr 28, 2018):

sorry i'm late.
Example
English = Visitor, (total 6 charector)
Thai = ผู้มาติดต่อ (total 11 charector)

thai

thank rivo.

<!-- gh-comment-id:385138079 --> @prasertwi commented on GitHub (Apr 28, 2018): sorry i'm late. Example English = Visitor, (total 6 charector) Thai = ผู้มาติดต่อ (total 11 charector) ![thai](https://user-images.githubusercontent.com/1924296/39391750-a4cb100a-4ad2-11e8-9e4b-5ed51d133ffb.jpg) thank rivo.
Author
Owner

@rivo commented on GitHub (May 3, 2018):

Thanks a lot for the detailed explanation. Indeed, my handling of combining characters was wrong. I've fixed it just now. Let me know when you still find something that looks wrong.

<!-- gh-comment-id:386199118 --> @rivo commented on GitHub (May 3, 2018): Thanks a lot for the detailed explanation. Indeed, my handling of combining characters was wrong. I've fixed it just now. Let me know when you still find something that looks wrong.
Author
Owner

@prasertwi commented on GitHub (May 5, 2018):

Ok, display correct for thai character.
thaitview
Thank you for your hard work rivo.

<!-- gh-comment-id:386774052 --> @prasertwi commented on GitHub (May 5, 2018): Ok, display correct for thai character. ![thaitview](https://user-images.githubusercontent.com/1924296/39659000-21e3b198-5049-11e8-9d76-3f1c269af3b0.png) Thank you for your hard work rivo.
Author
Owner

@stephencheng commented on GitHub (May 17, 2018):

hi @rivo, I spotted a bug in this commit, it causes a unrecoverable panic. I spent quite some time to trace to the line of code: on Line of 364 in util.go

Note that I traced every commit for my code until this could be nailed down to this commit.

image

Some error messages for your information:

panic: runtime error: index out of range [recovered]
panic: runtime error: index out of range
goroutine 1 [running]:
vendor/github.com/rivo/tview.(*Application).Run.func1(0xc4202e7ce0)
vendor/github.com/rivo/tview/application.go:96 +0x82 panic(0x1870220, 0x1ef3280)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/panic.go:502 +0x229
github.com/rivo/tview.printWithStyle(0x1a36280, 0xc4203c8000, 0x0, 0x0, 0x74, 0x24, 0x5, 0x2, 0x400000f00000000, 0x0, ...)
vendor/github.com/rivo/tview/util.go:364 +0xfa4
vendor/github.com/rivo/tview.Print(0x1a36280, 0xc4203c8000, 0x0, 0x0, 0x74, 0x24, 0x5, 0x2, 0xf, 0x5, ...)
vendor/github.com/rivo/tview/util.go:294 +0x9b
vendor/github.com/rivo/tview.(*Table).Draw(0xc4201fbf40, 0x1a36280, 0xc4203c8000)
vendor/github.com/rivo/tview/table.go:687 +0xfaa
vendor/github.com/rivo/tview.(*Flex).Draw(0xc4202db020, 0x1a36280, 0xc4203c8000)
vendor/github.com/rivo/tview/flex.go:156 +0x3ad
vendor/github.com/rivo/tview.(*Flex).Draw(0xc4202dafc0, 0x1a36280, 0xc4203c8000)
vendor/github.com/rivo/tview/flex.go:156 +0x3ad
vendor/github.com/rivo/tview.(*Flex).Draw(0xc4202daf60, 0x1a36280, 0xc4203c8000)
vendor/github.com/rivo/tview/flex.go:156 +0x3ad

<!-- gh-comment-id:389764122 --> @stephencheng commented on GitHub (May 17, 2018): hi @rivo, I spotted a bug in this commit, it causes a unrecoverable panic. I spent quite some time to trace to the line of code: on Line of 364 in util.go Note that I traced every commit for my code until this could be nailed down to this commit. ![image](https://user-images.githubusercontent.com/1396675/40160769-fcb7a7be-59f1-11e8-8bf5-1eec35d1b34e.png) Some error messages for your information: ``` panic: runtime error: index out of range [recovered] panic: runtime error: index out of range goroutine 1 [running]: vendor/github.com/rivo/tview.(*Application).Run.func1(0xc4202e7ce0) vendor/github.com/rivo/tview/application.go:96 +0x82 panic(0x1870220, 0x1ef3280) /usr/local/Cellar/go/1.10.1/libexec/src/runtime/panic.go:502 +0x229 github.com/rivo/tview.printWithStyle(0x1a36280, 0xc4203c8000, 0x0, 0x0, 0x74, 0x24, 0x5, 0x2, 0x400000f00000000, 0x0, ...) vendor/github.com/rivo/tview/util.go:364 +0xfa4 vendor/github.com/rivo/tview.Print(0x1a36280, 0xc4203c8000, 0x0, 0x0, 0x74, 0x24, 0x5, 0x2, 0xf, 0x5, ...) vendor/github.com/rivo/tview/util.go:294 +0x9b vendor/github.com/rivo/tview.(*Table).Draw(0xc4201fbf40, 0x1a36280, 0xc4203c8000) vendor/github.com/rivo/tview/table.go:687 +0xfaa vendor/github.com/rivo/tview.(*Flex).Draw(0xc4202db020, 0x1a36280, 0xc4203c8000) vendor/github.com/rivo/tview/flex.go:156 +0x3ad vendor/github.com/rivo/tview.(*Flex).Draw(0xc4202dafc0, 0x1a36280, 0xc4203c8000) vendor/github.com/rivo/tview/flex.go:156 +0x3ad vendor/github.com/rivo/tview.(*Flex).Draw(0xc4202daf60, 0x1a36280, 0xc4203c8000) vendor/github.com/rivo/tview/flex.go:156 +0x3ad ```
Author
Owner

@stephencheng commented on GitHub (May 17, 2018):

@rivo submitting a pull request to fix this:
https://github.com/rivo/tview/pull/117/commits/e91e46ac1096a7c0bbdaef67094a6431be9d193b
Thanks

<!-- gh-comment-id:389773696 --> @stephencheng commented on GitHub (May 17, 2018): @rivo submitting a pull request to fix this: https://github.com/rivo/tview/pull/117/commits/e91e46ac1096a7c0bbdaef67094a6431be9d193b Thanks
Author
Owner

@rivo commented on GitHub (May 18, 2018):

Thanks for spotting this. I committed a fix to this myself. It also affected other parts of the code and the preferred solution in Line 364 was not to wrap it in an extra if statement but simply to swap the partial conditions.

I also think that in a pull request, bugfixes should not be mixed with new features or other, unrelated additions to the code. They should be sent in separate PRs.

<!-- gh-comment-id:390342042 --> @rivo commented on GitHub (May 18, 2018): Thanks for spotting this. I committed a fix to this myself. It also affected other parts of the code and the preferred solution in Line 364 was not to wrap it in an extra `if` statement but simply to swap the partial conditions. I also think that in a pull request, bugfixes should not be mixed with new features or other, unrelated additions to the code. They should be sent in separate PRs.
Author
Owner

@stephencheng commented on GitHub (May 19, 2018):

Thanks for fixing the this. Yes, I have no clue how to completely fix the root cause of the problem but just patch it. It did work for me though :)

<!-- gh-comment-id:390380938 --> @stephencheng commented on GitHub (May 19, 2018): Thanks for fixing the this. Yes, I have no clue how to completely fix the root cause of the problem but just patch it. It did work for me though :)
Author
Owner

@rivo commented on GitHub (May 19, 2018):

It's ok. :-) Your code did help me to find out what the problem was.

<!-- gh-comment-id:390397413 --> @rivo commented on GitHub (May 19, 2018): It's ok. :-) Your code did help me to find out what the problem was.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/tview#81
No description provided.