packages feed

tuispec 0.3.1.0 → 0.3.1.1

raw patch · 6 files changed

+49/−8 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,9 @@ # Changelog +## 0.3.1.1 — 2026-06-06++* Fix selector clicks landing on the wrong column. A regex/substring selector resolved to its matching line's first non-blank column instead of the actual match position, so clicking centred text (e.g. a label behind a box border) hit the line's left edge and missed. `regexOrigins` now reports the match's start column via new origin-returning matchers `regexLikeMatchOrigin`/`wildcardContainsOrigin`, in terms of which the boolean `regexLikeMatch`/`wildcardContains` are now defined (so match and origin can't diverge).+ ## 0.3.1.0 — 2026-06-06  * Add mouse click simulation. DSL: `click`/`clickWith` (0-based coordinate) and `clickSelector`/`clickSelectorWith` (Playwright-style, resolves a selector to its match origin and honors `ambiguityMode`). New `MouseButton`, `MouseEncoding`, and `ClickOptions`/`defaultClickOptions` types. JSON-RPC: a `click` method accepting either `{col,row}` (1-based) or `{selector}`, with optional `button` and `encoding`. Clicks emit a press + release; SGR encoding is the default (what `vty`/Brick enable), with an `x10` override.
SKILL.md view
@@ -112,6 +112,12 @@   ignored. Throws `ChoiceSelectionError` on failure. - `artifactRoot tui`, `artifactFile tui rel`, `writeArtifactFile tui rel txt`   — locate and write into the per-test artifact directory.+- `click tui col row` / `clickSelector tui selector` — simulate a mouse click+  at a 0-based coordinate or on the element a selector matches (Playwright+  style; honors `ambiguityMode`). Use `clickWith` / `clickSelectorWith` with+  `ClickOptions` to choose the button or the legacy X10 encoding. The target+  app must have mouse tracking enabled (`vty`/Brick apps do once mouse mode is+  on); the default SGR encoding suits any modern TUI. - `currentViewRect tui rect` — return the viewport text cropped to a region. - `dumpFailureBundle` / `withFailureBundle` — capture diagnostic state on   failure (snapshot + viewport + action log + warnings + exit status).
src/TuiSpec/Internal.hs view
@@ -19,8 +19,10 @@      -- * Pattern matching     regexLikeMatch,+    regexLikeMatchOrigin,     cleanPattern,     wildcardContains,+    wildcardContainsOrigin,      -- * Theme helpers     resolveAutoSnapshotTheme,@@ -33,6 +35,7 @@ import Control.Exception (SomeException, catch) import Data.Char (isAlphaNum, toLower) import Data.List (isSuffixOf)+import Data.Maybe (isJust) import Data.Text (Text) import Data.Text qualified as T import Text.Read (readMaybe)@@ -79,7 +82,18 @@ -} regexLikeMatch :: Text -> Text -> Bool regexLikeMatch patternText haystack =-    any (`wildcardContains` haystack) alternatives+    isJust (regexLikeMatchOrigin patternText haystack)++{- | Like 'regexLikeMatch', but returns the 0-based column where the match+begins — the start of the first literal segment of the earliest-matching+alternative. This is the position a user sees and would click, so selector+clicks must target it rather than, say, the line's first non-blank column.+-}+regexLikeMatchOrigin :: Text -> Text -> Maybe Int+regexLikeMatchOrigin patternText haystack =+    case [col | alt <- alternatives, Just col <- [wildcardContainsOrigin alt haystack]] of+        [] -> Nothing+        cols -> Just (minimum cols)   where     alternatives =         filter (not . T.null) $@@ -92,7 +106,23 @@ -- | Check whether a @.*@-delimited pattern matches within a haystack. wildcardContains :: Text -> Text -> Bool wildcardContains patternText haystack =-    checkSegments 0 segments+    isJust (wildcardContainsOrigin patternText haystack)++{- | Like 'wildcardContains', but returns the 0-based start column of the match+— the position of the first literal (non-@.*@) segment — or 'Nothing'. A+pattern that is empty or all wildcards matches at column 0.+-}+wildcardContainsOrigin :: Text -> Text -> Maybe Int+wildcardContainsOrigin patternText haystack =+    case segments of+        [] -> Just 0+        (firstSeg : rest) ->+            let (prefix, suffix) = T.breakOn firstSeg haystack+                firstCol = T.length prefix+             in if not (T.null suffix)+                    && checkSegments (firstCol + T.length firstSeg) rest+                    then Just firstCol+                    else Nothing   where     segments = filter (not . T.null) (T.splitOn ".*" patternText) 
src/TuiSpec/Runner.hs view
@@ -91,7 +91,7 @@ import Test.Tasty (TestTree) import Test.Tasty.HUnit (assertFailure, testCase) import Text.Read (readMaybe)-import TuiSpec.Internal (cleanPattern, ignoreIOError, regexLikeMatch, resolveAutoSnapshotTheme, safeFileStem, safeIndex, snapshotMetadataPath, wildcardContains)+import TuiSpec.Internal (cleanPattern, ignoreIOError, regexLikeMatch, regexLikeMatchOrigin, resolveAutoSnapshotTheme, safeFileStem, safeIndex, snapshotMetadataPath, wildcardContains) import TuiSpec.ProjectRoot (resolveProjectRoot) import TuiSpec.Replay (RecordingDirection (DirectionFrame), RecordingEvent (..)) import TuiSpec.Types@@ -1972,13 +1972,14 @@             listToMaybe (regexOrigins patternText (viewportText viewport))  {- | All 0-based @(col, row)@ origins of a lightweight regex pattern, one per-matching line, taken at the line's first non-blank column.+matching line, at the column where the pattern's first literal segment matches+(so a selector click lands on the matched text, not the line's left edge). -} regexOrigins :: Text -> Text -> [(Int, Int)] regexOrigins patternText textValue =-    [ (T.length (T.takeWhile (== ' ') line), rowIdx)+    [ (col, rowIdx)     | (rowIdx, line) <- zip [0 ..] (T.lines textValue)-    , regexLikeMatch patternText line+    , Just col <- [regexLikeMatchOrigin patternText line]     ]  -- | All 0-based @(col, row)@ origins of a literal substring within viewport text.
src/TuiSpec/Types.hs view
@@ -168,7 +168,7 @@  -- | The tuispec library/protocol version. tuispecVersion :: String-tuispecVersion = "0.3.1.0"+tuispecVersion = "0.3.1.1"  -- | Key modifiers for combo key presses. data Modifier
tuispec.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.8 name: tuispec-version: 0.3.1.0+version: 0.3.1.1 build-type: Simple license: MIT license-file: LICENSE