better data type
This commit is contained in:
parent
06bafae9e0
commit
a0872a8ec3
2 changed files with 40 additions and 50 deletions
|
@ -17,78 +17,68 @@ import Utility.PartialPrelude
|
||||||
|
|
||||||
type FormatString = String
|
type FormatString = String
|
||||||
|
|
||||||
{- A format consists of a list of fragments, with other text suffixed to
|
{- A format consists of a list of fragments. -}
|
||||||
- the end. -}
|
type Format = [Frag]
|
||||||
data Format = Format { spans :: [Frag], suffix :: String }
|
|
||||||
|
{- A fragment is either a constant string, or a variable, with a padding. -}
|
||||||
|
data Frag = Const String | Var String Padding
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
{- A fragment is a variable (which may be padded), prefixed by some text. -}
|
{- Positive padding is right justification; negative padding is left
|
||||||
data Frag = Frag { prefix :: String, varname :: String, pad :: Int }
|
- justification. -}
|
||||||
deriving (Show)
|
type Padding = Int
|
||||||
|
|
||||||
newFormat :: Format
|
empty :: Frag -> Bool
|
||||||
newFormat = Format [] ""
|
empty (Const "") = True
|
||||||
|
empty _ = False
|
||||||
|
|
||||||
{- Expands a Format using some variables, generating a formatted string.
|
{- Expands a Format using some variables, generating a formatted string.
|
||||||
- This can be repeatedly called, efficiently. -}
|
- This can be repeatedly called, efficiently. -}
|
||||||
format :: Format -> M.Map String String -> String
|
format :: Format -> M.Map String String -> String
|
||||||
format f vars = concat $ concat $ reverse $ [suffix f] : go (spans f) []
|
format f vars = concatMap expand f
|
||||||
where
|
where
|
||||||
go [] c = c
|
expand (Const s) = s
|
||||||
go (s:rest) c = go rest $ [prefix s, val s]:c
|
expand (Var name padding) = justify padding $
|
||||||
val (Frag { varname = var, pad = p }) =
|
fromMaybe "" $ M.lookup name vars
|
||||||
justify p $ fromMaybe "" $ M.lookup var vars
|
justify p s
|
||||||
justify p v
|
| p > 0 = take (p - length s) spaces ++ s
|
||||||
| p > 0 = take (p - length v) spaces ++ v
|
| p < 0 = s ++ take (-1 * (length s + p)) spaces
|
||||||
| p < 0 = v ++ take (-1 * (length v + p)) spaces
|
| otherwise = s
|
||||||
| otherwise = v
|
|
||||||
spaces = repeat ' '
|
spaces = repeat ' '
|
||||||
|
|
||||||
{- Generates a Format that can be used to expand variables in a
|
{- Generates a Format that can be used to expand variables in a
|
||||||
- format string, such as "${foo} ${bar}\n"
|
- format string, such as "${foo} ${bar;10} ${baz;-10}\n"
|
||||||
-
|
|
||||||
- To handle \n etc, printf is used, first escaping %, to
|
|
||||||
- avoid it needing any printf arguments.
|
|
||||||
-
|
|
||||||
- Left padding is enabled by "${var;width}"
|
|
||||||
- Right padding is enabled by "${var;-width}"
|
|
||||||
-
|
-
|
||||||
- (This is the same type of format string used by dpkg-query.)
|
- (This is the same type of format string used by dpkg-query.)
|
||||||
-}
|
-}
|
||||||
gen :: FormatString -> Format
|
gen :: FormatString -> Format
|
||||||
gen = scan newFormat . printf . escapeprintf
|
gen = finalize . scan []
|
||||||
where
|
where
|
||||||
escapeprintf = replace "%" "%%"
|
-- The Format is built up in reverse, for efficiency,
|
||||||
-- The Format is built up with fields reversed, for
|
-- To finalize it, fix the reversing and do some
|
||||||
-- efficiency.
|
-- optimisations, including fusing adjacent Consts.
|
||||||
finalize f v = f
|
finalize = filter (not . empty) . fuse []
|
||||||
{ suffix = (reverse $ suffix f) ++ v
|
fuse f [] = f
|
||||||
, spans = (reverse $ spans f)
|
fuse f (Const c1:Const c2:vs) = fuse f $ Const (c2++c1) : vs
|
||||||
}
|
fuse f (v:vs) = fuse (v:f) vs
|
||||||
|
|
||||||
scan f (a:b:cs)
|
scan f (a:b:cs)
|
||||||
| a == '$' && b == '{' = invar f [] cs
|
| a == '$' && b == '{' = invar f [] cs
|
||||||
| otherwise = scan f { suffix = a:suffix f } (b:cs)
|
| otherwise = scan (Const [a] : f ) (b:cs)
|
||||||
scan f v = finalize f v
|
scan f v = Const v : f
|
||||||
invar f var [] = finalize f $ novar var
|
|
||||||
|
invar f var [] = Const (novar var) : f
|
||||||
invar f var (c:cs)
|
invar f var (c:cs)
|
||||||
| c == '}' = foundvar f var 0 cs
|
| c == '}' = foundvar f var 0 cs
|
||||||
| isAlphaNum c = invar f (c:var) cs
|
| isAlphaNum c = invar f (c:var) cs
|
||||||
| c == ';' = inpad "" f var cs
|
| c == ';' = inpad "" f var cs
|
||||||
| otherwise = scan f { suffix = (reverse $ novar $ c:var) ++ suffix f } cs
|
| otherwise = scan ((Const $ reverse $ novar $ c:var):f) cs
|
||||||
|
|
||||||
inpad p f var (c:cs)
|
inpad p f var (c:cs)
|
||||||
| c == '}' = foundvar f var (readpad $ reverse p) cs
|
| c == '}' = foundvar f var (readpad $ reverse p) cs
|
||||||
| otherwise = inpad (c:p) f var cs
|
| otherwise = inpad (c:p) f var cs
|
||||||
inpad p f var [] = finalize f $ novar $ p++";"++var
|
inpad p f var [] = Const (novar $ p++";"++var) : f
|
||||||
readpad = fromMaybe 0 . readMaybe
|
readpad = fromMaybe 0 . readMaybe
|
||||||
|
|
||||||
novar v = "${" ++ reverse v
|
novar v = "${" ++ reverse v
|
||||||
foundvar f v p cs = scan f' cs
|
foundvar f v p cs = scan (Var (reverse v) p : f) cs
|
||||||
where
|
|
||||||
f' = f
|
|
||||||
{ suffix = ""
|
|
||||||
, spans = newspan:spans f
|
|
||||||
}
|
|
||||||
newspan = Frag
|
|
||||||
{ prefix = reverse $ suffix f
|
|
||||||
, varname = reverse v
|
|
||||||
, pad = p
|
|
||||||
}
|
|
||||||
|
|
|
@ -435,8 +435,8 @@ subdirectories).
|
||||||
* --format=value
|
* --format=value
|
||||||
|
|
||||||
Specifies a custom output format. The value is a format string,
|
Specifies a custom output format. The value is a format string,
|
||||||
in which '${var}' is expanded to the value of a variable. To right-align
|
in which '${var}' is expanded to the value of a variable. To right-justify
|
||||||
a variable with whitespace, use '${var;width}' ; to left-align
|
a variable with whitespace, use '${var;width}' ; to left-justify
|
||||||
a variable, use '${var;-width}'. Also, '\n' is a newline, '\0' is a NULL,
|
a variable, use '${var;-width}'. Also, '\n' is a newline, '\0' is a NULL,
|
||||||
etc.
|
etc.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue