marvi 0.1.0 → 0.1.1
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 +4 -4
- data/exe/marvi +1 -1
- data/lib/marvi/ast_walker.rb +20 -12
- data/lib/marvi/document.rb +3 -2
- data/lib/marvi/renderer/curses.rb +66 -12
- data/lib/marvi/version.rb +1 -1
- data/marvi-0.1.0.gem +0 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 41854d878cdc8137d35b7c54ff30ffb13b90206869828a6db31bd53b8d279f1b
|
|
4
|
+
data.tar.gz: 396301e10a2d99ffd4c27526b1e792495c286450ae3e4c213ace369ea2b96706
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f7493dd561c802f8db70acf7f87fdc62f49aec9b74f9681197598e4781885598ce5a5ccf1acfad2975ab22a669556ada2282363b9d4342047ece848334686072
|
|
7
|
+
data.tar.gz: 2c3e48d560413d982c451a9c3a562c102ac06da98900cf1441f73c05077f9dfa8682c6d6d4ea3e44a43ef7387cbeefe67d949b651a9e1d65808a5634348ff17d
|
data/exe/marvi
CHANGED
data/lib/marvi/ast_walker.rb
CHANGED
|
@@ -23,7 +23,8 @@ module Marvi
|
|
|
23
23
|
when :header
|
|
24
24
|
render_header(el)
|
|
25
25
|
when :p
|
|
26
|
-
|
|
26
|
+
src = el.options[:location]
|
|
27
|
+
[RichLine.new(render_inline_children(el), source_line: src), RichLine.blank]
|
|
27
28
|
when :ul
|
|
28
29
|
el.children.flat_map { |child| render_block(child, indent: indent, list_type: :ul) } + [RichLine.blank]
|
|
29
30
|
when :ol
|
|
@@ -37,7 +38,8 @@ module Marvi
|
|
|
37
38
|
when :blockquote
|
|
38
39
|
render_blockquote(el)
|
|
39
40
|
when :hr
|
|
40
|
-
|
|
41
|
+
src = el.options[:location]
|
|
42
|
+
[RichLine.new([Span.new(text: "─" * 60, color: :cyan)], source_line: src), RichLine.blank]
|
|
41
43
|
when :table
|
|
42
44
|
render_table(el)
|
|
43
45
|
when :blank
|
|
@@ -50,17 +52,19 @@ module Marvi
|
|
|
50
52
|
def render_header(el)
|
|
51
53
|
level = el.options[:level]
|
|
52
54
|
color = HEADER_COLORS[level - 1]
|
|
55
|
+
src = el.options[:location]
|
|
53
56
|
prefix = Span.new(text: "#" * level + " ", bold: true, color: color)
|
|
54
57
|
content = render_inline_children(el).map do |s|
|
|
55
58
|
Span.new(text: s.text, bold: true, italic: s.italic, color: s.color || color, bg_color: s.bg_color)
|
|
56
59
|
end
|
|
57
|
-
[RichLine.new([prefix] + content), RichLine.blank]
|
|
60
|
+
[RichLine.new([prefix] + content, source_line: src), RichLine.blank]
|
|
58
61
|
end
|
|
59
62
|
|
|
60
63
|
def render_li(el, indent:, list_type:, list_index:)
|
|
61
64
|
bullet = list_type == :ol ? "#{list_index}." : "•"
|
|
62
65
|
prefix = Span.new(text: "#{" " * indent}#{bullet} ", color: :cyan)
|
|
63
|
-
|
|
66
|
+
src = el.options[:location]
|
|
67
|
+
lines = []
|
|
64
68
|
|
|
65
69
|
el.children.each do |child|
|
|
66
70
|
case child.type
|
|
@@ -70,13 +74,13 @@ module Marvi
|
|
|
70
74
|
lines += nested
|
|
71
75
|
when :p
|
|
72
76
|
if lines.empty?
|
|
73
|
-
lines << RichLine.new([prefix] + render_inline_children(child))
|
|
77
|
+
lines << RichLine.new([prefix] + render_inline_children(child), source_line: src)
|
|
74
78
|
else
|
|
75
79
|
lines += render_block(child)
|
|
76
80
|
end
|
|
77
81
|
else
|
|
78
82
|
if lines.empty?
|
|
79
|
-
lines << RichLine.new([prefix] + render_inline(child))
|
|
83
|
+
lines << RichLine.new([prefix] + render_inline(child), source_line: src)
|
|
80
84
|
else
|
|
81
85
|
lines << RichLine.new(render_inline(child))
|
|
82
86
|
end
|
|
@@ -86,23 +90,27 @@ module Marvi
|
|
|
86
90
|
end
|
|
87
91
|
|
|
88
92
|
def render_codeblock(el)
|
|
93
|
+
src = el.options[:location]
|
|
89
94
|
lang = el.options[:lang]
|
|
90
95
|
lines = []
|
|
91
|
-
lines << RichLine.new([Span.new(text: lang, color: :yellow)]) if lang
|
|
92
|
-
el.value.chomp.split("\n").
|
|
93
|
-
|
|
96
|
+
lines << RichLine.new([Span.new(text: lang, color: :yellow)], source_line: src) if lang
|
|
97
|
+
el.value.chomp.split("\n").each_with_index do |line, i|
|
|
98
|
+
line_src = src ? src + i + (lang ? 1 : 0) : nil
|
|
99
|
+
lines << RichLine.new([Span.new(text: " #{line}", color: :green, bg_color: :dark)], source_line: line_src)
|
|
94
100
|
end
|
|
95
101
|
lines << RichLine.blank
|
|
96
102
|
lines
|
|
97
103
|
end
|
|
98
104
|
|
|
99
105
|
def render_blockquote(el)
|
|
100
|
-
inner
|
|
106
|
+
inner = el.children.flat_map { |child| render_block(child) }
|
|
101
107
|
prefix = Span.new(text: "│ ", color: :cyan)
|
|
102
|
-
|
|
108
|
+
# preserve source_line from inner lines
|
|
109
|
+
inner.map { |line| RichLine.new([prefix] + line.spans, source_line: line.source_line) } + [RichLine.blank]
|
|
103
110
|
end
|
|
104
111
|
|
|
105
112
|
def render_table(el)
|
|
113
|
+
src = el.options[:location]
|
|
106
114
|
rows = el.children.flat_map(&:children)
|
|
107
115
|
header_row = el.children.find { |s| s.type == :thead }&.children&.first
|
|
108
116
|
|
|
@@ -112,7 +120,7 @@ module Marvi
|
|
|
112
120
|
|
|
113
121
|
lines = []
|
|
114
122
|
top = col_widths.map { |w| "─" * (w + 2) }.join("┬")
|
|
115
|
-
lines << RichLine.new([Span.new(text: "┌#{top}┐", color: :cyan)])
|
|
123
|
+
lines << RichLine.new([Span.new(text: "┌#{top}┐", color: :cyan)], source_line: src)
|
|
116
124
|
|
|
117
125
|
rows.each_with_index do |row, ri|
|
|
118
126
|
is_header = row == header_row
|
data/lib/marvi/document.rb
CHANGED
|
@@ -14,10 +14,11 @@ module Marvi
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
class RichLine
|
|
17
|
-
attr_reader :spans
|
|
17
|
+
attr_reader :spans, :source_line
|
|
18
18
|
|
|
19
|
-
def initialize(spans = [])
|
|
19
|
+
def initialize(spans = [], source_line: nil)
|
|
20
20
|
@spans = spans
|
|
21
|
+
@source_line = source_line
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def plain_text
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "curses"
|
|
4
|
+
require "shellwords"
|
|
4
5
|
|
|
5
6
|
module Marvi
|
|
6
7
|
module Renderer
|
|
@@ -17,9 +18,11 @@ module Marvi
|
|
|
17
18
|
|
|
18
19
|
ITALIC_ATTR = (defined?(::Curses::A_ITALIC) ? ::Curses::A_ITALIC : 0)
|
|
19
20
|
|
|
20
|
-
def render(markdown)
|
|
21
|
-
@
|
|
22
|
-
@
|
|
21
|
+
def render(markdown, file: nil)
|
|
22
|
+
@file = file
|
|
23
|
+
@markdown = markdown
|
|
24
|
+
@lines = ASTWalker.new.walk(markdown)
|
|
25
|
+
@scroll = 0
|
|
23
26
|
|
|
24
27
|
::Curses.init_screen
|
|
25
28
|
::Curses.start_color
|
|
@@ -51,18 +54,68 @@ module Marvi
|
|
|
51
54
|
|
|
52
55
|
def handle_key(key)
|
|
53
56
|
case key
|
|
54
|
-
when "q", "Q", 27
|
|
55
|
-
when "j", ::Curses::Key::DOWN
|
|
56
|
-
when "k", ::Curses::Key::UP
|
|
57
|
-
when "d"
|
|
58
|
-
when "u"
|
|
57
|
+
when "q", "Q", 27 then throw :quit
|
|
58
|
+
when "j", ::Curses::Key::DOWN then scroll_by(1)
|
|
59
|
+
when "k", ::Curses::Key::UP then scroll_by(-1)
|
|
60
|
+
when "d" then scroll_by(page_size / 2)
|
|
61
|
+
when "u" then scroll_by(-page_size / 2)
|
|
59
62
|
when "f", " ", ::Curses::Key::NPAGE then scroll_by(page_size)
|
|
60
|
-
when "b", ::Curses::Key::PPAGE
|
|
61
|
-
when "g"
|
|
62
|
-
when "G"
|
|
63
|
+
when "b", ::Curses::Key::PPAGE then scroll_by(-page_size)
|
|
64
|
+
when "g" then @scroll = 0; draw
|
|
65
|
+
when "G" then @scroll = max_scroll; draw
|
|
66
|
+
when "e" then launch_editor if @file
|
|
63
67
|
end
|
|
64
68
|
end
|
|
65
69
|
|
|
70
|
+
def launch_editor
|
|
71
|
+
editor = ENV["EDITOR"] || ENV["VISUAL"] || "vi"
|
|
72
|
+
line = current_source_line
|
|
73
|
+
cmd = build_editor_command(editor, @file, line)
|
|
74
|
+
|
|
75
|
+
::Curses.close_screen
|
|
76
|
+
system(cmd)
|
|
77
|
+
reload
|
|
78
|
+
reinit_curses
|
|
79
|
+
draw
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def reload
|
|
83
|
+
@markdown = File.read(@file)
|
|
84
|
+
@lines = ASTWalker.new.walk(@markdown)
|
|
85
|
+
@scroll = [@scroll, max_scroll].min
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def reinit_curses
|
|
89
|
+
::Curses.init_screen
|
|
90
|
+
::Curses.start_color
|
|
91
|
+
::Curses.use_default_colors
|
|
92
|
+
::Curses.noecho
|
|
93
|
+
::Curses.cbreak
|
|
94
|
+
::Curses.stdscr.keypad(true)
|
|
95
|
+
setup_colors
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def build_editor_command(editor, file, line)
|
|
99
|
+
base = File.basename(editor.split.first)
|
|
100
|
+
escaped = Shellwords.escape(file)
|
|
101
|
+
case base
|
|
102
|
+
when "code"
|
|
103
|
+
"#{editor} --goto #{escaped}:#{line}"
|
|
104
|
+
when "subl", "sublime_text"
|
|
105
|
+
"#{editor} #{escaped}:#{line}"
|
|
106
|
+
else
|
|
107
|
+
# vim, nvim, nano, emacs, micro, etc.
|
|
108
|
+
"#{editor} +#{line} #{escaped}"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def current_source_line
|
|
113
|
+
visible_lines.each { |line| return line.source_line if line.source_line }
|
|
114
|
+
# fall back to searching upward from scroll position
|
|
115
|
+
@scroll.downto(0) { |i| return @lines[i].source_line if @lines[i]&.source_line }
|
|
116
|
+
1
|
|
117
|
+
end
|
|
118
|
+
|
|
66
119
|
def draw
|
|
67
120
|
::Curses.clear
|
|
68
121
|
visible_lines.each_with_index do |line, row|
|
|
@@ -78,7 +131,8 @@ module Marvi
|
|
|
78
131
|
::Curses.attron(::Curses.color_pair(COLOR_PAIRS[:cyan])) do
|
|
79
132
|
top = @scroll + 1
|
|
80
133
|
bottom = [@scroll + page_size, @lines.size].min
|
|
81
|
-
|
|
134
|
+
edit_hint = @file ? " e edit" : ""
|
|
135
|
+
status = " #{top}-#{bottom}/#{@lines.size} j/k scroll g/G top/bottom#{edit_hint} q quit"
|
|
82
136
|
::Curses.addstr(status.ljust(::Curses.cols)[0, ::Curses.cols])
|
|
83
137
|
end
|
|
84
138
|
end
|
data/lib/marvi/version.rb
CHANGED
data/marvi-0.1.0.gem
ADDED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: marvi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mitsutaka Mimura
|
|
@@ -73,6 +73,7 @@ files:
|
|
|
73
73
|
- lib/marvi/renderer/ansi.rb
|
|
74
74
|
- lib/marvi/renderer/curses.rb
|
|
75
75
|
- lib/marvi/version.rb
|
|
76
|
+
- marvi-0.1.0.gem
|
|
76
77
|
- sig/marvi.rbs
|
|
77
78
|
homepage: https://github.com/takkanm/marvi
|
|
78
79
|
licenses:
|