Coder Social home page Coder Social logo

clj-pdf-markdown's Introduction

clj-pdf-markdown

A small Clojure library for converting CommonMark markdown to clj-pdf syntax.

At least for now, this library relies on top of commonmark-java which is a java-based markdown parser.

This is alpha software. Possible breaking changes can be expected. Feel free to contribute!

Note that clj-pdf-markdown is built for configurability, not performance.

Installation

Add the following dependency to project.clj:

clojars project

Usage

Basic usage

You can convert a markdown string to clj-pdf format using markdown->clj-pdf:

user=> (require '[clj-pdf-markdown.core :refer [markdown->clj-pdf]])
nil
user=> (markdown->clj-pdf "This is a *test*.")
[:paragraph {} "This is a " [:phrase {:style :italic} "test"] "."]

Configuration

You can pass a map of pdf custom args the converter to tweak the output.

user=> (markdown->clj-pdf {:paragraph {:align :center}} "This is a *test*.")
[:paragraph {:align :center} "This is a " [:phrase {:style :italic} "test"] "."]

Any custom map provided will the merged to following the default map used by the library:

(def pdf-default-args 
  {:anchor   {}
   :heading  {:h1 {:style {:size 16}}
              :h2 {:style {:size 15}}
              :h3 {:style {:size 14}}
              :h4 {:style {:size 13}}
              :h5 {:style {:size 12}}
              :h6 {:style {:size 11}}}
   :image     {}
   :line      {}
   :list      {:ol {:numbered true}
               :ul {:symbol   ""}}
   :paragraph {}
   :spacer    {:allow-extra-line-breaks? true
               :single-value 0
               :extra-starting-value 0}
   :wrap {:unwrap-singleton? true
          :global-wrapper :vector ;; :paragraph or :vector 
          }})

Documentation

anchor

user=> (markdown->clj-pdf {} "[I'm a single link](https://www.google.com)")
[:anchor {:target "https://www.google.com"} "I'm a single link"]

Note that any title arg in markdown will be ignored, since it is not supported in clj-pdf:

user=> (markdown->clj-pdf {} "[I'm a single link with title](https://www.google.com \"Google's Homepage\")")
[:anchor {:target "https://www.google.com"} "I'm a single link with title"]

When not alone, the anchor will be wrapped in paragraph.

user=> (markdown->clj-pdf {} "Text followed by: [a link](https://www.google.com)")
[:paragraph {} 
 "Text followed by: " 
 [:anchor {:target "https://www.google.com"} 
 "a link"]] 
             
user=> (markdown->clj-pdf {} "[link 1](https://www.google.com)[link 2](https://www.yahoo.com)")
[:paragraph {} 
 [:anchor {:target "https://www.google.com"} "link 1"] 
 [:anchor {:target "https://www.yahoo.com"} "link 2"]]

heading

user=> (markdown->clj-pdf {} "# Title _1_")
[:heading {:style {:size 16}} "Title " [:phrase {:style :italic} "1"]]

user=> (markdown->clj-pdf {} "## Sub-title _1_")
[:heading {:style {:size 5}} "Sub-title " [:phrase {:style :italic} "1"]]

To change pdf args, you must specify which level of heading it is, from :h1 to :h6:

user=> (markdown->clj-pdf {:heading {:h2 {:style {:size 20}}}} "## Title _Big_") 
[:heading {:style {:size 20}} "Title " [:phrase {:style :italic} "Big"]]

image

user=> (markdown->clj-pdf {} "![alt text](https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png \"Logo Title Text 1\")")
[:image {:annotation ["Logo Title Text 1" "alt text"]} "https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png"]

Images can also be inserted inline with other text by wrapping it inside of a chunk element.

user=> (markdown->clj-pdf {} "This is an image: ![alt text](http://via.placeholder.com/350x150 \"Logo Title Text 1\")")
[[:paragraph {} "Text before"] 
 [:line {}] 
 [:paragraph {} "text after"]]

Also, chunk will be added if x and y values are provided in image sub-map. These are relative offsets for the image. The image element itself still accepts it's normal properties shown above.

user=> (markdown->clj-pdf {:image {:x 10 :y 10}} "![alt text](http://via.placeholder.com/350x150 \"Logo Title Text 1\")")
[:chunk {:x 10 :y 10} [:image {:annotation ["Logo Title Text 1" "alt text"]} "http://via.placeholder.com/350x150"]]

line

user=> (markdown->clj-pdf {} "Text before
  #_=> ***
  #_=> text after")
[[:paragraph {} "Text before"] [:line {}] [:paragraph {} "text after"]]

When :pagebreak is provided a :line arg value, this will provide a [:pagebreak] instead of a line!

(markdown->clj-pdf {:line :pagebreak} "Text before
  #_=> ***
  #_=> Text after")
[[:paragraph {} "Text before"] [:pagebreak] [:paragraph {} "Text after"]]

list

Markdown supports two king of lists, ordered lists (:ol) and unordered lists (:ul).

user=> (markdown->clj-pdf {} "* List item one
  #_=> * List item two")
[:list {:symbol ""} "List item one" "List item two"]

user=> (markdown->clj-pdf {} "1. This is the first item
  #_=> 2. This is the second item")
[:list {:numbered true} "This is the first item" "This is the second item"]

If you want to customize lists, you must specify the right intermediate key like so:

user=> (markdown->clj-pdf {:list {:ul {:symbol "* "}}} "* List item one
  #_=> * List item two")
[:list {:symbol "* "} "List item one" "List item two"]

user=> (markdown->clj-pdf {:list {:ol {:roman true}}} "1. This is the first item
  #_=> 2. This is the second item")
[:list {:roman true} "This is the first item" "This is the second item"]

paragraph

By default, a string will be wraped in paragraph except if it is plain and alone.

user=> (markdown->clj-pdf {} "This is simple text")
"This is simple text"
user=> (markdown->clj-pdf {} "Content with some *style*.")
[:paragraph {} "Content with some " [:phrase {:style :italic} "style"] "."]

Note that, you don't want to unwrap single strings, you can specify it:

user=> (markdown->clj-pdf {:wrap {:unwrap-singleton? false} "This is simple text")
[[:paragraph {} "This is simple text"]]

When there is more than one element at the document level, it gets globally wrapped in a vector. Undercover, clj-pdf will expand sequences containing elements:

(clj-pdf.core/pdf
 [{}
  [[:paragraph "1"] [:paragraph "2"]]]
 "doc.pdf")

is equivalent to

(clj-pdf.core/pdf
 [{}
  [:paragraph "1"] 
  [:paragraph "2"]]
 "doc.pdf")

spacer

user=> (markdown->clj-pdf {} "This is
  #_=> a spacer.")
[:paragraph {} "This is" [:spacer 0] "a spacer."]

user=> (markdown->clj-pdf {:spacer {:single-value 10}} "This is
  #_=> a huge spacer")
[:paragraph {} "This is" [:spacer 10] "a huge spacer"]

Note that if you break the line twice, you will get multiple paragraphs instead of spacers:

user=> (markdown->clj-pdf {} "This is paragraph 1
  #_=> 
  #_=> paragraph 2
  #_=> 
  #_=> paragraph 3")
[[:paragraph {} "This is paragraph 1"] [:paragraph {} "paragraph 2"] [:paragraph {} "paragraph 3"]]

Also, by default, clj-pdf-markdown render extra line-breaks (third+)

user=> (markdown->clj-pdf {:spacer {:extra-starting-value 0 :allow-extra-line-breaks? true}} 
        "Text\n\n\nText after 3 line-breaks\n\n\n\n\nText after 5 line-breaks")
[[:paragraph {} "Text"] 
 [:paragraph {} [:spacer 0] "Text after 3 line-breaks"] 
 [:paragraph {} [:spacer 2] "Text after 5 line-breaks"]]
user=> (markdown->clj-pdf {:spacer {:extra-starting-value 1 :allow-extra-line-breaks? true}} 
        "Text\n\n\nText after 3 line-breaks\n\n\n\n\nText after 5 line-breaks")
[[:paragraph {} "Text"] 
 [:paragraph {} [:spacer 1] "Text after 3 line-breaks"] 
 [:paragraph {} [:spacer 3] "Text after 5 line-breaks"]]

Note that extra line-breaks can be disabled.

user=> (markdown->clj-pdf {:spacer {:extra-starting-value 1 :allow-extra-line-breaks? false}}
        "Text\n\n\nText after 3 line-breaks\n\n\n\n\nText after 5 line-breaks")
[[:paragraph {} "Text"] 
 [:paragraph {} "Text after 3 line-breaks"] 
 [:paragraph {} "Text after 5 line-breaks"]]

Changelog

0.2.1 (May 29, 2018)

  • removed debugging println (thanks to @svdm)

0.2.0 (Jan 9, 2018)

  • removed commonmark-hiccup dep
  • controled wrapping behavior with :wrap option
  • handles extra spacers

License

Copyright © 2017 Leon Talbot

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

clj-pdf-markdown's People

Contributors

leontalbot avatar svdm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

svdm collbox

clj-pdf-markdown's Issues

Blockquote elements error on rendering

Trying to render a blockquote throws an exception right now:

user> (markdown->clj-pdf "> This is a quote")
java.lang.IllegalArgumentException: No matching field found: getLiteral for class org.commonmark.node.BlockQuote

The issue is that the :default case of the render method relies on .getLiteral on the parsed element. This works fine for code blocks etc, but blockquotes are parsed differently by commonmark-java. For this case it creates a BlockQuote containing one or more Paragraph nodes. The BlockQuote node itself has no .getLiteral implementation, hence the error.

Something like this seems to work, but I'm not familiar enough with this lib and clj-pdf to be sure it's entirely the right approach:

(defmethod render :BlockQuote
  [pdf-config node]
  (->> node
       (render-children* pdf-config)
       (wrap-paragraph pdf-config node)))

It also has the downside of using a plain :paragraph, which makes it hard to style quotes.

List inside list is not rendered

If there is list in list it will not be shown after compilation.

e.g.:

  • first version
    • a
    • b
  • second version
    • c

The points "a, b, c" will not be rendered.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.