hslua-module-doclayout-1.1.1.2/0000755000000000000000000000000007346545000014443 5ustar0000000000000000hslua-module-doclayout-1.1.1.2/CHANGELOG.md0000644000000000000000000000326107346545000016256 0ustar0000000000000000# Changelog `hslua-module-doclayout` uses [PVP Versioning][1]. The changelog is available [on GitHub][2]. ## 1.1.1.2 Released 2024-06-10. - Fixed another documentation bugs: `render` returns a `string`. ## 1.1.1.1 Released 2024-06-09. - Fixed minor typos in docstrings. ## 1.1.1 Released 2024-01-23. - Relaxed upper bound for text, allowing text-2.1. - Improved doc strings. - Test with latest GHC versions. ## 1.1.0 Release pending. - Require hslua-2.3 and tasty-lua-1.1. - Type info is added to all fields. - The `Doc` type is now associated with this module's docs, making it easier to generate documentation. ## 1.0.4 Released 2022-04-03. - Allow doclayout-0.4. ## 1.0.3 Released 2022-02-18. - Relaxed upper bound for hslua, allowing hslua-2.2. ## 1.0.2 Released 2022-02-05. - Modify functions, ensuring that the main document is always the first argument. This allows convenient use of these functions as methods. - Improved documentation. ## 1.0.1 Released 2022-01-31. - Updated to hslua-2.1. - Functions that take a `Doc` as the first argument are added as methods to `Doc` values. ## 1.0.0 Released 2021-10-24. * Upgraded to hslua-2.0. * Switched module name from `Foreign.Lua.Module.DocLayout` to `HsLua.Module.DocLayout`. ## 0.2.0.1 Released 2020-10-28. * Relax upper bounds for hslua, allowing hslua-1.3.* ## 0.2.0 * Full test coverage of all provided Lua functions. * Use documented module, including all function docs in the exported Haskell structure. * Test with all GHC 8 major versions. ## 0.1.0 * Initial release. [1]: https://pvp.haskell.org [2]: https://github.com/hslua/hslua-module-doclayout/releases hslua-module-doclayout-1.1.1.2/LICENSE0000644000000000000000000000206607346545000015454 0ustar0000000000000000MIT License Copyright (c) 2020-2024 Albert Krewinkel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. hslua-module-doclayout-1.1.1.2/README.md0000644000000000000000000001361207346545000015725 0ustar0000000000000000# hslua-module-doclayout [![GitHub CI][CI badge]](https://github.com/hslua/hslua-module-doclayout/actions) [![Hackage][Hackage badge]](https://hackage.haskell.org/package/hslua-module-doclayout) [![Stackage Lts][Stackage Lts badge]](http://stackage.org/lts/package/hslua-module-doclayout) [![Stackage Nightly][Stackage Nightly badge]](http://stackage.org/nightly/package/hslua-module-doclayout) [![MIT license][License badge]](LICENSE) Lua module wrapping the [doclayout] Haskell package. [doclayout]: https://hackage.haskell.org/package/doclayout [CI badge]: https://github.com/hslua/hslua-module-doclayout/workflows/CI/badge.svg [Hackage badge]: https://img.shields.io/hackage/v/hslua-module-doclayout.svg?logo=haskell [Stackage Lts badge]: http://stackage.org/package/hslua-module-doclayout/badge/lts [Stackage Nightly badge]: http://stackage.org/package/hslua-module-doclayout/badge/nightly [License badge]: https://img.shields.io/badge/license-MIT-blue.svg Example ------- ``` haskell loadProg :: Lua Status loadProg = do openlibs preloadModule "doclayout" dostring $ unlines [ "doc = require 'doclayout'" , "local example_doc = (doc.literal 'Line' + 'One')" , " // (doc.literal 'Line' + 'Two')" , "-- prints:" , "-- Line One" , "--" , "-- Line Two" , "print(doc.render(example_doc))" , "" , "-- prints:" , "-- Line" , "-- One" , "--" , "-- Line" , "-- Two" , "local columns = 5" , "print(doc.render(example_doc, columns))" ] ``` Documentation ------------- ### Functions #### render `render (doc[, colwidth])` Render the `Doc` using the given column width. Parameters: `doc` : Doc to render `colwidth` : Maximum number of characters per line ### Doc construction All functions return a fresh `Doc` element. #### after_break `after_break` Creates a `Doc` which is conditionally included only if it comes at the beginning of a line. #### before_non_blank `before_non_blank (doc)` Conditionally includes the given `Doc` unless it is followed by a blank space. #### blankline `blankline` Inserts a blank line unless one exists already. #### blanklines `blanklines (n)` Insert blank lines unless they exist already. Parameters: `n` : Number of blank lines to insert. #### braces `braces (doc)` Puts a `Doc` in curly braces. #### brackets `brackets (doc)` Puts a `Doc` in square brackets. #### cblock `cblock (width, doc)` Like `lblock` but aligned centered. Parameters: `width` : Width of the created block, in characters `doc` : Contents of the block ([Doc]) #### chomp `chomp (doc)` Chomps trailing blank space off of a `Doc`. #### concat `concat (docs[, sep])` Concatenate the given `Doc`s, interspersing `sep` if specified. Parameters: `docs` : List of `Doc`s `sep` : Separator `Doc` #### cr A carriage return. Does nothing if we're at the beginning of a line; otherwise inserts a newline. #### double_quotes `double_quotes (doc)` Wraps a `Doc` in double quotes #### empty The empty document. #### flush `flush (doc)` Makes a `Doc` flush against the left margin. #### hang `hang (indent, start, doc)` Creates a hanging indent. Parameters: `indent` : Indentation width in characters `start` : Start, printed unindented `doc` : Doc which is indented by `indent` spaces on every line. #### inside `inside (start, end, contents)` Encloses a `Doc` inside a start and end `Doc`. Parameters: `start` : Doc before contents `end` : Doc after contents `contents` : Contents Doc #### lblock `lblock (width, doc)` Creates a block with the given width and content, aligned to the left. Parameters: `width` : Width of the created block, in characters `doc` : Contents of the block ([Doc]) #### literal `literal (string)` Creates a `Doc` from a string. #### nest `nest (indent)` Indents a `Doc` by the specified number of spaces. Parameters: `indent` : Indentation width. #### nestle `nestle (doc)` Removes leading blank lines from a `Doc`. #### nowrap `nowrap (doc)` Makes a `Doc` non-reflowable. #### parens `parens (doc)` Puts a `Doc` in parentheses. #### prefixed `prefixed (prefix, doc)` Uses the specified string as a prefix for every line of the inside document (except the first, if not at the beginning of the line). Parameters: `prefix` : Prefix to prepend to each line `doc` : Inside Doc. #### quotes `quotes (doc)` Wraps a `Doc` in single quotes. #### rblock `rblock (indent, doc)` Like `lblock` but aligned to the right. Parameters: `width` : Width of the created block, in characters `doc` : Contents of the block ([Doc]) #### space A breaking (reflowable) space. #### vfill `vfill` Creates an expandable border that, when placed next to a box, expands to the height of the box. Parameters: `text` : Border text ### Operators #### `..` Concatenate two `Doc` elements. #### `+` Concatenate two `Doc`s, inserting a reflowable space between them. #### `/` If `a` and `b` are `Doc` elements, then `a / b` puts `a` above `b`. #### `//` If `a` and `b` are `Doc` elements, then `a // b` puts `a` above `b`, inserting a blank line between them. ### Document Querying #### is_empty `is_empty (doc)` Returns `true` iff `doc` is the empty document, `false` otherwise. #### min_offset `min_offset (doc)` Returns the minimal width of a @'Doc'@ when reflowed at breakable spaces. #### update_column `update_column (doc, i)` Returns the column that would be occupied by the last laid out character. #### height `height (doc)` Returns the height of a block or other Doc. #### real_length `real_length (str)` Returns the real length of a string in a monospace font: 0 for a combining character, 1, for a regular character, 2 for an East Asian wide character. #### offset `offset (doc)` Returns the width of a `Doc` (as number of characters). License ------- This package is made available under the MIT license. See [`LICENSE`](LICENSE) for details. hslua-module-doclayout-1.1.1.2/hslua-module-doclayout.cabal0000644000000000000000000000524607346545000022036 0ustar0000000000000000cabal-version: 2.2 name: hslua-module-doclayout version: 1.1.1.2 synopsis: Lua module wrapping Text.DocLayout. description: Lua module wrapping @Text.DocLayout@. homepage: https://github.com/hslua/hslua-module-doclayout bug-reports: https://github.com/hslua/hslua-module-doclayout/issues license: MIT license-file: LICENSE author: Albert Krewinkel maintainer: Albert Krewinkel copyright: © 2020-2024 Albert Krewinkel category: Foreign build-type: Simple extra-doc-files: README.md CHANGELOG.md extra-source-files: test/test-doclayout.lua tested-with: GHC == 8.4.4 , GHC == 8.6.5 , GHC == 8.8.4 , GHC == 8.10.7 , GHC == 9.0.2 , GHC == 9.2.6 , GHC == 9.4.8 , GHC == 9.6 , GHC == 9.8 source-repository head type: git location: https://github.com/hslua/hslua-module-doclayout.git common common-options build-depends: base >= 4.11 && < 5 , doclayout >= 0.2 && < 0.5 , hslua >= 2.3 && < 2.4 , text >= 1.2 && < 2.2 default-language: Haskell2010 other-extensions: OverloadedStrings , TypeApplications ghc-options: -Wall -Wcompat -Widentities -Wincomplete-uni-patterns -Wincomplete-record-updates if impl(ghc >= 8.0) ghc-options: -Wredundant-constraints if impl(ghc >= 8.2) ghc-options: -fhide-source-paths if impl(ghc >= 8.4) ghc-options: -Wmissing-export-lists -Wpartial-fields if impl(ghc >= 8.8) ghc-options: -Wmissing-deriving-strategies library import: common-options hs-source-dirs: src exposed-modules: HsLua.Module.DocLayout other-extensions: CPP , FlexibleInstances , LambdaCase test-suite hslua-module-doclayout-test import: common-options build-depends: hslua-module-doclayout , tasty , tasty-hunit , tasty-lua >= 1.1 && < 1.2 type: exitcode-stdio-1.0 hs-source-dirs: test main-is: test-hslua-module-doclayout.hs build-depends: hslua-module-doclayout ghc-options: -threaded hslua-module-doclayout-1.1.1.2/src/HsLua/Module/0000755000000000000000000000000007346545000017473 5ustar0000000000000000hslua-module-doclayout-1.1.1.2/src/HsLua/Module/DocLayout.hs0000644000000000000000000004031707346545000021737 0ustar0000000000000000{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {-| Module : HsLua.Module.DocLayout Copyright : © 2020-2024 Albert Krewinkel License : MIT Maintainer : Albert Krewinkel Provides a Lua module which wraps @'Text.DocLayout'@. The @'Doc'@ type is specialized to @'Text'@. This module defines orphan instances for @Doc Text@. -} module HsLua.Module.DocLayout ( -- * Module documentedModule , pushModule , preloadModule , description , fields , functions -- * Doc constructors and combinators , after_break , before_non_blank , blankline , blanklines , braces , brackets , cblock , chomp , concat , cr , double_quotes , empty , flush , hang , inside , lblock , literal , nest , nestle , nowrap , parens , prefixed , quotes , rblock , space , vfill -- * Rendering , render -- * Document Querying , is_empty , height , min_offset , offset , real_length , update_column -- * Marshaling , peekDoc , pushDoc ) where import Prelude hiding (concat) import Data.List (intersperse) import Data.Text (Text) import HsLua as Lua hiding (concat) import Text.DocLayout (Doc, (<+>), ($$), ($+$)) import qualified Data.Text as T import qualified Text.DocLayout as Doc -- -- Module -- -- | Textual description of the "doclayout" module. description :: Text description = "Plain-text document layouting." -- | Self-documenting module. documentedModule :: LuaError e => Module e documentedModule = Module { moduleName = "doclayout" , moduleFields = fields , moduleDescription = description , moduleFunctions = functions , moduleOperations = [] , moduleTypeInitializers = [initType typeDoc] } -- -- Fields -- -- | Exposed fields. fields :: forall e. LuaError e => [Field e] fields = [ blankline , cr , empty , space ] -- | Wrapped and documented 'Doc.blankline' value. blankline :: forall e. LuaError e => Field e blankline = Field { fieldName = "blankline" , fieldDescription = "Inserts a blank line unless one exists already." , fieldType = udTypeSpec @e typeDoc , fieldPushValue = pushDoc Doc.blankline } -- | Wrapped and documented 'Doc.cr' value. cr :: forall e. LuaError e => Field e cr = Field { fieldName = "cr" , fieldDescription = "A carriage return. Does nothing if we're at " <> "the beginning of a line; " <> "otherwise inserts a newline." , fieldType = udTypeSpec @e typeDoc , fieldPushValue = pushDoc Doc.cr } -- | Wrapped and documented 'Doc.empty' value. empty :: forall e. LuaError e => Field e empty = Field { fieldName = "empty" , fieldDescription = "The empty document." , fieldType = udTypeSpec @e typeDoc , fieldPushValue = pushDoc Doc.empty } -- | Wrapped and documented 'Doc.space' value. space :: forall e. LuaError e => Field e space = Field { fieldName = "space" , fieldDescription = "A breaking (reflowable) space." , fieldType = udTypeSpec @e typeDoc , fieldPushValue = pushDoc Doc.space } -- -- Functions -- -- | Exposed module functions. functions :: LuaError e => [DocumentedFunction e] functions = [ -- Constructors after_break , before_non_blank , blanklines , braces , brackets , cblock , chomp , concat , double_quotes , flush , hang , inside , lblock , literal , nest , nestle , nowrap , parens , prefixed , quotes , rblock , vfill -- rendering , render -- querying , is_empty , height , min_offset , offset , real_length , update_column ] typeDoc :: LuaError e => DocumentedType e (Doc Text) typeDoc = deftype "Doc" [ operation Add $ binaryOp (<+>) "Concatenated docs, with breakable space between them." , operation Concat $ binaryOp (<>) "Concatenation of the input docs" , operation Div $ binaryOp ($$) "Puts a above b" , operation Eq $ lambda ### liftPure2 (==) <#> docParam "a" <#> docParam "b" =#> boolResult "whether the two Docs are equal" , operation Idiv $ binaryOp ($+$) "Puts a above b" , operation Tostring $ lambda ### liftPure (Doc.render Nothing) <#> docParam "doc" =#> textResult "Rendered Doc without reflowing." ] [ method before_non_blank , method braces , method brackets , method cblock , method chomp , method double_quotes , method is_empty , method flush , method hang , method height , method inside , method lblock , method min_offset , method nest , method nestle , method nowrap , method offset , method parens , method prefixed , method quotes , method rblock , method render , method update_column , method vfill ] where binaryOp op descr = lambda ### liftPure2 op <#> docParam "a" <#> docParam "b" =#> docResult descr -- | Render a @'Doc'@. The text is reflowed on breakable spaces -- to match the given line length. Text is not reflowed if the -- line length parameter is omitted or nil. render :: LuaError e => DocumentedFunction e render = defun "render" ### liftPure2 (flip Doc.render) <#> docParam "doc" <#> opt (integralParam "colwidth" "planned maximum line length") =#> functionResult pushText "string" "rendered doc" #? T.unlines [ "Render a [[Doc]]. The text is reflowed on breakable spaces to" , "match the given line length. Text is not reflowed if the line" , "line length parameter is omitted or nil." ] -- -- Querying -- -- | @True@ iff the document is empty. is_empty :: LuaError e => DocumentedFunction e is_empty = defun "is_empty" ### liftPure Doc.isEmpty <#> docParam "doc" =#> boolResult "`true` iff `doc` is the empty document, `false` otherwise." #? "Checks whether a doc is empty." -- | Returns the width of a @'Doc'@. offset :: LuaError e => DocumentedFunction e offset = defun "offset" ### liftPure Doc.offset <#> docParam "doc" =#> integralResult "doc width" #? "Returns the width of a [[Doc]] as number of characters." -- | Returns the minimal width of a @'Doc'@ when reflowed at -- breakable spaces. min_offset :: LuaError e => DocumentedFunction e min_offset = defun "min_offset" ### liftPure Doc.minOffset <#> docParam "doc" =#> integralResult "minimal possible width" #? ("Returns the minimal width of a [[Doc]] when reflowed at " <> "breakable spaces.") -- | Returns the column that would be occupied by the last laid -- out character. update_column :: LuaError e => DocumentedFunction e update_column = defun "update_column" ### liftPure2 Doc.updateColumn <#> docParam "doc" <#> integralParam "i" "start column" =#> integralResult "column number" #? ("Returns the column that would be occupied by the last " <> "laid out character.") -- | Returns the height of a block or other Doc. height :: LuaError e => DocumentedFunction e height = defun "height" ### liftPure Doc.height <#> docParam "doc" =#> integralResult "doc height" #? "Returns the height of a block or other Doc." -- | Returns the real length of a string in a monospace font: 0 -- for a combining character, 1, for a regular character, 2 for -- an East Asian wide character. real_length :: DocumentedFunction e real_length = defun "real_length" ### liftPure Doc.realLength <#> textParam "str" "UTF-8 string to measure" =#> integralResult "text length" #? ("Returns the real length of a string in a monospace font: " <> "0 for a combining character, 1 for a regular character, " <> "2 for an East Asian wide character.") -- -- Constructors -- -- | Creates a @'Doc'@ which is conditionally included only if it -- comes at the beginning of a line. after_break :: LuaError e => DocumentedFunction e after_break = defun "after_break" ### liftPure Doc.afterBreak <#> textParam "text" "content to include when placed after a break" =#> docResult "new doc" #? ("Creates a [[Doc]] which is conditionally included only if it " <> "comes at the beginning of a line.\n\n" <> "An example where this is useful is for escaping line-initial " <> "`.` in roff man.") -- | Conditionally includes the given @'Doc'@ unless it is -- followed by a blank space. before_non_blank :: LuaError e => DocumentedFunction e before_non_blank = defun "before_non_blank" ### liftPure Doc.beforeNonBlank <#> docParam "doc" =#> docResult "conditional doc" #? ("Conditionally includes the given `doc` unless it is " <> "followed by a blank space.") -- | Insert blank lines unless they exist already. blanklines :: LuaError e => DocumentedFunction e blanklines = defun "blanklines" ### liftPure Doc.blanklines <#> integralParam "n" "number of blank lines" =#> docResult "conditional blank lines" #? "Inserts blank lines unless they exist already." -- | Puts a @'Doc'@ in curly braces. braces :: LuaError e => DocumentedFunction e braces = defun "braces" ### liftPure Doc.braces <#> docParam "doc" =#> docResult "`doc` enclosed by {}." #? "Puts the `doc` in curly braces." -- | Puts a @'Doc'@ in square brackets. brackets :: LuaError e => DocumentedFunction e brackets = defun "brackets" ### liftPure Doc.brackets <#> docParam "doc" =#> docResult "doc enclosed by []." #? "Puts the `doc` in square brackets" -- | Like @'lblock'@ but aligned centered. cblock :: LuaError e => DocumentedFunction e cblock = defun "cblock" ### liftPure2 (flip Doc.cblock) <#> docParam "doc" <#> integralParam "width" "block width in chars" =#> docResult ("doc, aligned centered in a block with max " <> "`width` chars per line.") #? ("Creates a block with the given width and content, " <> "aligned centered.") -- | Chomps trailing blank space off of a @'Doc'@. chomp :: LuaError e => DocumentedFunction e chomp = defun "chomp" ### liftPure Doc.chomp <#> docParam "doc" =#> docResult "`doc` without trailing blanks" #? "Chomps trailing blank space off of the `doc`." -- | Concatenates a list of @'Doc'@s. concat :: LuaError e => DocumentedFunction e concat = defun "concat" ### liftPure2 (\docs optSep -> mconcat $ maybe docs (`intersperse` docs) optSep) <#> parameter (peekList peekDoc) "`{Doc,...}`" "docs" "list of Docs" <#> opt (parameter peekDoc "Doc" "sep" "separator (default: none)") =#> docResult "concatenated doc" #? "Concatenates a list of `Doc`s." -- | Wraps a @'Doc'@ in double quotes double_quotes :: LuaError e => DocumentedFunction e double_quotes = defun "double_quotes" ### liftPure Doc.doubleQuotes <#> docParam "doc" =#> docResult "`doc` enclosed by `\"` chars" #? "Wraps a `Doc` in double quotes." -- | Makes a @'Doc'@ flush against the left margin. flush :: LuaError e => DocumentedFunction e flush = defun "flush" ### liftPure Doc.flush <#> docParam "doc" =#> docResult "flushed `doc`" #? "Makes a `Doc` flush against the left margin." -- | Creates a hanging indent. hang :: LuaError e => DocumentedFunction e hang = defun "hang" ### liftPure3 (\doc ind start -> Doc.hang ind start doc) <#> docParam "doc" <#> integralParam "ind" "indentation width" <#> docParam "start" =#> docResult ("`doc` prefixed by `start` on the first line, " <> "subsequent lines indented by `ind` spaces.") #? "Creates a hanging indent." -- | Encloses a @'Doc'@ inside a start and end @'Doc'@. inside :: LuaError e => DocumentedFunction e inside = defun "inside" ### liftPure3 (\contents start end -> Doc.inside start end contents) <#> docParam "contents" <#> docParam "start" <#> docParam "end" =#> docResult "enclosed contents" #? "Encloses a [[Doc]] inside a start and end [[Doc]]." -- | Creates a block with the given width and content, aligned to -- the left. lblock :: LuaError e => DocumentedFunction e lblock = defun "lblock" ### liftPure2 (flip Doc.lblock) <#> docParam "doc" <#> integralParam "width" "block width in chars" =#> docResult "doc put into block with max `width` chars per line." #? ("Creates a block with the given width and content, " <> "aligned to the left.") -- | Creates a @'Doc'@ from a string. literal :: LuaError e => DocumentedFunction e literal = defun "literal" ### liftPure Doc.literal <#> textParam "text" "literal value" =#> docResult "doc contatining just the literal string" #? "Creates a `Doc` from a string." -- | Indents a @'Doc'@ by the specified number of spaces. nest :: LuaError e => DocumentedFunction e nest = defun "nest" ### liftPure2 (flip Doc.nest) <#> docParam "doc" <#> integralParam "ind" "indentation size" =#> docResult "`doc` indented by `ind` spaces" #? "Indents a `Doc` by the specified number of spaces." -- | Removes leading blank lines from a @'Doc'@. nestle :: LuaError e => DocumentedFunction e nestle = defun "nestle" ### liftPure Doc.nestle <#> docParam "doc" =#> docResult "`doc` with leading blanks removed" #? "Removes leading blank lines from a `Doc`." -- | Makes a @'Doc'@ non-reflowable. nowrap :: LuaError e => DocumentedFunction e nowrap = defun "nowrap" ### liftPure Doc.nowrap <#> docParam "doc" =#> docResult "same as input, but non-reflowable" #? "Makes a `Doc` non-reflowable." -- | Puts a @'Doc'@ in parentheses. parens :: LuaError e => DocumentedFunction e parens = defun "parens" ### liftPure Doc.parens <#> docParam "doc" =#> docResult "doc enclosed by ()." #? "Puts the `doc` in parentheses." -- | Uses the specified string as a prefix for every line of the -- inside document (except the first, if not at the beginning of -- the line). prefixed :: LuaError e => DocumentedFunction e prefixed = defun "prefixed" ### liftPure2 (flip Doc.prefixed) <#> docParam "doc" <#> stringParam "prefix" "prefix for each line" =#> docResult "prefixed `doc`" #? ("Uses the specified string as a prefix for every line of " <> "the inside document (except the first, if not at the " <> "beginning of the line).") -- | Wraps a @'Doc'@ in single quotes. quotes :: LuaError e => DocumentedFunction e quotes = defun "quotes" ### liftPure Doc.quotes <#> docParam "doc" =#> docResult "doc enclosed in `'`." #? "Wraps a `Doc` in single quotes." -- | Like @'rblock'@ but aligned to the right. rblock :: LuaError e => DocumentedFunction e rblock = defun "rblock" ### liftPure2 (flip Doc.rblock) <#> docParam "doc" <#> integralParam "width" "block width in chars" =#> docResult ("doc, right aligned in a block with max " <> "`width` chars per line.") #? ("Creates a block with the given width and content, " <> "aligned to the right.") -- | An expandable border that, when placed next to a box, -- expands to the height of the box. Strings cycle through the -- list provided. vfill :: LuaError e => DocumentedFunction e vfill = defun "vfill" ### liftPure Doc.vfill <#> textParam "border" "vertically expanded characters" =#> docResult "automatically expanding border Doc" #? ("An expandable border that, when placed next to a box, " <> "expands to the height of the box. Strings cycle through the " <> "list provided.") -- -- Marshaling -- -- | Retrieve a @Doc Text@ value from the Lua stack. Strings are -- converted to plain @'Doc'@ values. peekDoc :: LuaError e => Peeker e (Doc Text) peekDoc idx = liftLua (Lua.ltype idx) >>= \case Lua.TypeString -> let stringToDoc s = if T.null s then Doc.empty else Doc.literal s in stringToDoc <$> Lua.peekText idx Lua.TypeNumber -> Doc.literal <$> Lua.peekText idx _ -> peekUD typeDoc idx -- | Push a @Doc Text@ value to the Lua stack. pushDoc :: LuaError e => Pusher e (Doc Text) pushDoc = pushUD typeDoc instance Peekable (Doc Text) where safepeek = peekDoc instance Pushable (Doc Text) where push = pushDoc -- -- Parameters -- -- | @Doc@ typed function parameter. docParam :: LuaError e => Text -> Parameter e (Doc Text) docParam name = parameter peekDoc "Doc" name "document" -- -- Results -- -- | Function result of type @'Doc'@. docResult :: LuaError e => Text -- ^ Description -> FunctionResults e (Doc Text) docResult = functionResult pushDoc "Doc" hslua-module-doclayout-1.1.1.2/test/0000755000000000000000000000000007346545000015422 5ustar0000000000000000hslua-module-doclayout-1.1.1.2/test/test-doclayout.lua0000644000000000000000000002256607346545000021120 0ustar0000000000000000-- -- Tests for the doclayout module -- local doclayout = require 'doclayout' local tasty = require 'tasty' local group = tasty.test_group local test = tasty.test_case local assert = tasty.assert -- Check existence static fields return { group 'constructors' { test('empty', function () assert.are_equal(type(doclayout.empty), 'userdata') end), test('blankline', function () assert.are_equal(type(doclayout.blankline), 'userdata') end), test('cr', function () assert.are_equal(type(doclayout.cr), 'userdata') end), test('space', function () assert.are_equal(type(doclayout.space), 'userdata') end), test('chomp', function () local doc = 'a' .. doclayout.blanklines(2) assert.are_equal(doclayout.chomp(doc), doclayout.literal 'a') end), test('nestle', function () local doc = doclayout.blanklines(3) .. 'a' assert.are_equal(doclayout.nestle(doc), doclayout.literal 'a') end), group 'enclosing' { test('quotes', function () local doc = doclayout.literal 'single' assert.are_equal( doclayout.quotes(doc), "'" .. doclayout.literal 'single' .. "'" ) end), test('double quotes', function () local doc = doclayout.literal 'double' assert.are_equal( doclayout.double_quotes(doc), '"' .. doclayout.literal 'double' .. '"' ) end), test('inside', function () local doc = doclayout.literal 'Hello,' + 'World!' assert.are_equal( doclayout.inside(doc, 'Yo! ', ' Wassup?'), 'Yo! ' .. doc .. ' Wassup?' ) end), }, group 'concat' { test('with sep', function () local list = { doclayout.literal 'one', doclayout.literal 'two', doclayout.literal 'three' } local sep = doclayout.cr assert.are_equal( doclayout.concat(list, sep), list[1] .. sep .. list[2] .. sep .. list[3]) end), test('without sep', function () local list = { doclayout.literal 'one', doclayout.literal 'two', doclayout.literal 'three' } assert.are_equal(doclayout.concat(list), list[1] .. list[2] .. list[3]) end), }, }, group 'render' { test('empty doc', function () assert.are_equal(doclayout.render(doclayout.empty), '') end), test('reflow', function () local greeting = doclayout.literal 'Hi!' .. doclayout.space .. doclayout.literal 'How' .. doclayout.space .. doclayout.literal 'are' .. doclayout.space .. doclayout.literal 'you?' assert.are_equal(greeting:render(7), 'Hi! How\nare\nyou?') end), test('after_break', function () local doc = doclayout.literal 'hi' + doclayout.after_break '!' .. doclayout.after_break '?' .. doclayout.literal 'x' .. doclayout.after_break '?' assert.are_equal(doc:render(2), 'hi\n!x') end), test('before_non_blank', function () local doc = doclayout.before_non_blank '!!' .. ' ab' / doclayout.before_non_blank '!!' .. 'a b' assert.are_equal(doclayout.render(doc), ' ab\n!!a b') end), test('blanks at beginning', function () local doc = doclayout.blanklines(2) .. 'aa' -- only one newline, as the top of doc is treated as implicit blank assert.are_equal(doclayout.render(doc), '\naa') end), test('blanklines', function () local doc = 'aa' .. doclayout.blanklines(2) .. 'bb' assert.are_equal(doclayout.render(doc), 'aa\n\n\nbb') end), test('braces', function () local doc = doclayout.braces 'maybe' assert.are_equal(doclayout.render(doc), '{maybe}') end), test('brackets', function () local doc = doclayout.brackets '1' assert.are_equal(doclayout.render(doc), '[1]') end), test('flush', function () local doc = doclayout.flush(doclayout.nest('hi', 2)) assert.are_equal(doclayout.render(doc), 'hi') end), test('hang', function () local doc = doclayout.hang('aa\nbb\ncc', 4, ' - ') assert.are_equal( doclayout.render(doc), table.concat{ ' - aa\n', ' bb\n', ' cc', } ) end), test('nest', function () local doc = doclayout.nest('aa\n\nbb\ncc', 2) assert.are_equal( doclayout.render(doc), table.concat{ ' aa\n', '\n', ' bb\n', ' cc' } ) end), test('nowrap', function() local doc = doclayout.nowrap(doclayout.literal 'first' + 'second') assert.are_equal(doc:render(8), 'first second') end), test('parens', function () local doc = doclayout.parens 'lisp' assert.are_equal(doclayout.render(doc), '(lisp)') -- as method assert.are_equal(doc:parens():render(), '((lisp))') end), test('prefixed', function () local doc = doclayout.prefixed(doclayout.literal 'aa' // 'bb', '# ' ) assert.are_equal(doclayout.render(doc), '# aa\n#\n# bb') -- as method assert.are_equal( (doclayout.literal'aa' // 'bb'):prefixed('# '):render(), '# aa\n#\n# bb' ) end), group 'table helpers' { test('cblock', function () local doc = doclayout.cblock('| ', 2) .. doclayout.cblock('aa', 4) .. doclayout.cblock(' |', 2) assert.are_equal(doclayout.render(doc), '| aa |') end), test('lblock', function () local doc = doclayout.lblock('| ', 2) .. doclayout.lblock('aa', 4) .. doclayout.lblock(' |', 2) assert.are_equal(doclayout.render(doc), '| aa |') end), test('rblock', function () local doc = doclayout.rblock('| ', 2) .. doclayout.rblock('aa', 4) .. doclayout.rblock(' |', 2) assert.are_equal(doclayout.render(doc), '| aa |') end), test('vfill', function () local doc = doclayout.vfill '| ' .. doclayout.lblock(doclayout.literal 'aa' // 'bbb', 4) .. doclayout.vfill(' |') assert.are_equal( doclayout.render(doc), table.concat{ '| aa |\n', '| |\n', '| bbb |' } ) end) } }, group 'document querying' { test('is_empty', function () assert.is_truthy(doclayout.is_empty(doclayout.empty)) assert.is_truthy(doclayout.is_empty('')) assert.is_falsy(doclayout.is_empty('non-empty')) end), test('height', function () assert.are_equal(doclayout.height(doclayout.empty), 1) assert.are_equal(doclayout.height('line'), 1) assert.are_equal(doclayout.height(doclayout.literal 'p' / 'q'), 2) assert.are_equal(doclayout.height(doclayout.literal 'p' // 'q'), 3) end), test('min_offset', function () assert.are_equal(doclayout.min_offset 'four', 4) assert.are_equal( doclayout.min_offset(doclayout.literal 'four' + 'radio'), 5 ) end), test('offset', function () assert.are_equal(doclayout.offset 'four', 4) assert.are_equal(doclayout.offset(doclayout.literal 'four' / 'radio'), 5) end), test('real_length', function () assert.are_equal(doclayout.real_length(''), 0) assert.are_equal(doclayout.real_length('a'), 1) assert.are_equal(doclayout.real_length('❄'), 1) assert.are_equal(doclayout.real_length('シ'), 2) assert.are_equal(doclayout.real_length('four'), 4) end), test('update_column', function () local doc = 'long' .. doclayout.cr .. 'longer' assert.are_equal(doclayout.update_column(doc, 0), 6) -- fails with doclayout < 0.4: -- assert.are_equal(doclayout.update_column(doclayout.empty, 42), 42) assert.are_equal(doclayout.update_column('four', 4), 8) end) }, group 'Doc type' { test('empty strings equal the empty Doc', function () assert.are_equal(doclayout.empty .. '', doclayout.empty) end), test('strings can be used as Doc values', function () assert.are_equal(doclayout.render('hello world'), 'hello world') end), test('numbers can be used as Doc values', function () assert.are_equal(doclayout.render(42), '42') end), test('equality', function () assert.is_truthy(doclayout.literal "true", doclayout.literal "true") end), test('concatenate docs', function () assert.are_equal( tostring(doclayout.literal 'Rock-' .. doclayout.literal 'Ola'), 'Rock-Ola' ) end), test('has tostring method', function () local str = 'just a literal string for now' assert.are_equal(tostring(str), str) end), test('adding concatenates with space', function () local helloworld = doclayout.literal 'Hello,' .. doclayout.space .. doclayout.literal 'World' assert.are_equal(doclayout.literal 'Hello,' + 'World', helloworld) end), test('dividing sets the first above the second', function () local first = doclayout.literal 'first' local second = doclayout.literal 'second' assert.are_equal(first / second, first .. doclayout.cr .. second) end), test('// separates docs with blank line', function () local first = doclayout.literal 'first' local second = doclayout.literal 'second' assert.are_equal(first // second, first .. doclayout.blankline .. second) end), } } hslua-module-doclayout-1.1.1.2/test/test-hslua-module-doclayout.hs0000644000000000000000000000327607346545000023343 0ustar0000000000000000{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} {-| Module : Main Copyright : © 2020-2024 Albert Krewinkel License : MIT Maintainer : Albert Krewinkel Tests for the `doclayout` Lua module. -} module Main (main) where import Control.Monad (void) import HsLua (Lua) import HsLua.Module.DocLayout (documentedModule) import Test.Tasty (TestTree, defaultMain, testGroup) import Test.Tasty.HUnit (assertEqual, testCase) import Test.Tasty.Lua (translateResultsFromFile) import qualified HsLua as Lua main :: IO () main = do luaTestResults <- Lua.run @Lua.Exception $ do Lua.openlibs Lua.registerModule documentedModule Lua.pop 1 -- pop module table translateResultsFromFile "test/test-doclayout.lua" defaultMain $ testGroup "hslua-module-doclayout" [tests, luaTestResults] -- | HSpec tests for the Lua 'system' module tests :: TestTree tests = testGroup "HsLua doclayout module" [ testCase "module can be pushed to the stack" $ Lua.run (void (Lua.pushModule documentedModule) :: Lua ()) , testCase "module can be added to the preloader" . Lua.run $ do Lua.openlibs Lua.preloadModule documentedModule assertEqual' "function not added to preloader" Lua.TypeFunction =<< do Lua.getglobal' "package.preload.doclayout" Lua.ltype (-1) , testCase "module can be loaded as `layout`" . Lua.run $ do Lua.openlibs Lua.preloadModuleWithName documentedModule "layout" assertEqual' "loading the module fails " Lua.OK =<< Lua.dostring "require 'layout'" ] assertEqual' :: (Show a, Eq a) => String -> a -> a -> Lua () assertEqual' msg expected = Lua.liftIO . assertEqual msg expected