kramdown-ansi 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGES.md +5 -0
- data/Gemfile +5 -0
- data/LICENSE +19 -0
- data/README.md +108 -0
- data/Rakefile +40 -0
- data/bin/git-md +48 -0
- data/bin/md +14 -0
- data/kramdown-ansi.gemspec +35 -0
- data/lib/kramdown/ansi/pager.rb +37 -0
- data/lib/kramdown/ansi/width.rb +61 -0
- data/lib/kramdown/ansi.rb +224 -0
- data/lib/kramdown/version.rb +8 -0
- data/spec/assets/README.ansi +415 -0
- data/spec/assets/kitten.jpg +0 -0
- data/spec/kramdown/ansi/pager_spec.rb +60 -0
- data/spec/kramdown/ansi/width_spec.rb +82 -0
- data/spec/kramdown/ansi_spec.rb +16 -0
- data/spec/spec_helper.rb +16 -0
- metadata +189 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7249444853b46b626b782ea417e62827627ba0d1da6f54cc8801f8459839f775
|
4
|
+
data.tar.gz: 75884f2bf3c0e3b06e71c28f9f4775315745b76ab9cf0d73ec57e49829cd7f6f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 10c992685654c67686a24e4a323ab04619d8957faa61a119569e16dbdb82119278b2756b3cf8d3ba921f7343997d12ddb6632fc8fc3379b00be844862e730d4a
|
7
|
+
data.tar.gz: d3342cdf38698f5f59035b0a06dff0341a3fc66127d4de3fd7de46d25d55831175a087f6375fb2052f5e10ff1aabb026026361ab3e73f9a87329b19f3be2d05d
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright Florian Frank
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the “Software”), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# Kramdown ANSI - Output markdown with ANSI
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
Kramdown::ANSI: A library for rendering Markdown(ish) documents with beautiful
|
6
|
+
ANSI escape sequences in the terminal.
|
7
|
+
|
8
|
+
## Installation (gem & bundler)
|
9
|
+
|
10
|
+
To install Kramdown::ANSI, you can use the following methods:
|
11
|
+
|
12
|
+
1. Type
|
13
|
+
|
14
|
+
```shell
|
15
|
+
gem install kramdown-ansi
|
16
|
+
```
|
17
|
+
|
18
|
+
in your terminal.
|
19
|
+
|
20
|
+
1. Or add the line
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
gem 'kramdown-ansi'
|
24
|
+
```
|
25
|
+
|
26
|
+
to your Gemfile and run `bundle install` in your terminal.
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
In your own software the library can be used as shown in this example:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
require 'kramdown/ansi'
|
34
|
+
|
35
|
+
puts Kramdown::ANSI.parse(markdown)
|
36
|
+
```
|
37
|
+
|
38
|
+
## Executables
|
39
|
+
|
40
|
+
| Method | Description |
|
41
|
+
| :----- | :---------- |
|
42
|
+
| `md` executable | Outputs Markdown files with ANSI escape sequences in the terminal |
|
43
|
+
| `git-md` executable | A Git plugin that outputs Markdown formatted git commit messages into the terminal |
|
44
|
+
|
45
|
+
### The md executable
|
46
|
+
|
47
|
+
The `md` executable can by used with file arguments:
|
48
|
+
|
49
|
+
```shell
|
50
|
+
md Foo.md Bar.md …
|
51
|
+
```
|
52
|
+
|
53
|
+
or as a unix filter:
|
54
|
+
|
55
|
+
```shell
|
56
|
+
cat Foo.md Bar.md | md
|
57
|
+
```
|
58
|
+
|
59
|
+
It outputs the markdown files with ANSI escape sequences in the terminal. If
|
60
|
+
the file has more lines than the current terminal window has, it attempts to
|
61
|
+
open a pager command like `less` or `more` and pipes its output into it.
|
62
|
+
By setting the `PAGER` environment variable accordingly one can define a custom
|
63
|
+
command for this purpose.
|
64
|
+
|
65
|
+
### The git-md executable
|
66
|
+
|
67
|
+
The `git-md` executable is a git plugin that can be used to output markdown
|
68
|
+
formatted git commit messages (just like `git log`) into the terminal using
|
69
|
+
|
70
|
+
```shell
|
71
|
+
git md
|
72
|
+
```
|
73
|
+
|
74
|
+
You can pass arguments to it like you would of `git log`, e.g.
|
75
|
+
|
76
|
+
```shell
|
77
|
+
git md -p
|
78
|
+
```
|
79
|
+
|
80
|
+
to show the patches additionally to the log messages.
|
81
|
+
|
82
|
+
By setting the `GIT_PAGER` or `PAGER` environment variable accordingly one can
|
83
|
+
define a custom command for this purpose as well, unless a different
|
84
|
+
pager command was defined setting `git config set core.pager FOO`, in which
|
85
|
+
case the FOO command is used as a pager for all git commands including `git
|
86
|
+
md`.
|
87
|
+
|
88
|
+
## Download
|
89
|
+
|
90
|
+
The homepage of this library is located at
|
91
|
+
|
92
|
+
* https://github.com/flori/kramdown-ansi
|
93
|
+
|
94
|
+
## Author
|
95
|
+
|
96
|
+
<b>Kramdown ANSI</b> was written by Florian Frank [Florian Frank](mailto:flori@ping.de)
|
97
|
+
|
98
|
+
## License
|
99
|
+
|
100
|
+
This software is licensed under the <i>MIT</i> license.
|
101
|
+
|
102
|
+
## Mandatory Kitten Image
|
103
|
+
|
104
|
+

