This commit is contained in:
Magnus Root 2026-05-07 15:00:44 +03:00
parent 1ca37c4a47
commit 81638bf5f8
3 changed files with 5 additions and 83 deletions

2
go.mod
View file

@ -6,6 +6,7 @@ require (
github.com/charmbracelet/bubbles v0.18.0
github.com/charmbracelet/bubbletea v0.25.0
github.com/charmbracelet/lipgloss v0.10.0
github.com/mattn/go-runewidth v0.0.15
)
require (
@ -14,7 +15,6 @@ require (
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect

View file

@ -6,6 +6,7 @@ import (
"strings"
"github.com/charmbracelet/lipgloss"
"github.com/mattn/go-runewidth"
)
// === UI стили ===
@ -330,83 +331,8 @@ func renderLineWithCursor(line string, cursorX int, fileType string) string {
// === ANSI утилиты ===
// runeWidth возвращает визуальную ширину символа в терминале.
// Большинство символов = 1, но wide characters (CJK, emoji) = 2.
func runeWidth(r rune) int {
// Управляющие символы
if r < 32 || r == 127 {
return 0
}
// ASCII и Latin-1
if r < 0x300 {
return 1
}
// Combining marks (нулевая ширина)
if r >= 0x300 && r <= 0x36F {
return 0
}
if r >= 0x1AB0 && r <= 0x1AFF {
return 0
}
if r >= 0x1DC0 && r <= 0x1DFF {
return 0
}
if r >= 0x20D0 && r <= 0x20FF {
return 0
}
if r >= 0xFE20 && r <= 0xFE2F {
return 0
}
// CJK и широкие блоки
switch {
case r >= 0x1100 && r <= 0x115F:
return 2 // Hangul Jamo
case r == 0x2329 || r == 0x232A:
return 2
case r >= 0x2E80 && r <= 0x303E:
return 2 // CJK Radicals
case r >= 0x3040 && r <= 0x33FF:
return 2 // Japanese
case r >= 0x3400 && r <= 0x4DBF:
return 2 // CJK Extension A
case r >= 0x4E00 && r <= 0xA4CF:
return 2 // CJK Unified
case r >= 0xA960 && r <= 0xA97F:
return 2 // Hangul Jamo Extended-A
case r >= 0xAC00 && r <= 0xD7AF:
return 2 // Hangul Syllables
case r >= 0xF900 && r <= 0xFAFF:
return 2 // CJK Compatibility
case r >= 0xFE10 && r <= 0xFE19:
return 2
case r >= 0xFE30 && r <= 0xFE6F:
return 2
case r >= 0xFF00 && r <= 0xFF60:
return 2 // Fullwidth
case r >= 0xFFE0 && r <= 0xFFE6:
return 2
case r >= 0x1B000 && r <= 0x1B0FF:
return 2 // Kana Supplement
case r >= 0x1F004 && r <= 0x1F0CF:
return 2 // Playing cards etc
case r >= 0x1F100 && r <= 0x1F1FF:
return 1 // Enclosed Alphanumeric Supplement (flags base)
case r >= 0x1F200 && r <= 0x1F2FF:
return 2 // Enclosed IdeographicSupplement
case r >= 0x1F300 && r <= 0x1F9FF:
return 2 // Misc symbols, emoji
case r >= 0x1FA00 && r <= 0x1FAFF:
return 2 // Chess, symbols
case r >= 0x20000 && r <= 0x2FFFD:
return 2 // CJK Extension B-F
case r >= 0x30000 && r <= 0x3FFFD:
return 2
}
return 1
}
// visibleWidth возвращает визуальную ширину строки в терминале,
// учитывая ANSI escape-коды и double-width символы (CJK, emoji).
// учитывая ANSI escape-коды и double-width символы через go-runewidth.
func visibleWidth(s string) int {
w := 0
inEsc := false
@ -421,7 +347,7 @@ func visibleWidth(s string) int {
}
continue
}
w += runeWidth(r)
w += runewidth.RuneWidth(r)
}
return w
}
@ -467,7 +393,7 @@ func truncateVisible(s string, maxWidth int) string {
}
continue
}
rw := runeWidth(r)
rw := runewidth.RuneWidth(r)
if vis+rw > maxWidth {
break
}

View file

@ -1,4 +0,0 @@
```bash
deqwdq wdaw
SDW
```