You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
show_doc and the Alt+d documentation dialog shown by autocompletion are hard-wired to RDoc::RI::Driver. This proposes a small public extension point, a list of "document providers", so that other documentation backends (RI-compatible or not) can plug into the same UI without monkey-patching irb internals.
Motivation
irb currently has exactly one way to influence where documentation comes from: IRB.conf[:EXTRA_DOC_DIRS], which only adds more RI data directories. There is no way to serve documentation from a different format or source (a different language's manual, YARD-generated docs, RBS-embedded comments, a project-local doc store, etc.) through show_doc or the completion dialog.
Rurema (the Japanese Ruby reference manual) ships bitclust-irb, added in rurema/bitclust#326 (merged 2026-08-20, released in bitclust 1.7.0). Because there was no hook into show_doc, it had to register an entirely separate refe command through the public IRB::Command.register API instead of extending show_doc itself. A follow-up PR (rurema/bitclust#332) adds a fallback that searches docs.ruby-lang.org (its search index plus the Markdown pages) when no local database is present. Users have to remember two commands (show_doc for RI, refe for the Japanese manual) and only one of them gets the Alt+d dialog treatment.
A provider hook would let show_doc NAME and the completion dialog consult multiple backends in order, with RI as the default, so bitclust-irb (and similarly YARD's yri, or other translated manuals) could integrate directly instead of bolting on a parallel command.
require'rdoc/ri/driver'opts=RDoc::RI::Driver.process_args([])ShowDoc.const_set(:Ri,RDoc::RI::Driver.new(opts))
...
Ri.display_name(name)# or Ri.interactive when name is nil
and warns "Can't display document because rdoc is not installed." when rdoc can't be required.
lib/irb/input-method.rb (RelineInputMethod) independently drives the same backend for the Alt+d dialog:
rdoc_ri_driver builds an RDoc::RI::Driver.new(options), honoring IRB.conf[:EXTRA_DOC_DIRS].
retrieve_rdoc_document(name) calls driver.expand_name(name) then driver.add_method / driver.class_document to build an RDoc::Markup::Document.
rdoc_dialog_contents(name, width) renders that document with RDoc::Markup::ToAnsi for the popup.
display_document(matched) handles the Alt+d full-screen view: CommandDocument targets go through IRB::Command.load_command, MethodDocument targets go through the RI driver's display_names (or add_method + display when there are several candidate names, e.g. ambiguous receivers like {}.any?).
The whole dialog proc is only installed when require 'rdoc' succeeds (start in RelineInputMethod).
lib/irb/completion.rb supplies the names passed to the above. DocumentTarget, CommandDocument, and MethodDocument (MethodDocument#names can hold more than one name for an ambiguous receiver) came from #1180 ("Display command description in doc dialog on tab completion", merged 2026-03-13); rdoc_error_document for failed lookups was added by #1229 ("Keep completion alive when RDoc document retrieval fails", 2026-07-16). The names themselves are RI-style: the regexp completor emits things like "String.gsub" (a dot even for instance methods: RI's expand_name resolves it), "Array.new", or ["Hash.any?", "Proc.any?"] for an ambiguous {}.any?; the type-based completor gets the same shape from ReplTypeCompletor#doc_namespace. show_doc itself accepts anything RI accepts (Array, Array#each, Array.new, Array::new).
Proposal
Add a small ordered registry of document providers, defaulting to just the existing RDoc/RI behavior so nothing changes out of the box:
IRB.doc_providers# => [IRB::RDocDocumentProvider.new]IRB.doc_providers.unshift(MyProvider.new)# e.g. in ~/.irbrc; earlier providers win
(An alternative shape would be IRB.conf[:DOC_PROVIDERS], consistent with EXTRA_DOC_DIRS; either works, but a plain array with push/unshift seems simpler to use and to reason about ordering with.)
A provider is a duck type, no base class required:
classMyProvider# name is whatever show_doc / the completor already produce today (RI-style# names such as "String#gsub", "String.gsub", "Array.new", "Array"). Return# a String to be shown via IRB::Pager, or nil if this provider has nothing# for the name, so the next provider gets a chance.defdocument(name)end# Optional. A short preview for the completion dialog: an array of lines# that fit within `width` columns (ANSI escapes allowed). Return nil to# skip the dialog for this name. Providers may omit this method entirely.defdialog_contents(name,width)endend
Resolution: providers are asked in order, and the first non-nil document/dialog_contents result wins. show_doc with no argument would keep starting RI's interactive session directly (providers are not consulted for that case, since "interactive" is RI-specific). When no provider returns anything, today's "not found" / "rdoc not installed" messages are kept.
The built-in IRB::RDocDocumentProvider would just be the existing code moved behind this interface: document wrapping Ri.display_name (captured instead of printed directly), dialog_contents wrapping retrieve_rdoc_document + RDoc::Markup::ToAnsi. So most of this is a refactor, not new behavior. A MethodDocument with multiple candidate names (ambiguous receivers) can be handled by calling document/dialog_contents once per name and combining, same as display_document does today with driver.add_method in a loop.
Sketch of ShowDoc#execute after the change, just to illustrate the shape (not final):
defexecute(arg)name=unwrap_string_literal(arg)ifname.nil?# unchanged: still delegates straight to RI's interactive sessionIRB::RDocDocumentProvider.new.interactivereturnendIRB.doc_providers.eachdo |provider|
if(doc=provider.document(name))Pager.page_content(doc)returnendend# not found: keep today's messages (RI's "Nothing known about ...")end
With this in place, bitclust-irb could register a provider instead of a separate refe command, and show_doc String#gsub would show the Japanese manual page when available, falling back to RI.
Notes / open questions
Naming: IRB.doc_providers vs. IRB.conf[:DOC_PROVIDERS], and the provider method names (document/dialog_contents vs. something else), are open to bikeshedding.
Whether show_doc with no argument (RI's interactive mode) should also become pluggable, or stay RI-only as sketched above.
This is related to, but does not by itself solve, Consider letting help fall back to RI documentation #1242 ("Consider letting help fall back to RI documentation"): a provider abstraction would let help fall back to "documentation from some provider" rather than specifically RI, but that's a separate change to the help command.
Other plausible providers besides bitclust-irb: YARD's yri, RBS-embedded documentation, project-local documentation, or manuals translated into other languages.
I'm happy to send a PR implementing this if the direction looks acceptable to maintainers; bitclust-irb would be the first external consumer.
Summary
show_docand the Alt+d documentation dialog shown by autocompletion are hard-wired toRDoc::RI::Driver. This proposes a small public extension point, a list of "document providers", so that other documentation backends (RI-compatible or not) can plug into the same UI without monkey-patching irb internals.Motivation
irb currently has exactly one way to influence where documentation comes from:
IRB.conf[:EXTRA_DOC_DIRS], which only adds more RI data directories. There is no way to serve documentation from a different format or source (a different language's manual, YARD-generated docs, RBS-embedded comments, a project-local doc store, etc.) throughshow_docor the completion dialog.Rurema (the Japanese Ruby reference manual) ships
bitclust-irb, added in rurema/bitclust#326 (merged 2026-08-20, released in bitclust 1.7.0). Because there was no hook intoshow_doc, it had to register an entirely separaterefecommand through the publicIRB::Command.registerAPI instead of extendingshow_docitself. A follow-up PR (rurema/bitclust#332) adds a fallback that searches docs.ruby-lang.org (its search index plus the Markdown pages) when no local database is present. Users have to remember two commands (show_docfor RI,refefor the Japanese manual) and only one of them gets the Alt+d dialog treatment.A provider hook would let
show_doc NAMEand the completion dialog consult multiple backends in order, with RI as the default, sobitclust-irb(and similarly YARD'syri, or other translated manuals) could integrate directly instead of bolting on a parallel command.Current implementation
lib/irb/command/show_doc.rb(ShowDoc#execute) always does:and warns
"Can't display document becauserdocis not installed."whenrdoccan't be required.lib/irb/input-method.rb(RelineInputMethod) independently drives the same backend for the Alt+d dialog:rdoc_ri_driverbuilds anRDoc::RI::Driver.new(options), honoringIRB.conf[:EXTRA_DOC_DIRS].retrieve_rdoc_document(name)callsdriver.expand_name(name)thendriver.add_method/driver.class_documentto build anRDoc::Markup::Document.rdoc_dialog_contents(name, width)renders that document withRDoc::Markup::ToAnsifor the popup.display_document(matched)handles the Alt+d full-screen view:CommandDocumenttargets go throughIRB::Command.load_command,MethodDocumenttargets go through the RI driver'sdisplay_names(oradd_method+displaywhen there are several candidate names, e.g. ambiguous receivers like{}.any?).require 'rdoc'succeeds (startinRelineInputMethod).lib/irb/completion.rbsupplies the names passed to the above.DocumentTarget,CommandDocument, andMethodDocument(MethodDocument#namescan hold more than one name for an ambiguous receiver) came from #1180 ("Display command description in doc dialog on tab completion", merged 2026-03-13);rdoc_error_documentfor failed lookups was added by #1229 ("Keep completion alive when RDoc document retrieval fails", 2026-07-16). The names themselves are RI-style: the regexp completor emits things like"String.gsub"(a dot even for instance methods: RI'sexpand_nameresolves it),"Array.new", or["Hash.any?", "Proc.any?"]for an ambiguous{}.any?; the type-based completor gets the same shape fromReplTypeCompletor#doc_namespace.show_docitself accepts anything RI accepts (Array,Array#each,Array.new,Array::new).Proposal
Add a small ordered registry of document providers, defaulting to just the existing RDoc/RI behavior so nothing changes out of the box:
(An alternative shape would be
IRB.conf[:DOC_PROVIDERS], consistent withEXTRA_DOC_DIRS; either works, but a plain array with push/unshift seems simpler to use and to reason about ordering with.)A provider is a duck type, no base class required:
Resolution: providers are asked in order, and the first non-nil
document/dialog_contentsresult wins.show_docwith no argument would keep starting RI's interactive session directly (providers are not consulted for that case, since "interactive" is RI-specific). When no provider returns anything, today's "not found" / "rdoc not installed" messages are kept.The built-in
IRB::RDocDocumentProviderwould just be the existing code moved behind this interface:documentwrappingRi.display_name(captured instead of printed directly),dialog_contentswrappingretrieve_rdoc_document+RDoc::Markup::ToAnsi. So most of this is a refactor, not new behavior. AMethodDocumentwith multiple candidate names (ambiguous receivers) can be handled by callingdocument/dialog_contentsonce per name and combining, same asdisplay_documentdoes today withdriver.add_methodin a loop.Sketch of
ShowDoc#executeafter the change, just to illustrate the shape (not final):With this in place,
bitclust-irbcould register a provider instead of a separaterefecommand, andshow_doc String#gsubwould show the Japanese manual page when available, falling back to RI.Notes / open questions
IRB.doc_providersvs.IRB.conf[:DOC_PROVIDERS], and the provider method names (document/dialog_contentsvs. something else), are open to bikeshedding.show_docwith no argument (RI's interactive mode) should also become pluggable, or stay RI-only as sketched above.helpfall back to "documentation from some provider" rather than specifically RI, but that's a separate change to thehelpcommand.bitclust-irb: YARD'syri, RBS-embedded documentation, project-local documentation, or manuals translated into other languages.bitclust-irbwould be the first external consumer.Related
DocumentTarget/CommandDocument/MethodDocumentinlib/irb/completion.rb.rdoc_error_documentfor failed RDoc lookups.helpto fall back to RI docs; a provider hook is related but doesn't itself implement that fallback.bitclust-irbgem, which today registers a separaterefecommand because there is noshow_docextension point.日本語要約
show_docコマンドおよび自動補完の Alt+d ドキュメントダイアログはRDoc::RI::Driverに直結しており、他のドキュメント源(翻訳マニュアルや YARD など)を差し込む手段がありません。本 issue は、RI をデフォルトとしつつ外部の「ドキュメントプロバイダ」を登録できる小さな公開フック(IRB.doc_providers案)を提案します。rurema 側では bitclust-irb(rurema/bitclust#326)が該当フックの不在によりやむを得ず別コマンドrefeを登録している経緯があり、本提案が採用されればshow_docから直接日本語マニュアルを引けるようになります。実装の方向性が受け入れられるなら PR を送る用意があります。🤖 Generated with Claude Code