   text = text.replace(/^\s*<!doctype(\s+.*)?>\s*/i, '')
 
   roaster text, options, (error, html) =>
-    if error
-      callback(error)
-    else
-      html = sanitize(html)
-      html = resolveImagePaths(html, filePath)
-      html = tokenizeCodeBlocks(html)
-      callback(null, html.html().trim())
+    return callback(error) if error
+
+    defaultLanguage = if path.extname(filePath) is '.litcoffee'
+      'coffeescript'
+    else 'text'
+
+    html = sanitize(html)
+    html = resolveImagePaths(html, filePath)
+    html = tokenizeCodeBlocks(html,defaultLanguage)
+    callback(null, html.html().trim())
 
 exports.toText = (text, filePath, callback) ->
   exports.toHtml text, filePath, (error, html) ->


  for preElement in $.merge(html.filter("pre"), html.find("pre"))
    codeBlock = $(preElement.firstChild)
    fenceName = codeBlock.attr('class')?.replace(/^lang-/, '') ? 'text'

    highlighter ?= new Highlights(registry: atom.syntax)
    highlightedHtml = highlighter.highlightSync

    preElement.remove()

  html
path = require 'path'
_ = require 'underscore-plus'
cheerio = require 'cheerio'
Highlights = require 'highlights'
{$} = require 'atom'
roaster = null # Defer until used
{scopeForFenceName} = require './extension-helper'

highlighter = null

exports.toHtml = (text='', filePath, callback) ->
  roaster ?= require 'roaster'
  options =
    sanitize: false
    breaks: atom.config.get('markdown-preview.breakOnSingleNewline')

  # Remove the <!doctype> since otherwise marked will escape it
  # https://github.com/chjj/marked/issues/354
  text = text.replace(/^\s*<!doctype(\s+.*)?>\s*/i, '')

  roaster text, options, (error, html) =>
    return callback(error) if error

    defaultLanguage = if path.extname(filePath) is '.litcoffee'
      'coffeescript'
    else 'text'

    html = sanitize(html)
    html = resolveImagePaths(html, filePath)
    html = tokenizeCodeBlocks(html,defaultLanguage)
    callback(null, html.html().trim())

exports.toText = (text, filePath, callback) ->
  exports.toHtml text, filePath, (error, html) ->
    if error
      callback(error)
    else
      string = $(document.createElement('div')).append(html)[0].innerHTML
      callback(error, string)

sanitize = (html) ->
  o = cheerio.load("<div>#{html}</div>")
  o('script').remove()
  attributesToRemove = [
    'onabort'
    'onblur'
    'onchange'
    'onclick'
    'ondbclick'
    'onerror'
    'onfocus'
    'onkeydown'
    'onkeypress'
    'onkeyup'
    'onload'
    'onmousedown'
    'onmousemove'
    'onmouseover'
    'onmouseout'
    'onmouseup'
    'onreset'
    'onresize'
    'onscroll'
    'onselect'
    'onsubmit'
    'onunload'
  ]
  o('*').removeAttr(attribute) for attribute in attributesToRemove
  o.html()

resolveImagePaths = (html, filePath) ->
  html = $(html)
  for imgElement in html.find("img")
    img = $(imgElement)
    if src = img.attr('src')
      continue if src.match /^(https?:\/\/)/
      img.attr('src', path.resolve(path.dirname(filePath), src))

  html

tokenizeCodeBlocks = (html,defaultLanguage='text') ->
  html = $(html)

  if fontFamily = atom.config.get('editor.fontFamily')
    $(html).find('code').css('font-family', fontFamily)

  for preElement in $.merge(html.filter("pre"), html.find("pre"))
    codeBlock = $(preElement.firstChild)
    fenceName = codeBlock.attr('class')?.replace(/^lang-/, '') ? defaultLanguage

    highlighter ?= new Highlights(registry: atom.syntax)
    highlightedHtml = highlighter.highlightSync
      fileContents: codeBlock.text()
      scopeName: scopeForFenceName(fenceName)

    highlightedBlock = $(highlightedHtml)
    # The `editor` class messes things up as `.editor` has absolutely positioned lines
    highlightedBlock.removeClass('editor').addClass("lang-#{fenceName}")
    highlightedBlock.insertAfter(preElement)
    preElement.remove()

  html
