kramdown-ansi 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![cat](spec/assets/kitten.jpg)
|
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)
|