Org reader: respect column width settings
Table column properties can optionally specify a column's width with which it is displayed in the buffer. Some exporters, notably the ODT exporter in org-mode v9.0, use these values to calculate relative column widths. The org reader now implements the same behavior. Note that the org-mode LaTeX and HTML exporters in Emacs don't support this feature yet, which should be kept in mind by users who use the column widths parameters. Closes: #3246
This commit is contained in:
parent
d7fb9db295
commit
f4a8f12387
2 changed files with 47 additions and 27 deletions
|
@ -116,7 +116,7 @@ noteMarker = try $ do
|
||||||
-- | Succeeds if the parser is at the end of a block.
|
-- | Succeeds if the parser is at the end of a block.
|
||||||
endOfBlock :: OrgParser ()
|
endOfBlock :: OrgParser ()
|
||||||
endOfBlock = lookAhead . try $ do
|
endOfBlock = lookAhead . try $ do
|
||||||
void blankline <|> anyBlockStart <|> void noteMarker
|
void blankline <|> anyBlockStart
|
||||||
where
|
where
|
||||||
-- Succeeds if there is a new block starting at this position.
|
-- Succeeds if there is a new block starting at this position.
|
||||||
anyBlockStart :: OrgParser ()
|
anyBlockStart :: OrgParser ()
|
||||||
|
|
|
@ -46,10 +46,11 @@ import qualified Text.Pandoc.Builder as B
|
||||||
import Text.Pandoc.Builder ( Inlines, Blocks )
|
import Text.Pandoc.Builder ( Inlines, Blocks )
|
||||||
import Text.Pandoc.Definition
|
import Text.Pandoc.Definition
|
||||||
import Text.Pandoc.Options
|
import Text.Pandoc.Options
|
||||||
import Text.Pandoc.Shared ( compactify', compactify'DL )
|
import Text.Pandoc.Shared ( compactify', compactify'DL, safeRead )
|
||||||
|
|
||||||
import Control.Monad ( foldM, guard, mzero, void )
|
import Control.Monad ( foldM, guard, mzero, void )
|
||||||
import Data.Char ( isSpace, toLower, toUpper)
|
import Data.Char ( isSpace, toLower, toUpper)
|
||||||
|
import Data.Default ( Default )
|
||||||
import Data.List ( foldl', isPrefixOf )
|
import Data.List ( foldl', isPrefixOf )
|
||||||
import Data.Maybe ( fromMaybe, isNothing )
|
import Data.Maybe ( fromMaybe, isNothing )
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
|
@ -687,18 +688,24 @@ commentLine = commentLineStart *> anyLine *> pure mempty
|
||||||
--
|
--
|
||||||
-- Tables
|
-- Tables
|
||||||
--
|
--
|
||||||
|
data ColumnProperty = ColumnProperty
|
||||||
|
{ columnAlignment :: Maybe Alignment
|
||||||
|
, columnRelWidth :: Maybe Int
|
||||||
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance Default ColumnProperty where
|
||||||
|
def = ColumnProperty Nothing Nothing
|
||||||
|
|
||||||
data OrgTableRow = OrgContentRow (F [Blocks])
|
data OrgTableRow = OrgContentRow (F [Blocks])
|
||||||
| OrgAlignRow [Alignment]
|
| OrgAlignRow [ColumnProperty]
|
||||||
| OrgHlineRow
|
| OrgHlineRow
|
||||||
|
|
||||||
-- OrgTable is strongly related to the pandoc table ADT. Using the same
|
-- OrgTable is strongly related to the pandoc table ADT. Using the same
|
||||||
-- (i.e. pandoc-global) ADT would mean that the reader would break if the
|
-- (i.e. pandoc-global) ADT would mean that the reader would break if the
|
||||||
-- global structure was to be changed, which would be bad. The final table
|
-- global structure was to be changed, which would be bad. The final table
|
||||||
-- should be generated using a builder function. Column widths aren't
|
-- should be generated using a builder function.
|
||||||
-- implemented yet, so they are not tracked here.
|
|
||||||
data OrgTable = OrgTable
|
data OrgTable = OrgTable
|
||||||
{ orgTableAlignments :: [Alignment]
|
{ orgTableColumnProperties :: [ColumnProperty]
|
||||||
, orgTableHeader :: [Blocks]
|
, orgTableHeader :: [Blocks]
|
||||||
, orgTableRows :: [[Blocks]]
|
, orgTableRows :: [[Blocks]]
|
||||||
}
|
}
|
||||||
|
@ -715,8 +722,20 @@ table = try $ do
|
||||||
orgToPandocTable :: OrgTable
|
orgToPandocTable :: OrgTable
|
||||||
-> Inlines
|
-> Inlines
|
||||||
-> Blocks
|
-> Blocks
|
||||||
orgToPandocTable (OrgTable aligns heads lns) caption =
|
orgToPandocTable (OrgTable colProps heads lns) caption =
|
||||||
B.table caption (zip aligns $ repeat 0) heads lns
|
let totalWidth = if any (not . isNothing) (map columnRelWidth colProps)
|
||||||
|
then Just . sum $ map (fromMaybe 1 . columnRelWidth) colProps
|
||||||
|
else Nothing
|
||||||
|
in B.table caption (map (convertColProp totalWidth) colProps) heads lns
|
||||||
|
where
|
||||||
|
convertColProp :: Maybe Int -> ColumnProperty -> (Alignment, Double)
|
||||||
|
convertColProp totalWidth colProp =
|
||||||
|
let
|
||||||
|
align' = fromMaybe AlignDefault $ columnAlignment colProp
|
||||||
|
width' = fromMaybe 0 $ (\w t -> (fromIntegral w / fromIntegral t))
|
||||||
|
<$> (columnRelWidth colProp)
|
||||||
|
<*> totalWidth
|
||||||
|
in (align', width')
|
||||||
|
|
||||||
tableRows :: OrgParser [OrgTableRow]
|
tableRows :: OrgParser [OrgTableRow]
|
||||||
tableRows = try $ many (tableAlignRow <|> tableHline <|> tableContentRow)
|
tableRows = try $ many (tableAlignRow <|> tableHline <|> tableContentRow)
|
||||||
|
@ -732,22 +751,22 @@ tableContentCell = try $
|
||||||
tableAlignRow :: OrgParser OrgTableRow
|
tableAlignRow :: OrgParser OrgTableRow
|
||||||
tableAlignRow = try $ do
|
tableAlignRow = try $ do
|
||||||
tableStart
|
tableStart
|
||||||
cells <- many1Till tableAlignCell newline
|
colProps <- many1Till columnPropertyCell newline
|
||||||
-- Empty rows are regular (i.e. content) rows, not alignment rows.
|
-- Empty rows are regular (i.e. content) rows, not alignment rows.
|
||||||
guard $ any (/= AlignDefault) cells
|
guard $ any (/= def) colProps
|
||||||
return $ OrgAlignRow cells
|
return $ OrgAlignRow colProps
|
||||||
|
|
||||||
tableAlignCell :: OrgParser Alignment
|
columnPropertyCell :: OrgParser ColumnProperty
|
||||||
tableAlignCell =
|
columnPropertyCell = emptyCell <|> propCell <?> "alignment info"
|
||||||
choice [ try $ emptyCell *> return AlignDefault
|
where
|
||||||
, try $ skipSpaces
|
emptyCell = ColumnProperty Nothing Nothing <$ (try $ skipSpaces *> endOfCell)
|
||||||
|
propCell = try $ ColumnProperty
|
||||||
|
<$> (skipSpaces
|
||||||
*> char '<'
|
*> char '<'
|
||||||
*> tableAlignFromChar
|
*> optionMaybe tableAlignFromChar)
|
||||||
<* many digit
|
<*> (optionMaybe (many1 digit >>= safeRead)
|
||||||
<* char '>'
|
<* char '>'
|
||||||
<* emptyCell
|
<* emptyCell)
|
||||||
] <?> "alignment info"
|
|
||||||
where emptyCell = try $ skipSpaces *> endOfCell
|
|
||||||
|
|
||||||
tableAlignFromChar :: OrgParser Alignment
|
tableAlignFromChar :: OrgParser Alignment
|
||||||
tableAlignFromChar = try $
|
tableAlignFromChar = try $
|
||||||
|
@ -769,7 +788,8 @@ rowsToTable = foldM rowToContent emptyTable
|
||||||
where emptyTable = OrgTable mempty mempty mempty
|
where emptyTable = OrgTable mempty mempty mempty
|
||||||
|
|
||||||
normalizeTable :: OrgTable -> OrgTable
|
normalizeTable :: OrgTable -> OrgTable
|
||||||
normalizeTable (OrgTable aligns heads rows) = OrgTable aligns' heads rows
|
normalizeTable (OrgTable colProps heads rows) =
|
||||||
|
OrgTable colProps' heads rows
|
||||||
where
|
where
|
||||||
refRow = if heads /= mempty
|
refRow = if heads /= mempty
|
||||||
then heads
|
then heads
|
||||||
|
@ -778,7 +798,7 @@ normalizeTable (OrgTable aligns heads rows) = OrgTable aligns' heads rows
|
||||||
_ -> mempty
|
_ -> mempty
|
||||||
cols = length refRow
|
cols = length refRow
|
||||||
fillColumns base padding = take cols $ base ++ repeat padding
|
fillColumns base padding = take cols $ base ++ repeat padding
|
||||||
aligns' = fillColumns aligns AlignDefault
|
colProps' = fillColumns colProps def
|
||||||
|
|
||||||
-- One or more horizontal rules after the first content line mark the previous
|
-- One or more horizontal rules after the first content line mark the previous
|
||||||
-- line as a header. All other horizontal lines are discarded.
|
-- line as a header. All other horizontal lines are discarded.
|
||||||
|
@ -788,7 +808,7 @@ rowToContent :: OrgTable
|
||||||
rowToContent orgTable row =
|
rowToContent orgTable row =
|
||||||
case row of
|
case row of
|
||||||
OrgHlineRow -> return singleRowPromotedToHeader
|
OrgHlineRow -> return singleRowPromotedToHeader
|
||||||
OrgAlignRow as -> return . setAligns $ as
|
OrgAlignRow props -> return . setProperties $ props
|
||||||
OrgContentRow cs -> appendToBody cs
|
OrgContentRow cs -> appendToBody cs
|
||||||
where
|
where
|
||||||
singleRowPromotedToHeader :: OrgTable
|
singleRowPromotedToHeader :: OrgTable
|
||||||
|
@ -797,8 +817,8 @@ rowToContent orgTable row =
|
||||||
orgTable{ orgTableHeader = b , orgTableRows = [] }
|
orgTable{ orgTableHeader = b , orgTableRows = [] }
|
||||||
_ -> orgTable
|
_ -> orgTable
|
||||||
|
|
||||||
setAligns :: [Alignment] -> OrgTable
|
setProperties :: [ColumnProperty] -> OrgTable
|
||||||
setAligns aligns = orgTable{ orgTableAlignments = aligns }
|
setProperties ps = orgTable{ orgTableColumnProperties = ps }
|
||||||
|
|
||||||
appendToBody :: F [Blocks] -> F OrgTable
|
appendToBody :: F [Blocks] -> F OrgTable
|
||||||
appendToBody frow = do
|
appendToBody frow = do
|
||||||
|
|
Loading…
Reference in a new issue