diff --git a/feedback.yaml b/feedback.yaml index c3d40cd23259b2da871e0ae346cb68a88b8239c9..b26d8e2f70a8b3107d252b5a18639d652a86e8ee 100644 --- a/feedback.yaml +++ b/feedback.yaml @@ -8,3 +8,5 @@ loops: command: nix run .#horizon-gen-nix filter: find: horizon.dhall + procex: + command: nix run .#procex -L diff --git a/horizon.dhall b/horizon.dhall index 6a37b3e17d4b01e050322180a6eb1916e7b3ca34..c4c0061cb85844acf4377f08e990ad07785a5016 100644 --- a/horizon.dhall +++ b/horizon.dhall @@ -1238,7 +1238,7 @@ let packages = , zlib = H.callHackage "zlib" "0.6.3.0" } -in H.HorizonExport.MakePackageSet +in H.HorizonExport.MakePackageSet { packagesDir = "pkgs" , packageSetFile = "initial-packages.nix" , packageSet = { compiler = "ghc-9.4.4", packages = toMap packages } diff --git a/shell/ShellRC.hs b/shell/ShellRC.hs index bdcc0aa5c85a0d2a4d35e56f880dde4e7bfb804e..0be6013ca97a561c2ab01bab2f919fbca3623936 100644 --- a/shell/ShellRC.hs +++ b/shell/ShellRC.hs @@ -1,9 +1,9 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NoMonomorphismRestriction #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wno-missing-signatures #-} {-# OPTIONS_GHC -Wno-unused-imports #-} @@ -11,27 +11,27 @@ module ShellRC where -import Polysemy.State -import Control.Monad (void) -import Control.Monad.IO.Class -import Brick (BrickEvent (VtyEvent), EventM, gets, +import Brick (BrickEvent (VtyEvent), EventM, Padding (..), ViewportType (Vertical), Widget, - attrMap, attrName, bg, fg, hBox, - halt, on, padLeftRight, txt, vScrollBy, - viewport, viewportScroll, visible, - withAttr) + attrMap, attrName, bg, fg, gets, + hBox, halt, on, padLeftRight, txt, + vScrollBy, viewport, viewportScroll, + visible, withAttr) import qualified Brick +import Brick.Widgets.Border import qualified Brick.Widgets.List as Brick import Brick.Widgets.Table (Table, renderTable, table) import qualified Brick.Widgets.Table as Brick import qualified Control.Lens as L +import Control.Monad (forM, void) +import Control.Monad.IO.Class import Cursor.List.NonEmpty import qualified Data.Aeson as A import qualified Data.Aeson.Key as A import qualified Data.Aeson.KeyMap as A import qualified Data.Aeson.Lens as L -import qualified Data.ByteString.Lazy as B +import qualified Data.ByteString as B import Data.ByteString.Lazy.UTF8 as BLU import qualified Data.ByteString.Lazy.UTF8 as BU import Data.Kind (Type) @@ -39,22 +39,24 @@ import qualified Data.List import Data.List.NonEmpty (NonEmpty ((:|))) import qualified Data.Map as Map import Data.Maybe (fromMaybe) +import Data.Monoid import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Encoding as T +import qualified Data.Text.Encoding.Error as T import qualified Data.Vector as V import qualified Data.Yaml as Y import qualified Data.Yaml.Pretty as Y import qualified Dhall -import Data.Monoid import Graphics.Vty.Attributes import Graphics.Vty.Input.Events import Horizon.Spec import Network.HTTP.Simple import Path +import Polysemy +import Polysemy.State import Procex.Prelude import Procex.Shell hiding (promptFunction) -import Polysemy import System.Directory import System.Environment @@ -110,26 +112,48 @@ renderHaskellSource (FromGit x) = renderGitSource x renderHaskellSource (FromHackage x) = renderHackageSource x type PackageListCursor :: Type -type PackageListCursor = NonEmptyCursor (Name, HaskellPackage) (Name, HaskellPackage) +type PackageListCursor = NonEmptyCursor (Name, HaskellPackage, Text) (Name, HaskellPackage, Text) + +type HorizonTUIState :: Type +data HorizonTUIState where + MkHorizonTUIState :: { + packageListCursor :: PackageListCursor, + lastChar :: Maybe Char + } -> HorizonTUIState packageListToMatrix :: PackageListCursor -> [[Widget n]] packageListToMatrix (NonEmptyCursor xs y zs) = V.toList $ mconcat [ - fmap (\(k, v) -> [renderName k, renderHaskellSource $ source v]) $ V.fromList $ reverse $ Data.List.take 100 xs, - pure $ (\(k, v) -> fmap (withAttr (attrName "highlight")) [visible (renderName k), renderHaskellSource $ source v]) $ y, - fmap (\(k, v) -> [renderName k, renderHaskellSource $ source v]) $ V.fromList $ Data.List.take 100 zs + fmap (\(k, v, _) -> [renderName k, renderHaskellSource $ source v]) $ V.fromList $ reverse $ Data.List.take 100 xs, + pure $ (\(k, v, _) -> fmap (withAttr (attrName "highlight")) [visible (renderName k), renderHaskellSource $ source v]) $ y, + fmap (\(k, v, _) -> [renderName k, renderHaskellSource $ source v]) $ V.fromList $ Data.List.take 100 zs ] +renderCursorPackageInfo :: PackageListCursor -> Widget n +renderCursorPackageInfo (NonEmptyCursor _ y _) = txt . L.view L._3 $ y + packageListToTable :: PackageListCursor -> Table n packageListToTable = table . packageListToMatrix -renderPackageList :: PackageListCursor -> Widget Text -renderPackageList = viewport "Viewy" Vertical . renderTable . packageListToTable +renderPackageList :: Text -> PackageListCursor -> Widget Text +renderPackageList x = viewport x Vertical . renderTable . packageListToTable + +nonEmptyCursorSelectNextClamped :: (a -> b) -> (b -> a) -> NonEmptyCursor a b -> NonEmptyCursor a b +nonEmptyCursorSelectNextClamped f g s = fromMaybe s $ nonEmptyCursorSelectNext f g s + +nonEmptyCursorSelectPrevClamped :: (a -> b) -> (b -> a) -> NonEmptyCursor a b -> NonEmptyCursor a b +nonEmptyCursorSelectPrevClamped f g s = fromMaybe s $ nonEmptyCursorSelectPrev f g s -scrollDown :: EventM e (PackageListCursor, c) () -scrollDown = Brick.modify (\(s, c) -> (fromMaybe s $ nonEmptyCursorSelectNext id id s, c)) +scrollDown :: EventM e HorizonTUIState () +scrollDown = Brick.modify (\(MkHorizonTUIState s c) -> MkHorizonTUIState (nonEmptyCursorSelectNextClamped id id s) c) -scrollUp :: EventM e (PackageListCursor, c) () -scrollUp = Brick.modify (\(s, c) -> (fromMaybe s $ nonEmptyCursorSelectPrev id id s, c)) +scrollUp :: EventM e HorizonTUIState () +scrollUp = Brick.modify (\(MkHorizonTUIState s c) -> MkHorizonTUIState (nonEmptyCursorSelectPrevClamped id id s) c) + +endOfFile :: EventM e HorizonTUIState () +endOfFile = Brick.modify (\(MkHorizonTUIState s c) -> MkHorizonTUIState (nonEmptyCursorSelectLast id id s) c) + +startOfFile :: EventM e HorizonTUIState () +startOfFile = Brick.modify (\(MkHorizonTUIState s c) -> MkHorizonTUIState (nonEmptyCursorSelectFirst id id s) c) type Vim :: Type -> (Type -> Type) -> Type -> Type data Vim y m a where @@ -148,19 +172,19 @@ data Vim y m a where makeSem ''Vim -interpretVim :: Member (Embed (EventM e (PackageListCursor, c))) r => Sem (Vim y ': r) a -> Sem r a +interpretVim :: Member (Embed (EventM e HorizonTUIState)) r => Sem (Vim y ': r) a -> Sem r a interpretVim = interpret $ \case - Del -> embed $ pure () - Find -> embed $ pure () - MoveDown -> embed $ scrollDown - MoveEndOfFile -> embed $ Brick.modify (\(x, c) -> (nonEmptyCursorSelectLast id id x, c)) - MoveLeft -> embed $ pure () - MoveRight -> embed $ pure () - MoveStartOfFile -> embed $ Brick.modify (\(x, c) -> (nonEmptyCursorSelectFirst id id x , c)) - MoveUp -> embed $ scrollUp - Paste -> embed $ pure () - Quit -> embed $ halt - Yank -> embed $ pure () + Del -> embed $ pure () + Find -> embed $ pure () + MoveDown -> embed $ scrollDown + MoveEndOfFile -> embed $ endOfFile + MoveLeft -> embed $ pure () + MoveRight -> embed $ pure () + MoveStartOfFile -> embed $ startOfFile + MoveUp -> embed $ scrollUp + Paste -> embed $ pure () + Quit -> embed $ halt + Yank -> embed $ pure () brickEventToVim :: Members '[Vim y, State (Maybe Char)] r => BrickEvent Text e -> Sem r () brickEventToVim (VtyEvent (EvKey KDown [])) = moveDown @@ -171,34 +195,32 @@ brickEventToVim (VtyEvent (EvKey (KChar 'G') [])) = moveEndOfFile brickEventToVim (VtyEvent (EvKey (KChar 'g') [])) = do x <- get case x of - Just 'g' -> do - moveStartOfFile + Just 'g' -> do + moveStartOfFile put Nothing _ -> put $ Just 'g' brickEventToVim (VtyEvent (EvKey (KChar 'q') [])) = quit brickEventToVim (VtyEvent (EvKey (KChar 'w') [])) = write -brickEventToVim _ = pure () - + semStateToBrickState :: Member (Embed (EventM e s)) r => L.Lens' s t -> Sem (State t ': r) a -> Sem r a semStateToBrickState f = interpret $ \case Put x -> embed $ Brick.put . L.set f x =<< Brick.get Get -> embed $ L.view f <$> Brick.get - -handleEvent :: BrickEvent Text e -> EventM Text (PackageListCursor, Maybe Char) () -handleEvent x = do - runM . semStateToBrickState (L.lens snd (\z k -> (fst z, k))) . interpretVim . brickEventToVim $ x +handleEvent :: BrickEvent Text e -> EventM Text HorizonTUIState () handleEvent (VtyEvent (EvKey (KChar 'b') [])) = do - (MkName x, _) <- Brick.gets (nonEmptyCursorCurrent . fst) - let z = mq + (MkName x, _, _) <- Brick.gets (nonEmptyCursorCurrent . packageListCursor) + _ <- liftIO $ captureLazyNoThrow $ mq "nix" "build" "-L" (T.unpack $ ".#" <> x) - (pipeHOut 1 $ \_ stdout -> B.hGetContents stdout >>= B.putStr) - (pipeHOut 2 $ \_ stderr -> B.hGetContents stderr >>= B.writeFile "./log") + (pipeHOut 1 $ \_ stdout -> B.hGetContents stdout >>= (\_ -> pure ())) + (pipeHOut 2 $ \_ stderr -> B.hGetContents stderr >>= (\_ -> pure ())) pure () +handleEvent x = do + runM . semStateToBrickState (L.lens lastChar (\(MkHorizonTUIState s c) x -> MkHorizonTUIState s x )) . interpretVim . brickEventToVim $ x handleEvent _ = pure () @@ -207,12 +229,26 @@ appAttrMap = attrMap defAttr [ (attrName "highlight", fg yellow) , (attrName "good", white `on` green) ] -packageListMain :: Brick.App (PackageListCursor, Maybe Char) e Text -packageListMain = Brick.App (pure . renderPackageList . fst) (const $ const Nothing) handleEvent (pure ()) (const (appAttrMap)) +packageListMain :: Brick.App HorizonTUIState e Text +packageListMain = Brick.App ((\x -> pure $ hBox [renderPackageList "F" x, border $ renderCursorPackageInfo x]) . packageListCursor) (const $ const Nothing) handleEvent (pure ()) (const (appAttrMap)) + +buildCursor :: HorizonExport -> IO PackageListCursor +buildCursor (MakePackageSet (MkPackageSetExportSettings d _ (MkPackageSet _ (MkPackageList (Map.toList -> y:ys))))) = do + (z : zs) <- forM (y:ys) $ \(x, k) -> do + q <- readDerivation d x + pure (x, k, q) + pure $ makeNonEmptyCursor id (z :| zs) + +readDerivation :: PackagesDir -> Name -> IO Text +readDerivation (MkPackagesDir d) (MkName x) = do + f' <- parseRelFile $ T.unpack (x <> ".nix") + let j = d </> f' + q <- B.readFile $ toFilePath j + pure $ T.decodeUtf8Lenient q go :: IO () go = do x <- Dhall.inputFile @HorizonExport Dhall.auto "horizon.dhall" - case x of - MakePackageSet (MkPackageSetExportSettings _ _ (MkPackageSet _ (MkPackageList (Map.toList -> y:ys)))) -> Brick.defaultMain packageListMain $ (makeNonEmptyCursor id (y :| ys), Nothing) + k <- buildCursor x + Brick.defaultMain packageListMain $ MkHorizonTUIState k Nothing pure ()