rich-ri 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0ebea7b8adc8c270a62c2f34f0ede696b4440199e801d3126f1c828bd6606f6
4
- data.tar.gz: 9d01b69cee3ae3f39c045240a67f7559ba9cf511fbd86dc6cb429dc0cfee38c3
3
+ metadata.gz: 95c76ed20ec9838602c3383b2e69d8e4058ef66b3b0b68407e61200c41e76898
4
+ data.tar.gz: b21c83e29a2eda62583447d52f530199217e89e704eeb9a4e697031318c2cef8
5
5
  SHA512:
6
- metadata.gz: 57e14eb941738b7a3d7850990b777f94ceaa1d1b30cd4b03068cf0dd7047cad15f0d858e66df315b10275d17bf01cebd4e92de5893bc31641fcf23db0ac42ac2
7
- data.tar.gz: 982792737323335b89e85bd0fffa9f2fbd675d4192f14545ff654a14ac974815f76445758da6e2f4a49b4825029a82585d72748a496cdbda76245da016d22320
6
+ metadata.gz: 1b5d3313a6f77aa580faaad650df0333aa22bdb42f6b3b9f7870157822bfac65ae79accf53de783619fd6b2cf8b8b58dfc0d98e55bb5eed8a055af69e68cdb4b
7
+ data.tar.gz: 2dff498b7fa8d4b7594e6ec88a446a8b9ea638dc206a7eef5b1b11d59024bce039104c9511829b6ec07777b760fd98b9a0a15674c58f9038902225e534848a8d
data/CHANGELOG.md CHANGED
@@ -6,6 +6,31 @@ User-visible changes are recorded here. This project follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.1.1] - 2026-10-06
10
+
11
+ ### Fixed
12
+
13
+ - Tab at the interactive prompt no longer ends the session when an installed gem
14
+ has documentation pages.
15
+ - An empty configuration file means no overrides, as documented, instead of
16
+ stopping every command.
17
+ - Names with pattern characters, such as `Array[`, are reported as unknown and no
18
+ longer end interactive lookup.
19
+ - Configuration paths outside ASCII are read under the C locale.
20
+ - Ctrl-C is left to the pager while a page is open; it no longer leaves the pager
21
+ running in a terminal without echo.
22
+ - Colors reach less when `LESS` ends with a string-valued option such as `-P`.
23
+ - The `dark` and `light` presets keep the terminal palette at basic color depth,
24
+ where `dark` used to paint every role white.
25
+ - Type signatures no longer disable bat for the rest of the page, and a bat that
26
+ prints nothing no longer stops it.
27
+ - Documentation stored by an RDoc class that the running RDoc lacks is reported
28
+ as an incompatible cache.
29
+ - The manual no longer has an empty "Style roles" section.
30
+ - Unexpected failures are reported in one line, with the error class, instead of
31
+ a backtrace.
32
+ - Bash completion keeps a name that contains `=`, such as a setter, intact.
33
+
9
34
  ## [0.1.0] - 2026-10-05
10
35
 
11
36
  ### Added
@@ -53,5 +78,6 @@ User-visible changes are recorded here. This project follows
53
78
  - Invalid dump paths and a missing manual viewer produce actionable errors.
54
79
  - Contributor checks handle shallow pull request merge histories.
55
80
 
56
- [Unreleased]: https://github.com/hvpaiva/rich-ri/compare/v0.1.0...HEAD
81
+ [Unreleased]: https://github.com/hvpaiva/rich-ri/compare/v0.1.1...HEAD
57
82
  [0.1.0]: https://github.com/hvpaiva/rich-ri/releases/tag/v0.1.0
