diff --git a/offsetsGtk.hs b/offsetsGtk.hs index 42f2e90..b64d0fe 100644 --- a/offsetsGtk.hs +++ b/offsetsGtk.hs @@ -1,6 +1,15 @@ {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-} +{- + +this is a prototype of a hakurei-like tokenizer, where the sentence is clickable. +the function must accept a list of strings, because xcdat works that way. +also, you must FIX the current problem of just getting what's next to the cursor + +-} + + module Main where import qualified GI.Gtk as Gtk @@ -9,53 +18,66 @@ import qualified Data.Text as T import Data.Text (Text) import Data.Maybe (fromMaybe) import Control.Monad (void) +import Data.Int (Int32) --- | 'getWordAtOffset' takes a list of words and an offset (index) --- and returns the word at that offset if it exists. -getWordAtOffset :: [Text] -> Int -> Maybe Text -getWordAtOffset wordsList offset = - if offset >= 0 && offset < length wordsList - then Just (wordsList !! offset) - else Nothing +-- | Given a list of tokens and a character offset (into the concatenated text), +-- 'findTokenAtOffset' returns the index and token that covers that offset. +findTokenAtOffset :: [Text] -> Int -> Maybe (Int, Text) +findTokenAtOffset tokens offset = go tokens 0 0 + where + go [] _ _ = Nothing + go (t:ts) idx start = + let tokenLength = T.length t + in if offset < start + tokenLength + then Just (idx, t) + else go ts (idx + 1) (start + tokenLength) main :: IO () main = do -- Create a new GTK application with a unique application ID. app <- Gtk.applicationNew (Just "com.example.HaskellGiExample") [] - -- Connect to the application's "activate" signal. void $ Gio.onApplicationActivate app $ do - -- Create an application window (GTK 4 style). - window <- Gtk.applicationWindowNew app - - -- Create a text view widget. + window <- Gtk.applicationWindowNew app textView <- Gtk.textViewNew - -- Define some sample text. - let sampleText = "Haskell GI makes GUI programming and text processing elegant" + -- Assume these are the tokens from a tokenizer. + let tokens = ["これ", "は", "日本語", "の", "文章", "です"] + sampleText = T.concat tokens -- Concatenate tokens without spaces. - -- Set the sample text in the text view's buffer. buffer <- Gtk.textViewGetBuffer textView Gtk.textBufferSetText buffer sampleText (-1) - -- Process the text: split into words and retrieve the word at a given offset. - let wordsList = T.words sampleText - offset = 3 -- For example, get the 4th word (zero-indexed) - wordAtOffset = fromMaybe "No word found" (getWordAtOffset wordsList offset) + -- Add a click gesture to the text view. + gesture <- Gtk.gestureClickNew + Gtk.widgetAddController textView gesture - putStrLn $ "The word at offset " ++ show offset ++ " is: " ++ T.unpack wordAtOffset + -- When the user clicks, get the text iterator at that location. + void $ Gtk.onGestureClickPressed gesture $ \_ x y -> do + -- Convert the x and y coordinates (Double) to Int32 as required. + let ix = fromIntegral (round x) :: Int32 + iy = fromIntegral (round y) :: Int32 + (success, iter) <- Gtk.textViewGetIterAtLocation textView ix iy + if success + then do + offset32 <- Gtk.textIterGetOffset iter + let offset = fromIntegral offset32 :: Int + tokenInfo = findTokenAtOffset tokens offset + case tokenInfo of + Just (i, token) -> + putStrLn $ "Clicked token " ++ show i ++ ": " ++ T.unpack token + Nothing -> + putStrLn "Clicked outside any token." + else putStrLn "Could not determine text position." - -- Set the text view as the sole child of the window (wrap in Just). + -- Set the text view as the sole child of the window. Gtk.windowSetChild window (Just textView) - -- Connect the window's close-request signal to quit the application. void $ Gtk.on window #closeRequest $ do Gio.applicationQuit app return False - -- Show the window. Gtk.widgetShow window - -- Run the application (which handles initialization and the main loop). _ <- Gio.applicationRun app Nothing return ()