phoityne-0.0.1.0: app/Phoityne/IO/GUI/GTK/TextEditor.hs
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE BinaryLiterals #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Phoityne.IO.GUI.GTK.TextEditor (
TextEditorData(..)
, LineTextDoubleClickedHandler
, CodeNoteCloseEventHandler
, CodeTextKeyPressEventHandler
, CodeBufferChangedEventHandler
, CodeBufferDeleteRangeEventHandler
, CodeBufferInsertTextEventHandler
, setupCodeNote
, activateCodeNote
, highLightBreakPoint
, offLightBreakPoint
, addBreakPointTagAtLine
, isCurrentTextEditor
, getCodeViewContent
, isTextEditorModified
, setTextEditorModified
, getCodeTextLineNumber
, blockIndentTextEditor
, blockUnIndentTextEditor
, blockCommentTextEditor
, blockUnCommentTextEditor
, setContent2TextEditor
, setCursorOnTextEditor
, deleteRangeOnTextEditor
, insertText2TextEditor
, getSelectedText
, deleteBreakPointTag
, deleteBreakPointTagAtLine
, updateBreakPointTag
, searchEndIter
) where
-- モジュール
import Phoityne.Constant
import Phoityne.IO.GUI.GTK.Constant
import Phoityne.IO.GUI.GTK.Utility
-- システム
import System.Log.Logger
import GHC.Float
import Graphics.UI.Gtk
import Control.Monad
import Control.Monad.IO.Class
import Data.String.Utils
import qualified Control.Exception as E
import qualified Data.Text as T
import qualified Data.ByteString as BS
-- |
--
--
type LineTextDoubleClickedHandler
= Bool -- isTagExists
-> Int -- lineNo
-> IO ()
-- |
--
--
type HSCode = BS.ByteString
-- |
--
--
type CodeNoteCloseEventHandler = TextEditorData -> IO ()
-- |
--
--
data TextEditorData =
TextEditorData {
lineTextEditorData :: TextView
, codeTextEditorData :: TextView
, boxTextEditorData :: HBox
, tabLabelTextEditorData :: Label
} deriving (Eq)
-- |
--
--
type CodeTextKeyPressEventHandler = String -> Bool -> Bool -> Bool -> Int -> IO Bool
-- |
--
--
type CodeBufferChangedEventHandler = IO ()
-- |
--
--
type CodeBufferDeleteRangeEventHandler = (Int, Int) -> (Int, Int) -> String -> IO ()
-- |
--
--
type CodeBufferInsertTextEventHandler = (Int, Int) -> String -> IO ()
-- |
--
--
searchEndIter :: TextEditorData -> Int -> Int -> String -> IO (Int, Int)
searchEndIter (TextEditorData _ codeView _ _) startLineNo startColNo str = do
buf <- textViewGetBuffer codeView
iter <- textBufferGetIterAtLineOffset buf startLineNo startColNo
forwardTextIter iter $ length str
lineNo <- textIterGetLine iter
colNo <- textIterGetLineOffset iter
return (lineNo, colNo)
-- |
--
--
setupCodeNote :: Builder
-> String -- ファイル名
-> FilePath -- ファイルパス
-> HSCode -- コンテンツ
-> CodeNoteCloseEventHandler
-> LineTextDoubleClickedHandler
-> Maybe Int -- スクロールライン
-> CodeTextKeyPressEventHandler
-> CodeBufferChangedEventHandler
-> CodeBufferDeleteRangeEventHandler
-> CodeBufferInsertTextEventHandler
-> IO TextEditorData
setupCodeNote builder name path code evh lineViewEvh _ codeKeyEVH bufEVH delRangeEVH insertTextEVH = do
img <- imageNewFromIcon (T.pack "window-close") 8
withIcon img
where
withIcon Nothing = do
criticalM _LOG_NAME $ "[setupCodeNote] close icon not found."
E.throwIO . userError $ "[setupCodeNote] close icon not found."
withIcon (Just image) = do
-- ページタブのラベルとクローズボタンの生成
box <- hBoxNew False 0
label <- labelNew $ Just name
fontDesc <- fontDescriptionNew
fontDescriptionSetFamily fontDesc (_FONT_DESC)
fontDescriptionSetSize fontDesc 9
widgetOverrideFont label $ Just fontDesc
closeButton <- toolButtonNew (Just image) (Nothing::Maybe T.Text)
boxPackStart box label PackNatural 0
boxPackStart box closeButton PackNatural 0
widgetShowAll box
menuWidget <- labelNew $ Just path
widgetOverrideFont menuWidget $ Just fontDesc
-- ノートブックに新規ページの生成
note <- builderGetObject builder castToNotebook _NAME_CODE_NOTE
textEditor <- createTextEditor builder code lineViewEvh label codeKeyEVH bufEVH delRangeEVH insertTextEVH
_ <- notebookAppendPageMenu note (boxTextEditorData textEditor) box menuWidget
notebookSetTabReorderable note (boxTextEditorData textEditor) True
_ <- onToolButtonClicked closeButton (codeNoteCloseEventHandler note textEditor evh)
setFont note
widgetShowAll note
-- activateCodeNote builder textEditor lineNo
return textEditor
-- |
--
--
createTextEditor :: Builder
-> HSCode
-> LineTextDoubleClickedHandler
-> Label
-> CodeTextKeyPressEventHandler
-> CodeBufferChangedEventHandler
-> CodeBufferDeleteRangeEventHandler
-> CodeBufferInsertTextEventHandler
-> IO TextEditorData
createTextEditor builder code evh tabLabel codeKeyEVH bufEVH delRangeEVH insertTextEVH = do
tagTable <- builderGetObject builder castToTextTagTable _NAME_TAG_TABLE
lineBuf <- textBufferNew $ Just tagTable
codeBuf <- textBufferNew $ Just tagTable
lineTextView <- textViewNewWithBuffer lineBuf
codeTextView <- textViewNewWithBuffer codeBuf
textTagTableLookup tagTable (T.unpack _BREAK_POINT_HIGHLIGHT_TAG) >>= \case
Just _ -> return ()
Nothing -> do
tag <- textTagNew (Just _BREAK_POINT_HIGHLIGHT_TAG)
set tag [textTagBackground := "blue", textTagForeground := "white", textTagBackgroundSet := True]
textTagTableAdd tagTable tag
box <- hBoxNew False 0
lineScroll <- scrolledWindowNew Nothing Nothing
scrolledWindowSetPlacement lineScroll CornerTopRight
codeScroll <- scrolledWindowNew Nothing Nothing
ajust <- scrolledWindowGetVAdjustment codeScroll
scrolledWindowSetVAdjustment lineScroll ajust
set lineScroll [ scrolledWindowHscrollbarPolicy := PolicyNever
, scrolledWindowVscrollbarPolicy := PolicyAutomatic]
textViewSetBorderWindowSize codeTextView TextWindowTop 5
textViewSetBorderWindowSize codeTextView TextWindowBottom 5
textViewSetBorderWindowSize codeTextView TextWindowLeft 5
textViewSetBorderWindowSize codeTextView TextWindowRight 5
textViewSetBorderWindowSize lineTextView TextWindowTop 5
textViewSetBorderWindowSize lineTextView TextWindowBottom 5
--textViewSetBorderWindowSize lineTextView TextWindowLeft 10
--textViewSetBorderWindowSize lineTextView TextWindowRight 5
textViewSetEditable lineTextView True
textViewSetCursorVisible lineTextView False
textViewSetJustification lineTextView JustifyRight
widgetModifyBg lineTextView StateNormal $ Color 0xd8d8 0xd8d8 0xd8d8
containerAdd lineScroll lineTextView
containerAdd codeScroll codeTextView
boxPackStart box lineScroll PackNatural 0
boxPackStart box codeScroll PackGrow 0
setFont lineTextView
setFont codeTextView
_ <- on lineTextView buttonPressEvent $ lineTextDoubleClickedHandler lineTextView evh
codeBuf <- textViewGetBuffer codeTextView
lineBuf <- textViewGetBuffer lineTextView
textBufferSetByteString codeBuf code
lineCount <- textBufferGetLineCount codeBuf
let lineStr = createLineNoText [1..lineCount] ""
textBufferSetText lineBuf lineStr
fontDesc <- fontDescriptionNew
fontDescriptionSetFamily fontDesc (_FONT_DESC)
fontDescriptionSetSize fontDesc 9
widgetOverrideFont (castToWidget lineTextView) $ Just fontDesc
widgetOverrideFont (castToWidget codeTextView) $ Just fontDesc
{-
-- 行番号の垂直スクロールバーを消す。お試し。
widgetSetSizeRequest (castToWidget lineScroll) 0 (-1)
scrolledWindowGetVScrollbar lineScroll >>= \case
Nothing -> return ()
Just s -> widgetHide (castToWidget s)
-}
saveBt <- builderGetObject builder castToToolButton _NAME_TOOL_BT_SAVE
textBufferSetModified codeBuf False
_ <- on codeBuf bufferChanged $ codeTextBufferChangedHandler lineBuf codeBuf bufEVH
_ <- on codeBuf modifiedChanged $ codeTextModifiedHandler codeBuf tabLabel saveBt
_ <- on codeTextView keyPressEvent $ codeTextKeyPressEventHandler lineTextView codeTextView codeKeyEVH
_ <- on codeTextView buttonPressEvent $ codeTextButtonPressEventHandler codeTextView
_ <- on codeBuf deleteRange $ codeTextDeleteRangeEventHandler codeTextView delRangeEVH
_ <- on codeBuf bufferInsertText $ codeTextInsertTextEventHandler codeTextView insertTextEVH
return $ TextEditorData lineTextView codeTextView box tabLabel
where
createLineNoText [] acc = acc
createLineNoText (x:[]) acc = acc ++ " " ++ show x ++ " "
createLineNoText (x:xs) acc = acc ++ " " ++ show x ++ " \n" ++ createLineNoText xs acc
codeTextModifiedHandler codeBuf label saveBt = do
textBufferGetModified codeBuf >>= \case
False -> do
str <- labelGetText label
labelSetText label $ init . init $ (str :: String)
widgetSetSensitive saveBt False
True -> do
str <- labelGetText label
labelSetText label $ str ++ (" *"::String)
widgetSetSensitive saveBt True
codeTextBufferChangedHandler lineBuf codeBuf _ = do
ll <- textBufferGetLineCount lineBuf
cl <- textBufferGetLineCount codeBuf
updateLineNo lineBuf codeBuf ll cl
updateLineNo lineBuf _ ll cl
| ll == cl = return ()
| ll < cl = do
let lineTxt = "\n" ++ createLineNoText [ll+1 .. cl] ""
endIter <- textBufferGetEndIter lineBuf
textBufferInsert lineBuf endIter lineTxt
| otherwise = do
startIter <- textBufferGetIterAtLine lineBuf (cl-1)
textIterForwardToLineEnd startIter
endIter <- textBufferGetEndIter lineBuf
textBufferDelete lineBuf startIter endIter
codeTextDeleteRangeEventHandler view evh si ei = do
slineNo <- textIterGetLine si
sColNo <- textIterGetLineOffset si
elineNo <- textIterGetLine ei
eColNo <- textIterGetLineOffset ei
buf <- textViewGetBuffer view
str <- textBufferGetText buf si ei False
evh (slineNo, sColNo) (elineNo, eColNo) str
codeTextInsertTextEventHandler _ evh si str = do
startLineNo <- textIterGetLine si
startColNo <- textIterGetLineOffset si
evh (startLineNo, startColNo) str
-- |
-- Event Handler
--
codeNoteCloseEventHandler :: Notebook -> TextEditorData -> CodeNoteCloseEventHandler -> IO ()
codeNoteCloseEventHandler note wid evh = do
notebookPageNum note (boxTextEditorData wid) >>= \case
Just idx -> notebookRemovePage note idx
Nothing -> errorM _LOG_NAME $ "[codeNoteCloseEventHandler]unexpected error."
evh wid
-- |
--
--
activateCodeNote :: Builder -> TextEditorData -> Int -> IO ()
activateCodeNote builder wid lineNo = do
note <- builderGetObject builder castToNotebook _NAME_CODE_NOTE
notebookPageNum note (boxTextEditorData wid) >>= \case
Just idx -> notebookSetCurrentPage note idx
Nothing -> errorM _LOG_NAME $ "[activateCodeNote]invalid node page."
window <- builderGetObject builder castToWindow _WINDOW_NAME
widgetShowAll window
forceEvent
let codeTextView = codeTextEditorData wid
codeBuf <- textViewGetBuffer codeTextView
iter <- textBufferGetIterAtLine codeBuf lineNo
_ <- textViewScrollToIter codeTextView iter 0.0 (Just (0.0, 0.5))
widgetGrabFocus codeTextView
-- |
-- Event Handler
--
lineTextDoubleClickedHandler :: TextView -> LineTextDoubleClickedHandler -> EventM EButton Bool
lineTextDoubleClickedHandler self evh = eventClick >>= \case
DoubleClick -> doubleClicked >> return True
_ -> return False
where
doubleClicked = do
(_, posYd) <- eventCoordinates
liftIO $ do
scrollY <- textViewGetVadjustment self >>= adjustmentGetValue
let posY = scrollY + posYd
(iter, _) <- textViewGetLineAtY self $ double2Int posY
isTagExists <- textIterBeginsTag iter Nothing
lineNo <- textIterGetLine iter
evh isTagExists lineNo
-- |
--
--
updateBreakPointTag :: TextEditorData -> Bool -> Int -> IO ()
updateBreakPointTag (TextEditorData lineView _ _ _) True lineNo = deleteBreakPointTagAtLine lineView lineNo
updateBreakPointTag (TextEditorData lineView _ _ _) False lineNo = addBreakPointTagAtLine lineView lineNo
-- |
--
--
addBreakPointTagAtLine :: TextView -> Int -> IO ()
addBreakPointTagAtLine self line = do
buf <- textViewGetBuffer self
iter <- textBufferGetIterAtLine buf line
addBreakPointTagAtIter self iter
-- |
--
--
addBreakPointTagAtIter :: TextView -> TextIter -> IO ()
addBreakPointTagAtIter self startIter = do
textBuf <- textIterGetBuffer startIter
tagTable <- textBufferGetTagTable textBuf
tag <- textTagNew Nothing
set tag [textTagBackground := "blue", textTagForeground := "white", textTagBackgroundSet := True]
textTagTableAdd tagTable tag
endIter <- textIterCopy startIter
_ <- textViewForwardDisplayLineEnd self endIter
textBufferApplyTag textBuf tag startIter endIter
-- |
-- 指定行についているタグをすべて削除する
--
deleteBreakPointTagAtLine :: TextView -> Int -> IO ()
deleteBreakPointTagAtLine textView line = do
buf <- textViewGetBuffer textView
iter <- textBufferGetIterAtLine buf line
deleteBreakPointTagAtIter iter
-- |
-- TextIterの位置についているタグをすべて削除する
--
deleteBreakPointTagAtIter :: TextIter -> IO ()
deleteBreakPointTagAtIter iter = do
textBuf <- textIterGetBuffer iter
tagTable <- textBufferGetTagTable textBuf
tags <- textIterGetTags iter
mapM_ (textTagTableRemove tagTable) tags
-- |
--
--
deleteBreakPointTag :: TextEditorData -> Int -> IO ()
deleteBreakPointTag (TextEditorData lineView _ _ _) lineNo = do
textBuf <- textViewGetBuffer lineView
tagTable <- textBufferGetTagTable textBuf
iter <- textBufferGetIterAtLine textBuf (lineNo - 1)
tags <- textIterGetTags iter
mapM_ (textTagTableRemove tagTable) tags
-- |
--
--
highLightBreakPoint :: TextEditorData -> Int -> Int -> Int -> Int -> IO ()
highLightBreakPoint textEditor sl sc el ec = do
let codeTextView = codeTextEditorData textEditor
codeBuf <- textViewGetBuffer codeTextView
--tagTable <- textBufferGetTagTable codeBuf
startLine <- normalizeLine codeBuf sl
startCol <- normalizeColumn codeBuf startLine sc
endLine <- normalizeLine codeBuf el
endCol <- normalizeColumn codeBuf endLine ec
startIter <- textBufferGetIterAtLineOffset codeBuf startLine startCol
endIter <- textBufferGetIterAtLineOffset codeBuf endLine (endCol + 1)
textBufferPlaceCursor codeBuf endIter
textBufferSelectRange codeBuf startIter endIter
where
normalizeLine buf l = do
nl <- normalizeLine_ buf l
return $ if 0 > nl then 0 else nl
normalizeLine_ buf l = do
allLines <- textBufferGetLineCount buf
return $ if l > allLines then allLines - 1 else l - 1
normalizeColumn buf line col = do
nc <- normalizeColumn_ buf line col
return $ if 0 > nc then 0 else nc
normalizeColumn_ buf line col = do
iter <- textBufferGetIterAtLine buf line
allChars <- textIterGetCharsInLine iter -- -1 for delimiters
let allChars' = allChars - 1
return $ if col > allChars' then allChars' - 1 else col - 1
-- |
--
--
offLightBreakPoint :: TextEditorData -> IO ()
offLightBreakPoint textEditor = do
let codeTextView = codeTextEditorData textEditor
codeBuf <- textViewGetBuffer codeTextView
startIter <- textBufferGetStartIter codeBuf
endIter <- textBufferGetEndIter codeBuf
textBufferRemoveTagByName codeBuf _BREAK_POINT_HIGHLIGHT_TAG startIter endIter
return ()
-- |
--
--
isCurrentTextEditor :: Builder -> TextEditorData -> IO Bool
isCurrentTextEditor bulder (TextEditorData _ _ box _) = do
getCurrentTextEditorHBox bulder >>= \case
Nothing -> return False
Just b -> return $ box == b
-- |
--
--
getCurrentTextEditorHBox :: Builder -> IO (Maybe HBox)
getCurrentTextEditorHBox builder = do
note <- builderGetObject builder castToNotebook _NAME_CODE_NOTE
notebookGetCurrentPage note >>= \case
(-1) -> return Nothing
idx -> notebookGetNthPage note idx >>= \case
Nothing -> return Nothing
Just w -> return . Just $ castToHBox w
-- |
--
--
getCodeViewContent :: TextEditorData -> IO BS.ByteString
getCodeViewContent (TextEditorData _ codeView _ _) = do
buf <- textViewGetBuffer codeView
textBufferSetModified buf False
startIter <- textBufferGetStartIter buf
endIter <- textBufferGetEndIter buf
textBufferGetByteString buf startIter endIter False
-- |
--
--
isTextEditorModified :: TextEditorData -> IO Bool
isTextEditorModified (TextEditorData _ codeView _ _) = do
buf <- textViewGetBuffer codeView
textBufferGetModified buf
-- |
--
--
setTextEditorModified :: TextEditorData -> Bool -> IO ()
setTextEditorModified (TextEditorData _ codeView _ _) isModified = do
buf <- textViewGetBuffer codeView
textBufferSetModified buf isModified
-- |
--
--
codeTextButtonPressEventHandler :: TextView -> EventM EButton Bool
codeTextButtonPressEventHandler textView = eventButton >>= \case
RightButton -> liftIO $ do
buf <- textViewGetBuffer textView
clip <- widgetGetClipboard textView selectionPrimary
textBufferHasSelection buf >>= \case
False -> textBufferPasteClipboardAtCursor buf clip True >> return True
True -> textBufferCopyClipboard buf clip >> return True
_ -> return False
-- |
-- Event Handler
--
codeTextKeyPressEventHandler :: TextView -> TextView -> CodeTextKeyPressEventHandler -> EventM EKey Bool
codeTextKeyPressEventHandler lineTextView codeTextView evh = do
name <- eventKeyName
mods <- eventModifier
liftIO $ do
buf <- textViewGetBuffer codeTextView
mark <- textBufferGetInsert buf
iter <- textBufferGetIterAtMark buf mark
lineNo <- textIterGetLine iter
buf <- textViewGetBuffer lineTextView
iter <- textBufferGetIterAtLine buf lineNo
isTagExists <- textIterBeginsTag iter Nothing
evh (T.unpack name) (elem Shift mods) (elem Control mods) isTagExists lineNo
-- |
--
--
getCodeTextLineNumber :: TextEditorData -> IO (Int, Int)
getCodeTextLineNumber (TextEditorData _ codeView _ _) = do
buf <- textViewGetBuffer codeView
mark <- textBufferGetInsert buf
iter <- textBufferGetIterAtMark buf mark
lineNo <- textIterGetLine iter
colNo <- textIterGetLineOffset iter
return (lineNo, colNo)
-- |
--
--
blockIndentTextEditor :: TextEditorData -> IO ()
blockIndentTextEditor te@(TextEditorData _ codeView _ _) = do
(startLine, endLine) <- getSelectedLineNumbers te
buf <- textViewGetBuffer codeView
insertIndent buf startLine endLine
where
insertIndent buf lineNo endNo = do
iter <- textBufferGetIterAtLine buf lineNo
textBufferInsert buf iter _INDENT_SPACE
if lineNo == endNo then return ()
else insertIndent buf (lineNo+1) endNo
-- |
--
--
blockUnIndentTextEditor :: TextEditorData -> IO ()
blockUnIndentTextEditor te@(TextEditorData _ codeView _ _) = do
(startLine, endLine) <- getSelectedLineNumbers te
buf <- textViewGetBuffer codeView
deleteIndent buf startLine endLine
where
deleteIndent buf lineNo endNo = do
iter <- textBufferGetIterAtLine buf lineNo
next <- textIterCopy iter
forwardTextIter next 2 >>= \case
Nothing -> return ()
Just endIter -> do
indent <- textBufferGetText buf iter endIter False
when (_INDENT_SPACE == indent) $ textBufferDelete buf iter endIter
if lineNo == endNo then return ()
else deleteIndent buf (lineNo+1) endNo
-- |
--
--
blockCommentTextEditor :: TextEditorData -> IO ()
blockCommentTextEditor te@(TextEditorData _ codeView _ _) = do
(startLine, endLine) <- getSelectedLineNumbers te
buf <- textViewGetBuffer codeView
insertComment buf startLine endLine
where
insertComment buf lineNo endNo = do
iter <- textBufferGetIterAtLine buf lineNo
cnt <- getSpaceCount buf iter
when (cnt /= (-1)) $ do
forwardTextIter iter cnt >>= \case
Nothing -> return ()
Just startIter -> textBufferInsert buf startIter _COMMENT_TAG
if lineNo == endNo then return ()
else insertComment buf (lineNo+1) endNo
getSpaceCount buf iter = do
isEndLine <- textIterEndsLine iter
isEndBuf <- textIterIsEnd iter
if isEndLine || isEndBuf then return (-1) else do
endIter <- textIterCopy iter
_ <- textIterForwardToLineEnd endIter
str <- textBufferGetText buf iter endIter False
return $ length $ takeWhile (== ' ') str
-- |
--
--
blockUnCommentTextEditor :: TextEditorData -> IO ()
blockUnCommentTextEditor te@(TextEditorData _ codeView _ _) = do
(startLine, endLine) <- getSelectedLineNumbers te
buf <- textViewGetBuffer codeView
deleteComment buf startLine endLine
where
deleteComment buf lineNo endNo = do
iter <- textBufferGetIterAtLine buf lineNo
(isCmnt, idx) <- getCommentInfo buf iter
iterMay <- forwardTextIter iter idx
when isCmnt $ deleteCommentTag buf iterMay
if lineNo == endNo then return ()
else deleteComment buf (lineNo+1) endNo
deleteCommentTag _ Nothing = return ()
deleteCommentTag buf (Just iter) = do
next <- textIterCopy iter
forwardTextIter next (length _COMMENT_TAG) >>= \case
Nothing -> return ()
Just endIter -> textBufferDelete buf iter endIter
getCommentInfo :: TextBuffer -> TextIter -> IO (Bool, Int)
getCommentInfo buf iter = do
endIter <- textIterCopy iter
textIterForwardToLineEnd endIter >>= \case
False -> return (False, 0) -- 最終行はFalseとなる問題あり。
True -> do
str <- textBufferGetText buf iter endIter False
if startswith _COMMENT_TAG (strip str) then return (True, length (head (split _COMMENT_TAG str)))
else return (False, length (takeWhile (== ' ') str))
-- |
--
--
getSelectedLineNumbers :: TextEditorData -> IO (Int, Int)
getSelectedLineNumbers te@(TextEditorData _ codeView _ _) = do
buf <- textViewGetBuffer codeView
textBufferHasSelection buf >>= \case
True -> do
(startIter, endIter) <- textBufferGetSelectionBounds buf
s <- textIterGetLine startIter
e <- textIterGetLine endIter
return (s, e)
False -> do
(l, _) <- getCodeTextLineNumber te
return (l, l)
-- |
--
--
setContent2TextEditor :: TextEditorData -> BS.ByteString -> IO ()
setContent2TextEditor (TextEditorData _ codeView _ _) bs = do
buf <- textViewGetBuffer codeView
textBufferSetByteString buf bs
textBufferSetModified buf False
-- |
--
--
setCursorOnTextEditor :: TextEditorData -> Int -> Int -> IO ()
setCursorOnTextEditor (TextEditorData _ codeView _ _) lineNo colNo = do
buf <- textViewGetBuffer codeView
iter <- textBufferGetIterAtLineOffset buf lineNo colNo
textBufferPlaceCursor buf iter
mark <- textBufferGetInsert buf
textViewScrollToMark codeView mark 0.0 (Just (0.0, 0.5))
-- |
--
--
insertText2TextEditor :: TextEditorData -> Int -> Int -> String -> IO ()
insertText2TextEditor (TextEditorData _ codeView _ _) startLineNo startColNo str = do
buf <- textViewGetBuffer codeView
iter <- textBufferGetIterAtLineOffset buf startLineNo startColNo
textBufferInsert buf iter str
-- |
--
--
deleteRangeOnTextEditor :: TextEditorData -> Int -> Int -> Int -> Int -> IO ()
deleteRangeOnTextEditor (TextEditorData _ codeView _ _) startLineNo startColNo endLineNo endColNo = do
buf <- textViewGetBuffer codeView
startIter <- textBufferGetIterAtLineOffset buf startLineNo startColNo
endIter <- textBufferGetIterAtLineOffset buf endLineNo endColNo
textBufferDelete buf startIter endIter
-- |
--
--
getSelectedText :: TextEditorData -> IO String
getSelectedText (TextEditorData _ codeView _ _) = do
buf <- textViewGetBuffer codeView
textBufferHasSelection buf >>= \case
True -> do
(startIter, endIter) <- textBufferGetSelectionBounds buf
textBufferGetText buf startIter endIter False
False -> return ""