packages feed

nano-ui-0.1.0.0: test/integration/Cases/Shaping.hs

module Cases.Shaping
  ( runBidiRunsTest
  , runShapedCaretTest
  ) where

import Data.IORef (IORef)
import Data.Primitive.PrimArray (primArrayFromList)
import NanoUI
import NanoUI.Bidi (BidiRun (..), bidiRuns, needsBidi)
import NanoUI.Testing (Context, caretX, selectionSpans, textIndexAtX)
import NanoUI.Testing.Assert (assert, assertEq)

-- | Direction runs come out in visual order, with numbers and spaces
-- resolved against their neighbours.
runBidiRunsTest :: Context -> IORef Int -> IO ()
runBidiRunsTest _ failed = do
  assert failed (not (needsBidi "plain text 123"))
  assertEq failed [] (bidiRuns "")
  assertEq failed [BidiRun 0 5 False] (bidiRuns "hello")
  -- A left-to-right line: the space before Hebrew stays with the Latin.
  assertEq failed [BidiRun 0 4 False, BidiRun 4 7 True] (bidiRuns "abc \x05D0\x05D1\x05D2")
  -- A right-to-left line puts the trailing Latin word on the left.
  assertEq failed [BidiRun 4 7 False, BidiRun 0 4 True] (bidiRuns "\x05D0\x05D1\x05D2 abc")
  -- Numbers in Hebrew read left to right, left of the word before them.
  assertEq failed [BidiRun 5 8 False, BidiRun 0 5 True] (bidiRuns "\x05E9\x05DC\x05D5\x05DD 123")
  -- Latin in the middle of an Arabic line.
  assertEq
    failed
    [BidiRun 7 10 True, BidiRun 4 7 False, BidiRun 0 4 True]
    (bidiRuns "\x0645\x0631\x062D abc\x0628\x0627\x0644")

-- | Carets, hit testing and selection spans follow a host's shaped layout,
-- including right-to-left carets that decrease.
runShapedCaretTest :: Context -> IORef Int -> IO ()
runShapedCaretTest _ failed = do
  let rtl = "\x05D0\x05D1\x05D2"
      mixed = "ab\x05D0\x05D1"
      shape t
        | t == rtl = Just (ShapedText 30 30 (primArrayFromList [30, 20, 10, 0]))
        | t == mixed = Just (ShapedText 40 40 (primArrayFromList [0, 10, 40, 30, 20]))
        | otherwise = Nothing
      fm = (monospaceMetrics 16) {fmShape = shape}
  assertEq failed 30 (caretX fm rtl 0)
  assertEq failed 0 (caretX fm rtl 3)
  assertEq failed 0 (caretX fm rtl 99)
  assertEq failed 2 (textIndexAtX fm rtl 12)
  assertEq failed 0 (textIndexAtX fm rtl 100)
  assertEq failed [(10, 30)] (selectionSpans fm rtl 0 2)
  assertEq failed [] (selectionSpans fm rtl 2 2)
  -- Selecting the Hebrew of a mixed line covers its run, not the Latin.
  assertEq failed [(20, 40)] (selectionSpans fm mixed 2 4)
  assertEq failed [(0, 10)] (selectionSpans fm mixed 0 1)
  assertEq failed 3 (textIndexAtX fm mixed 29)