|
105
|
+
|
106
|
+
---
|
107
|
+
|
108
|
+
This is the end.
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# vim: set filetype=ruby et sw=2 ts=2:
|
2
|
+
|
3
|
+
require 'gem_hadar'
|
4
|
+
|
5
|
+
GemHadar do
|
6
|
+
name 'kramdown-ansi'
|
7
|
+
path_name 'kramdown'
|
8
|
+
module_type :module
|
9
|
+
author 'Florian Frank'
|
10
|
+
email 'flori@ping.de'
|
11
|
+
homepage "https://github.com/flori/#{name}"
|
12
|
+
summary 'Output markdown in the terminal with ANSI escape sequences'
|
13
|
+
description <<~EOT
|
14
|
+
Kramdown::ANSI: A library for rendering Markdown(ish) documents with
|
15
|
+
beautiful ANSI escape sequences in the terminal.
|
16
|
+
EOT
|
17
|
+
test_dir 'spec'
|
18
|
+
ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', '.AppleDouble', '.bundle',
|
19
|
+
'.yardoc', 'doc', 'tags', 'errors.lst', 'cscope.out', 'coverage', 'tmp',
|
20
|
+
'yard'
|
21
|
+
package_ignore '.all_images.yml', '.tool-versions', '.gitignore', 'VERSION',
|
22
|
+
'.rspec', *Dir.glob('.github/**/*', File::FNM_DOTMATCH)
|
23
|
+
readme 'README.md'
|
24
|
+
|
25
|
+
executables << 'md' << 'git-md'
|
26
|
+
|
27
|
+
required_ruby_version '~> 3.1'
|
28
|
+
|
29
|
+
dependency 'term-ansicolor', '~> 1.11'
|
30
|
+
dependency 'kramdown-parser-gfm', '~> 1.1'
|
31
|
+
dependency 'terminal-table', '~> 3.0'
|
32
|
+
development_dependency 'all_images', '~> 0.4'
|
33
|
+
development_dependency 'rspec', '~> 3.2'
|
34
|
+
development_dependency 'debug'
|
35
|
+
development_dependency 'simplecov'
|
36
|
+
|
37
|
+
licenses << 'MIT'
|
38
|
+
|
39
|
+
clobber 'coverage'
|
40
|
+
end
|
data/bin/git-md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'kramdown/ansi'
|
4
|
+
include Term::ANSIColor
|
5
|
+
require 'shellwords'
|
6
|
+
|
7
|
+
cmd = %{git log --color=always --pretty=format:"commit %H%C(auto)%d%nDate: %Cgreen%cD (%cr)%Creset%nAuthor: %Cblue%an <%ae>%Creset%n%nMARKUP%n%s%n%n%b%nMARKDOWN%n"}
|
8
|
+
|
9
|
+
core_pager = `git config get core.pager`.chomp.full?
|
10
|
+
git_pager = ENV['GIT_PAGER'].full?
|
11
|
+
default_pager = ENV['PAGER'].full?
|
12
|
+
if fallback_pager = `which less`.chomp.full? || `which more`.chomp.full?
|
13
|
+
fallback_pager << ' -r'
|
14
|
+
end
|
15
|
+
my_pager = git_pager || core_pager || default_pager || fallback_pager
|
16
|
+
|
17
|
+
repo_url = case git_origin_url = `git remote get-url origin`.chomp
|
18
|
+
when %r(\Ahttps://)
|
19
|
+
u = git_origin_url.sub(%r(\.git\z), '')
|
20
|
+
u << '/commit/'
|
21
|
+
when %r(\Agit@github.com:([^.]+))
|
22
|
+
"https://github.com/#$1/commit/"
|
23
|
+
end
|
24
|
+
|
25
|
+
Kramdown::ANSI::Pager.pager(command: my_pager) do |output|
|
26
|
+
IO.popen("#{cmd} #{Shellwords.join(ARGV)}") do |log|
|
27
|
+
until log.eof?
|
28
|
+
message = nil
|
29
|
+
log.each do |line|
|
30
|
+
case line
|
31
|
+
when /^MARKUP$/
|
32
|
+
message = ''
|
33
|
+
when /^MARKDOWN$/
|
34
|
+
output.puts Kramdown::ANSI.parse(message + "\n---\n")
|
35
|
+
message = nil
|
36
|
+
else
|
37
|
+
if message
|
38
|
+
message << line
|
39
|
+
else
|
40
|
+
output.puts line.sub(/(?<=^commit )(\h{40})/) {
|
41
|
+
yellow { repo_url ? hyperlink(repo_url + $1) { $1 } : $1 }
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/bin/md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'kramdown/ansi'
|
4
|
+
|
5
|
+
rendered = Kramdown::ANSI.parse(ARGF.read)
|
6
|
+
default_pager = ENV['PAGER'].full?
|
7
|
+
if fallback_pager = `which less`.chomp.full? || `which more`.chomp.full?
|
8
|
+
fallback_pager << ' -r'
|
9
|
+
end
|
10
|
+
my_pager = default_pager || fallback_pager
|
11
|
+
|
12
|
+
Kramdown::ANSI::Pager.pager(lines: rendered.count(?\n), command: my_pager) do |output|
|
13
|
+
output.puts rendered
|
14
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
# stub: kramdown-ansi 0.0.0 ruby lib
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "kramdown-ansi".freeze
|
6
|
+
s.version = "0.0.0".freeze
|
7
|
+
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
9
|
+
s.require_paths = ["lib".freeze]
|
10
|
+
s.authors = ["Florian Frank".freeze]
|
11
|
+
s.date = "2024-10-31"
|
12
|
+
s.description = "Kramdown::ANSI: A library for rendering Markdown(ish) documents with\nbeautiful ANSI escape sequences in the terminal.\n".freeze
|
13
|
+
s.email = "flori@ping.de".freeze
|
14
|
+
s.executables = ["md".freeze, "git-md".freeze]
|
15
|
+
s.extra_rdoc_files = ["README.md".freeze, "lib/kramdown/ansi.rb".freeze, "lib/kramdown/ansi/pager.rb".freeze, "lib/kramdown/ansi/width.rb".freeze, "lib/kramdown/version.rb".freeze]
|
16
|
+
s.files = ["CHANGES.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "bin/git-md".freeze, "bin/md".freeze, "kramdown-ansi.gemspec".freeze, "lib/kramdown/ansi.rb".freeze, "lib/kramdown/ansi/pager.rb".freeze, "lib/kramdown/ansi/width.rb".freeze, "lib/kramdown/version.rb".freeze, "spec/assets/README.ansi".freeze, "spec/assets/kitten.jpg".freeze, "spec/kramdown/ansi/pager_spec.rb".freeze, "spec/kramdown/ansi/width_spec.rb".freeze, "spec/kramdown/ansi_spec.rb".freeze, "spec/spec_helper.rb".freeze]
|
17
|
+
s.homepage = "https://github.com/flori/kramdown-ansi".freeze
|
18
|
+
s.licenses = ["MIT".freeze]
|
19
|
+
s.rdoc_options = ["--title".freeze, "Kramdown-ansi - Output markdown in the terminal with ANSI escape sequences".freeze, "--main".freeze, "README.md".freeze]
|
20
|
+
s.required_ruby_version = Gem::Requirement.new("~> 3.1".freeze)
|
21
|
+
s.rubygems_version = "3.5.22".freeze
|
22
|
+
s.summary = "Output markdown in the terminal with ANSI escape sequences".freeze
|
23
|
+
s.test_files = ["spec/kramdown/ansi/pager_spec.rb".freeze, "spec/kramdown/ansi/width_spec.rb".freeze, "spec/kramdown/ansi_spec.rb".freeze, "spec/spec_helper.rb".freeze]
|
24
|
+
|
25
|
+
s.specification_version = 4
|
26
|
+
|
27
|
+
s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.19".freeze])
|
28
|
+
s.add_development_dependency(%q<all_images>.freeze, ["~> 0.4".freeze])
|
29
|
+
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.2".freeze])
|
30
|
+
s.add_development_dependency(%q<debug>.freeze, [">= 0".freeze])
|
31
|
+
s.add_development_dependency(%q<simplecov>.freeze, [">= 0".freeze])
|
32
|
+
s.add_runtime_dependency(%q<term-ansicolor>.freeze, ["~> 1.11".freeze])
|
33
|
+
s.add_runtime_dependency(%q<kramdown-parser-gfm>.freeze, ["~> 1.1".freeze])
|
34
|
+
s.add_runtime_dependency(%q<terminal-table>.freeze, ["~> 3.0".freeze])
|
35
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'tins/terminal'
|
2
|
+
|
3
|
+
module Kramdown::ANSI::Pager
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# If called without a block returns either the provided command for paging if
|
7
|
+
# the given number of lines are exceeding the available number of terminal
|
8
|
+
# lines or nil. If a block was provided it yields to an IO handle for the
|
9
|
+
# pager command in the latter case or STDOUT in the former.
|
10
|
+
#
|
11
|
+
# @param command [String] the pager command (optional)
|
12
|
+
# @param lines [Integer] the number of lines in the output (optional)
|
13
|
+
# @yield [IO] yields the output IO handle for further processing
|
14
|
+
# @return [NilClass] returns nil if STDOUT is used or STDOUT is not a TTY.
|
15
|
+
def pager(command: nil, lines: nil, &block)
|
16
|
+
if block
|
17
|
+
if my_pager = pager(command:, lines:)
|
18
|
+
IO.popen(my_pager, 'w') do |output|
|
19
|
+
output.sync = true
|
20
|
+
yield output
|
21
|
+
output.close
|
22
|
+
end
|
23
|
+
else
|
24
|
+
yield STDOUT
|
25
|
+
end
|
26
|
+
else
|
27
|
+
return unless STDOUT.tty?
|
28
|
+
if lines
|
29
|
+
if lines >= Tins::Terminal.lines
|
30
|
+
pager(command:)
|
31
|
+
end
|
32
|
+
else
|
33
|
+
command
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'tins/terminal'
|
2
|
+
require 'term/ansicolor'
|
3
|
+
|
4
|
+
module Kramdown::ANSI::Width
|
5
|
+
include Term::ANSIColor
|
6
|
+
extend Term::ANSIColor
|
7
|
+
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# Returns the width of the terminal in characters, given a percentage.
|
11
|
+
#
|
12
|
+
# @param percentage [Numeric] the percentage value (defaults to 100.0)
|
13
|
+
# @return [Integer] the calculated width
|
14
|
+
def width(percentage: 100.0)
|
15
|
+
((Float(percentage) * Tins::Terminal.columns) / 100).floor
|
16
|
+
end
|
17
|
+
|
18
|
+
# Wraps text to a specified width.
|
19
|
+
#
|
20
|
+
# @param text [String] the text to wrap
|
21
|
+
# @option percentage [Numeric] the percentage value for the width (defaults to nil)
|
22
|
+
# @option length [Integer] the character length for the width (defaults to nil)
|
23
|
+
# @return [String] the wrapped text
|
24
|
+
# @raise [ArgumentError] if neither `percentage` nor `length` is provided
|
25
|
+
def wrap(text, percentage: nil, length: nil)
|
26
|
+
percentage.nil? ^ length.nil? or
|
27
|
+
raise ArgumentError, "either pass percentage or length argument"
|
28
|
+
percentage and length ||= width(percentage:)
|
29
|
+
text.gsub(/(?<!\n)\n(?!\n)/, ' ').lines.map do |line|
|
30
|
+
if length >= 1 && uncolor { line }.length > length
|
31
|
+
line.gsub(/(.{1,#{length}})(\s+|$)/, "\\1\n").strip
|
32
|
+
else
|
33
|
+
line.strip
|
34
|
+
end
|
35
|
+
end * ?\n
|
36
|
+
end
|
37
|
+
|
38
|
+
# Truncates a given string to a specified length or percentage. If the text
|
39
|
+
# is longer an ellipsis sequence is added at the end of the generated string,
|
40
|
+
# to indicate that a truncation has been performed.
|
41
|
+
#
|
42
|
+
# @param text [String] the input string to truncate
|
43
|
+
# @option percentage [Numeric] the percentage value for the width (defaults to nil)
|
44
|
+
# @option length [Integer] the character length for the width (defaults to nil)
|
45
|
+
# @option ellipsis [Character] the truncation indicator (defaults to ?…)
|
46
|
+
# @return [String] the truncated string
|
47
|
+
# @raise [ArgumentError] if neither `percentage` nor `length` is provided
|
48
|
+
def truncate(text, percentage: nil, length: nil, ellipsis: ?…)
|
49
|
+
percentage.nil? ^ length.nil? or
|
50
|
+
raise ArgumentError, "either pass percentage or length argument"
|
51
|
+
percentage and length ||= width(percentage:)
|
52
|
+
ellipsis_length = ellipsis.size
|
53
|
+
if length < ellipsis_length
|
54
|
+
+''
|
55
|
+
elsif text.size >= length + ellipsis_length
|
56
|
+
text[0, length - ellipsis_length] + ellipsis
|
57
|
+
else
|
58
|
+
text
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
require 'kramdown'
|
2
|
+
require 'kramdown-parser-gfm'
|
3
|
+
require 'terminal-table'
|
4
|
+
require 'term/ansicolor'
|
5
|
+
module Kramdown
|
6
|
+
class Kramdown::ANSI < Kramdown::Converter::Base
|
7
|
+
end
|
8
|
+
end
|
9
|
+
require 'kramdown/ansi/width'
|
10
|
+
require 'kramdown/ansi/pager'
|
11
|
+
|
12
|
+
class Kramdown::ANSI < Kramdown::Converter::Base
|
13
|
+
include Term::ANSIColor
|
14
|
+
include Kramdown::ANSI::Width
|
15
|
+
|
16
|
+
class ::Kramdown::Parser::Mygfm < ::Kramdown::Parser::GFM
|
17
|
+
def initialize(source, options)
|
18
|
+
options[:gfm_quirks] << :no_auto_typographic
|
19
|
+
super
|
20
|
+
@block_parsers -= %i[
|
21
|
+
definition_list block_html block_math
|
22
|
+
footnote_definition abbrev_definition
|
23
|
+
]
|
24
|
+
@span_parsers -= %i[ footnote_marker inline_math ]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.parse(source)
|
29
|
+
@doc = Kramdown::Document.new(
|
30
|
+
source, input: :mygfm, auto_ids: false, entity_output: :as_char
|
31
|
+
).to_ansi
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(root, options)
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
def convert(el, opts = {})
|
39
|
+
send("convert_#{el.type}", el, opts)
|
40
|
+
end
|
41
|
+
|
42
|
+
def inner(el, opts, &block)
|
43
|
+
result = +''
|
44
|
+
options = opts.dup.merge(parent: el)
|
45
|
+
el.children.each_with_index do |inner_el, index|
|
46
|
+
options[:index] = index
|
47
|
+
options[:result] = result
|
48
|
+
begin
|
49
|
+
content = send("convert_#{inner_el.type}", inner_el, options)
|
50
|
+
result << (block&.(inner_el, index, content) || content)
|
51
|
+
rescue NameError => e
|
52
|
+
warning "Caught #{e.class} for #{inner_el.type}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
def convert_root(el, opts)
|
59
|
+
inner(el, opts)
|
60
|
+
end
|
61
|
+
|
62
|
+
def convert_blank(_el, opts)
|
63
|
+
opts[:result] =~ /\n\n\Z|\A\Z/ ? "" : "\n"
|
64
|
+
end
|
65
|
+
|
66
|
+
def convert_text(el, _opts)
|
67
|
+
el.value
|
68
|
+
end
|
69
|
+
|
70
|
+
def convert_header(el, opts)
|
71
|
+
newline bold { underline { inner(el, opts) } }
|
72
|
+
end
|
73
|
+
|
74
|
+
def convert_p(el, opts)
|
75
|
+
length = width(percentage: 90) - opts[:list_indent].to_i
|
76
|
+
length < 0 and return ''
|
77
|
+
newline wrap(inner(el, opts), length:)
|
78
|
+
end
|
79
|
+
|
80
|
+
def convert_strong(el, opts)
|
81
|
+
bold { inner(el, opts) }
|
82
|
+
end
|
83
|
+
|
84
|
+
def convert_em(el, opts)
|
85
|
+
italic { inner(el, opts) }
|
86
|
+
end
|
87
|
+
|
88
|
+
def convert_a(el, opts)
|
89
|
+
url = el.attr['href']
|
90
|
+
hyperlink(url) { inner(el, opts) }
|
91
|
+
end
|
92
|
+
|
93
|
+
def convert_codespan(el, _opts)
|
94
|
+
blue { el.value }
|
95
|
+
end
|
96
|
+
|
97
|
+
def convert_codeblock(el, _opts)
|
98
|
+
blue { el.value }
|
99
|
+
end
|
100
|
+
|
101
|
+
def convert_blockquote(el, opts)
|
102
|
+
newline ?“ + inner(el, opts).sub(/\n+\z/, '') + ?”
|
103
|
+
end
|
104
|
+
|
105
|
+
def convert_hr(_el, _opts)
|
106
|
+
newline ?─ * width(percentage: 100)
|
107
|
+
end
|
108
|
+
|
109
|
+
def convert_img(el, _opts)
|
110
|
+
url = el.attr['src']
|
111
|
+
alt = el.attr['alt']
|
112
|
+
alt.strip.size == 0 and alt = url
|
113
|
+
alt = '🖼 ' + alt
|
114
|
+
hyperlink(url) { alt }
|
115
|
+
end
|
116
|
+
|
117
|
+
def convert_ul(el, opts)
|
118
|
+
list_indent = opts[:list_indent].to_i
|
119
|
+
inner(el, opts) { |_inner_el, index, content|
|
120
|
+
result = '· %s' % content
|
121
|
+
result = newline(result, count: index <= el.children.size - 1 ? 1 : 2)
|
122
|
+
result.gsub(/^/, ' ' * list_indent)
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
def convert_ol(el, opts)
|
127
|
+
list_indent = opts[:list_indent].to_i
|
128
|
+
inner(el, opts) { |_inner_el, index, content|
|
129
|
+
result = '%u. %s' % [ index + 1, content ]
|
130
|
+
result = newline(result, count: index <= el.children.size - 1 ? 1 : 2)
|
131
|
+
result.gsub(/^/, ' ' * list_indent)
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
def convert_li(el, opts)
|
136
|
+
opts = opts.dup
|
137
|
+
opts[:list_indent] = 2 + opts[:list_indent].to_i
|
138
|
+
newline inner(el, opts).sub(/\n+\Z/, '')
|
139
|
+
end
|
140
|
+
|
141
|
+
def convert_html_element(el, opts)
|
142
|
+
if el.value == 'i' || el.value == 'em'
|
143
|
+
italic { inner(el, opts) }
|
144
|
+
elsif el.value == 'b' || el.value == 'strong'
|
145
|
+
bold { inner(el, opts) }
|
146
|
+
else
|
147
|
+
''
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def convert_table(el, opts)
|
152
|
+
table = Terminal::Table.new
|
153
|
+
table.style = {
|
154
|
+
all_separators: true,
|
155
|
+
border: :unicode_round,
|
156
|
+
}
|
157
|
+
opts[:table] = table
|
158
|
+
inner(el, opts)
|
159
|
+
el.options[:alignment].each_with_index do |a, i|
|
160
|
+
a == :default and next
|
161
|
+
opts[:table].align_column(i, a)
|
162
|
+
end
|
163
|
+
newline table.to_s
|
164
|
+
end
|
165
|
+
|
166
|
+
def convert_thead(el, opts)
|
167
|
+
rows = inner(el, opts)
|
168
|
+
rows = rows.split(/\s*\|\s*/)[1..].map(&:strip)
|
169
|
+
opts[:table].headings = rows
|
170
|
+
''
|
171
|
+
end
|
172
|
+
|
173
|
+
def convert_tbody(el, opts)
|
174
|
+
res = +''
|
175
|
+
res << inner(el, opts)
|
176
|
+
end
|
177
|
+
|
178
|
+
def convert_tfoot(el, opts)
|
179
|
+
''
|
180
|
+
end
|
181
|
+
|
182
|
+
def convert_tr(el, opts)
|
183
|
+
return '' if el.children.empty?
|
184
|
+
full_width = width(percentage: 90)
|
185
|
+
cols = el.children.map { |c| convert(c, opts).strip }
|
186
|
+
row_size = cols.sum(&:size)
|
187
|
+
return '' if row_size.zero?
|
188
|
+
opts[:table] << cols.map { |c|
|
189
|
+
length = (full_width * (c.size / row_size.to_f)).floor
|
190
|
+
wrap(c, length:)
|
191
|
+
}
|
192
|
+
''
|
193
|
+
end
|
194
|
+
|
195
|
+
def convert_td(el, opts)
|
196
|
+
inner(el, opts)
|
197
|
+
end
|
198
|
+
|
199
|
+
def convert_entity(el, _opts)
|
200
|
+
el.value.char
|
201
|
+
end
|
202
|
+
|
203
|
+
def convert_xml_comment(*)
|
204
|
+
''
|
205
|
+
end
|
206
|
+
|
207
|
+
def convert_xml_pi(*)
|
208
|
+
''
|
209
|
+
end
|
210
|
+
|
211
|
+
def convert_br(_el, opts)
|
212
|
+
''
|
213
|
+
end
|
214
|
+
|
215
|
+
def convert_smart_quote(el, _opts)
|
216
|
+
el.value.to_s =~ /[rl]dquo/ ? "\"" : "'"
|
217
|
+
end
|
218
|
+
|
219
|
+
def newline(text, count: 1)
|
220
|
+
text.gsub(/\n*\z/, ?\n * count)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
Kramdown::Converter.const_set(:Ansi, Kramdown::ANSI)
|