Permalink
Browse files

Got FFI::Upskirt::Document rendering Markdown as HTML.

  • Loading branch information...
1 parent a11c0bd commit 9ed5fd6cf83b5a9c7b705cacd7f5fa5a44184348 @postmodern committed May 12, 2011
Showing with 295 additions and 4 deletions.
  1. +83 −4 lib/ffi/upskirt/buffer.rb
  2. +162 −0 lib/ffi/upskirt/document.rb
  3. +50 −0 lib/ffi/upskirt/renderer.rb
View
@@ -10,13 +10,92 @@ class Buffer < FFI::Struct
:unit, :size_t,
:ref, :int
+ #
+ # Creates a new empty buffer.
+ #
+ # @param [Integer] size
+ # The size of the new buffer.
+ #
+ # @yield [buffer]
+ # The given block will be passed the new buffer.
+ #
+ # @yieldparam [Buffer] buffer
+ # The new buffer.
+ #
+ # @return []
+ # Once the block has returned, the buffer will be released.
+ #
+ def self.create_empty(size)
+ buffer = new(Upskirt.bufnew(size))
+
+ yield buffer
+
+ Upskirt.bufrelease(buffer)
+ end
+
+ #
+ # Creates a new buffer.
+ #
+ # @param [String] text
+ # The text to populate the buffer with.
+ #
+ # @yield [buffer]
+ # The given block will be passed the new buffer.
+ #
+ # @yieldparam [Buffer] buffer
+ # The new buffer.
+ #
+ # @return []
+ # Once the block has returned, the buffer will be deallocated.
+ #
+ def self.create_from(text)
+ data = FFI::MemoryPointer.new(:char,text.length + 1)
+ data.put_string(0,text)
+
+ buffer = new()
+ buffer[:size] = text.length
+ buffer[:data] = data
+
+ yield buffer
+
+ data.free
+ end
+
+ #
+ # Increases the size of the buffer.
+ #
+ # @param [Integer] length
+ # The length to increase the buffer by.
+ #
+ def grow(length)
+ Upskirt.bufgrow(self,length)
+ end
+
+ #
+ # The contents of the buffer.
+ #
+ # @return [String]
+ # The data within the buffer.
+ #
+ def to_s
+ self[:data].get_string(0,self[:size])
+ end
+
+ #
+ # Applies smartypants rendering to the buffer.
+ #
+ # @return [String]
+ # The smartypants rendered contents of the buffer.
+ #
def to_smartypants
- smart_buffer = Upskirt.bufnew(128)
+ result = nil
+
+ Buffer.create_empty(128) do |smart_buffer|
+ Upskirt.upshtml_smartypants(smart_buffer,self)
- Upskirt.upshtml_smartypants(smart_buffer,self)
- result = smart_buffer.data.get_string(0,smart_buffer.size)
+ result = self.to_s
+ end
- smart_buffer.free
return result
end
View
@@ -1,12 +1,174 @@
+require 'ffi/upskirt/types'
+require 'ffi/upskirt/buffer'
+require 'ffi/upskirt/renderer'
+
module FFI
module Upskirt
class Document
+ # The `render_mode` enum
+ RENDER_MODES = Upskirt.enum_type(:render_mode)
+
+ # The `markdown_extensions` enum
+ EXTENSIONS = Upskirt.enum_type(:markdown_extensions)
+
+ # Valid options for {#initialize}
+ VALID_OPTIONS = RENDER_MODES.symbols + EXTENSIONS.symbols
+
+ attr_accessor :no_intra_emphasis
+
+ attr_accessor :tables
+
+ attr_accessor :fenced_code
+
+ attr_accessor :autolink
+
+ attr_accessor :strikethrough
+
+ attr_accessor :lax_html_blocks
+
+ attr_accessor :space_headers
+
+ attr_accessor :skip_html
+
+ attr_accessor :skip_style
+
+ attr_accessor :skip_images
+
+ attr_accessor :skip_links
+
+ attr_accessor :expand_tabs
+
+ attr_accessor :safelink
+
+ attr_accessor :toc
+
+ attr_accessor :hard_wrap
+
+ attr_accessor :github_blockcode
+
+ attr_accessor :use_xhtml
+
+ attr_accessor :smart
+
+ #
+ # Creates a new Document.
+ #
+ # @param [String] source
+ # The markdown source of the document.
+ #
+ # @param [Hash] options
+ # Additional options.
+ #
+ # @option options [Boolean] :smart
+ # Enables additional smartypants rendering.
+ #
def initialize(source='',options={})
@source = source
+ @smart = options.delete(:smart)
+
+ (VALID_OPTIONS & options.keys).each do |key|
+ instance_variable_set("@#{key}",options[key])
+ end
end
+ #
+ # Converts the Markdown Document to HTML.
+ #
+ # @return [String]
+ # The rendered HTML.
+ #
def to_html
+ result = nil
+
+ Renderer.html(render_flags) do |renderer|
+ result = render(renderer)
+ end
+
+ return result
+ end
+
+ #
+ # Creates a Table of Contents (TOC) of the document.
+ #
+ # @return [String]
+ # The rendered Table of Contents.
+ #
+ def to_toc
+ result = nil
+
+ Renderer.toc do |renderer|
+ result = render(renderer)
+ end
+
+ return result
+ end
+
+ protected
+
+ #
+ # The enabled markdown extensions flags.
+ #
+ # @return [Integer]
+ # The combined flags as an unsigned integer.
+ #
+ def extensions
+ flags = 0
+
+ EXTENSIONS.symbols.each do |name|
+ if instance_variable_get("@#{name}")
+ flags |= EXTENSIONS[name]
+ end
+ end
+
+ return flags
+ end
+
+ #
+ # The enabled rendering flags.
+ #
+ # @return [Integer]
+ # The combined flags as an unsigned integer.
+ #
+ def render_flags
+ flags = 0
+
+ RENDER_MODES.symbols.each do |name|
+ if instance_variable_get("@#{name}")
+ flags |= RENDER_MODES[name]
+ end
+ end
+
+ return flags
+ end
+
+ #
+ # Renders the markdown source.
+ #
+ # @param [Renderer] renderer
+ # The renderer to use.
+ #
+ # @return [String]
+ # The rendered output.
+ #
+ def render(renderer)
+ result = nil
+
+ Buffer.create_from(@source) do |input_buffer|
+ Buffer.create_empty(128) do |output_buffer|
+ output_buffer.grow(@source.length * 1.2)
+
+ Upskirt.ups_markdown(output_buffer,input_buffer,renderer,extensions)
+
+ result = if @smart
+ output_buffer.to_smartypants
+ else
+ output_buffer.to_s
+ end
+ end
+ end
+
+ return result
end
end
@@ -1,3 +1,5 @@
+require 'ffi/upskirt/upskirt'
+
module FFI
module Upskirt
class Renderer < FFI::Struct
@@ -29,6 +31,54 @@ class Renderer < FFI::Struct
:doc_footerm, :doc_footer_callback,
:opaque, :pointer
+ #
+ # Creates a new HTML renderer.
+ #
+ # @param [Integer] flags
+ # Render flags for the new renderer.
+ #
+ # @yield [renderer]
+ # The given block will be passed the new renderer.
+ #
+ # @yieldparam [Renderer] renderer
+ # The new renderer.
+ #
+ # @return []
+ # After the given block has returned, the renderer will be freed.
+ #
+ def Renderer.html(flags)
+ renderer = new
+ Upskirt.upshtml_renderer(renderer,flags)
+
+ yield renderer
+
+ Upskirt.upshtml_free_renderer(renderer)
+ end
+
+ #
+ # Creates a new Table of Contents (TOC) renderer.
+ #
+ # @param [Integer] flags
+ # Render flags for the new renderer.
+ #
+ # @yield [renderer]
+ # The given block will be passed the new renderer.
+ #
+ # @yieldparam [Renderer] renderer
+ # The new renderer.
+ #
+ # @return []
+ # After the given block has returned, the renderer will be freed.
+ #
+ def Renderer.toc
+ renderer = new
+ Upskirt.upshtml_toc_renderer(renderer)
+
+ yield renderer
+
+ Upskirt.upshtml_free_renderer(renderer)
+ end
+
end
end
end

0 comments on commit 9ed5fd6

Please sign in to comment.