83
+ [0.1.1]: https://github.com/hvpaiva/rich-ri/releases/tag/v0.1.1
@@ -4,7 +4,7 @@
4
4
  _rich_ri() {
5
5
  # _init_completion assigns prev through Bash's dynamic scope.
6
6
  # shellcheck disable=SC2034
7
- local cur prev words cword value _description
7
+ local cur prev words cword value _description prefix
8
8
  COMPREPLY=()
9
9
  _init_completion -n ':=' || return
10
10
  while IFS=$'\t' read -r value _description; do
@@ -15,7 +15,11 @@ _rich_ri() {
15
15
  fi
16
16
  [[ $cur == *:* ]] && __ltrim_colon_completions "$cur"
17
17
  if [[ $cur == *=* && $COMP_WORDBREAKS == *'='* ]]; then
18
- COMPREPLY=("${COMPREPLY[@]#*=}")
18
+ prefix=${cur%"${cur##*=}"}
19
+ COMPREPLY=("${COMPREPLY[@]#"$prefix"}")
20
+ if ((${#COMPREPLY[@]} == 1)) && [[ -z ${COMPREPLY[0]} ]]; then
21
+ COMPREPLY=()
22
+ fi
19
23
  fi
20
24
  return 0
21
25
  }
@@ -105,7 +105,9 @@ configuration does not start a pager.
105
105
  `terminal` uses your terminal's ANSI palette, preserving rich-ri's default
106
106
  appearance. `dark` and `light` supply foreground colors suited to those
107
107
  backgrounds. They do not set the terminal background or try to detect it.
108
- Choose explicitly if your terminal palette needs different contrast.
108
+ Choose explicitly if your terminal palette needs different contrast. At `basic`
109
+ color depth both presets keep the terminal palette, because sixteen colors cannot
110
+ tell their shades apart.
109
111
 
110
112
  Each style is a colon-separated string. A bare color sets the foreground;
111
113
  `fg=COLOR` and `bg=COLOR` set foreground and background explicitly. Attributes
@@ -213,7 +215,7 @@ an empty value, to fall back to the file or an earlier layer.
213
215
  | `RI` | Default command-line options, parsed as shell words. |
214
216
  | `RI_PAGER` | Documentation pager command; overrides the file, below `--pager-command`. |
215
217
  | `PAGER` | Fallback documentation pager; also used by man according to its own rules. |
216
- | `LESS` | Options for less; rich-ri appends `-R` for its child documentation pager. |
218
+ | `LESS` | Options for less; rich-ri adds `-R` for its child documentation pager. |
217
219
  | `BAT_THEME` | Backward-compatible bat theme override when `RICH_RI_BAT_THEME` is unset. |
218
220
  | `NO_COLOR` | Nonempty values disable automatic colors. |
219
221
  | `TERM` | `dumb` disables automatic colors; `256color` indicates 256-color capability. |
data/docs/development.md CHANGED
@@ -72,15 +72,20 @@ To test the minimum runtime dependencies, use Ruby 3.4 with Bash, Zsh, Fish and
72
72
  bash-completion 2.x installed locally, then run:
73
73
 
74
74
  ```sh
75
- BUNDLE_GEMFILE=gemfiles/legacy.gemfile bundle install
76
- BUNDLE_GEMFILE=gemfiles/legacy.gemfile bundle exec ruby -rrdoc/rdoc -e \
77
- 'RDoc::RDoc.new.document(ARGV)' -- --ri --quiet --op tmp/legacy-ri test/fixtures/example.rb
78
- BUNDLE_GEMFILE=gemfiles/minimum.gemfile bundle install
79
- LEGACY_RI_STORE="$PWD/tmp/legacy-ri" BUNDLE_GEMFILE=gemfiles/minimum.gemfile \
80
- RICH_RI_REQUIRE_SHELLS=1 bundle exec ruby bin/test-compatibility
75
+ (
76
+ export BUNDLE_PATH="$PWD/tmp/compatibility-gems"
77
+ BUNDLE_GEMFILE=gemfiles/legacy.gemfile bundle install
78
+ BUNDLE_GEMFILE=gemfiles/legacy.gemfile bundle exec ruby -rrdoc/rdoc -e \
79
+ 'RDoc::RDoc.new.document(ARGV)' -- --ri --quiet --op tmp/legacy-ri test/fixtures/example.rb
80
+ BUNDLE_GEMFILE=gemfiles/minimum.gemfile bundle install
81
+ LEGACY_RI_STORE="$PWD/tmp/legacy-ri" BUNDLE_GEMFILE=gemfiles/minimum.gemfile \
82
+ RICH_RI_REQUIRE_SHELLS=1 bundle exec ruby bin/test-compatibility
83
+ )
81
84
  ```
82
85
 
83
- The first bundle generates a store using RDoc 6.14. The second runs the runtime
86
+ The subshell's own bundle path keeps RDoc 6.14 out of the active Ruby, where
87
+ installing it would replace the RubyGems plugin that `gem rdoc` loads. The first
88
+ bundle generates a store using RDoc 6.14. The second runs the runtime
84
89
  tests using the minimum direct dependencies compatible with RDoc 8.1, including
85
90
  lookup and completion against that older store. Maintenance-only tests and the
86
91
  optional server/profiler modes use the main bundle; missing-gem behavior is tested
data/docs/usage.md CHANGED
@@ -143,5 +143,8 @@ needed gem to that bundle too.
143
143
 
144
144
  ## Exit status
145
145
 
146
- The command exits with 0 on success, 1 for lookup or usage errors and 130 when
147
- interrupted. A closed output pipe is a normal exit.
146
+ The command exits with 0 on success, 1 for any failure and 130 when
147
+ interrupted. A closed output pipe is a normal exit, and so is a name that RDoc
148
+ answers with similar names or with the pages of its source. While a pager is
149
+ open, Ctrl-C belongs to the pager; at the interactive prompt it ends the session
150
+ with status 0.
data/lib/rich_ri/ansi.rb CHANGED
@@ -18,6 +18,7 @@ module RichRI
18
18
  # Documentation may contain literal terminal controls. Show them as text;
19
19
  # only styles produced by this reader may reach the terminal as escapes.
20
20
  def self.sanitize(text)
21
+ text = text.dup.force_encoding(Encoding::UTF_8) unless text.encoding == Encoding::UTF_8 || text.ascii_only?
21
22
  text.gsub(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f\u0080-\u009f\u202a-\u202e\u2066-\u2069]|\r(?!\n)/) do |char|
22
23
  format("\\u%04x", char.ord)
23
24
  end
data/lib/rich_ri/bat.rb CHANGED
@@ -37,7 +37,7 @@ module RichRI
37
37
  completed = false
38
38
  writer = Thread.new { write(input, text) }
39
39
  Timeout.timeout(@timeout) do
40
- result = output.read(@max_output + 1).to_s
40
+ result = output.read(@max_output + 1) || +""
41
41
  next if result.bytesize > @max_output
42
42
 
43
43
  writer.value
data/lib/rich_ri/cli.rb CHANGED
@@ -32,31 +32,39 @@ module RichRI
32
32
  0
33
33
  rescue Errno::EPIPE
34
34
  0
35
- rescue OptionParser::ParseError, ArgumentError, RDoc::Error, TypeError, LoadError, SystemCallError => e
36
- if (dependency = optional_dependency(e))
35
+ rescue OptionParser::ParseError, ArgumentError, RDoc::Error, TypeError, LoadError, SystemCallError, RegexpError => e
36
+ report(e)
37
+ rescue StandardError => e
38
+ warn "rich-ri: #{e.class}: #{RichRI.sanitize(e.message)}"
39
+ 1
40
+ rescue Interrupt
41
+ 130
42
+ end
43
+
44
+ private
45
+
46
+ def report(error)
47
+ if (dependency = optional_dependency(error))
37
48
  warn "rich-ri: --#{dependency == 'webrick' ? 'server' : 'profile'} requires the optional #{dependency} gem.\n" \
38
49
  "Install it for your active Ruby: gem install #{dependency}"
39
- elsif incompatible_cache?(e)
50
+ elsif incompatible_cache?(error)
40
51
  warn "rich-ri: incompatible RI cache format for this Ruby and RDoc.\n" \
41
52
  "Regenerate the documentation with your current Ruby and RDoc. For gems: gem rdoc GEM_NAME --ri.\n" \
42
53
  "For Ruby core documentation, see https://github.com/hvpaiva/rich-ri/blob/main/docs/troubleshooting.md"
43
54
  else
44
- warn "rich-ri: #{RichRI.sanitize(e.message)}\nRun rich-ri --help for usage."
55
+ warn "rich-ri: #{RichRI.sanitize(error.message)}\nRun rich-ri --help for usage."
45
56
  end
46
57
  1
47
- rescue Interrupt
48
- 130
49
58
  end
50
59
 
51
- private
52
-
53
60
  def optional_dependency(error)
54
61
  error.path if error.is_a?(LoadError) && %w[profile webrick].include?(error.path)
55
62
  end
56
63
 
57
64
  def incompatible_cache?(error)
58
65
  (error.is_a?(TypeError) && error.message.match?(/class RDoc::Markup::\w+ not a struct/)) ||
59
- (error.is_a?(ArgumentError) && error.message == "dump format error")
66
+ (error.is_a?(ArgumentError) &&
67
+ (error.message == "dump format error" || error.message.start_with?("undefined class/module RDoc::")))
60
68
  end
61
69
 
62
70
  def color?(mode)
@@ -102,7 +110,7 @@ module RichRI
102
110
  previous_pager = ENV.fetch("RI_PAGER", nil)
103
111
  ENV["RI_PAGER"] = command if command
104
112
  previous = ENV.fetch("LESS", nil)
105
- ENV["LESS"] = "#{previous || '-Fi'} -R"
113
+ ENV["LESS"] = "-R #{previous || '-Fi'}"
106
114
  yield
107
115
  ensure
108
116
  ENV["LESS"] = previous
@@ -42,7 +42,7 @@ module RichRI
42
42
  end
43
43
 
44
44
  def self.text!(value, name)
45
- if value.is_a?(String) && !value.strip.empty? && RichRI.sanitize(value) == value && !value.match?(/[\r\n\t]/)
45
+ if value.is_a?(String) && !value.strip.empty? && RichRI.sanitize(value).b == value.b && !value.match?(/[\r\n\t]/)
46
46
  return
47
47
  end
48
48
 
@@ -73,7 +73,7 @@ module RichRI
73
73
  def read_file
74
74
  raise ArgumentError, "Configuration is not a readable regular file: #{@path}" unless File.file?(@path)
75
75
 
76
- content = File.read(@path, MAX_BYTES + 1)
76
+ content = File.read(@path, MAX_BYTES + 1).to_s
77
77
  raise ArgumentError, "Configuration exceeds #{MAX_BYTES} bytes: #{@path}" if content.bytesize > MAX_BYTES
78
78
 
79
79
  stream = Psych.parse_stream(content, filename: @path)
@@ -47,7 +47,20 @@ module RichRI
47
47
  end
48
48
 
49
49
  def page
50
- super { |io| yield(@list && !@formatter_klass ? ListOutput.new(io) : io) }
50
+ interrupt = nil
51
+ super do |io|
52
+ interrupt = trap("INT", "IGNORE") if paging?
53
+ yield(@list && !@formatter_klass ? ListOutput.new(io) : io)
54
+ end
55
+ ensure
56
+ trap("INT", interrupt) if interrupt
57
+ end
58
+
59
+ def expand_name(name)
60
+ super
61
+ rescue RegexpError
62
+ # RDoc builds a pattern from the name without escaping it.
63
+ raise NotFoundError, name
51
64
  end
52
65
 
53
66
  def start_server
@@ -76,7 +89,8 @@ module RichRI
76
89
  next if (store.cache[:pages] || []).empty?
77
90
 
78
91
  source = store.type == :gem ? store.source.sub(/-\d[^-]*\z/, "") : store.source
79
- candidates << "#{source}:" if source.start_with?(name)
92
+ # RubyGems reports its directories as binary strings, which Reline refuses to offer.
93
+ candidates << "#{source}:".force_encoding(Encoding::UTF_8) if source.start_with?(name)
80
94
  end
81
95
  end
82
96
  candidates.uniq.sort
@@ -26,7 +26,7 @@ module RichRI
26
26
  shell_session(text) || other_language(text, format, theme: @shell_theme)
27
27
  elsif SESSION_FORMATS.include?(format)
28
28
  shell_session(text) || text
29
- elsif %i[c cpp javascript js json yaml yml diff sql rbs].include?(format)
29
+ elsif %i[c cpp javascript js json yaml yml diff sql].include?(format)
30
30
  other_language(text, format)
31
31
  else
32
32
  text
data/lib/rich_ri/theme.rb CHANGED
@@ -35,7 +35,8 @@ module RichRI
35
35
  @name = name.dup.freeze
36
36
  @depth = (depth == "auto" ? self.class.detect_depth(env) : depth).dup.freeze
37
37
  @styles = COLORS.dup
38
- apply_styles(PALETTES.fetch(name, {}))
38
+ # Sixteen colors cannot tell the shades of a preset apart; the terminal's own palette can.
39
+ apply_styles(PALETTES.fetch(name, {})) unless @depth == "basic"
39
40
  apply_styles(styles)
40
41
  @styles.transform_values!(&:freeze)
41
42
  @styles.freeze
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RichRI
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/man/man1/rich-ri.1 CHANGED
@@ -1,4 +1,4 @@
1
- .TH RICH-RI 1 "" "rich-ri 0.1.0" "User Commands"
1
+ .TH RICH-RI 1 "" "rich-ri 0.1.1" "User Commands"
2
2
  .SH NAME
3
3
  rich-ri - readable, colorful Ruby documentation
4
4
  .SH SYNOPSIS
@@ -151,7 +151,6 @@ Show this help.
151
151
  .TP
152
152
  .B \-v, \-\-version
153
153
  Show the rich\-ri version.
154
- .SS Style roles
155
154
  .SH EXAMPLES
156
155
  .nf
157
156
  rich\-ri Array#map
@@ -187,7 +186,8 @@ broken file. Use --no-config to bypass it for other commands.
187
186
  .TP
188
187
  .B theme
189
188
  terminal (default), dark or light. Presets change foreground colors;
190
- they do not detect or set the terminal background.
189
+ they do not detect or set the terminal background. With basic color depth
190
+ dark and light keep the terminal palette.
191
191
  .TP
192
192
  .B color
193
193
  auto (default), always or never. Auto colors only terminal output, unless
@@ -411,7 +411,7 @@ bat comes from PATH; its configuration file is disabled.
411
411
  bat calls have a two-second deadline, a 1 MiB input limit and an 8 MiB output limit.
412
412
  Failed or invalid output leaves the original text and disables bat for the rest of the page.
413
413
  .SH EXIT STATUS
414
- 0: success (including a closed output pipe); 1: lookup or usage failure;
414
+ 0: success (including a closed output pipe); 1: any failure;
415
415
  130: interrupted.
416
416
  .SH SEE ALSO
417
417
  ri(1), ruby(1), less(1), bat(1)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rich-ri
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Highlander Paiva