mdless 1.0.31 → 1.0.33

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e0a66c5ea1522d66b1cca9ad1e74e66b4e5dd301fd5b42eb9ff20d912074c02
4
- data.tar.gz: 75e46348a488ae50975f931b3164a127ae085d53b1eba3ebd1264ce19e5c6048
3
+ metadata.gz: 124d704b9e69d3c7afbba30442cc2e3f3b9ebd92edc16b345c3a5489b64a5823
4
+ data.tar.gz: 0e257d07a7c684441140ad2d526711c41127f97af37ae798311d9f04e5f832fd
5
5
  SHA512:
6
- metadata.gz: 362da8ff8940e858a31a5c40a375454d54b0632bfef39ab50426257424887115f56dfe92909ba00e365a6953c7c4381db34a3bb4b78995702c2e9668d82506c7
7
- data.tar.gz: 0e1df0694ecfc053517aa22cd0430e554dc06742a3443d37648f15cd2db82f97b5de697f18ab2982d9511d30d68a4165c813c23a8cfc33363bba92170cd539c3
6
+ metadata.gz: 621d98dd881546000fdff38ad51e691d1c729fce4a87f96dc19b5041b9fefefd826245ed9b865db272165b591a0d300b6d1c5dca71d2612b611bc9549dce3181
7
+ data.tar.gz: 33287f2fd78bdc15fd9bc15003a30df2396688475864063e012d96418c8e390a2c2e6c67c746831608a40e4bea0ee594540e209dbcc6806d3e7950c870406785
data/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # mdless
2
2
 
3
3
  <!--README-->
4
+
4
5
  `mdless` is a utility that provides a formatted and highlighted view of Markdown files in Terminal.
5
6
 
6
7
  I often use iTerm2 in visor mode, so `qlmanage -p` is annoying. I still wanted a way to view Markdown files quickly and without cruft.
7
8
 
8
9
  <!--GITHUB-->![mdless screenshot](screenshots/mdless.png)<!--END GITHUB-->
9
- <!--JEKYLL {% gif /uploads/2015/08/mdless.gif %} -->
10
+ <!--JEKYLL{% gif /uploads/2015/08/mdless.gif %}-->
10
11
 
11
12
  ## Features
12
13
 
@@ -17,7 +18,7 @@ I often use iTerm2 in visor mode, so `qlmanage -p` is annoying. I still wanted a
17
18
  - Display footnotes after each paragraph
18
19
  - Inline image display (local, optionally remote) if using iTerm2 2.9+
