diff options
| -rw-r--r-- | lib/Daffm/Action/Core.hs | 1 | ||||
| -rw-r--r-- | lib/Daffm/Attrs.hs | 12 | ||||
| -rw-r--r-- | lib/Daffm/State.hs | 35 | ||||
| -rw-r--r-- | lib/Daffm/Types.hs | 4 | ||||
| -rw-r--r-- | lib/Daffm/View.hs | 14 | ||||
| -rw-r--r-- | notes.org | 7 |
6 files changed, 63 insertions, 10 deletions
diff --git a/lib/Daffm/Action/Core.hs b/lib/Daffm/Action/Core.hs index a726c77..72bccef 100644 --- a/lib/Daffm/Action/Core.hs +++ b/lib/Daffm/Action/Core.hs @@ -48,6 +48,7 @@ openSelectedFile :: AppEvent () openSelectedFile = do currentFile >>= \case Just (FileInfo {filePath, fileType = Directory}) -> loadDir filePath + Just (FileInfo {filePath, fileLinkType = Just Directory}) -> loadDir filePath Just _ -> do opener <- gets (fromMaybe "echo '%F' | xargs -i xdg-open {}" . stateOpenerScript) cmdSubstitutions opener >>= suspendAndRunShellCommand False diff --git a/lib/Daffm/Attrs.hs b/lib/Daffm/Attrs.hs index d7b7097..f1d4e16 100644 --- a/lib/Daffm/Attrs.hs +++ b/lib/Daffm/Attrs.hs @@ -15,6 +15,15 @@ fileSelectedAttr = listSelectedAttr <> fileAttr directoryAttr :: A.AttrName directoryAttr = listAttr <> A.attrName "directory" +linkAttr :: A.AttrName +linkAttr = listAttr <> A.attrName "link" + +invalidLinkAttr :: A.AttrName +invalidLinkAttr = linkAttr <> A.attrName "invalid" + +directoryLinkAttr :: A.AttrName +directoryLinkAttr = linkAttr <> A.attrName "directory" + directorySelectedAttr :: A.AttrName directorySelectedAttr = listSelectedAttr <> directoryAttr @@ -29,6 +38,9 @@ appAttrMap = (listSelectedAttr, bg V.black), (directoryAttr, fg V.brightCyan), (directorySelectedAttr, fg V.brightCyan), + (directoryLinkAttr, fg V.green), + (linkAttr, fg V.brightWhite), + (invalidLinkAttr, fg V.red), (fileAttr, fg V.white), (fileSelectedAttr, fg V.white), (searchMarchAttr, fg V.magenta) diff --git a/lib/Daffm/State.hs b/lib/Daffm/State.hs index 1429897..150f34b 100644 --- a/lib/Daffm/State.hs +++ b/lib/Daffm/State.hs @@ -1,11 +1,16 @@ +{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} + +{-# HLINT ignore "Redundant multi-way if" #-} module Daffm.State where import qualified Brick.Widgets.Edit as Editor import qualified Brick.Widgets.List as L import Control.Applicative ((<|>)) +import Control.Exception (try) import Control.Monad (filterM, forM) import Daffm.Types import Daffm.Utils (trim) +import Data.Either (fromRight) import Data.List (findIndex, sortBy) import qualified Data.Map.Strict as Map import Data.Maybe (fromMaybe) @@ -13,7 +18,8 @@ import qualified Data.Set as Set import qualified Data.Text as Text import qualified Data.Text.Zipper.Generic as Zipper import qualified Data.Vector as Vec -import System.Directory (doesDirectoryExist, doesPathExist, getCurrentDirectory, getHomeDirectory, listDirectory, makeAbsolute, setCurrentDirectory) +import GHC.IO.Exception (IOException (IOError)) +import System.Directory (doesDirectoryExist, doesPathExist, getCurrentDirectory, getHomeDirectory, getSymbolicLinkTarget, listDirectory, makeAbsolute, setCurrentDirectory) import System.FilePath (joinPath, takeDirectory) import System.PosixCompat (fileExist) import qualified System.PosixCompat as Posix @@ -73,7 +79,7 @@ textAsString f = Text.pack . f . Text.unpack loadDirToState :: FilePathText -> AppState -> IO AppState loadDirToState dir' appState@(AppState {stateCwd, stateListPositionHistory}) = do normalizedDir <- (normalizePath . stripTrailingSlash . stripQuotes . trim) dir' >>= withCwdFallback - stat <- Posix.getSymbolicLinkStatus $ Text.unpack normalizedDir + stat <- Posix.getFileStatus $ Text.unpack normalizedDir let (dir, targetFilePathM) = if Posix.isDirectory stat then (normalizedDir, Nothing) @@ -106,20 +112,39 @@ getFileInfo :: FilePathText -> IO FileInfo getFileInfo name = do path <- makeAbsolute $ Text.unpack name stat <- Posix.getSymbolicLinkStatus path + let either2Maybe :: Either IOError a -> Maybe a + either2Maybe = either (const Nothing) Just + linkStat <- either2Maybe <$> try (Posix.getFileStatus path) + linkTarget <- + if + | Posix.isSymbolicLink stat -> Just . Text.pack <$> getSymbolicLinkTarget path + | otherwise -> pure Nothing pure $ FileInfo { filePath = Text.pack path, fileName = name, fileSize = Posix.fileSize stat, fileMode = Posix.fileMode stat, - fileType = fileTypeFromStatus stat + fileType = fileTypeFromStatus stat, + fileLinkType = fileTypeFromStatus <$> linkStat, + fileLinkTarget = linkTarget } fileSorter :: FileInfo -> FileInfo -> Ordering -fileSorter (FileInfo {fileType = Directory, fileName = fa}) (FileInfo {fileType = Directory, fileName = fb}) = - compare (Text.toLower fa) (Text.toLower fb) +fileSorter + (FileInfo {fileType = Directory, fileName = fa}) + (FileInfo {fileType = Directory, fileName = fb}) = + compare (Text.toLower fa) (Text.toLower fb) +fileSorter + (FileInfo {fileType = SymbolicLink, fileLinkType = Just Directory, fileName = fa}) + (FileInfo {fileType = SymbolicLink, fileLinkType = Just Directory, fileName = fb}) = + compare (Text.toLower fa) (Text.toLower fb) +fileSorter (FileInfo {fileType = Directory}) (FileInfo {fileType = SymbolicLink, fileLinkType = Just Directory}) = LT +fileSorter (FileInfo {fileType = SymbolicLink, fileLinkType = Just Directory}) (FileInfo {fileType = Directory}) = GT fileSorter (FileInfo {fileType = Directory}) _ = LT fileSorter _ (FileInfo {fileType = Directory}) = GT +fileSorter (FileInfo {fileLinkType = Just Directory}) _ = LT +fileSorter _ (FileInfo {fileLinkType = Just Directory}) = GT fileSorter (FileInfo {fileName = fa}) (FileInfo {fileName = fb}) = compare (Text.toLower fa) (Text.toLower fb) diff --git a/lib/Daffm/Types.hs b/lib/Daffm/Types.hs index dc6ca36..e7751c4 100644 --- a/lib/Daffm/Types.hs +++ b/lib/Daffm/Types.hs @@ -30,7 +30,9 @@ data FileInfo = FileInfo filePath :: FilePathText, fileSize :: FileOffset, fileMode :: FileMode, - fileType :: FileType + fileType :: FileType, + fileLinkType :: Maybe FileType, + fileLinkTarget :: Maybe FilePathText } deriving (Show) diff --git a/lib/Daffm/View.hs b/lib/Daffm/View.hs index 081cd38..e65a13a 100644 --- a/lib/Daffm/View.hs +++ b/lib/Daffm/View.hs @@ -4,7 +4,7 @@ import Brick.Types (Widget) import Brick.Widgets.Core (Padding (Max, Pad), emptyWidget, hBox, hLimit, padLeft, padRight, str, txt, vBox, vLimit, withAttr, (<+>)) import Brick.Widgets.Edit (renderEditor) import qualified Brick.Widgets.List as L -import Daffm.Attrs (directoryAttr, directorySelectedAttr, fileAttr, fileSelectedAttr, searchMarchAttr) +import Daffm.Attrs (directoryAttr, directoryLinkAttr, directorySelectedAttr, fileAttr, fileSelectedAttr, invalidLinkAttr, linkAttr, searchMarchAttr) import Daffm.Keymap (showKeySequence) import Daffm.Types (AppState (..), FileInfo (..), FileType (..), FocusTarget (..)) import Data.Int (Int64) @@ -78,9 +78,21 @@ showFileMode mode = permchars fileNameView :: Bool -> FileInfo -> Widget FocusTarget fileNameView True (FileInfo {fileName, fileType = Directory}) = withAttr directorySelectedAttr $ txt $ fileName <> "/" fileNameView False (FileInfo {fileName, fileType = Directory}) = withAttr directoryAttr $ txt $ fileName <> "/" +fileNameView _ file@(FileInfo {fileType = SymbolicLink}) = symbolicLinkNameView file fileNameView True (FileInfo {fileName}) = withAttr fileSelectedAttr $ txt fileName fileNameView False (FileInfo {fileName}) = withAttr fileAttr $ txt fileName +symbolicLinkNameView :: FileInfo -> Widget n +symbolicLinkNameView (FileInfo {fileName, fileLinkTarget, fileLinkType = Just Directory}) = + withAttr directoryLinkAttr (txt $ fileName <> "/") <+> txt " -> " <+> symTargetView (Just Directory) fileLinkTarget +symbolicLinkNameView (FileInfo {fileName, fileLinkType, fileLinkTarget}) = + withAttr linkAttr (txt fileName) <+> txt " -> " <+> symTargetView fileLinkType fileLinkTarget + +symTargetView :: Maybe FileType -> Maybe Text.Text -> Widget n +symTargetView _ Nothing = withAttr invalidLinkAttr $ txt "<none>" +symTargetView Nothing (Just target) = withAttr invalidLinkAttr $ txt target +symTargetView _ (Just target) = txt target + cmdlineView :: AppState -> Widget FocusTarget cmdlineView (AppState {stateFocusTarget = FocusCmdline, stateCmdlineEditor}) = txt ":" <+> renderEditor (txt . Text.unlines) True stateCmdlineEditor @@ -28,16 +28,17 @@ - [X] Config extend (extend = true will extend config.toml) - [X] Finish nvim integration - [X] Command: search, search-next, search-prev -- [ ] Store last directory path (for auto cd in shell) -- [ ] Store selections path (for copy/move/paste across instances) +- [X] cd into dir symlinks - [ ] Command: bind -- [ ] cd into dir symlinks ** Right after - [ ] cmdline tab completion - [ ] Allow escaping % in commands - [ ] theme from config - [ ] Cmdline history +- [ ] Store last directory path (for auto cd in shell) +- [ ] Store selections path (for copy/move/paste across instances) - [ ] Rethink % substituions +- [ ] Preserve back directory when going inside sym link to directories ** Later - [ ] Fix keymap evaluation? (If vd is bound, it doesnt evaluate a v binding) - [ ] Allow escaping % in commands |
