mirror of
https://github.com/aljazceru/njump.git
synced 2025-12-17 22:34:25 +01:00
using a custom RunIterator that takes emojis into account and shapes them with a different font.
it doesn't actually work since the different outputs returned are treated by LineWrapper as necessarily belonging to different lines, so we'll have to do something different.
This commit is contained in:
8
go.mod
8
go.mod
@@ -4,11 +4,13 @@ go 1.21.4
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.5.0
|
||||
github.com/apatters/go-wordwrap v1.0.0
|
||||
github.com/dgraph-io/badger/v4 v4.2.0
|
||||
github.com/dmolesUC3/emoji v0.0.0-20190226181050-1849526eb21f
|
||||
github.com/fiatjaf/eventstore v0.3.3
|
||||
github.com/fiatjaf/khatru v0.2.1
|
||||
github.com/fogleman/gg v1.3.0
|
||||
github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8
|
||||
github.com/go-text/typesetting v0.0.0-20231221124458-48cc05a56658
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/gomarkdown/markdown v0.0.0-20231115200524-a660076da3fd
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
@@ -17,6 +19,7 @@ require (
|
||||
github.com/nbd-wtf/nostr-sdk v0.0.4
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pemistahl/lingua-go v1.4.0
|
||||
github.com/rs/cors v1.10.0
|
||||
github.com/rs/zerolog v1.29.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
@@ -41,8 +44,6 @@ require (
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fasthttp/websocket v1.5.3 // indirect
|
||||
github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8 // indirect
|
||||
github.com/go-text/typesetting v0.0.0-20231221124458-48cc05a56658 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.3.1 // indirect
|
||||
@@ -58,7 +59,6 @@ require (
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/pemistahl/lingua-go v1.4.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@@ -7,8 +7,6 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
|
||||
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/apatters/go-wordwrap v1.0.0 h1:G6ni4Pt7/I4ED+A5ZvsK8e9XwETD04veDKxEL2QN830=
|
||||
github.com/apatters/go-wordwrap v1.0.0/go.mod h1:3sM7HcArQ+utXnjDQ4d1xjrd8b/wbKuDr/RmbiHgjwI=
|
||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
@@ -59,6 +57,8 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa
|
||||
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dmolesUC3/emoji v0.0.0-20190226181050-1849526eb21f h1:l4W9/rRyCN5QtPsgMvERrQ3mKSsaO/b191TPxe2ROO8=
|
||||
github.com/dmolesUC3/emoji v0.0.0-20190226181050-1849526eb21f/go.mod h1:+5FBTP/tHiFB2yrIvWaLq9PchgdvVu99lBK5ZrEzl9w=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
@@ -78,10 +78,10 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8 h1:VkKnvzbvHqgEfm351rfr8Uclu5fnwq8HP2ximUzJsBM=
|
||||
github.com/go-text/render v0.0.0-20230619120952-35bccb6164b8/go.mod h1:h29xCucjNsDcYb7+0rJokxVwYAq+9kQ19WiFuBKkYtc=
|
||||
github.com/go-text/typesetting v0.0.0-20230616162802-9c17dd34aa4a h1:VjN8ttdfklC0dnAdKbZqGNESdERUxtE3l8a/4Grgarc=
|
||||
github.com/go-text/typesetting v0.0.0-20230616162802-9c17dd34aa4a/go.mod h1:evDBbvNR/KaVFZ2ZlDSOWWXIUKq0wCOEtzLxRM8SG3k=
|
||||
github.com/go-text/typesetting v0.0.0-20231221124458-48cc05a56658 h1:KeDKnC99J3l5qJK4zV13Au2UwPn4N20TnIlM0YvILj8=
|
||||
github.com/go-text/typesetting v0.0.0-20231221124458-48cc05a56658/go.mod h1:d22AnmeKq/on0HNv73UFriMKc4Ez6EqZAofLhAzpSzI=
|
||||
github.com/go-text/typesetting-utils v0.0.0-20231211103740-d9332ae51f04 h1:zBx+p/W2aQYtNuyZNcTfinWvXBQwYtDfme051PR/lAY=
|
||||
github.com/go-text/typesetting-utils v0.0.0-20231211103740-d9332ae51f04/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
@@ -146,6 +146,8 @@ github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/
|
||||
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
@@ -200,7 +202,6 @@ github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+g
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@@ -323,6 +324,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
|
||||
@@ -12,11 +12,14 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dmolesUC3/emoji"
|
||||
"github.com/fogleman/gg"
|
||||
"github.com/go-text/typesetting/di"
|
||||
"github.com/go-text/typesetting/font"
|
||||
"github.com/go-text/typesetting/language"
|
||||
"github.com/go-text/typesetting/shaping"
|
||||
"github.com/pemistahl/lingua-go"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
const nSupportedScripts = 13
|
||||
@@ -325,3 +328,81 @@ func shortenURLs(text string) string {
|
||||
return strings.Replace(urlStr, "/////", strings.Join(pathParts, "/"), 1)
|
||||
})
|
||||
}
|
||||
|
||||
type shapedOutputIterator struct {
|
||||
rawText []rune
|
||||
idx int
|
||||
savedIdx int
|
||||
shaper *shaping.HarfbuzzShaper
|
||||
fontSize int
|
||||
face font.Face
|
||||
language language.Language
|
||||
script language.Script
|
||||
direction di.Direction
|
||||
}
|
||||
|
||||
var _ shaping.RunIterator = (*shapedOutputIterator)(nil)
|
||||
|
||||
func (it *shapedOutputIterator) Next() (int, shaping.Output, bool) {
|
||||
idx, nextIdx, run, ok := it.readNext()
|
||||
if ok {
|
||||
it.idx = nextIdx
|
||||
}
|
||||
return idx, run, ok
|
||||
}
|
||||
|
||||
func (it *shapedOutputIterator) Peek() (int, shaping.Output, bool) {
|
||||
idx, _, out, more := it.readNext()
|
||||
return idx, out, more
|
||||
}
|
||||
|
||||
func (it *shapedOutputIterator) readNext() (int, int, shaping.Output, bool) {
|
||||
if it.idx >= len(it.rawText) {
|
||||
return it.idx, -1, shaping.Output{}, false
|
||||
}
|
||||
|
||||
// if the next character is an emoji then return a block of emojis
|
||||
if emoji.IsEmoji(it.rawText[it.idx]) {
|
||||
shapedEmoji := it.shaper.Shape(shaping.Input{
|
||||
Text: it.rawText,
|
||||
RunStart: it.idx,
|
||||
RunEnd: it.idx + 1,
|
||||
Face: emojiFont,
|
||||
Size: fixed.I(int(it.fontSize)),
|
||||
Script: it.script,
|
||||
Language: it.language,
|
||||
Direction: it.direction,
|
||||
})
|
||||
return it.idx, it.idx + 1, shapedEmoji, true
|
||||
}
|
||||
// otherwise we consume runes until we find an emoji and return everything
|
||||
|
||||
var runesConsumed int = 0
|
||||
for r, rn := range it.rawText[it.idx:] {
|
||||
if emoji.IsEmoji(rn) {
|
||||
// reached an emoji, stop now
|
||||
break
|
||||
}
|
||||
runesConsumed = r
|
||||
}
|
||||
|
||||
shapedRunes := it.shaper.Shape(shaping.Input{
|
||||
Text: it.rawText,
|
||||
RunStart: it.idx,
|
||||
RunEnd: it.idx + runesConsumed + 1,
|
||||
Face: it.face,
|
||||
Size: fixed.I(int(it.fontSize)),
|
||||
Script: it.script,
|
||||
Language: it.language,
|
||||
Direction: it.direction,
|
||||
})
|
||||
return it.idx, it.idx + runesConsumed + 1, shapedRunes, true
|
||||
}
|
||||
|
||||
func (it *shapedOutputIterator) Save() {
|
||||
it.savedIdx = it.idx
|
||||
}
|
||||
|
||||
func (it *shapedOutputIterator) Restore() {
|
||||
it.idx = it.savedIdx
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
sdk "github.com/nbd-wtf/nostr-sdk"
|
||||
"github.com/nfnt/resize"
|
||||
xfont "golang.org/x/image/font"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -183,24 +182,24 @@ func drawText(paragraphs []string, width, height int) image.Image {
|
||||
|
||||
i := 1
|
||||
for _, paragraph := range paragraphs {
|
||||
text := []rune(paragraph)
|
||||
rawText := []rune(paragraph)
|
||||
if len(rawText) == 0 {
|
||||
rawText = []rune{' '}
|
||||
}
|
||||
|
||||
lang, script, dir, face := getLanguageAndScriptAndDirectionAndFont(text)
|
||||
shaper := &shaping.HarfbuzzShaper{}
|
||||
|
||||
shapedRunes := shaper.Shape(shaping.Input{
|
||||
Text: text,
|
||||
RunStart: 0,
|
||||
RunEnd: len(text),
|
||||
Face: face,
|
||||
Size: fixed.I(int(r.FontSize)),
|
||||
Script: script,
|
||||
Language: lang,
|
||||
Direction: dir,
|
||||
})
|
||||
lang, script, dir, face := getLanguageAndScriptAndDirectionAndFont(rawText)
|
||||
iterator := &shapedOutputIterator{
|
||||
rawText: rawText,
|
||||
shaper: &shaping.HarfbuzzShaper{},
|
||||
fontSize: FONT_SIZE,
|
||||
language: lang,
|
||||
script: script,
|
||||
direction: dir,
|
||||
face: face,
|
||||
}
|
||||
|
||||
var wrapper shaping.LineWrapper
|
||||
lines, _ := wrapper.WrapParagraph(shaping.WrapConfig{}, width, []rune(text), shaping.NewSliceIterator([]shaping.Output{shapedRunes}))
|
||||
lines, _ := wrapper.WrapParagraph(shaping.WrapConfig{}, width, rawText, iterator)
|
||||
|
||||
for _, line := range lines {
|
||||
for _, out := range line {
|
||||
|
||||
Reference in New Issue
Block a user