blob: 731f0398bb82e76d89c988aa9cdc9991a71e730a [file] [log] [blame]
# -*- coding: utf-8 -*-
#
#--
# Copyright (C) 2009-2016 Thomas Leitner <t_leitner@gmx.at>
#
# This file is part of kramdown which is licensed under the MIT.
#++
#
#--
# Parts of this file are based on code from RubyPants:
#
# = RubyPants -- SmartyPants ported to Ruby
#
# Ported by Christian Neukirchen <mailto:chneukirchen@gmail.com>
# Copyright (C) 2004 Christian Neukirchen
#
# Incooporates ideas, comments and documentation by Chad Miller
# Copyright (C) 2004 Chad Miller
#
# Original SmartyPants by John Gruber
# Copyright (C) 2003 John Gruber
#
#
# = RubyPants -- SmartyPants ported to Ruby
#
#
# [snip]
#
# == Authors
#
# John Gruber did all of the hard work of writing this software in
# Perl for Movable Type and almost all of this useful documentation.
# Chad Miller ported it to Python to use with Pyblosxom.
#
# Christian Neukirchen provided the Ruby port, as a general-purpose
# library that follows the *Cloth API.
#
#
# == Copyright and License
#
# === SmartyPants license:
#
# Copyright (c) 2003 John Gruber
# (http://daringfireball.net)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# * Neither the name "SmartyPants" nor the names of its contributors
# may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# This software is provided by the copyright holders and contributors
# "as is" and any express or implied warranties, including, but not
# limited to, the implied warranties of merchantability and fitness
# for a particular purpose are disclaimed. In no event shall the
# copyright owner or contributors be liable for any direct, indirect,
# incidental, special, exemplary, or consequential damages (including,
# but not limited to, procurement of substitute goods or services;
# loss of use, data, or profits; or business interruption) however
# caused and on any theory of liability, whether in contract, strict
# liability, or tort (including negligence or otherwise) arising in
# any way out of the use of this software, even if advised of the
# possibility of such damage.
#
# === RubyPants license
#
# RubyPants is a derivative work of SmartyPants and smartypants.py.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# This software is provided by the copyright holders and contributors
# "as is" and any express or implied warranties, including, but not
# limited to, the implied warranties of merchantability and fitness
# for a particular purpose are disclaimed. In no event shall the
# copyright owner or contributors be liable for any direct, indirect,
# incidental, special, exemplary, or consequential damages (including,
# but not limited to, procurement of substitute goods or services;
# loss of use, data, or profits; or business interruption) however
# caused and on any theory of liability, whether in contract, strict
# liability, or tort (including negligence or otherwise) arising in
# any way out of the use of this software, even if advised of the
# possibility of such damage.
#
# == Links
#
# John Gruber:: http://daringfireball.net
# SmartyPants:: http://daringfireball.net/projects/smartypants
#
# Chad Miller:: http://web.chad.org
#
# Christian Neukirchen:: http://kronavita.de/chris
#
#++
#
module Kramdown
module Parser
class Kramdown
SQ_PUNCT = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]'
SQ_CLOSE = %![^\ \\\\\t\r\n\\[{(-]!
SQ_RULES = [
[/("|')(?=[_*]{1,2}\S)/, [:lquote1]],
[/("|')(?=#{SQ_PUNCT}(?!\.\.)\B)/, [:rquote1]],
# Special case for double sets of quotes, e.g.:
# <p>He said, "'Quoted' words in a larger quote."</p>
[/(\s?)"'(?=\w)/, [1, :ldquo, :lsquo]],
[/(\s?)'"(?=\w)/, [1, :lsquo, :ldquo]],
# Special case for decade abbreviations (the '80s):
[/(\s?)'(?=\d\ds)/, [1, :rsquo]],
# Get most opening single/double quotes:
[/(\s)('|")(?=\w)/, [1, :lquote2]],
# Single/double closing quotes:
[/(#{SQ_CLOSE})('|")/, [1, :rquote2]],
# Special case for e.g. "<i>Custer</i>'s Last Stand."
[/("|')(?=\s|s\b|$)/, [:rquote1]],
# Any remaining single quotes should be opening ones:
[/(.?)'/m, [1, :lsquo]],
[/(.?)"/m, [1, :ldquo]],
] #'"
SQ_SUBSTS = {
[:rquote1, '"'] => :rdquo,
[:rquote1, "'"] => :rsquo,
[:rquote2, '"'] => :rdquo,
[:rquote2, "'"] => :rsquo,
[:lquote1, '"'] => :ldquo,
[:lquote1, "'"] => :lsquo,
[:lquote2, '"'] => :ldquo,
[:lquote2, "'"] => :lsquo,
}
SMART_QUOTES_RE = /[^\\]?["']/
# Parse the smart quotes at current location.
def parse_smart_quotes
start_line_number = @src.current_line_number
substs = SQ_RULES.find {|reg, subst| @src.scan(reg)}[1]
substs.each do |subst|
if subst.kind_of?(Integer)
add_text(@src[subst])
else
val = SQ_SUBSTS[[subst, @src[subst.to_s[-1,1].to_i]]] || subst
@tree.children << Element.new(:smart_quote, val, nil, :location => start_line_number)
end
end
end
define_parser(:smart_quotes, SMART_QUOTES_RE, '[^\\\\]?["\']')
end
end
end