module Hledger.UI.Editor (
endPosition
,runEditor
,runIadd
)
where
import Control.Applicative ((<|>))
import Data.List (intercalate)
import Data.Maybe (catMaybes)
import Data.Bifunctor (bimap)
import Safe
import System.Environment
import System.Exit
import System.FilePath
import System.Info (os)
import System.Process
import Hledger
type TextPosition = (Int, Maybe Int)
endPosition :: Maybe TextPosition
endPosition :: Maybe TextPosition
endPosition = TextPosition -> Maybe TextPosition
forall a. a -> Maybe a
Just (-Int
1, Maybe Int
forall a. Maybe a
Nothing)
runIadd :: FilePath -> IO ExitCode
runIadd :: FilePath -> IO ExitCode
runIadd FilePath
f = FilePath -> IO ProcessHandle
runCommand (FilePath
"hledger-iadd -f " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
f) IO ProcessHandle -> (ProcessHandle -> IO ExitCode) -> IO ExitCode
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ProcessHandle -> IO ExitCode
waitForProcess
runEditor :: Maybe TextPosition -> FilePath -> IO ExitCode
runEditor :: Maybe TextPosition -> FilePath -> IO ExitCode
runEditor Maybe TextPosition
mpos FilePath
f = Maybe TextPosition -> FilePath -> IO FilePath
editFileAtPositionCommand Maybe TextPosition
mpos FilePath
f IO FilePath -> (FilePath -> IO ProcessHandle) -> IO ProcessHandle
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= FilePath -> IO ProcessHandle
runCommand IO ProcessHandle -> (ProcessHandle -> IO ExitCode) -> IO ExitCode
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ProcessHandle -> IO ExitCode
waitForProcess
editFileAtPositionCommand :: Maybe TextPosition -> FilePath -> IO String
editFileAtPositionCommand :: Maybe TextPosition -> FilePath -> IO FilePath
editFileAtPositionCommand Maybe TextPosition
mpos FilePath
f = do
FilePath
cmd <- IO FilePath
getEditCommand
let editor :: FilePath
editor = FilePath -> FilePath
lowercase (FilePath -> FilePath) -> FilePath -> FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath
takeBaseName (FilePath -> FilePath) -> FilePath -> FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> [FilePath] -> FilePath
forall a. a -> [a] -> a
headDef FilePath
"" ([FilePath] -> FilePath) -> [FilePath] -> FilePath
forall a b. (a -> b) -> a -> b
$ FilePath -> [FilePath]
words' FilePath
cmd
f' :: FilePath
f' = FilePath -> FilePath
singleQuoteIfNeeded FilePath
f
mpos' :: Maybe (FilePath, Maybe FilePath)
mpos' = (FilePath, Maybe FilePath) -> Maybe (FilePath, Maybe FilePath)
forall a. a -> Maybe a
Just ((FilePath, Maybe FilePath) -> Maybe (FilePath, Maybe FilePath))
-> (TextPosition -> (FilePath, Maybe FilePath))
-> TextPosition
-> Maybe (FilePath, Maybe FilePath)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> FilePath)
-> (Maybe Int -> Maybe FilePath)
-> TextPosition
-> (FilePath, Maybe FilePath)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap Int -> FilePath
forall a. Show a => a -> FilePath
show ((Int -> FilePath) -> Maybe Int -> Maybe FilePath
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int -> FilePath
forall a. Show a => a -> FilePath
show) (TextPosition -> Maybe (FilePath, Maybe FilePath))
-> Maybe TextPosition -> Maybe (FilePath, Maybe FilePath)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe TextPosition
mpos
join :: [a] -> [Maybe [a]] -> [a]
join [a]
sep = [a] -> [[a]] -> [a]
forall a. [a] -> [[a]] -> [a]
intercalate [a]
sep ([[a]] -> [a]) -> ([Maybe [a]] -> [[a]]) -> [Maybe [a]] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe [a]] -> [[a]]
forall a. [Maybe a] -> [a]
catMaybes
args :: [FilePath]
args = case FilePath
editor of
FilePath
"emacs" -> case Maybe (FilePath, Maybe FilePath)
mpos' of
Maybe (FilePath, Maybe FilePath)
Nothing -> [FilePath
f']
Just (Char
'-' : FilePath
_, Maybe FilePath
_) -> [FilePath
f', FilePath
"-f", FilePath
"end-of-buffer"]
Just (FilePath
l, Maybe FilePath
mc) -> [Char
'+' Char -> FilePath -> FilePath
forall a. a -> [a] -> [a]
: FilePath -> [Maybe FilePath] -> FilePath
forall {a}. [a] -> [Maybe [a]] -> [a]
join FilePath
":" [FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
l, Maybe FilePath
mc], FilePath
f']
FilePath
e | FilePath
e FilePath -> [FilePath] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FilePath
"emacsclient", FilePath
"nano"] -> case Maybe (FilePath, Maybe FilePath)
mpos' of
Maybe (FilePath, Maybe FilePath)
Nothing -> [FilePath
f']
Just (Char
'-' : FilePath
_, Maybe FilePath
_) -> [FilePath
f']
Just (FilePath
l, Maybe FilePath
mc) -> [Char
'+' Char -> FilePath -> FilePath
forall a. a -> [a] -> [a]
: FilePath -> [Maybe FilePath] -> FilePath
forall {a}. [a] -> [Maybe [a]] -> [a]
join FilePath
":" [FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
l, Maybe FilePath
mc], FilePath
f']
FilePath
"vscode" -> case Maybe (FilePath, Maybe FilePath)
mpos' of
Maybe (FilePath, Maybe FilePath)
Nothing -> [FilePath
f']
Just (Char
'-' : FilePath
_, Maybe FilePath
_) -> [FilePath
f']
Just (FilePath
l, Maybe FilePath
mc) -> [FilePath
"--goto", FilePath -> [Maybe FilePath] -> FilePath
forall {a}. [a] -> [Maybe [a]] -> [a]
join FilePath
":" [FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
f', FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
l, Maybe FilePath
mc]]
FilePath
"kak" -> case Maybe (FilePath, Maybe FilePath)
mpos' of
Maybe (FilePath, Maybe FilePath)
Nothing -> [FilePath
f']
Just (Char
'-' : FilePath
_, Maybe FilePath
_) -> [FilePath
"+:", FilePath
f']
Just (FilePath
l, Maybe FilePath
mc) -> [Char
'+' Char -> FilePath -> FilePath
forall a. a -> [a] -> [a]
: FilePath -> [Maybe FilePath] -> FilePath
forall {a}. [a] -> [Maybe [a]] -> [a]
join FilePath
":" [FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
l, Maybe FilePath
mc], FilePath
f']
FilePath
e | FilePath
e FilePath -> [FilePath] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FilePath
"vi", FilePath
"vim", FilePath
"view", FilePath
"nvim", FilePath
"evim", FilePath
"eview",
FilePath
"gvim", FilePath
"gview", FilePath
"rvim", FilePath
"rview",
FilePath
"rgvim", FilePath
"rgview", FilePath
"ex"] -> case Maybe (FilePath, Maybe FilePath)
mpos' of
Maybe (FilePath, Maybe FilePath)
Nothing -> [FilePath
f']
Just (Char
'-' : FilePath
_, Maybe FilePath
_) -> [FilePath
"+", FilePath
f']
Just (FilePath
l, Maybe FilePath
_) -> [Char
'+' Char -> FilePath -> FilePath
forall a. a -> [a] -> [a]
: FilePath
l, FilePath
f']
FilePath
_ -> [FilePath
f']
FilePath -> IO FilePath
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath -> IO FilePath) -> FilePath -> IO FilePath
forall a b. (a -> b) -> a -> b
$ [FilePath] -> FilePath
unwords ([FilePath] -> FilePath) -> [FilePath] -> FilePath
forall a b. (a -> b) -> a -> b
$ FilePath
cmdFilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
:[FilePath]
args
getEditCommand :: IO String
getEditCommand :: IO FilePath
getEditCommand = do
Maybe FilePath
hledger_ui_editor_env <- FilePath -> IO (Maybe FilePath)
lookupEnv FilePath
"HLEDGER_UI_EDITOR"
Maybe FilePath
editor_env <- FilePath -> IO (Maybe FilePath)
lookupEnv FilePath
"EDITOR"
let defaultEditor :: Maybe FilePath
defaultEditor = FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just (FilePath -> Maybe FilePath) -> FilePath -> Maybe FilePath
forall a b. (a -> b) -> a -> b
$ if FilePath
os FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
"mingw32" then FilePath
"notepad.exe" else FilePath
"emacsclient -a '' -nw"
let Just FilePath
cmd = Maybe FilePath
hledger_ui_editor_env Maybe FilePath -> Maybe FilePath -> Maybe FilePath
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe FilePath
editor_env Maybe FilePath -> Maybe FilePath -> Maybe FilePath
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe FilePath
defaultEditor
FilePath -> IO FilePath
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
cmd