Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split every tab in two panes #206

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,3 +529,4 @@ would like to add, please submit an issue or PR.
## Maintainers

- [cdepillabout](https://github.com/cdepillabout)
- [gelisam](https://github.com/gelisam)
95 changes: 61 additions & 34 deletions src/Termonad/App.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ import GI.Gtk
, Entry(Entry)
, FontButton(FontButton)
, Label(Label)
, Paned(Paned)
, PolicyType(PolicyTypeAutomatic)
, PositionType(PositionTypeRight)
, ResponseType(ResponseTypeAccept, ResponseTypeNo, ResponseTypeYes)
, ScrolledWindow(ScrolledWindow)
, SpinButton(SpinButton)
, pattern STYLE_PROVIDER_PRIORITY_APPLICATION
, aboutDialogNew
Expand Down Expand Up @@ -138,24 +138,26 @@ import Termonad.Lenses
, lensShowTabBar
, lensScrollbackLen
, lensTMNotebook
, lensTMNotebookTabTermContainer
, lensTMNotebookTabFocusedTerm
, lensTMNotebookTabs
, lensTMNotebookTabTerm
, lensTMStateApp
, lensTMStateAppWin
, lensTMStateConfig
, lensTMStateFontDesc
, lensTMStateNotebook
, lensTMTermScrolledWindow
, lensTerm
, lensWordCharExceptions
, traversalTMNotebookTabTerms
)
import Termonad.PreferencesFile (saveToPreferencesFile)
import Termonad.Term
( createTerm
( createTerms
, relabelTabs
, termExitFocused
, termNextPage
, termPrevPage
, termExitFocused
, termTogglePane
, setShowTabs
, showScrollbarToPolicy
)
Expand All @@ -169,11 +171,12 @@ import Termonad.Types
, TMNotebookTab
, TMState
, TMState'(TMState)
, TMTerm
, getFocusedTermFromState
, modFontSize
, newEmptyTMState
, tmNotebookTabTermContainer
, tmNotebookTabs
, tmNotebookTabPaned
, tmStateApp
, tmStateNotebook
)
Expand Down Expand Up @@ -257,7 +260,7 @@ modifyFontSizeForAllTerms modFontSizeFunc mvarTMState = do
lensTMStateNotebook .
lensTMNotebookTabs .
traverse .
lensTMNotebookTabTerm .
traversalTMNotebookTabTerms .
lensTerm
foldMap (\vteTerm -> terminalSetFont vteTerm (Just fontDesc)) terms

Expand All @@ -277,13 +280,13 @@ fontConfigFromFontDescription fontDescription = do
maybeFontFamily <- fontDescriptionGetFamily fontDescription
return $ (`FontConfig` fontSize) <$> maybeFontFamily

compareScrolledWinAndTab :: ScrolledWindow -> TMNotebookTab -> Bool
compareScrolledWinAndTab scrollWin flTab =
let ScrolledWindow managedPtrFLTab = tmNotebookTabTermContainer flTab
comparePanedAndTab :: Paned -> TMNotebookTab -> Bool
comparePanedAndTab paned flTab =
let Paned managedPtrFLTab = tmNotebookTabPaned flTab
foreignPtrFLTab = managedForeignPtr managedPtrFLTab
ScrolledWindow managedPtrScrollWin = scrollWin
foreignPtrScrollWin = managedForeignPtr managedPtrScrollWin
in foreignPtrFLTab == foreignPtrScrollWin
Paned managedPtrPaned = paned
foreignPtrPaned = managedForeignPtr managedPtrPaned
in foreignPtrFLTab == foreignPtrPaned

updateFLTabPos :: TMState -> Int -> Int -> IO ()
updateFLTabPos mvarTMState oldPos newPos =
Expand Down Expand Up @@ -382,7 +385,7 @@ setupTermonad tmConfig app win builder = do
boxPackStart box note True True 0

mvarTMState <- newEmptyTMState tmConfig app win note fontDesc
terminal <- createTerm handleKeyPress mvarTMState
(terminalL, _terminalR) <- createTerms handleKeyPress mvarTMState

void $ onNotebookPageRemoved note $ \_ _ -> do
pages <- notebookGetNPages note
Expand All @@ -391,57 +394,74 @@ setupTermonad tmConfig app win builder = do
else setShowTabs tmConfig note

void $ onNotebookSwitchPage note $ \_ pageNum -> do
modifyMVar_ mvarTMState $ \tmState -> do
followUp <- modifyMVar mvarTMState $ \tmState -> do
let notebook = tmStateNotebook tmState
tabs = tmNotebookTabs notebook
maybeNewTabs = updateFocusFL (fromIntegral pageNum) tabs
case maybeNewTabs of
Nothing -> pure tmState
Nothing -> do
pure (tmState, pure ())
Just (tab, newTabs) -> do
widgetGrabFocus $ tab ^. lensTMNotebookTabTerm . lensTerm
pure $
tmState &
lensTMStateNotebook . lensTMNotebookTabs .~ newTabs
let followUp = do
let newFocus = tab ^. lensTMNotebookTabFocusedTerm . lensTerm
widgetGrabFocus newFocus
Comment on lines +405 to +407
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm glad you were able to figure out how to do this. I should really document the need to pull out these types of follow-up IO actions and run them after modifying the MVar. Hope this didn't take too long to figure out.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't too bad; my initial attempt deadlocked, but I was able to figure out by adding a few print statements here and there.

tmState'
= tmState
& lensTMStateNotebook . lensTMNotebookTabs .~ newTabs
pure (tmState', followUp)
followUp

void $ onNotebookPageReordered note $ \childWidg pageNum -> do
maybeScrollWin <- castTo ScrolledWindow childWidg
case maybeScrollWin of
maybePaned <- castTo Paned childWidg
case maybePaned of
Nothing ->
fail $
"In setupTermonad, in callback for onNotebookPageReordered, " <>
"child widget is not a ScrolledWindow.\n" <>
"child widget is not a Paned.\n" <>
"Don't know how to continue.\n"
Just scrollWin -> do
Just paned -> do
TMState{tmStateNotebook} <- readMVar mvarTMState
let fl = tmStateNotebook ^. lensTMNotebookTabs
let maybeOldPosition =
findIndexR (compareScrolledWinAndTab scrollWin) (focusList fl)
findIndexR (comparePanedAndTab paned) (focusList fl)
case maybeOldPosition of
Nothing ->
fail $
"In setupTermonad, in callback for onNotebookPageReordered, " <>
"the ScrolledWindow is not already in the FocusList.\n" <>
"the Paned is not already in the FocusList.\n" <>
"Don't know how to continue.\n"
Just oldPos -> do
updateFLTabPos mvarTMState oldPos (fromIntegral pageNum)
relabelTabs mvarTMState

newTabAction <- simpleActionNew "newtab" Nothing
void $ onSimpleActionActivate newTabAction $ \_ -> void $ createTerm handleKeyPress mvarTMState
void $ onSimpleActionActivate newTabAction $ \_ -> void $ createTerms handleKeyPress mvarTMState
actionMapAddAction app newTabAction
applicationSetAccelsForAction app "app.newtab" ["<Shift><Ctrl>T"]

nextPaneAction <- simpleActionNew "nextpane" Nothing
void $ onSimpleActionActivate nextPaneAction $ \_ ->
termTogglePane mvarTMState
actionMapAddAction app nextPaneAction
applicationSetAccelsForAction app "app.nextpane" ["<Ctrl>Page_Down"]

prevPaneAction <- simpleActionNew "prevpane" Nothing
void $ onSimpleActionActivate prevPaneAction $ \_ ->
termTogglePane mvarTMState
actionMapAddAction app prevPaneAction
applicationSetAccelsForAction app "app.prevpane" ["<Ctrl>Page_Up"]

nextPageAction <- simpleActionNew "nextpage" Nothing
void $ onSimpleActionActivate nextPageAction $ \_ ->
termNextPage mvarTMState
actionMapAddAction app nextPageAction
applicationSetAccelsForAction app "app.nextpage" ["<Ctrl>Page_Down"]
applicationSetAccelsForAction app "app.nextpage" ["<Ctrl><Shift>Page_Down"]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably a controversial change! Switching between tabs is a bigger change than switching between panes, and it makes more sense to me to use the the Shift version of the hotkey for the bigger change.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with your reasoning here, although I don't personally use the <Ctrl>Page_Down key.

I imagine I might have to finally start working on #83 !

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, now that I think about it, this key combination only makes sense because with the two-panes approach, there is an obvious next-pane and prev-pane. Once arbitrary splittings are allowed, we'll need key combinations to move up, down, left and right, not prev and next. So I think <Ctrl>Page_Down can continue to be reserved for tabs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some example solutions here earlier.

tmux by way of example, employs a "previous / next" concept so that you can use:

  • ctl+b then ; to toggle previous pane (effectively switches between two panes)
  • ctl+b then { or ctl+b then } for moving panes
  • ctl+b then arrow key for simply changing to the next pane in that direction.


prevPageAction <- simpleActionNew "prevpage" Nothing
void $ onSimpleActionActivate prevPageAction $ \_ ->
termPrevPage mvarTMState
actionMapAddAction app prevPageAction
applicationSetAccelsForAction app "app.prevpage" ["<Ctrl>Page_Up"]
applicationSetAccelsForAction app "app.prevpage" ["<Ctrl><Shift>Page_Up"]

closeTabAction <- simpleActionNew "closetab" Nothing
void $ onSimpleActionActivate closeTabAction $ \_ ->
Expand Down Expand Up @@ -478,13 +498,13 @@ setupTermonad tmConfig app win builder = do
void $ onSimpleActionActivate enlargeFontAction $ \_ ->
modifyFontSizeForAllTerms (modFontSize 1) mvarTMState
actionMapAddAction app enlargeFontAction
applicationSetAccelsForAction app "app.enlargefont" ["<Ctrl>plus"]
applicationSetAccelsForAction app "app.enlargefont" ["<Ctrl>KP_Add"]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops! this doesn't belong to this draft PR...


reduceFontAction <- simpleActionNew "reducefont" Nothing
void $ onSimpleActionActivate reduceFontAction $ \_ ->
modifyFontSizeForAllTerms (modFontSize (-1)) mvarTMState
actionMapAddAction app reduceFontAction
applicationSetAccelsForAction app "app.reducefont" ["<Ctrl>minus"]
applicationSetAccelsForAction app "app.reducefont" ["<Ctrl>KP_Subtract"]

findAction <- simpleActionNew "find" Nothing
void $ onSimpleActionActivate findAction $ \_ -> doFind mvarTMState
Expand Down Expand Up @@ -528,8 +548,9 @@ setupTermonad tmConfig app win builder = do
ResponseTypeYes -> False
_ -> True

-- Focus on the left terminal
widgetShowAll win
widgetGrabFocus $ terminal ^. lensTerm
widgetGrabFocus $ terminalL ^. lensTerm

appActivate :: TMConfig -> Application -> IO ()
appActivate tmConfig app = do
Expand Down Expand Up @@ -717,10 +738,15 @@ applyNewPreferences mvarTMState = do

applyNewPreferencesToTab :: TMState -> TMNotebookTab -> IO ()
applyNewPreferencesToTab mvarTMState tab = do
for_ (tab ^.. traversalTMNotebookTabTerms) $ \tmTerm -> do
applyNewPreferencesToTerm mvarTMState tmTerm

applyNewPreferencesToTerm :: TMState -> TMTerm -> IO ()
applyNewPreferencesToTerm mvarTMState tmTerm = do
tmState <- readMVar mvarTMState
let fontDesc = tmState ^. lensTMStateFontDesc
term = tab ^. lensTMNotebookTabTerm . lensTerm
scrolledWin = tab ^. lensTMNotebookTabTermContainer
term = tmTerm ^. lensTerm
scrolledWin = tmTerm ^. lensTMTermScrolledWindow
options = tmState ^. lensTMStateConfig . lensOptions
terminalSetFont term (Just fontDesc)
terminalSetCursorBlinkMode term (cursorBlinkMode options)
Expand All @@ -731,6 +757,7 @@ applyNewPreferencesToTab mvarTMState tab = do
let vScrollbarPolicy = showScrollbarToPolicy (options ^. lensShowScrollbar)
scrolledWindowSetPolicy scrolledWin PolicyTypeAutomatic vScrollbarPolicy


-- | Show the preferences dialog.
--
-- When the user clicks on the Ok button, it copies the new settings to TMState.
Expand Down
18 changes: 18 additions & 0 deletions src/Termonad/Gtk.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Termonad.Prelude

import Control.Monad.Fail (MonadFail, fail)
import Data.GI.Base (ManagedPtr, withManagedPtr)
import Data.GI.Base.GObject (gtypeFromInstance)
import GHC.Stack (HasCallStack)
import GI.Gdk
( GObject
Expand Down Expand Up @@ -58,3 +59,20 @@ widgetEq a b = do
withManagedPtr managedPtrA $ \ptrA ->
withManagedPtr managedPtrB $ \ptrB ->
pure (ptrA == ptrB)

printWidgetTree :: Gtk.IsWidget a => a -> IO ()
printWidgetTree widget_ = do
widget <- Gtk.toWidget widget_
go "" widget
where
go :: Text -> Gtk.Widget -> IO ()
go indent w = do
type_ <- gtypeFromInstance w
name <- Gtk.gtypeName type_
let ptr = Gtk.managedForeignPtr . Gtk.toManagedPtr $ w
putStrLn $ indent <> pack name <> " " <> pack (show ptr)
maybeContainer <- Gtk.castTo Gtk.Container w
for_ maybeContainer $ \container -> do
children <- Gtk.containerGetChildren container
for_ children $ \child -> do
go (" " <> indent) child
61 changes: 57 additions & 4 deletions src/Termonad/Lenses.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,85 @@

module Termonad.Lenses where

import Control.Lens (makeLensesFor, makePrisms)
import Termonad.Prelude

import Control.Lens (Lens', Traversal', makeLensesFor, makePrisms)
import Data.FocusList (FocusList)
import Termonad.Types
import qualified Data.FocusList as FocusList
import qualified Data.Maybe as Unsafe (fromJust)
import qualified Data.Sequence as Seq

$(makeLensesFor
[ ("term", "lensTerm")
[ ("tmTermScrolledWindow", "lensTMTermScrolledWindow")
, ("term", "lensTerm")
, ("pid", "lensPid")
, ("unique", "lensUnique")
]
''TMTerm
)

$(makeLensesFor
[ ("tmNotebookTabTermContainer", "lensTMNotebookTabTermContainer")
, ("tmNotebookTabTerm", "lensTMNotebookTabTerm")
[ ("tmNotebookTabPaned", "lensTMNotebookTabPaned")
, ("tmNotebookTabLeftTerm", "lensTMNotebookTabLeftTerm")
, ("tmNotebookTabRightTerm", "lensTMNotebookTabRightTerm")
, ("tmNotebookTabFocusIsOnLeft", "lensTMNotebookTabFocusIsOnLeft")
, ("tmNotebookTabLabel", "lensTMNotebookTabLabel")
]
''TMNotebookTab
)

lensTMNotebookTabFocusedTerm :: Lens' TMNotebookTab TMTerm
lensTMNotebookTabFocusedTerm f notebookTab
= if tmNotebookTabFocusIsOnLeft notebookTab
then lensTMNotebookTabLeftTerm f notebookTab
else lensTMNotebookTabRightTerm f notebookTab

lensTMNotebookTabNonFocusedTerm :: Lens' TMNotebookTab TMTerm
lensTMNotebookTabNonFocusedTerm f notebookTab
= if tmNotebookTabFocusIsOnLeft notebookTab
then lensTMNotebookTabRightTerm f notebookTab
else lensTMNotebookTabLeftTerm f notebookTab

traversalTMNotebookTabTerms :: Traversal' TMNotebookTab TMTerm
traversalTMNotebookTabTerms f notebookTab
= (\termL termR -> notebookTab
{ tmNotebookTabLeftTerm = termL
, tmNotebookTabRightTerm = termR
})
<$> f (tmNotebookTabLeftTerm notebookTab)
<*> f (tmNotebookTabRightTerm notebookTab)

$(makeLensesFor
[ ("tmNotebook", "lensTMNotebook")
, ("tmNotebookTabs", "lensTMNotebookTabs")
]
''TMNotebook
)

-- TODO: This should be available in focuslist-0.1.1.0 as traversalFocusItem.
-- focuslist-0.1.1.0 should likely be available in LTS-19.
-- We should delete this function and use traversalFocusItem when Termonad moves to using LTS-19.
traversalFLItem :: forall a. Traversal' (FocusList a) a
traversalFLItem f flA
= let seqA = FocusList.toSeqFL flA
maybeFocus = FocusList.getFocus (FocusList.getFocusFL flA)
maybeFocusItem = FocusList.getFocusItemFL flA
in case (maybeFocus, maybeFocusItem) of
(Just i, Just a)
-> let makeUpdatedFL :: a -> FocusList a
makeUpdatedFL a'
= Unsafe.fromJust -- safe because i and the length are unchanged
$ FocusList.fromFoldableFL
(FocusList.Focus i)
(Seq.update i a' seqA)
in makeUpdatedFL <$> f a
_
-> pure flA

traversalTMNotebookFocusedTab :: Traversal' TMNotebook TMNotebookTab
traversalTMNotebookFocusedTab = lensTMNotebookTabs . traversalFLItem

$(makeLensesFor
[ ("tmStateApp", "lensTMStateApp")
, ("tmStateAppWin", "lensTMStateAppWin")
Expand Down