diff options
Diffstat (limited to 'jterm.hs')
-rw-r--r-- | jterm.hs | 64 |
1 files changed, 38 insertions, 26 deletions
@@ -1,7 +1,8 @@ +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE StrictData #-} +{-# LANGUAGE ViewPatterns #-} import Control.Concurrent import Control.Exception @@ -20,6 +21,7 @@ import qualified Data.Text as T import qualified Data.Text.IO as T import Data.Text.Rope (Position (..), Rope) import qualified Data.Text.Rope as R +import Data.Word (Word64) import Foreign.C.String import Foreign.C.Types import GHC.IO.Encoding @@ -34,14 +36,17 @@ import System.Environment import System.IO.Unsafe import System.Posix.Pty +doubleClickDelay :: Time doubleClickDelay = 300 +(-.) :: (Ord a, Num a) => a -> a -> a a -. b | b > a = 0 | otherwise = a - b infixl 1 -. +memo :: (Ord k) => (k -> a) -> k -> a memo f = unsafePerformIO $ do mvar <- newMVar M.empty pure $ \x -> unsafePerformIO $ do @@ -64,7 +69,7 @@ data Buffer = Buffer } search :: Rope -> Rope -> Word -> Maybe Word -search needle haystack p = go (n - 1) p +search needle haystack = go (n - 1) where index rope i = R.splitAt (i + 1) rope & fst & R.splitAt i & snd go i j @@ -80,7 +85,7 @@ search needle haystack p = go (n - 1) p n = R.length needle bsearch :: Rope -> Rope -> Word -> Maybe Word -bsearch needle haystack p = go 0 p +bsearch needle haystack = go 0 where index rope i = R.splitAt (i + 1) rope & fst & R.splitAt i & snd go i j @@ -122,6 +127,7 @@ expandAround rp p = | i < l = let (R.splitAt (i - 1) -> (_, sel), _) = R.splitAt i rp in R.toText sel getc _ = "" + searchFor :: Bool -> Int -> (Text -> Bool) -> (Text -> Bool) -> Word -> Word searchFor fwd n a b p = case getc p of "" -> if fwd then p - 1 else p @@ -130,6 +136,7 @@ expandAround rp p = then if fwd then p - 1 else p else searchFor fwd (n + if a c then 1 else if b c then -1 else 0) a b (if fwd then p + 1 else p - 1) +drawWin :: Display -> Drawable -> XftColor -> XftColor -> XftColor -> XftColor -> XftFont -> StateT Buffer IO () drawWin display win bgcolour fgcolour linecolour selcolour font = do buf <- get lift $ do @@ -138,7 +145,7 @@ drawWin display win bgcolour fgcolour linecolour selcolour font = do bracket (createGC display win) (freeGC display) $ \gc -> do bracket (createPixmap display win n m (defaultDepthOfScreen (defaultScreenOfDisplay display))) (freePixmap display) $ \p -> do withXftDraw display p (defaultVisualOfScreen (defaultScreenOfDisplay display)) (defaultColormap display 0) $ \draw -> do - xftDrawRect draw bgcolour 0 0 n m + xftDrawRect draw bgcolour (0 :: Int) (0 :: Int) n m -- Get rope covering window area let winlines = fromIntegral m `div` fromIntegral height @@ -153,12 +160,13 @@ drawWin display win bgcolour fgcolour linecolour selcolour font = do Position l1 c1 = R.lengthAsPosition presel Position l2 c2 = R.lengthAsPosition (presel <> sel) - xftDrawRect draw linecolour 0 (l1 * fromIntegral height + 4) n height + xftDrawRect draw linecolour (0 :: Int) (l1 * fromIntegral height + 4) n height drawRope False draw fgcolour bgcolour 0 height (R.lines presel) drawRope True draw fgcolour selcolour (fromIntegral c1 * width) (fromIntegral (l1 + 1) * height) (R.lines sel) drawRope False draw fgcolour bgcolour (fromIntegral c2 * width) (fromIntegral (l2 + 1) * height) (R.lines postsel) copyArea display p win gc 0 0 n m 0 0 where + drawRope :: Bool -> XftDraw -> XftColor -> XftColor -> Int -> Int -> [Text] -> IO () drawRope _ _ _ _ _ _ [] = pure () drawRope drawbg draw fgcolour bgcolour x y (l : ls) = do when drawbg $ xftDrawRect draw bgcolour x (y - height + 4) (width * T.length l) height @@ -174,6 +182,7 @@ fontSize display font = unsafePerformIO $ do height <- xftfont_height font pure (height, xglyphinfo_xOff extents) +key :: CUInt -> Word64 -> Rope key mod k = case (mod, k) of (_, 32) -> " " (0, 39) -> "'" @@ -322,7 +331,7 @@ handleEvent display win bgcolour fgcolour linecolour selcolour font event = do case search selstr (content b) (1 + end) of Just p -> do (_, _, _, _, m, _, _) <- lift $ getGeometry display win - let (height, width) = fontSize display font + let (height, _) = fontSize display font pageheight = fromIntegral m `div` fromIntegral height put $ b {cursor = (p, p + end - start), pos = max (pos b) $ R.lengthInLines (R.splitAt p (content b) & fst) + 1 -. pageheight} Nothing -> pure () @@ -395,12 +404,12 @@ handleEvent display win bgcolour fgcolour linecolour selcolour font event = do (_, 65364) -> scrolldown 1 (_, 65365) -> do (_, _, _, _, m, _, _) <- lift $ getGeometry display win - let (height, width) = fontSize display font + let (height, _) = fontSize display font pageheight = fromIntegral m `div` fromIntegral height scrollup ((681 * pageheight) `div` 1000) (_, 65366) -> do (_, _, _, _, m, _, _) <- lift $ getGeometry display win - let (height, width) = fontSize display font + let (height, _) = fontSize display font pageheight = fromIntegral m `div` fromIntegral height scrolldown ((681 * pageheight) `div` 1000) (_, 65288) -> do @@ -408,7 +417,7 @@ handleEvent display win bgcolour fgcolour linecolour selcolour font event = do delins (start - 1) end "" _ -> when (toAppend /= "") $ do delins start end toAppend - when (toAppend == "\n" && start == R.length (content b)) $ sendline + when (toAppend == "\n" && start == R.length (content b)) sendline redraw T toAppend -> do let noesc = stripAnsiEscapeCodes toAppend @@ -417,9 +426,11 @@ handleEvent display win bgcolour fgcolour linecolour selcolour font event = do redraw Notify -> do prop <- lift $ internAtom display "JTERM_CLIPBOARD" False - Just (R.fromText . T.pack . map castCCharToChar -> str) <- lift $ getWindowProperty8 display prop win - delins start end str - redraw + lift (getWindowProperty8 display prop win) >>= \case + Just (R.fromText . T.pack . map castCCharToChar -> str) -> do + delins start end str + redraw + _ -> pure () Expose -> redraw Selection e -> lift $ allocaXEvent $ \ev -> do setEventType ev selectionNotify @@ -439,7 +450,7 @@ handleEvent display win bgcolour fgcolour linecolour selcolour font event = do b <- get let cmd = between (ptycursor b) (R.length $ content b) (content b) put $ b {ptycursor = R.length (content b)} - lift $ send b $ cmd + lift $ send b cmd sendCommand b c = do attrs <- getTerminalAttributes (pty b) @@ -450,28 +461,29 @@ handleEvent display win bgcolour fgcolour linecolour selcolour font event = do lift $ sync display False between s e rp = R.splitAt e rp & fst & R.splitAt s & snd - + delins = delins' False - + delins' movepty s e ins = do b <- get let l = R.length ins p = ptycursor b - p' = if e < p then p + l + s - e - else if s < p then s - else p + p' + | e < p = p + l + s - e + | s < p = s + | otherwise = p (cs, ce) = cursor b - c' = if cs <= e && ce > e then (s + l, ce) - else if cs < s && ce >= s then (cs, s) - else if cs >= s && ce <= e then (s + l, s + l) - else if ce < s then (cs, ce) - else (cs + l + s - e, ce + l + s - e) + c' + | cs <= e && ce > e = (s + l, ce) + | cs < s && ce >= s = (cs, s) + | cs >= s && ce <= e = (s + l, s + l) + | ce < s = (cs, ce) + | otherwise = (cs + l + s - e, ce + l + s - e) put $ b {content = doedit s e (content b) ins, cursor = c', ptycursor = if movepty then s + l else p'} - where doedit s e rp ins = - let (before, _) = R.splitAt s rp - (_, after) = R.splitAt e rp + let (before, _) = R.splitAt s rp + (_, after) = R.splitAt e rp in before <> ins <> after xy2lc :: Word -> Word -> IO (Word, Word) |