{-# OPtIONS_HADDOCK show-extensions #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE BangPatterns #-}

{-|
Module      : GVTI
Description : GraphViz Tabular Interface main conversion functionality.
Copyright   : (c) Oleksandr Zhabenko, 2017-2023
License     : MIT
Maintainer  : oleksandr.zhabenko@yahoo.com
Stability   : Experimental

A program @gvti@ converts a specially formated @.csv@ file with a colon as a field separator obtained from the electronic table
into a visualized by GraphViz graph in the one of the supported by GraphViz graphics format. The proper GraphViz installation is required.
This is the main functionality module.
-}

module GVTI (getFormat,process2) where

import GHC.Base
import GHC.List
import GHC.Num
import System.IO
import Text.Show (show)
import Data.List (nub)
import System.Info (os)
import System.CPUTime (getCPUTime)
import System.Process (callCommand)
import GHC.Arr
import EndOfExe (showE)
import Data.Maybe (isJust,fromJust)
import qualified Data.Foldable as F (foldr)

isSep :: Char -> Bool
isSep :: Char -> Bool
isSep = (forall a. Eq a => a -> a -> Bool
== Char
':')

isSepG :: String -> Char -> Bool
isSepG :: [Char] -> Char -> Bool
isSepG [Char]
delims Char
c = Char
c forall a. Eq a => a -> [a] -> Bool
`elem` [Char]
delims

-- | Returns @True@ if OS is Windows.
isWindows :: Bool
isWindows :: Bool
isWindows = forall a. Int -> [a] -> [a]
take Int
5 [Char]
os forall a. Eq a => a -> a -> Bool
== [Char]
"mingw"
{-# INLINE isWindows #-}

divideString :: (Char -> Bool) -> String -> [String]
divideString :: (Char -> Bool) -> [Char] -> [[Char]]
divideString Char -> Bool
p [Char]
xs
 | forall a. [a] -> Bool
null [Char]
xs = []
 | Bool
otherwise = let ([Char]
zs,[Char]
ys) = forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
p [Char]
xs in [Char]
zsforall a. a -> [a] -> [a]
:(if forall a. [a] -> Bool
null [Char]
ys then [[Char]
""] else (Char -> Bool) -> [Char] -> [[Char]]
divideString Char -> Bool
p (forall a. Int -> [a] -> [a]
drop Int
1 [Char]
ys))

isEscapeChar :: Char -> Bool
isEscapeChar :: Char -> Bool
isEscapeChar Char
x = Char
x forall a. Eq a => a -> a -> Bool
== Char
'\n' Bool -> Bool -> Bool
|| Char
x forall a. Eq a => a -> a -> Bool
== Char
'\r'

dropEmptyLines :: String -> [String] -> [String]
dropEmptyLines :: [Char] -> [[Char]] -> [[Char]]
dropEmptyLines [Char]
_ [] = []
dropEmptyLines [Char]
delims ([Char]
ys:[[Char]]
yss)
 | let ts :: [Char]
ts = forall a. (a -> Bool) -> [a] -> [a]
dropWhile ([Char] -> Char -> Bool
isSepG [Char]
delims) [Char]
ys in forall a. (a -> Bool) -> [a] -> Bool
all Char -> Bool
isEscapeChar [Char]
ts Bool -> Bool -> Bool
|| forall a. [a] -> Bool
null [Char]
ts = [Char] -> [[Char]] -> [[Char]]
dropEmptyLines [Char]
delims [[Char]]
yss
 | Bool
otherwise = [Char]
ysforall a. a -> [a] -> [a]
:[Char] -> [[Char]] -> [[Char]]
dropEmptyLines [Char]
delims [[Char]]
yss

cells 
  :: String -- ^ The list of 'Char' delimiters to be used.
  -> String 
  -> Array Int [String] 
cells :: [Char] -> [Char] -> Array Int [[Char]]
cells [Char]
delims [Char]
xs = forall a b i. (a -> b) -> Array i a -> Array i b
amap ((Char -> Bool) -> [Char] -> [[Char]]
divideString ([Char] -> Char -> Bool
isSepG [Char]
delims)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall i e. Ix i => (i, i) -> [e] -> Array i e
listArray (Int
0,Int
l) forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[Char]] -> [[Char]]
dropEmptyLines [Char]
delims forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (\[Char]
rs -> if forall a. Int -> [a] -> [a]
drop (forall a. [a] -> Int
length [Char]
rs forall a. Num a => a -> a -> a
- Int
1) [Char]
rs forall a. Eq a => a -> a -> Bool
== [Char]
"\r" then forall a. [a] -> [a]
init [Char]
rs else [Char]
rs) forall a b. (a -> b) -> a -> b
$ [[Char]]
yss
  where ([[Char]]
yss,Int
l) = [Char] -> ([[Char]], Int)
linesL1 [Char]
xs
{-# INLINE cells #-}

-- | Inspired by: <https://hackage.haskell.org/package/base-4.14.0.0/docs/src/Data.OldList.html#lines>
linesL :: ([String],Int) -> String -> ([String],Int)
linesL :: ([[Char]], Int) -> [Char] -> ([[Char]], Int)
linesL ([[Char]]
xs,Int
y) [Char]
"" = ([[Char]]
xs,Int
y)
linesL ([[Char]]
xs,Int
y) [Char]
s  = ([[Char]], Int) -> [Char] -> ([[Char]], Int)
linesL ([Char]
lforall a. a -> [a] -> [a]
:[[Char]]
xs,Int
y forall a. Num a => a -> a -> a
+ Int
1) (case [Char]
s' of { [] -> [] ; Char
_:[Char]
s'' -> [Char]
s'' })
  where ([Char]
l, [Char]
s') = forall a. (a -> Bool) -> [a] -> ([a], [a])
break (forall a. Eq a => a -> a -> Bool
== Char
'\n') [Char]
s

-- | Inspired by: <https://hackage.haskell.org/package/base-4.14.0.0/docs/src/Data.OldList.html#lines>
linesL1 :: String -> ([String],Int)
linesL1 :: [Char] -> ([[Char]], Int)
linesL1 = ([[Char]], Int) -> [Char] -> ([[Char]], Int)
linesL ([],-Int
1)

processCells :: String -> Array Int [String] -> String
processCells :: [Char] -> Array Int [[Char]] -> [Char]
processCells [Char]
xs Array Int [[Char]]
arr = [Char] -> (Array Int [Char], [Char]) -> [Char]
makeRecordGv [Char]
xs forall b c a. (b -> c) -> (a -> b) -> a -> c
. Array Int [[Char]] -> (Array Int [Char], [Char])
convertElemsToStringGv forall b c a. (b -> c) -> (a -> b) -> a -> c
. Array Int [[Char]] -> Array Int [[Char]]
filterNeeded forall b c a. (b -> c) -> (a -> b) -> a -> c
. Array Int [[Char]] -> Array Int [[Char]]
changeNeededCells forall a b. (a -> b) -> a -> b
$ Array Int [[Char]]
arr
{-# INLINE processCells #-}

processCellsG :: String -> String -> String -> String
processCellsG :: [Char] -> [Char] -> [Char] -> [Char]
processCellsG [Char]
delims [Char]
xs = [Char] -> Array Int [[Char]] -> [Char]
processCells [Char]
xs forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char] -> Array Int [[Char]]
cells [Char]
delims
{-# INLINE processCellsG #-}

-- | Do not change the lengths of element lists
changeNeededCells :: Array Int [String] -> Array Int [String]
changeNeededCells :: Array Int [[Char]] -> Array Int [[Char]]
changeNeededCells Array Int [[Char]]
arr = forall i e. Ix i => (i, i) -> [e] -> Array i e
listArray (forall i e. Array i e -> (i, i)
bounds Array Int [[Char]]
arr) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (\(Int
i, [[Char]]
e) -> Int -> [[Char]] -> Array Int [[Char]] -> [[Char]]
changeLine Int
i [[Char]]
e Array Int [[Char]]
arr) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall i e. Ix i => Array i e -> [(i, e)]
assocs forall a b. (a -> b) -> a -> b
$ Array Int [[Char]]
arr
{-# INLINE changeNeededCells #-}

-- | Changes every line by changing (if needed) one empty String to the needed one non-empty. It is necessary for this to find the parent cell for the
-- line in the previous elements of the 'Array'. The contents of the cell (if exist) are substituted instead of the empty 'String' in the line being
-- processed. Afterwards, drops all the preceding empty strings in the line. The length of the line now is not constant.
changeLine :: Int -> [String] -> Array Int [String] -> [String]
changeLine :: Int -> [[Char]] -> Array Int [[Char]] -> [[Char]]
changeLine Int
i [[Char]]
yss Array Int [[Char]]
arr =
  let !n :: Int
n = forall a. [a] -> Int
length forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
takeWhile forall a. [a] -> Bool
null forall a b. (a -> b) -> a -> b
$ [[Char]]
yss
      !xs :: [Char]
xs = Int -> Int -> Array Int [[Char]] -> [Char]
parentCellContents Int
n Int
i Array Int [[Char]]
arr in if forall a. [a] -> Bool
null [Char]
xs then forall a. Int -> [a] -> [a]
drop Int
n [[Char]]
yss else [Char]
xsforall a. a -> [a] -> [a]
:(forall a. Int -> [a] -> [a]
drop Int
n [[Char]]
yss)
{-# NOINLINE changeLine #-}

parentCellContents :: Int -> Int -> Array Int [String] -> String
parentCellContents :: Int -> Int -> Array Int [[Char]] -> [Char]
parentCellContents Int
n Int
i Array Int [[Char]]
arr
 | Int
n forall a. Eq a => a -> a -> Bool
== Int
0 = []
 | Int
ll forall a. Eq a => a -> a -> Bool
== Int
0 = []
 | Bool
otherwise = (\([Char]
x, Int
_, Int
_) -> [Char]
x) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
F.foldr forall {c} {a}. (Ord c, Num c) => [a] -> ([a], c, c) -> ([a], c, c)
f ([], Int
0, Int
ll) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b i. (a -> b) -> Array i a -> Array i b
amap (forall a. [a] -> Int -> a
!! (Int
n forall a. Num a => a -> a -> a
- Int
1)) forall a b. (a -> b) -> a -> b
$ Array Int [[Char]]
arr
     where ll :: Int
ll = forall i e. Array i e -> Int
numElements Array Int [[Char]]
arr forall a. Num a => a -> a -> a
- Int
i forall a. Num a => a -> a -> a
- Int
1
           f :: [a] -> ([a], c, c) -> ([a], c, c)
f [a]
e ([a]
e0, c
m, c
k)
             | c
m forall a. Ord a => a -> a -> Bool
< c
k Bool -> Bool -> Bool
&& Bool -> Bool
not (forall a. [a] -> Bool
null [a]
e) = ([a]
e, c
m forall a. Num a => a -> a -> a
+ c
1, c
k)
             | Bool
otherwise = ([a]
e0, c
m forall a. Num a => a -> a -> a
+ c
1, c
k)

-- | Change the lengths of element lists by dropping the last empty strings in every element.
filterNeeded :: Array Int [String] -> Array Int [String]
filterNeeded :: Array Int [[Char]] -> Array Int [[Char]]
filterNeeded = forall a b i. (a -> b) -> Array i a -> Array i b
amap (forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. [a] -> Bool
null))
{-# INLINE filterNeeded #-}

-- | Makes conversion for every line
convertElemsToStringGv :: Array Int [String] -> (Array Int String, String)
convertElemsToStringGv :: Array Int [[Char]] -> (Array Int [Char], [Char])
convertElemsToStringGv Array Int [[Char]]
arr = (forall a b i. (a -> b) -> Array i a -> Array i b
amap [[Char]] -> [Char]
convertLineToStrGv Array Int [[Char]]
arr, Array Int [[Char]] -> [Char]
findAndMakeFilledWithClr Array Int [[Char]]
arr)

convertLineToStrGv :: [String] -> String
convertLineToStrGv :: [[Char]] -> [Char]
convertLineToStrGv [[Char]]
xss = [Char]
"\"" forall a. [a] -> [a] -> [a]
++ (let ys :: [Char]
ys = forall a b. (a -> [b]) -> [a] -> [b]
concatMap (forall a. [a] -> [a] -> [a]
++[Char]
"\"->\"") [[Char]]
xss in forall a. Int -> [a] -> [a]
take (forall a. [a] -> Int
length [Char]
ys forall a. Num a => a -> a -> a
- Int
3) [Char]
ys) forall a. [a] -> [a] -> [a]
++ [Char]
endOfLineGv
{-# INLINE convertLineToStrGv #-}

endOfLineGv :: String
endOfLineGv :: [Char]
endOfLineGv | Bool
isWindows = [Char]
"\r\n"
            | Bool
otherwise = [Char]
"\n"
{-# INLINE endOfLineGv #-}

findAndMakeFilledWithClr :: Array Int [String] -> String
findAndMakeFilledWithClr :: Array Int [[Char]] -> [Char]
findAndMakeFilledWithClr = forall a b. (a -> [b]) -> [a] -> [b]
concatMap ((Char
'\"'forall a. a -> [a] -> [a]
:) forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  (forall a. [a] -> [a] -> [a]
++ [Char]
"\" [style=filled, fillcolor=\"#ffffba\"];" forall a. [a] -> [a] -> [a]
++ [Char]
endOfLineGv)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Eq a => [a] -> [a]
nub forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Monoid a => [a] -> a
mconcat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall i e. Array i e -> [e]
elems forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b i. (a -> b) -> Array i a -> Array i b
amap [[Char]] -> [[Char]]
lineWithAtSign
{-# INLINE findAndMakeFilledWithClr #-}

-- | In every list (representing a line) returns only those strings that begin with at-sign.
lineWithAtSign :: [String] -> [String]
lineWithAtSign :: [[Char]] -> [[Char]]
lineWithAtSign = forall a. (a -> Bool) -> [a] -> [a]
filter [Char] -> Bool
beginsWithAtSign
{-# INLINE lineWithAtSign #-}

beginsWithAtSign :: String -> Bool
beginsWithAtSign :: [Char] -> Bool
beginsWithAtSign [Char]
xs = if forall a. Int -> [a] -> [a]
take Int
1 [Char]
xs forall a. Eq a => a -> a -> Bool
== [Char]
"@" then Bool
True else forall a. Int -> [a] -> [a]
take Int
2 [Char]
xs forall a. Eq a => a -> a -> Bool
== [Char]
"\"@"
{-# INLINE beginsWithAtSign #-}

-- | Makes all needed additions and synthesizes into a single 'String' ready to be recorded to the .gv file.
makeRecordGv :: String -> (Array Int String, String) -> String
makeRecordGv :: [Char] -> (Array Int [Char], [Char]) -> [Char]
makeRecordGv [Char]
xs (Array Int [Char]
arr1,[Char]
str2) = forall a. Monoid a => [a] -> a
mconcat [[Char]
"strict digraph 1 {", [Char]
endOfLineGv, [Char]
"overlap=false", [Char]
endOfLineGv, [Char]
"splines=",
  case [Char]
xs of { [Char]
"0" -> [Char]
"false" ; [Char]
"1" -> [Char]
"true" ; [Char]
"2" -> [Char]
"ortho" ; [Char]
"3" -> [Char]
"polyline" ; ~[Char]
vvv -> [Char]
"true" }, [Char]
endOfLineGv,
    forall a. Monoid a => [a] -> a
mconcat (forall i e. Array i e -> [e]
elems Array Int [Char]
arr1 forall a. Monoid a => a -> a -> a
`mappend` [[Char]
str2]), [Char]
"}", [Char]
endOfLineGv]
{-# INLINE makeRecordGv #-}

-- | Processes the given text (the first 'String' argument). The second one is used to get a name of the command to be
-- executed to obtain a visualization file. The third argument is used for the 'getFormat'. The fourth argument is the
-- basic name for the created files (without prefixes and extensions), the fifth one is an option for GraphVize splines
-- functionality. The sixth argument is used to specify whether to remove at-signs from the created files.
process2 :: String -> String -> String -> String -> String -> String -> String -> IO ()
process2 :: [Char]
-> [Char]
-> [Char]
-> [Char]
-> [Char]
-> [Char]
-> [Char]
-> IO ()
process2 [Char]
delims [Char]
xxs [Char]
yys [Char]
bnames [Char]
splines [Char]
remAts [Char]
text
  | forall a. [a] -> Int
length [Char]
text forall a. Ord a => a -> a -> Bool
> Int
0 = do
      Integer
ts <- IO Integer
getCPUTime
      [[Char]
bnames1,[Char]
splines1] <- [Char] -> [Char] -> IO [[Char]]
proc2Params2 [Char]
bnames [Char]
splines
      if [Char]
remAts forall a. Eq a => a -> a -> Bool
== [Char]
"y"
        then do
          let ys :: [Char]
ys = forall a. (a -> Bool) -> [a] -> [a]
filter (forall a. Eq a => a -> a -> Bool
/=Char
'@') forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char] -> [Char] -> [Char]
processCellsG [Char]
delims [Char]
splines1 forall a b. (a -> b) -> a -> b
$ [Char]
text in [Char] -> [Char] -> IO ()
writeFile (forall a. Show a => a -> [Char]
show Integer
ts forall a. [a] -> [a] -> [a]
++ [Char]
"." forall a. [a] -> [a] -> [a]
++ [Char]
bnames1 forall a. [a] -> [a] -> [a]
++ [Char]
".gv") [Char]
ys
          [Char] -> IO ()
putStrLn [Char]
"The visualization will be created without the at-sign."
          Char -> Integer -> [Char] -> [Char] -> [Char] -> IO ()
processFile Char
'n' Integer
ts [Char]
bnames1 [Char]
xxs [Char]
yys
        else do
          let ys :: [Char]
ys = [Char] -> [Char] -> [Char] -> [Char]
processCellsG [Char]
delims [Char]
splines1 [Char]
text in [Char] -> [Char] -> IO ()
writeFile ([Char]
"at." forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show Integer
ts forall a. [a] -> [a] -> [a]
++ [Char]
"." forall a. [a] -> [a] -> [a]
++ [Char]
bnames1 forall a. [a] -> [a] -> [a]
++ [Char]
".gv") [Char]
ys
          [Char] -> IO ()
putStrLn [Char]
"The visualization will be created with the at-sign preserved."
          Char -> Integer -> [Char] -> [Char] -> [Char] -> IO ()
processFile Char
'a' Integer
ts [Char]
bnames1 [Char]
xxs [Char]
yys
  | Bool
otherwise = forall a. HasCallStack => [Char] -> a
error [Char]
"GVTI.process2: Empty text to be processed! "

procCtrl :: Int -> IO String
procCtrl :: Int -> IO [Char]
procCtrl Int
1 = [Char] -> IO ()
putStrLn [Char]
"Please, input the basic name of the visualization file!" forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO [Char]
getLine
procCtrl Int
2 = do
  [Char] -> IO ()
putStrLn [Char]
"Please, specify the splines mode for GraphViz (see the documentation for GraphViz)"
  [Char] -> IO ()
putStrLn [Char]
"0 -- for \"splines=false\""
  [Char] -> IO ()
putStrLn [Char]
"1 -- for \"splines=true\""
  [Char] -> IO ()
putStrLn [Char]
"2 -- for \"splines=ortho\""
  [Char] -> IO ()
putStrLn [Char]
"3 -- for \"splines=polyline\""
  [Char] -> IO ()
putStrLn [Char]
"The default one is \"splines=true\""
  IO [Char]
getLine
procCtrl Int
_ = [Char] -> IO ()
putStrLn [Char]
"Would you like to remove all \'@\' signs from the visualization file?" forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO [Char]
getLine

processFile :: Char -> Integer -> String -> String -> String -> IO ()
processFile :: Char -> Integer -> [Char] -> [Char] -> [Char] -> IO ()
processFile Char
w Integer
t [Char]
zs [Char]
xxs [Char]
yys = do
  if forall a. (a -> Bool) -> [a] -> Bool
all (forall a. Maybe a -> Bool
isJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Maybe [Char]
showE) [[Char]
"fdp",[Char]
"twopi",[Char]
"circo",[Char]
"neato",[Char]
"sfdp",[Char]
"dot",[Char]
"patchwork",[Char]
"osage"]
    then Char -> Integer -> [Char] -> [Char] -> [Char] -> IO ()
processFile1 Char
w Integer
t [Char]
zs [Char]
xxs [Char]
yys
    else forall a. HasCallStack => [Char] -> a
error [Char]
"GVTI.processFile: Please, install the GraphViz so that its executables are in the directories mentioned in the variable PATH!"
{-# INLINE processFile #-}

processFile1 :: Char -> Integer -> String -> String -> String -> IO ()
processFile1 :: Char -> Integer -> [Char] -> [Char] -> [Char] -> IO ()
processFile1 Char
w Integer
t [Char]
zs [Char]
xxs [Char]
yys = do
  [[Char]
vs,[Char]
spec] <- [Char] -> [Char] -> IO [[Char]]
proc2Params [Char]
xxs [Char]
yys
  let u :: [Char]
u = forall a. Int -> [a] -> [a]
take Int
1 [Char]
vs
  if forall a. [a] -> Bool
null [Char]
u Bool -> Bool -> Bool
|| [Char]
u forall a. Eq a => a -> a -> Bool
== [Char]
"\n" Bool -> Bool -> Bool
|| [Char]
u forall a. Eq a => a -> a -> Bool
== [Char]
"\x0000"
    then forall a. HasCallStack => [Char] -> a
error [Char]
"GVTI.processFile1: Please, specify the needed character."
    else do
      let temp :: [Char] -> [Char]
temp = forall a. HasCallStack => Maybe a -> a
fromJust forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Maybe [Char]
showE forall b c a. (b -> c) -> (a -> b) -> a -> c
. (\[Char]
x -> case [Char]
x of { [Char]
"c" -> [Char]
"circo" ; [Char]
"d" -> [Char]
"dot" ; [Char]
"f" -> [Char]
"fdp" ; [Char]
"n" -> [Char]
"neato" ;
           [Char]
"o" ->[Char]
"osage" ; [Char]
"p" -> [Char]
"patchwork" ; [Char]
"s" -> [Char]
"sfdp" ; [Char]
"t" -> [Char]
"twopi" ; ~[Char]
vv -> [Char]
"sfdp" })
          q :: [Char]
q = [Char] -> [Char]
getFormat [Char]
spec
      [Char] -> IO ()
callCommand forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
temp [Char]
u forall a. [a] -> [a] -> [a]
++ (if Char
w forall a. Eq a => a -> a -> Bool
== Char
'n' then [Char]
" -T" forall a. [a] -> [a] -> [a]
++ [Char]
q forall a. [a] -> [a] -> [a]
++ [Char]
" " else [Char]
" -T" forall a. [a] -> [a] -> [a]
++ [Char]
q forall a. [a] -> [a] -> [a]
++ [Char]
" at.") forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> [Char]
show Integer
t forall a. [a] -> [a] -> [a]
++ [Char]
"." forall a. [a] -> [a] -> [a]
++ [Char]
zs forall a. [a] -> [a] -> [a]
++ [Char]
".gv -O "

proc2Params :: String -> String -> IO [String]
proc2Params :: [Char] -> [Char] -> IO [[Char]]
proc2Params [Char]
xxs [Char]
yys
 | forall a. [a] -> Bool
null [Char]
xxs = if forall a. [a] -> Bool
null [Char]
yys then forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Int -> IO [Char]
getFormat1 [Int
1,Int
2] else do { [Char]
vs <- Int -> IO [Char]
getFormat1 Int
1 ; forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
vs,[Char]
yys] }
 | forall a. [a] -> Bool
null [Char]
yys = do { [Char]
spec <- Int -> IO [Char]
getFormat1 Int
2 ; forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
xxs,[Char]
spec] }
 | Bool
otherwise = forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
xxs,[Char]
yys]
{-# INLINE proc2Params #-}

specFormatFile :: IO String
specFormatFile :: IO [Char]
specFormatFile = do
  [Char] -> IO ()
putStrLn [Char]
"Please, specify the GraphViz output format for the file: "
  forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM [Char] -> IO ()
printFormF [[Char]
"do", [Char]
"xd", [Char]
"ps", [Char]
"pd", [Char]
"sv", [Char]
"sz", [Char]
"fi", [Char]
"pn", [Char]
"gi", [Char]
"jp", [Char]
"je", [Char]
"js", [Char]
"im", [Char]
"cm"] forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> [Char] -> IO ()
putStrLn [Char]
"otherwise there will be used the default -Tsvg" forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO [Char]
getLine
{-# INLINE specFormatFile #-}

proc2Params2 :: String -> String -> IO [String]
proc2Params2 :: [Char] -> [Char] -> IO [[Char]]
proc2Params2 [Char]
bnames [Char]
splines
 | forall a. [a] -> Bool
null [Char]
bnames = if forall a. [a] -> Bool
null [Char]
splines then forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Int -> IO [Char]
procCtrl [Int
1,Int
2] else do { [Char]
bnames1 <- Int -> IO [Char]
procCtrl Int
1 ; forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
bnames1,[Char]
splines] }
 | forall a. [a] -> Bool
null [Char]
splines = do { [Char]
splines1 <- Int -> IO [Char]
procCtrl Int
2 ; forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
bnames,[Char]
splines1] }
 | Bool
otherwise = forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
bnames,[Char]
splines]
{-# INLINE proc2Params2 #-}

getFormat1 :: Int -> IO String
getFormat1 :: Int -> IO [Char]
getFormat1 Int
1 = do
  [Char] -> IO ()
putStrLn [Char]
"Please, specify the GraphViz command: "
  forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM [Char] -> IO ()
printGraphFilter [[Char]
"d",[Char]
"f",[Char]
"t",[Char]
"c",[Char]
"n",[Char]
"s",[Char]
"p",[Char]
"o"] forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> [Char] -> IO ()
putStrLn [Char]
"otherwise there will be used the default sfdp" forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO [Char]
getLine
getFormat1 Int
_ = IO [Char]
specFormatFile
{-# INLINE getFormat1 #-}

-- | For the given argument (usually of two characters) return the full form of the file format to be generated by GraphViz and @mmsyn4@. The default one
-- is \"svg\".
getFormat :: String -> String
getFormat :: [Char] -> [Char]
getFormat [Char]
xs = case [Char]
xs of { [Char]
"cm" -> [Char]
"cmapx" ; [Char]
"do" -> [Char]
"dot" ; [Char]
"fi" -> [Char]
"fig" ; [Char]
"gi" -> [Char]
"gif" ; [Char]
"im" -> [Char]
"imap" ;
  [Char]
"je" -> [Char]
"jpeg" ; [Char]
"jp" -> [Char]
"jpg" ; [Char]
"js" -> [Char]
"json" ; [Char]
"pd" -> [Char]
"pdf" ; [Char]
"pn" -> [Char]
"png" ; [Char]
"ps" -> [Char]
"ps" ; [Char]
"sv" -> [Char]
"svg" ; [Char]
"sz" -> [Char]
"svgz" ; [Char]
"xd" -> [Char]
"xdot" ; ~[Char]
vvv -> [Char]
"svg" }
{-# INLINE getFormat #-}

printFormF :: String -> IO ()
printFormF :: [Char] -> IO ()
printFormF [Char]
xs = [Char] -> IO ()
putStrLn forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> [Char]
show [Char]
xs forall a. [a] -> [a] -> [a]
++ [Char]
" -- for -T" forall a. [a] -> [a] -> [a]
++ case [Char]
xs of { [Char]
"cm" -> [Char]
"cmapx" ; [Char]
"do" -> [Char]
"dot" ; [Char]
"fi" -> [Char]
"fig" ;
   [Char]
"gi" -> [Char]
"gif" ; [Char]
"im" -> [Char]
"imap" ; [Char]
"je" -> [Char]
"jpeg" ; [Char]
"jp" -> [Char]
"jpg" ; [Char]
"js" -> [Char]
"json" ; [Char]
"pd" -> [Char]
"pdf" ; [Char]
"pn" -> [Char]
"png" ;
      [Char]
"ps" -> [Char]
"ps" ; [Char]
"sv" -> [Char]
"svg" ; [Char]
"sz" -> [Char]
"svgz" ; [Char]
"xd" -> [Char]
"xdot" ; ~[Char]
vvv -> [Char]
"svg" } forall a. [a] -> [a] -> [a]
++ [Char]
"\""
{-# INLINE printFormF #-}

printGraphFilter :: String -> IO ()
printGraphFilter :: [Char] -> IO ()
printGraphFilter [Char]
xs = [Char] -> IO ()
putStrLn forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> [Char]
show (forall a. Int -> [a] -> [a]
take Int
1 [Char]
xs) forall a. [a] -> [a] -> [a]
++ [Char]
" -- for " forall a. [a] -> [a] -> [a]
++ case forall a. Int -> [a] -> [a]
take Int
1 [Char]
xs of { [Char]
"c" -> [Char]
"circo" ; [Char]
"d" -> [Char]
"dot" ;
  [Char]
"f" -> [Char]
"fdp" ; [Char]
"n" -> [Char]
"neato" ; [Char]
"o" -> [Char]
"osage" ; [Char]
"p" -> [Char]
"patchwork" ; [Char]
"s" -> [Char]
"sfdp" ; [Char]
"t" -> [Char]
"twopi" ;
    ~[Char]
vvv ->  [Char]
"sfdp" }
{-# INLINE printGraphFilter #-}