kramdown-man 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 880a3d1dd1e58aa950685bf312a66797f2d39d33c436eb9d67525289ce8abf45
4
+ data.tar.gz: e2f259869cb035f4868dab9ac584da53eafacbccc76b3323c3c32deb3133163c
5
+ SHA512:
6
+ metadata.gz: 7d2b3f3a3fa1d58fc40e980fe8a6193746c2d6b4b38ddbbe4682b7c209128df67cc30090d08deaad0c2e59d62bec6fa3226ab7670d8d13c499c431a21a2feec9
7
+ data.tar.gz: 14630b3b4ba02083266fc248b7179d409c79937f20fb81bb2feb0bf61c657b88999a8ec95e6912e1bd0bd7d0c012927d3cc58386f5cb95e4246745b698ccf0bc
@@ -0,0 +1,4 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
4
+ man/kramdown-man.1.md
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ doc/
3
+ pkg/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
@@ -0,0 +1,11 @@
1
+ ---
2
+ before_install:
3
+ - gem update --system
4
+ - gem install bundler -v "~> 2.0"
5
+ language: ruby
6
+ rvm:
7
+ - 2.5
8
+ - 2.6
9
+ - 2.7
10
+ - jruby
11
+ script: bundle exec rake spec
@@ -0,0 +1 @@
1
+ --markup markdown --markup-provider kramdown --title "kramdown-man Documentation" --protected
@@ -0,0 +1,45 @@
1
+ ### 0.1.7 / 2020-07-22
2
+
3
+ * Fixed a bug where kramdown's version of `kramdown/converter/man` was being
4
+ loaded instead of kramdown-man's version.
5
+
6
+ ### 0.1.6 / 2015-12-25
7
+
8
+ * Commented out duplicate Hash entries that were causing warnings.
9
+
10
+ ### 0.1.5 / 2013-05-19
11
+
12
+ * Translate unicode symbols into roff glyphs.
13
+ * Convert typographic symbols and smart quotes into glyphs.
14
+ * Simplify `\fB\fC` as `\fC` (Colin Watson).
15
+ * Use `\fB` for codespans (Colin Watson).
16
+ * Escape `--` as `\-\-` (Colin Watson).
17
+ * Escape `\` as `\e` (Colin Watson).
18
+ * Emit `.TP` or `.HP` if the paragraph begins with a strong element.
19
+
20
+ ### 0.1.4 / 2013-05-05
21
+
22
+ * Improve detection of tagged paragraphs.
23
+ * Support emitted a hanging paragraph (`.HP`) for command synopsis lines.
24
+ * Strip leading whitespace from each line of emitted text.
25
+
26
+ ### 0.1.3 / 2013-05-05
27
+
28
+ * Initial release:
29
+ * Converts markdown to [roff]:
30
+ * Supports codespans, emphasis and strong fonts.
31
+ * Supports normal and tagged paragraphs.
32
+ * Supports bullet lists.
33
+ * Supports multi-paragraph list items and blockquotes.
34
+ * Supports horizontal rules.
35
+ * Supports converting `[bash](man:bash(1))` links into man page references.
36
+ * Provides Rake task for converting `man/*.md` into man pages.
37
+ * Uses the pure-Ruby [Kramdown][kramdown] markdown parser.
38
+ * Supports [Ruby] 1.8.x, 1.9.x, 2.0.x, [JRuby], [Rubinius].
39
+
40
+ [kramdown]: http://kramdown.rubyforge.org/
41
+ [roff]: http://en.wikipedia.org/wiki/Roff
42
+
43
+ [Ruby]: http://www.ruby-lang.org/
44
+ [JRuby]: http://jruby.org/
45
+ [Rubinius]: http://rubini.us/
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org/'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake'
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+ gem 'rspec', '~> 3.0'
9
+ gem 'yard', '~> 0.9'
10
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013-2020 Hal Brodigan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,181 @@
1
+ # kramdown-man
2
+
3
+ * [Homepage](https://github.com/postmodern/kramdown-man#readme)
4
+ * [Issues](https://github.com/postmodern/kramdown-man/issues)
5
+ * [Documentation](http://rubydoc.info/gems/kramdown-man/frames)
6
+ * [Email](mailto:postmodern.mod3 at gmail.com)
7
+
8
+ [![Build Status](https://secure.travis-ci.org/postmodern/kramdown-man.png?branch=master)](https://travis-ci.org/postmodern/kramdown-man)
9
+
10
+ ## Description
11
+
12
+ A [Kramdown][kramdown] convert for converting Markdown files into man pages.
13
+
14
+ ## Features
15
+
16
+ * Converts markdown to [roff]:
17
+ * Supports codespans, emphasis and strong fonts.
18
+ * Supports normal, hanging and tagged paragraphs.
19
+ * Supports bullet lists.
20
+ * Supports multi-paragraph list items and blockquotes.
21
+ * Supports horizontal rules.
22
+ * Supports converting `[bash](man:bash(1))` links into man page references.
23
+ * Provides Rake task for converting `man/*.md` into man pages.
24
+ * Uses the pure-Ruby [Kramdown][kramdown] markdown parser.
25
+ * Supports [Ruby] 2.0 and [JRuby].
26
+
27
+ ## Synopsis
28
+
29
+ Render a man page from markdown:
30
+
31
+ $ kramdown-man <man/myprog.1.md >man/myprog.1
32
+
33
+ ## Examples
34
+
35
+ Render a man page from a markdown file:
36
+
37
+ require 'kramdown/man'
38
+
39
+ doc = Kramdown::Document.new(File.read('man/kramdown-man.1.md'))
40
+ File.write('man/kramdown-man.1',doc.to_man)
41
+
42
+ system 'man', 'man/kramdown-man.1'
43
+
44
+ Define a `man` and file tasks which render all `*.md` files within the
45
+ `man/` directory:
46
+
47
+ require 'kramdown/man/task'
48
+ Kramdown::Man::Task.new
49
+
50
+ ## Syntax
51
+
52
+ ### Formatting
53
+
54
+ `code`
55
+
56
+ `code`
57
+
58
+ *emphasis*
59
+
60
+ *emphasis*
61
+
62
+ **strong**
63
+
64
+ **strong**
65
+
66
+ ### Paragraphs
67
+
68
+ Normal paragraph.
69
+
70
+ Normal paragraph.
71
+
72
+ `command` [`--foo`] *FILE*
73
+
74
+ `command` [`--foo`] *FILE*
75
+
76
+ `--tagged`
77
+ Text here.
78
+
79
+ `--tagged`
80
+ Text here.
81
+
82
+ ### Links
83
+
84
+ [website](http://example.com/)
85
+
86
+ [website](http://example.com/)
87
+
88
+ [bash](man:bash(1))
89
+
90
+ [bash](man:bash(1))
91
+
92
+ Email <bob@example.com>
93
+
94
+ Email <bob@example.com>
95
+
96
+ ### Lists
97
+
98
+ * one
99
+ * two
100
+ * three
101
+
102
+ extra paragraph
103
+
104
+
105
+ * one
106
+ * two
107
+ * three
108
+
109
+ extra paragraph
110
+
111
+ 1. one
112
+ 2. two
113
+ 3. three
114
+
115
+ extra paragraph
116
+
117
+ 1. one
118
+ 2. two
119
+ 3. three
120
+
121
+ extra paragraph
122
+
123
+ ### Horizontal Rule
124
+
125
+ -------------------------------------------------------------------------------
126
+
127
+ -------------------------------------------------------------------------------
128
+
129
+ ### Blockquotes
130
+
131
+ > Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
132
+ >
133
+ > --Antoine de Saint-Exupéry
134
+
135
+ > Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
136
+ >
137
+ > --Antoine de Saint-Exupéry
138
+
139
+ ### Code Blocks
140
+
141
+ #include <stdio.h>
142
+
143
+ int main()
144
+ {
145
+ printf("hello world\n");
146
+ return 0;
147
+ }
148
+
149
+ #include <stdio.h>
150
+
151
+ int main()
152
+ {
153
+ printf("hello world\n");
154
+ return 0;
155
+ }
156
+
157
+ ## Requirements
158
+
159
+ * [kramdown] ~> 1.0
160
+
161
+ ## Install
162
+
163
+ $ gem install kramdown-man
164
+
165
+ ## Alternatives
166
+
167
+ * [Redcarpet::Render::ManPage](http://rubydoc.info/gems/redcarpet/Redcarpet/Render/ManPage)
168
+ * [ronn](https://github.com/rtomayko/ronn#readme)
169
+ * [md2man](https://github.com/sunaku/md2man#readme)
170
+
171
+ ## Copyright
172
+
173
+ Copyright (c) 2013-2020 Hal Brodigan
174
+
175
+ See {file:LICENSE.txt} for details.
176
+
177
+ [kramdown]: http://kramdown.gettalong.org/
178
+ [roff]: http://en.wikipedia.org/wiki/Roff
179
+
180
+ [Ruby]: http://www.ruby-lang.org/
181
+ [JRuby]: http://jruby.org/
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError => error
6
+ abort error.message
7
+ end
8
+
9
+ require 'rake'
10
+ require 'rubygems/tasks'
11
+ Gem::Tasks.new
12
+
13
+ require 'rspec/core/rake_task'
14
+ RSpec::Core::RakeTask.new
15
+ task :test => :spec
16
+ task :default => :spec
17
+
18
+ require 'yard'
19
+ YARD::Rake::YardocTask.new
20
+ task :doc => :yard
21
+
22
+ require 'kramdown/man/task'
23
+ Kramdown::Man::Task.new
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_dir = File.expand_path('../lib',File.dirname(__FILE__))
4
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
5
+
6
+ require 'kramdown'
7
+ require 'kramdown/man'
8
+
9
+ case ARGV[0]
10
+ when '-h', '--help'
11
+ warn "usage: #{File.dirname($0)} <INPUT.md >OUTPUT"
12
+ exit
13
+ end
14
+
15
+ doc = Kramdown::Document.new(ARGF.read)
16
+ puts doc.to_man
@@ -0,0 +1,13 @@
1
+ name: kramdown-man
2
+ summary: Converts markdown to man pages
3
+ description: A Kramdown converter for converting Markdown files into man pages.
4
+ license: MIT
5
+ authors: Postmodern
6
+ email: postmodern.mod3@gmail.com
7
+ homepage: https://github.com/postmodern/kramdown-man#readme
8
+
9
+ dependencies:
10
+ kramdown: ~> 1.0
11
+
12
+ development_dependencies:
13
+ bundler: ~> 2.0
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'kramdown/man/version'
14
+ Kramdown::Man::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+
24
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
25
+
26
+ gem.files = `git ls-files`.split($/)
27
+ gem.files = glob[gemspec['files']] if gemspec['files']
28
+
29
+ gem.executables = gemspec.fetch('executables') do
30
+ glob['bin/*'].map { |path| File.basename(path) }
31
+ end
32
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
33
+
34
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
35
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
36
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
37
+
38
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
39
+ %w[ext lib].select { |dir| File.directory?(dir) }
40
+ })
41
+
42
+ gem.requirements = gemspec['requirements']
43
+ gem.required_ruby_version = gemspec['required_ruby_version']
44
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
45
+ gem.post_install_message = gemspec['post_install_message']
46
+
47
+ split = lambda { |string| string.split(/,\s*/) }
48
+
49
+ if gemspec['dependencies']
50
+ gemspec['dependencies'].each do |name,versions|
51
+ gem.add_dependency(name,split[versions])
52
+ end
53
+ end
54
+
55
+ if gemspec['development_dependencies']
56
+ gemspec['development_dependencies'].each do |name,versions|
57
+ gem.add_development_dependency(name,split[versions])
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,811 @@
1
+ # encoding: utf-8
2
+ require_relative '../man/version'
3
+
4
+ require 'kramdown/converter/base'
5
+
6
+ module Kramdown
7
+ module Converter
8
+ #
9
+ # Converts markdown into a roff man-page.
10
+ #
11
+ class Man < ::Kramdown::Converter::Base
12
+
13
+ # Comment header
14
+ HEADER = [
15
+ ".\\\" Generated by kramdown-man #{::Kramdown::Man::VERSION}",
16
+ ".\\\" https://github.com/postmodern/kramdown-man#readme"
17
+ ].join("\n")
18
+
19
+ # Typographic Symbols and their UTF8 chars
20
+ TYPOGRAPHIC_SYMS = {
21
+ :ndash => '\-\-',
22
+ :mdash => '\[em]',
23
+ :hellip => '\.\.\.',
24
+ :laquo => '\[Fo]',
25
+ :raquo => '\[Fc]',
26
+ :laquo_space => '\[Fo]',
27
+ :raquo_space => '\[Fc]'
28
+ }
29
+
30
+ # Smart Quotes and their UTF8 chars
31
+ SMART_QUOTES = {
32
+ :lsquo => '\[oq]',
33
+ :rsquo => '\[cq]',
34
+ :ldquo => '\[lq]',
35
+ :rdquo => '\[rq]'
36
+ }
37
+
38
+ GLYPHS = {
39
+ 'Ð' => '\[-D]',
40
+ 'ð' => '\[Sd]',
41
+ 'Þ' => '\[TP]',
42
+ 'þ' => '\[Tp]',
43
+ 'ß' => '\[ss]',
44
+ # Ligatures and Other Latin Glyphs
45
+ 'ff' => '\[ff]',
46
+ 'fi' => '\[fi]',
47
+ 'fl' => '\[fl]',
48
+ 'ffi' => '\[Fi]',
49
+ 'ffl' => '\[Fl]',
50
+ 'Ł' => '\[/L]',
51
+ 'ł' => '\[/l]',
52
+ 'Ø' => '\[/O]',
53
+ 'ø' => '\[/o]',
54
+ 'Æ' => '\[AE]',
55
+ 'æ' => '\[ae]',
56
+ 'Œ' => '\[OE]',
57
+ 'œ' => '\[oe]',
58
+ 'IJ' => '\[IJ]',
59
+ 'ij' => '\[ij]',
60
+ 'ı' => '\[.i]',
61
+ 'ȷ' => '\[.j]',
62
+ # Accented Characters
63
+ 'Á' => '\[\'A]',
64
+ 'Ć' => '\[\'C]',
65
+ 'É' => '\[\'E]',
66
+ 'Í' => '\[\'I]',
67
+ 'Ó' => '\[\'O]',
68
+ 'Ú' => '\[\'U]',
69
+ 'Ý' => '\[\'Y]',
70
+ 'á' => '\[\'a]',
71
+ 'ć' => '\[\'c]',
72
+ 'é' => '\[\'e]',
73
+ 'í' => '\[\'i]',
74
+ 'ó' => '\[\'o]',
75
+ 'ú' => '\[\'u]',
76
+ 'ý' => '\[\'y]',
77
+ 'Ä' => '\[:A]',
78
+ 'Ë' => '\[:E]',
79
+ 'Ï' => '\[:I]',
80
+ 'Ö' => '\[:O]',
81
+ 'Ü' => '\[:U]',
82
+ 'Ÿ' => '\[:Y]',
83
+ 'ä' => '\[:a]',
84
+ 'ë' => '\[:e]',
85
+ 'ï' => '\[:i]',
86
+ 'ö' => '\[:o]',
87
+ 'ü' => '\[:u]',
88
+ 'ÿ' => '\[:y]',
89
+ 'Â' => '\[^A]',
90
+ 'Ê' => '\[^E]',
91
+ 'Î' => '\[^I]',
92
+ 'Ô' => '\[^O]',
93
+ 'Û' => '\[^U]',
94
+ 'â' => '\[^a]',
95
+ 'ê' => '\[^e]',
96
+ 'î' => '\[^i]',
97
+ 'ô' => '\[^o]',
98
+ 'û' => '\[^u]',
99
+ 'À' => '\[`A]',
100
+ 'È' => '\[`E]',
101
+ 'Ì' => '\[`I]',
102
+ 'Ò' => '\[`O]',
103
+ 'Ù' => '\[`U]',
104
+ 'à' => '\[`a]',
105
+ 'è' => '\[`e]',
106
+ 'ì' => '\[`i]',
107
+ 'ò' => '\[`o]',
108
+ 'ù' => '\[`u]',
109
+ 'Ã' => '\[~A]',
110
+ 'Ñ' => '\[~N]',
111
+ 'Õ' => '\[~O]',
112
+ 'ã' => '\[~a]',
113
+ 'ñ' => '\[~n]',
114
+ 'õ' => '\[~o]',
115
+ 'Š' => '\[vS]',
116
+ 'š' => '\[vs]',
117
+ 'Ž' => '\[vZ]',
118
+ 'ž' => '\[vz]',
119
+ 'Ç' => '\[,C]',
120
+ 'ç' => '\[,c]',
121
+ 'Å' => '\[oA]',
122
+ 'å' => '\[oa]',
123
+ # Accents
124
+ '˝' => '\[a"]',
125
+ '¯' => '\[a-]',
126
+ '˙' => '\[a.]',
127
+ # '^' => '\[a^]',
128
+ '´' => "\\´",
129
+ '`' => '\`',
130
+ '˘' => '\[ab]',
131
+ '¸' => '\[ac]',
132
+ '¨' => '\[ad]',
133
+ 'ˇ' => '\[ah]',
134
+ '˚' => '\[ao]',
135
+ # '~' => '\(ti',
136
+ '˛' => '\[ho]',
137
+ '^' => '\(ha',
138
+ '~' => '\[ti]',
139
+ # Quotes
140
+ '„' => '\[Bq]',
141
+ '‚' => '\[bq]',
142
+ '“' => '\[lq]',
143
+ '”' => '\[rq]',
144
+ '‘' => '\[oq]',
145
+ '’' => '\[cq]',
146
+ "'" => '\(aq',
147
+ '"' => '\[dq]',
148
+ '«' => '\[Fo]',
149
+ '»' => '\[Fc]',
150
+ '‹' => '\[fo]',
151
+ '›' => '\[fc]',
152
+ # Punctuation
153
+ '.' => '\.',
154
+ '¡' => '\[r!]',
155
+ '¿' => '\[r?]',
156
+ '—' => '\[em]',
157
+ '–' => '\[en]',
158
+ '‐' => '\[hy]',
159
+ # Brackets
160
+ '[' => '\[lB]',
161
+ ']' => '\[rB]',
162
+ '{' => '\[lC]',
163
+ '}' => '\[rC]',
164
+ '⟨' => '\[la]',
165
+ '⟩' => '\[ra]',
166
+ # '⎪' => '\[bv]',
167
+ # '⎪' => '\[braceex]',
168
+ '⎡' => '\[bracketlefttp]',
169
+ '⎣' => '\[bracketleftbt]',
170
+ '⎢' => '\[bracketleftex]',
171
+ '⎤' => '\[bracketrighttp]',
172
+ '⎦' => '\[bracketrightbt]',
173
+ '⎥' => '\[bracketrightex]',
174
+ '╭' => '\[lt]',
175
+ '⎧' => '\[bracelefttp]',
176
+ '┥' => '\[lk]',
177
+ '⎨' => '\[braceleftmid]',
178
+ '╰' => '\[lb]',
179
+ '⎩' => '\[braceleftbt]',
180
+ # '⎪' => '\[braceleftex]',
181
+ '╮' => '\[rt]',
182
+ '⎫' => '\[bracerighttp]',
183
+ '┝' => '\[rk]',
184
+ '⎬' => '\[bracerightmid]',
185
+ '╯' => '\[rb]',
186
+ '⎭' => '\[bracerightbt]',
187
+ '⎪' => '\[bracerightex]',
188
+ '⎛' => '\[parenlefttp]',
189
+ '⎝' => '\[parenleftbt]',
190
+ '⎜' => '\[parenleftex]',
191
+ '⎞' => '\[parenrighttp]',
192
+ '⎠' => '\[parenrightbt]',
193
+ '⎟' => '\[parenrightex]',
194
+ # Arrows
195
+ '←' => '\[<-]',
196
+ '→' => '\[->]',
197
+ '↔' => '\[<>]',
198
+ '↓' => '\[da]',
199
+ '↑' => '\[ua]',
200
+ '↕' => '\[va]',
201
+ '⇐' => '\[lA]',
202
+ '⇒' => '\[rA]',
203
+ '⇔' => '\[hA]',
204
+ '⇓' => '\[dA]',
205
+ '⇑' => '\[uA]',
206
+ '⇕' => '\[vA]',
207
+ '⎯' => '\[an]',
208
+ # Lines
209
+ # '|' => '\[ba]',
210
+ '│' => '\[br]',
211
+ # '_' => '\[ul]',
212
+ '‾' => '\[rn]',
213
+ '_' => '\[ru]',
214
+ '¦' => '\[bb]',
215
+ '/' => '\[sl]',
216
+ '\\' => '\e',
217
+ # Text markers
218
+ '○' => '\[ci]',
219
+ # '·' => '\[bu]',
220
+ '‡' => '\[dd]',
221
+ '†' => '\[dg]',
222
+ '◊' => '\[lz]',
223
+ '□' => '\[sq]',
224
+ '¶' => '\[ps]',
225
+ '§' => '\[sc]',
226
+ '☜' => '\[lh]',
227
+ '☞' => '\[rh]',
228
+ '@' => '\[at]',
229
+ '#' => '\[sh]',
230
+ '↵' => '\[CR]',
231
+ '✓' => '\[OK]',
232
+ # Legal Symbols
233
+ '©' => '\[co]',
234
+ '®' => '\[rg]',
235
+ '™' => '\[tm]',
236
+ # Currency symbols
237
+ '$' => '\[Do]',
238
+ '¢' => '\[ct]',
239
+ # '€' => '\[eu]',
240
+ '€' => '\[Eu]',
241
+ '¥' => '\[Ye]',
242
+ '£' => '\[Po]',
243
+ '¤' => '\[Cs]',
244
+ 'ƒ' => '\[Fn]',
245
+ # Units
246
+ '°' => '\[de]',
247
+ '‰' => '\[%0]',
248
+ '′' => '\[fm]',
249
+ '″' => '\[sd]',
250
+ 'µ' => '\[mc]',
251
+ 'ª' => '\[Of]',
252
+ 'º' => '\[Om]',
253
+ # Logical Symbols
254
+ '∧' => '\[AN]',
255
+ '∨' => '\[OR]',
256
+ # '¬' => '\[no]',
257
+ '¬' => '\[tno]',
258
+ '∃' => '\[te]',
259
+ '∀' => '\[fa]',
260
+ '∋' => '\[st]',
261
+ # '∴' => '\[3d]',
262
+ '∴' => '\[tf]',
263
+ '|' => '\[or]',
264
+ # Mathematical Symbols
265
+ '½' => '\[12]',
266
+ '¼' => '\[14]',
267
+ '¾' => '\[34]',
268
+ '⅛' => '\[18]',
269
+ '⅜' => '\[38]',
270
+ '⅝' => '\[58]',
271
+ '⅞' => '\[78]',
272
+ '¹' => '\[S1]',
273
+ '²' => '\[S2]',
274
+ '³' => '\[S3]',
275
+ '+' => '\[pl]',
276
+ '-' => '\-',
277
+ '−' => '\[mi]',
278
+ '∓' => '\[-+]',
279
+ # '±' => '\[+-]',
280
+ '±' => '\[t+-]',
281
+ '·' => '\[pc]',
282
+ '⋅' => '\[md]',
283
+ # '×' => '\[mu]',
284
+ '×' => '\[tmu]',
285
+ '⊗' => '\[c*]',
286
+ '⊕' => '\[c+]',
287
+ # '÷' => '\[di]',
288
+ '÷' => '\[tdi]',
289
+ '⁄' => '\[f/]',
290
+ '∗' => '\[**]',
291
+ '≤' => '\[<=]',
292
+ '≥' => '\[>=]',
293
+ '≪' => '\[<<]',
294
+ '≫' => '\[>>]',
295
+ '=' => '\[eq]',
296
+ '≠' => '\[!=]',
297
+ '≡' => '\[==]',
298
+ '≢' => '\[ne]',
299
+ '≅' => '\[=~]',
300
+ '≃' => '\[|=]',
301
+ '∼' => '\[ap]',
302
+ # '≈' => '\[~~]',
303
+ '≈' => '\[~=]',
304
+ '∝' => '\[pt]',
305
+ '∅' => '\[es]',
306
+ '∈' => '\[mo]',
307
+ '∉' => '\[nm]',
308
+ '⊂' => '\[sb]',
309
+ '⊄' => '\[nb]',
310
+ '⊃' => '\[sp]',
311
+ '⊅' => '\[nc]',
312
+ '⊆' => '\[ib]',
313
+ '⊇' => '\[ip]',
314
+ '∩' => '\[ca]',
315
+ '∪' => '\[cu]',
316
+ '∠' => '\[/_]',
317
+ '⊥' => '\[pp]',
318
+ # '∫' => '\[is]',
319
+ '∫' => '\[integral]',
320
+ '∑' => '\[sum]',
321
+ '∏' => '\[product]',
322
+ '∐' => '\[coproduct]',
323
+ '∇' => '\[gr]',
324
+ # '√' => '\[sr]',
325
+ '√' => '\[sqrt]',
326
+ '⌈' => '\[lc]',
327
+ '⌉' => '\[rc]',
328
+ '⌊' => '\[lf]',
329
+ '⌋' => '\[rf]',
330
+ '∞' => '\[if]',
331
+ 'ℵ' => '\[Ah]',
332
+ 'ℑ' => '\[Im]',
333
+ 'ℜ' => '\[Re]',
334
+ '℘' => '\[wp]',
335
+ '∂' => '\[pd]',
336
+ # 'ℏ' => '\[-h]',
337
+ 'ℏ' => '\[hbar]',
338
+ # Greek glyphs
339
+ 'Α' => '\[*A]',
340
+ 'Β' => '\[*B]',
341
+ 'Γ' => '\[*G]',
342
+ 'Δ' => '\[*D]',
343
+ 'Ε' => '\[*E]',
344
+ 'Ζ' => '\[*Z]',
345
+ 'Η' => '\[*Y]',
346
+ 'Θ' => '\[*H]',
347
+ 'Ι' => '\[*I]',
348
+ 'Κ' => '\[*K]',
349
+ 'Λ' => '\[*L]',
350
+ 'Μ' => '\[*M]',
351
+ 'Ν' => '\[*N]',
352
+ 'Ξ' => '\[*C]',
353
+ 'Ο' => '\[*O]',
354
+ 'Π' => '\[*P]',
355
+ 'Ρ' => '\[*R]',
356
+ 'Σ' => '\[*S]',
357
+ 'Τ' => '\[*T]',
358
+ 'Υ' => '\[*U]',
359
+ 'Φ' => '\[*F]',
360
+ 'Χ' => '\[*X]',
361
+ 'Ψ' => '\[*Q]',
362
+ 'Ω' => '\[*W]',
363
+ 'α' => '\[*a]',
364
+ 'β' => '\[*b]',
365
+ 'γ' => '\[*g]',
366
+ 'δ' => '\[*d]',
367
+ 'ε' => '\[*e]',
368
+ 'ζ' => '\[*z]',
369
+ 'η' => '\[*y]',
370
+ 'θ' => '\[*h]',
371
+ 'ι' => '\[*i]',
372
+ 'κ' => '\[*k]',
373
+ 'λ' => '\[*l]',
374
+ 'μ' => '\[*m]',
375
+ 'ν' => '\[*n]',
376
+ 'ξ' => '\[*c]',
377
+ 'ο' => '\[*o]',
378
+ 'π' => '\[*p]',
379
+ 'ρ' => '\[*r]',
380
+ 'ς' => '\[ts]',
381
+ 'σ' => '\[*s]',
382
+ 'τ' => '\[*t]',
383
+ 'υ' => '\[*u]',
384
+ 'ϕ' => '\[*f]',
385
+ 'χ' => '\[*x]',
386
+ 'ψ' => '\[*q]',
387
+ 'ω' => '\[*w]',
388
+ 'ϑ' => '\[+h]',
389
+ 'φ' => '\[+f]',
390
+ 'ϖ' => '\[+p]',
391
+ 'ϵ' => '\[+e]',
392
+ # Card symbols
393
+ '♣' => '\[CL]',
394
+ '♠' => '\[SP]',
395
+ '♥' => '\[HE]',
396
+ '♡' => '\[u2661]',
397
+ '♦' => '\[DI]',
398
+ '♢' => '\[u2662]'
399
+ }
400
+
401
+ # Regular expression to convert unicode characters into glyphs
402
+ GLYPH_REGEXP = Regexp.union(GLYPHS.keys)
403
+
404
+ #
405
+ # Initializes the converter.
406
+ #
407
+ # @param [Kramdown::Element] root
408
+ # The root of the markdown document.
409
+ #
410
+ # @param [Hash] options
411
+ # Markdown options.
412
+ #
413
+ def initialize(root,options)
414
+ super(root,options)
415
+
416
+ @ol_index = 0
417
+ end
418
+
419
+ #
420
+ # Converts the markdown document into a man-page.
421
+ #
422
+ # @param [Kramdown::Element] root
423
+ # The root of a markdown document.
424
+ #
425
+ # @return [String]
426
+ # The roff output.
427
+ #
428
+ def convert(root)
429
+ "#{HEADER}\n#{convert_root(root)}"
430
+ end
431
+
432
+ #
433
+ # Converts the root of a markdown document.
434
+ #
435
+ # @param [Kramdown::Element] root
436
+ # The root of the markdown document.
437
+ #
438
+ # @return [String]
439
+ # The roff output.
440
+ #
441
+ def convert_root(root)
442
+ root.children.map { |child|
443
+ convert_element(child)
444
+ }.compact.join("\n")
445
+ end
446
+
447
+ #
448
+ # Converts an element.
449
+ #
450
+ # @param [Kramdown::Element] element
451
+ # An arbitrary element within the markdown document.
452
+ #
453
+ # @return [String]
454
+ # The roff output.
455
+ #
456
+ def convert_element(element)
457
+ method = "convert_#{element.type}"
458
+ send(method,element) if respond_to?(method)
459
+ end
460
+
461
+ #
462
+ # Converts a `kd:blank` element.
463
+ #
464
+ # @param [Kramdown::Element] blank
465
+ # A `kd:blank` element.
466
+ #
467
+ # @return [String]
468
+ # The roff output.
469
+ #
470
+ def convert_blank(blank)
471
+ '.LP'
472
+ end
473
+
474
+ #
475
+ # Converts a `kd:text` element.
476
+ #
477
+ # @param [Kramdown::Element] text
478
+ # A `kd:text` element.
479
+ #
480
+ # @return [String]
481
+ # The roff output.
482
+ #
483
+ def convert_text(text)
484
+ escape(text.value.gsub(/^( +|\t)/,''))
485
+ end
486
+
487
+ #
488
+ # Converts a `kd:typographic_sym` element.
489
+ #
490
+ # @param [Kramdown::Element] sym
491
+ # A `kd:typographic_sym` element.
492
+ #
493
+ # @return [String]
494
+ # The roff output.
495
+ #
496
+ def convert_typographic_sym(sym)
497
+ TYPOGRAPHIC_SYMS[sym.value]
498
+ end
499
+
500
+ #
501
+ # Converts a `kd:smart_quote` element.
502
+ #
503
+ # @param [Kramdown::Element] quote
504
+ # A `kd:smart_quote` element.
505
+ #
506
+ # @return [String]
507
+ # The roff output.
508
+ #
509
+ def convert_smart_quote(quote)
510
+ SMART_QUOTES[quote.value]
511
+ end
512
+
513
+ #
514
+ # Converts a `kd:header` element.
515
+ #
516
+ # @param [Kramdown::Element] header
517
+ # A `kd:header` element.
518
+ #
519
+ # @return [String]
520
+ # The roff output.
521
+ #
522
+ def convert_header(header)
523
+ text = header.options[:raw_text]
524
+
525
+ case header.options[:level]
526
+ when 1 then ".TH #{text}"
527
+ when 2 then ".SH #{text}"
528
+ else ".SS #{text}"
529
+ end
530
+ end
531
+
532
+ #
533
+ # Converts a `kd:hr` element.
534
+ #
535
+ # @param [Kramdown::Element] hr
536
+ # A `kd:hr` element.
537
+ #
538
+ # @return [String]
539
+ # The roff output.
540
+ #
541
+ def convert_hr(hr)
542
+ ".ti 0\n\\l'\\n(.lu'"
543
+ end
544
+
545
+ #
546
+ # Converts a `kd:ul` element.
547
+ #
548
+ # @param [Kramdown::Element] ul
549
+ # A `kd:ul` element.
550
+ #
551
+ # @return [String]
552
+ # The roff output.
553
+ #
554
+ def convert_ul(ul)
555
+ content = ul.children.map { |li| convert_ul_li(li) }.join("\n")
556
+
557
+ return ".RS\n#{content}\n.RE"
558
+ end
559
+
560
+ #
561
+ # Converts a `kd:li` element within a `kd:ul` list.
562
+ #
563
+ # @param [Kramdown::Element] li
564
+ # A `kd:li` element.
565
+ #
566
+ # @return [String]
567
+ # The roff output.
568
+ #
569
+ def convert_ul_li(li)
570
+ li.children.each_with_index.map { |child,index|
571
+ if child.type == :p
572
+ content = convert_children(child.children)
573
+
574
+ if index == 0 then ".IP \\(bu 2\n#{content}"
575
+ else ".IP \\( 2\n#{content}"
576
+ end
577
+ end
578
+ }.compact.join("\n")
579
+ end
580
+
581
+ #
582
+ # Converts a `kd:ol` element.
583
+ #
584
+ # @param [Kramdown::Element] ol
585
+ # A `kd:ol` element.
586
+ #
587
+ # @return [String]
588
+ # The roff output.
589
+ #
590
+ def convert_ol(ol)
591
+ @ol_index += 1
592
+
593
+ header = ".nr step#{@ol_index} 0 1"
594
+ content = ol.children.map { |li| convert_ol_li(li) }.join("\n")
595
+
596
+ return "#{header}\n.RS\n#{content}\n.RE"
597
+ end
598
+
599
+ #
600
+ # Converts a `kd:li` element within a `kd:ol` list.
601
+ #
602
+ # @param [Kramdown::Element] li
603
+ # A `kd:li` element.
604
+ #
605
+ # @return [String]
606
+ # The roff output.
607
+ #
608
+ def convert_ol_li(li)
609
+ li.children.each_with_index.map { |child,index|
610
+ if child.type == :p
611
+ content = convert_children(child.children)
612
+
613
+ if index == 0 then ".IP \\n+[step#{@ol_index}]\n#{content}"
614
+ else ".IP \\n\n#{content}"
615
+ end
616
+ end
617
+ }.compact.join("\n")
618
+ end
619
+
620
+ #
621
+ # Converts a `kd:abbreviation` element.
622
+ #
623
+ # @param [Kramdown::Element] abbr
624
+ # A `kd:abbreviation` element.
625
+ #
626
+ # @return [String]
627
+ # The roff output.
628
+ #
629
+ def convert_abbreviation(abbr)
630
+ escape(abbr.value)
631
+ end
632
+
633
+ #
634
+ # Converts a `kd:blockquote` element.
635
+ #
636
+ # @param [Kramdown::Element] blockquote
637
+ # A `kd:blockquote` element.
638
+ #
639
+ # @return [String]
640
+ # The roff output.
641
+ #
642
+ def convert_blockquote(blockquote)
643
+ content = blockquote.children.map { |child|
644
+ case child.type
645
+ when :p then convert_children(child.children)
646
+ else convert_element(child)
647
+ end
648
+ }.join("\n")
649
+
650
+ return ".PP\n.RS\n#{content}\n.RE"
651
+ end
652
+
653
+ #
654
+ # Converts a `kd:codeblock` element.
655
+ #
656
+ # @param [Kramdown::Element] codeblock
657
+ # A `kd:codeblock` element.
658
+ #
659
+ # @return [String]
660
+ # The roff output.
661
+ #
662
+ def convert_codeblock(codeblock)
663
+ ".nf\n#{escape(codeblock.value).rstrip}\n.fi"
664
+ end
665
+
666
+ #
667
+ # Converts a `kd:comment` element.
668
+ #
669
+ # @param [Kramdown::Element] comment
670
+ # A `kd:comment` element.
671
+ #
672
+ # @return [String]
673
+ # The roff output.
674
+ #
675
+ def convert_comment(comment)
676
+ comment.value.lines.map { |line|
677
+ ".\\\" #{line}"
678
+ }.join("\n")
679
+ end
680
+
681
+ #
682
+ # Converts a `kd:p` element.
683
+ #
684
+ # @param [Kramdown::Element] p
685
+ # A `kd:p` element.
686
+ #
687
+ # @return [String]
688
+ # The roff output.
689
+ #
690
+ def convert_p(p)
691
+ children = p.children
692
+
693
+ if ((children.length >= 2) && (children.first.type == :codespan ||
694
+ children.first.type == :em ||
695
+ children.first.type == :strong))
696
+ newline = children.find_index { |el|
697
+ el.type == :text && el.value.start_with?("\n")
698
+ }
699
+
700
+ if newline
701
+ first_line = convert_children(children[0...newline])
702
+ rest = convert_children(children[newline..-1]).strip
703
+
704
+ ".TP\n#{first_line}\n#{rest}"
705
+ else
706
+ ".HP\n#{convert_children(children)}"
707
+ end
708
+ else
709
+ ".PP\n#{convert_children(children)}"
710
+ end
711
+ end
712
+
713
+ #
714
+ # Converts a `kd:em` element.
715
+ #
716
+ # @param [Kramdown::Element] em
717
+ # A `kd:em` element.
718
+ #
719
+ # @return [String]
720
+ # The roff output.
721
+ #
722
+ def convert_em(em)
723
+ "\\fI#{convert_children(em.children)}\\fP"
724
+ end
725
+
726
+ #
727
+ # Converts a `kd:strong` element.
728
+ #
729
+ # @param [Kramdown::Element] strong
730
+ # A `kd:strong` element.
731
+ #
732
+ # @return [String]
733
+ # The roff output.
734
+ #
735
+ def convert_strong(strong)
736
+ "\\fB#{convert_children(strong.children)}\\fP"
737
+ end
738
+
739
+ #
740
+ # Converts a `kd:codespan` element.
741
+ #
742
+ # @param [Kramdown::Element] codespan
743
+ # A `kd:codespan` element.
744
+ #
745
+ # @return [String]
746
+ # The roff output.
747
+ #
748
+ def convert_codespan(codespan)
749
+ "\\fB#{codespan.value}\\fR"
750
+ end
751
+
752
+ #
753
+ # Converts a `kd:a` element.
754
+ #
755
+ # @param [Kramdown::Element] a
756
+ # A `kd:a` element.
757
+ #
758
+ # @return [String]
759
+ # The roff output.
760
+ #
761
+ def convert_a(a)
762
+ href = escape(a.attr['href'])
763
+ text = convert_children(a.children)
764
+
765
+ case href
766
+ when /^mailto:/
767
+ email = href[7..-1]
768
+
769
+ unless text == email then "#{text}\n.MT #{email}\n.ME"
770
+ else "\n.MT #{email}\n.ME"
771
+ end
772
+ when /^man:/
773
+ match = href.match(/man:([A-Za-z0-9_-]+)(?:\((\d[a-z]?)\))?/)
774
+
775
+ if match[2] then "\n.BR #{match[1]} (#{match[2]})"
776
+ else "\n.BR #{match[1]}"
777
+ end
778
+ else
779
+ "#{text}\n.UR #{href}\n.UE"
780
+ end
781
+ end
782
+
783
+ #
784
+ # Converts the children of an element.
785
+ #
786
+ # @param [Array<Kramdown::Element>] children
787
+ # The children of an element.
788
+ #
789
+ # @return [String]
790
+ # The roff output.
791
+ #
792
+ def convert_children(children)
793
+ children.map { |child| convert_element(child) }.join.strip
794
+ end
795
+
796
+ #
797
+ # Escapes text for roff.
798
+ #
799
+ # @param [String] text
800
+ # The unescaped text.
801
+ #
802
+ # @return [String]
803
+ # The escaped text.
804
+ #
805
+ def escape(text)
806
+ text.gsub(GLYPH_REGEXP) { |char| GLYPHS[char] }
807
+ end
808
+
809
+ end
810
+ end
811
+ end