19
20
  - Syntax highlighting when [Pygments](http://pygments.org/) is installed
20
- - Only fenced code with a language defined (e.g. `\`\`\`python`) will be highlighted
21
+ - Only fenced code with a language defined (e.g. `python`) will be highlighted
21
22
  - Languages can also be determined by hashbang in the code block
22
23
  - List headlines in document
23
24
  - Display single section of the document based on headlines
@@ -114,4 +115,5 @@ Use 'r' to reverse foreground and background colors. `r white on_black` would di
114
115
  To set a background color, use `on_[color]` with one of the 8 colors. This can be used with foreground colors in the same setting, e.g. `white on_black`.
115
116
 
116
117
  Use 'd' (dark) to indicate the darker version of a foreground color. On macOS (and possibly other systems) you can use the brighter version of a color by prefixing with "intense", e.g. `intense_red` or `on_intense_black`.
118
+
117
119
  <!--END README-->
data/bin/mdless CHANGED
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
- # coding: utf-8
2
+ # frozen_string_literal: true
3
+
3
4
  require 'mdless'
4
5
 
5
6
  def class_exists?(class_name)
6
7
  klass = Module.const_get(class_name)
7
- return klass.is_a?(Class)
8
+ klass.is_a?(Class)
8
9
  rescue NameError
9
- return false
10
+ false
10
11
  end
11
12
 
12
13
  if class_exists? 'Encoding'
@@ -22,11 +22,11 @@ module CLIMarkdown
22
22
  opts.banner = "#{version} by Brett Terpstra\n\n> Usage: #{CLIMarkdown::EXECUTABLE_NAME} [options] [path]\n\n"
23
23
 
24
24
  @options[:color] = true
25
- opts.on( '-c', '--[no-]color', 'Colorize output (default on)' ) do |c|
25
+ opts.on('-c', '--[no-]color', 'Colorize output (default on)') do |c|
26
26
  @options[:color] = c
27
27
  end
28
28
 
29
- opts.on( '-d', '--debug LEVEL', 'Level of debug messages to output' ) do |level|
29
+ opts.on('-d', '--debug LEVEL', 'Level of debug messages to output') do |level|
30
30
  if level.to_i > 0 && level.to_i < 5
31
31
  @log.level = 5 - level.to_i
32
32
  else
@@ -35,7 +35,7 @@ module CLIMarkdown
35
35
  end
36
36
  end
37
37
 
38
- opts.on( '-h', '--help', 'Display this screen' ) do
38
+ opts.on('-h', '--help', 'Display this screen') do
39
39
  puts opts
40
40
  exit
41
41
  end
@@ -54,8 +54,8 @@ module CLIMarkdown
54
54
  end
55
55
  end
56
56
  end
57
- opts.on('-I', '--all-images', 'Include local and remote images in output (requires imgcat or chafa)' ) do
58
- if exec_available('imgcat') || exec_available('chafa')# && ENV['TERM_PROGRAM'] == 'iTerm.app'
57
+ opts.on('-I', '--all-images', 'Include local and remote images in output (requires imgcat or chafa)') do
58
+ if exec_available('imgcat') || exec_available('chafa') # && ENV['TERM_PROGRAM'] == 'iTerm.app'
59
59
  @options[:local_images] = true
60
60
  @options[:remote_images] = true
61
61
  else
@@ -64,51 +64,51 @@ module CLIMarkdown
64
64
  end
65
65
 
66
66
  @options[:links] = :inline
67
- opts.on( '--links=FORMAT', 'Link style ([inline, reference], default inline) [NOT CURRENTLY IMPLEMENTED]' ) do |format|
67
+ opts.on('--links=FORMAT', 'Link style ([inline, reference], default inline) [NOT CURRENTLY IMPLEMENTED]') do |format|
68
68
  if format =~ /^r/i
69
69
  @options[:links] = :reference
70
70
  end
71
71
  end
72
72
 
73
73
  @options[:list] = false
74
- opts.on( '-l', '--list', 'List headers in document and exit' ) do
74
+ opts.on('-l', '--list', 'List headers in document and exit' ) do
75
75
  @options[:list] = true
76
76
  end
77
77
 
78
78
  @options[:pager] = true
79
- opts.on( '-p', '--[no-]pager', 'Formatted output to pager (default on)' ) do |p|
79
+ opts.on('-p', '--[no-]pager', 'Formatted output to pager (default on)') do |p|
80
80
  @options[:pager] = p
81
81
  end
82
82
 
83
- opts.on( '-P', 'Disable pager (same as --no-pager)' ) do
83
+ opts.on('-P', 'Disable pager (same as --no-pager)') do
84
84
  @options[:pager] = false
85
85
  end
86
86
 
87
87
  @options[:section] = nil
88
- opts.on( '-s', '--section=NUMBER', 'Output only a headline-based section of the input (numeric from --list)' ) do |section|
89
- @options[:section] = section.to_i
88
+ opts.on('-s', '--section=NUMBER[,NUMBER]', 'Output only a headline-based section of the input (numeric from --list)') do |section|
89
+ @options[:section] = section.split(/ *, */).map(&:strip).map(&:to_i)
90
90
  end
91
91
 
92
92
  @options[:theme] = 'default'
93
- opts.on( '-t', '--theme=THEME_NAME', 'Specify an alternate color theme to load' ) do |theme|
93
+ opts.on('-t', '--theme=THEME_NAME', 'Specify an alternate color theme to load') do |theme|
94
94
  @options[:theme] = theme
95
95
  end
96
96
 
97
- opts.on( '-v', '--version', 'Display version number' ) do
97
+ opts.on('-v', '--version', 'Display version number') do
98
98
  puts version
99
99
  exit
100
100
  end
101
101
 
102
- @options[:width] = %x{tput cols}.strip.to_i
103
- opts.on( '-w', '--width=COLUMNS', 'Column width to format for (default terminal width)' ) do |columns|
102
+ @options[:width] = `tput cols`.strip.to_i
103
+ opts.on('-w', '--width=COLUMNS', 'Column width to format for (default: terminal width)') do |columns|
104
104
  @options[:width] = columns.to_i
105
105
  end
106
106
  end
107
107
 
108
108
  begin
109
109
  optparse.parse!
110
- rescue OptionParser::ParseError => pe
111
- $stderr.puts "error: #{pe.message}"
110
+ rescue OptionParser::ParseError => e
111
+ warn "error: #{e.message}"
112
112
  exit 1
113
113
  end
114
114
 
@@ -122,33 +122,33 @@ module CLIMarkdown
122
122
  @ref_links = {}
123
123
  @footnotes = {}
124
124
 
125
- if args.length > 0
126
- files = args.delete_if { |f| !File.exists?(f) }
127
- files.each {|file|
128
- @log.info(%Q{Processing "#{file}"})
125
+ if !args.empty?
126
+ files = args.delete_if { |f| !File.exist?(f) }
127
+ files.each do |file|
128
+ @log.info(%(Processing "#{file}"))
129
129
  @file = file
130
130
  begin
131
131
  input = IO.read(file).force_encoding('utf-8')
132
- rescue
132
+ rescue StandardError
133
133
  input = IO.read(file)
134
134
  end
135
- input.gsub!(/\r?\n/,"\n")
135
+ input.gsub!(/\r?\n/, "\n")
136
136
  if @options[:list]
137
137
  puts list_headers(input)
138
138
  Process.exit 0
139
139
  else
140
140
  convert_markdown(input)
141
141
  end
142
- }
142
+ end
143
143
  printout
144
- elsif ! STDIN.tty?
144
+ elsif !$stdin.isatty
145
145
  @file = nil
146
146
  begin
147
- input = STDIN.read.force_encoding('utf-8')
148
- rescue
149
- input = STDIN.read
147
+ input = $stdin.read.force_encoding('utf-8')
148
+ rescue StandardError
149
+ input = $stdin.read
150
150
  end
151
- input.gsub!(/\r?\n/,"\n")
151
+ input.gsub!(/\r?\n/, "\n")
152
152
  if @options[:list]
153
153
  puts list_headers(input)
154
154
  Process.exit 0
@@ -157,7 +157,7 @@ module CLIMarkdown
157
157
  end
158
158
  printout
159
159
  else
160
- $stderr.puts "No input"
160
+ warn 'No input'
161
161
  Process.exit 1
162
162
  end
163
163
 
@@ -172,19 +172,17 @@ module CLIMarkdown
172
172
  @log.error("Invalid theme key: #{key}") unless keys[0] =~ /^text/
173
173
  return c([:reset])
174
174
  end
175
- keys.each {|k|
175
+ keys.each do |k|
176
176
  if val.key?(k)
177
177
  val = val[k]
178
178
  else
179
179
  @log.error("Invalid theme key: #{k}")
180
180
  return c([:reset])
181
181
  end
182
- }
183
- if val.kind_of? String
182
+ end
183
+ if val.is_a? String
184
184
  val = "x #{val}"
185
- res = val.split(/ /).map {|k|
186
- k.to_sym
187
- }
185
+ res = val.split(/ /).map { |k| k.to_sym }
188
186
  c(res)
189
187
  else
190
188
  c([:reset])
@@ -192,7 +190,7 @@ module CLIMarkdown
192
190
  end
193
191
 
194
192
  def get_headers(input)
195
- unless @headers && @headers.length > 0
193
+ unless @headers && !@headers.empty?
196
194
  @headers = []
197
195
  headers = input.scan(/^((?!#!)(\#{1,6})\s*([^#]+?)(?: #+)?\s*|(\S.+)\n([=-]+))$/i)
198
196
 
@@ -490,6 +488,10 @@ module CLIMarkdown
490
488
  end
491
489
 
492
490
  def convert_markdown(input)
491
+ ## Replace setex headers with ATX
492
+ input.gsub!(/^([^\n]+)\n={3,}\s*$/m, "# \\1\n")
493
+ input.gsub!(/^([^\n]+?)\n-{3,}\s*$/m, "## \\1\n")
494
+
493
495
  @headers = get_headers(input)
494
496
  input += "\n\n@@@"
495
497
  # yaml/MMD headers
@@ -529,7 +531,6 @@ module CLIMarkdown
529
531
 
530
532
  end
531
533
 
532
-
533
534
  # Gather reference links
534
535
  input.gsub!(/^\s{,3}(?<![\e*])\[\b(.+)\b\]: +(.+)/) do |m|
535
536
  match = Regexp.last_match
@@ -546,34 +547,34 @@ module CLIMarkdown
546
547
  end
547
548
 
548
549
  if @options[:section]
549
- in_section = false
550
- top_level = 1
551
550
  new_content = []
552
-
553
- input.split(/\n/).each {|graf|
554
- if graf =~ /^(#+) *(.*?)( *#+)?$/
555
- level = $1.length
556
- title = $2
557
-
558
- if in_section
559
- if level >= top_level
551
+ @options[:section].each do |sect|
552
+ in_section = false
553
+ top_level = 1
554
+ input.split(/\n/).each do |graf|
555
+ if graf =~ /^(#+) *(.*?)( *#+)?$/
556
+ m = Regexp.last_match
557
+ level = m[1].length
558
+ title = m[2]
559
+ if in_section
560
+ if level >= top_level
561
+ new_content.push(graf)
562
+ else
563
+ in_section = false
564
+ break
565
+ end
566
+ elsif title.downcase == @headers[sect - 1][1].downcase
567
+ in_section = true
568
+ top_level = level + 1
560
569
  new_content.push(graf)
561
570
  else
562
- in_section = false
563
- break
571
+ next
564
572
  end
565
- elsif title.downcase == "#{@headers[@options[:section] - 1][1].downcase}"
566
- in_section = true
567
- top_level = level + 1
573
+ elsif in_section
568
574
  new_content.push(graf)
569
- else
570
- next
571
575
  end
572
- elsif in_section
573
- new_content.push(graf)
574
576
  end
575
- }
576
-
577
+ end
577
578
  input = new_content.join("\n")
578
579
  end
579
580
 
@@ -1042,8 +1043,6 @@ module CLIMarkdown
1042
1043
  args = case pg
1043
1044
  when 'delta'
1044
1045
  ' --pager="less -Xr"'
1045
- when 'more'
1046
- ' -r'
1047
1046
  when 'less'
1048
1047
  ' -Xr'
1049
1048
  when 'bat'
data/lib/mdless/theme.rb CHANGED
@@ -2,92 +2,92 @@ module CLIMarkdown
2
2
  module Theme
3
3
 
4
4
  THEME_DEFAULTS = {
5
- 'metadata' => {
6
- 'border' => 'd blue on_black',
7
- 'marker' => 'd black on_black',
8
- 'color' => 'd white on_black'
9
- },
10
- 'emphasis' => {
11
- 'bold' => 'b',
12
- 'italic' => 'u i',
13
- 'bold-italic' => 'b u i'
14
- },
15
- 'h1' => {
16
- 'color' => 'b intense_black on_white',
17
- 'pad' => 'd black on_white',
18
- 'pad_char' => '='
19
- },
20
- 'h2' => {
21
- 'color' => 'b white on_intense_black',
22
- 'pad' => 'd white on_intense_black',
23
- 'pad_char' => '-'
24
- },
25
- 'h3' => {
26
- 'color' => 'u b yellow'
27
- },
28
- 'h4' => {
29
- 'color' => 'u yellow'
30
- },
31
- 'h5' => {
32
- 'color' => 'b white'
33
- },
34
- 'h6' => {
35
- 'color' => 'b white'
36
- },
37
- 'link' => {
38
- 'brackets' => 'b black',
39
- 'text' => 'u b blue',
40
- 'url' => 'cyan'
41
- },
42
- 'image' => {
43
- 'bang' => 'red',
44
- 'brackets' => 'b black',
45
- 'title' => 'cyan',
46
- 'url' => 'u yellow'
47
- },
48
- 'list' => {
49
- 'bullet' => 'b intense_red',
50
- 'number' => 'b intense_blue',
51
- 'color' => 'intense_white'
52
- },
53
- 'footnote' => {
54
- 'brackets' => 'b black on_black',
55
- 'caret' => 'b yellow on_black',
56
- 'title' => 'x yellow on_black',
57
- 'note' => 'u white on_black'
58
- },
59
- 'code_span' => {
60
- 'marker' => 'b white',
61
- 'color' => 'b white on_intense_black'
62
- },
63
- 'code_block' => {
64
- 'marker' => 'intense_black',
65
- 'bg' => 'on_black',
66
- 'color' => 'white on_black',
67
- 'border' => 'blue',
68
- 'title' => 'magenta',
69
- 'eol' => 'intense_black on_black',
70
- 'pygments_theme' => 'monokai'
71
- },
72
- 'dd' => {
73
- 'marker' => 'd red',
74
- 'color' => 'b white'
75
- },
76
- 'hr' => {
77
- 'color' => 'd white'
78
- },
79
- 'table' => {
80
- 'border' => 'd black',
81
- 'header' => 'yellow',
82
- 'divider' => 'b black',
83
- 'color' => 'white',
84
- 'bg' => 'on_black'
85
- },
86
- 'html' => {
87
- 'brackets' => 'd yellow on_black',
88
- 'color' => 'yellow on_black'
89
- }
5
+ 'metadata' => {
6
+ 'border' => 'd blue on_black',
7
+ 'marker' => 'd black on_black',
8
+ 'color' => 'd white on_black'
9
+ },
10
+ 'emphasis' => {
11
+ 'bold' => 'b',
12
+ 'italic' => 'u i',
13
+ 'bold-italic' => 'b u i'
14
+ },
15
+ 'h1' => {
16
+ 'color' => 'b intense_black on_white',
17
+ 'pad' => 'd black on_white',
18
+ 'pad_char' => '='
19
+ },
20
+ 'h2' => {
21
+ 'color' => 'b white on_intense_black',
22
+ 'pad' => 'd white on_intense_black',
23
+ 'pad_char' => '-'
24
+ },
25
+ 'h3' => {
26
+ 'color' => 'u b yellow'
27
+ },
28
+ 'h4' => {
29
+ 'color' => 'u yellow'
30
+ },
31
+ 'h5' => {
32
+ 'color' => 'b white'
33
+ },
34
+ 'h6' => {
35
+ 'color' => 'b white'
36
+ },
37
+ 'link' => {
38
+ 'brackets' => 'b black',
39
+ 'text' => 'u b blue',
40
+ 'url' => 'cyan'
41
+ },
42
+ 'image' => {
43
+ 'bang' => 'red',
44
+ 'brackets' => 'b black',
45
+ 'title' => 'cyan',
46
+ 'url' => 'u yellow'
47
+ },
48
+ 'list' => {
49
+ 'bullet' => 'b intense_red',
50
+ 'number' => 'b intense_blue',
51
+ 'color' => 'intense_white'
52
+ },
53
+ 'footnote' => {
54
+ 'brackets' => 'b black on_black',
55
+ 'caret' => 'b yellow on_black',
56
+ 'title' => 'x yellow on_black',
57
+ 'note' => 'u white on_black'
58
+ },
59
+ 'code_span' => {
60
+ 'marker' => 'b white',
61
+ 'color' => 'b white on_intense_black'
62
+ },
63
+ 'code_block' => {
64
+ 'marker' => 'intense_black',
65
+ 'bg' => 'on_black',
66
+ 'color' => 'white on_black',
67
+ 'border' => 'blue',
68
+ 'title' => 'magenta',
69
+ 'eol' => 'intense_black on_black',
70
+ 'pygments_theme' => 'monokai'
71
+ },
72
+ 'dd' => {
73
+ 'marker' => 'd red',
74
+ 'color' => 'b white'
75
+ },
76
+ 'hr' => {
77
+ 'color' => 'd white'
78
+ },
79
+ 'table' => {
80
+ 'border' => 'd black',
81
+ 'header' => 'yellow',
82
+ 'divider' => 'b black',
83
+ 'color' => 'white',
84
+ 'bg' => 'on_black'
85
+ },
86
+ 'html' => {
87
+ 'brackets' => 'd yellow on_black',
88
+ 'color' => 'yellow on_black'
90
89
  }
90
+ }
91
91
 
92
92
  def load_theme_file(theme_file)
93
93
  new_theme = YAML.load(IO.read(theme_file))
@@ -98,15 +98,13 @@ module CLIMarkdown
98
98
  # File.open(theme_file,'w') {|f|
99
99
  # f.puts theme.to_yaml
100
100
  # }
101
- rescue
101
+ rescue StandardError
102
102
  @log.warn('Error merging user theme')
103
103
  theme = THEME_DEFAULTS
104
104
  if File.basename(theme_file) =~ /mdless\.theme/
105
105
  FileUtils.rm(theme_file)
106
106
  @log.info("Rewriting default theme file to #{theme_file}")
107
- File.open(theme_file,'w') {|f|
108
- f.puts theme.to_yaml
109
- }
107
+ File.open(theme_file, 'w') { |f| f.puts theme.to_yaml }
110
108
  end
111
109
  end
112
110
  theme
@@ -114,12 +112,12 @@ module CLIMarkdown
114
112
 
115
113
  def load_theme(theme)
116
114
  config_dir = File.expand_path('~/.config/mdless')
117
- default_theme_file = File.join(config_dir,'mdless.theme')
115
+ default_theme_file = File.join(config_dir, 'mdless.theme')
118
116
  if theme =~ /default/i || !theme
119
117
  theme_file = default_theme_file
120
118
  else
121
- theme = theme.strip.sub(/(\.theme)?$/,'.theme')
122
- theme_file = File.join(config_dir,theme)
119
+ theme = theme.strip.sub(/(\.theme)?$/, '.theme')
120
+ theme_file = File.join(config_dir, theme)
123
121
  end
124
122
 
125
123
  unless File.directory?(config_dir)
@@ -127,16 +125,14 @@ module CLIMarkdown
127
125
  FileUtils.mkdir_p(config_dir)
128
126
  end
129
127
 
130
- unless File.exists?(theme_file)
131
- unless File.exists?(default_theme_file)
128
+ unless File.exist?(theme_file)
129
+ if File.exist?(default_theme_file)
130
+ @log.info('Specified theme not found, using default')
131
+ theme_file = default_theme_file
132
+ else
132
133
  theme = THEME_DEFAULTS
133
134
  @log.info("Writing fresh theme file to #{theme_file}")
134
- File.open(theme_file,'w') {|f|
135
- f.puts theme.to_yaml
136
- }
137
- else
138
- @log.info("Specified theme not found, using default")
139
- theme_file = default_theme_file
135
+ File.open(theme_file, 'w') { |f| f.puts theme.to_yaml }
140
136
  end
141
137
  end
142
138
 
@@ -1,3 +1,3 @@
1
1
  module CLIMarkdown
2
- VERSION = '1.0.31'
2
+ VERSION = '1.0.33'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mdless
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.31
4
+ version: 1.0.33
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-02 00:00:00.000000000 Z
11
+ date: 2023-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake