Reputation: 498
I have searched several questions/answers/blogs without success. How to remove/delete duplicate commands from irb history?
Ideally I want to have the same behavior I configured for my bash. That is: after I execute a command every other entry in the history with the exactly same command is deleted.
But it would already be good to eliminate duplicates when I close irb.
My current .irbrc
:
require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
IRB.conf[:AUTO_INDENT] = true
Note: Ruby 2.4.1 (or newer!)
Upvotes: 2
Views: 533
Reputation: 1014
An AT_EXIT
hook is a perfectly acceptable way to do this. Though monkey patching is not needed. IRB provides facilities for doing this by creating your own input method.
IRB gets its input from an InputMethod
. History is provided by the
ReadlineInputMethod
, which is a subclass.
InputMethod
s are attached to a Context
. Entering conf
in an irb
session will give you access to the current context.
irb
will read input according to the current context's io
. For example:
irb [2.4.0] (screenstaring.com)$ conf.io
=> #<HistoryInputMethod:0x007fdc3403e180 @file_name="(line)", @line_no=3, @line=[nil, "4317.02 - 250 \n", "conf.id\n", "conf.io\n"], @eof=false, @stdin=#<IO:fd 0>, @stdout=#<IO:fd 1>, @prompt="irb [2.4.0] (screenstaring.com)$ ", @ignore_settings=[], @ignore_patterns=[]>
Uses my Bash-like history control class (for more info see below).
You can set conf.io
to anything that conforms to the InputMethod
interface:
conf.io = MyInputMethod.new
Whatever MyInputMethod#gets
returns will be evaluated by IRB. Typically it reads from stdin
.
To tell IRB to use your InputMethod
at startup you can set the :SCRIPT
config option:
# .irbrc
IRB.conf[:SCRIPT] = MyInputMethod.new
IRB will use :SCRIPT
's value as input method when creating a Context
. This can be set to a file to use its contents as the input method.
By default it's nil
, which results in stdin
being used (via Readline
, if it's available).
To create an input method that ignores duplicates override ReadlineInputMethod#gets
:
class MyInputMethod < IRB::ReadlineInputMethod
def gets
line = super # super adds line to HISTORY
HISTORY.pop if HISTORY[-1] == HISTORY[-2]
line
end
end
The InputMethod
defined in my .irbrc
allows one to set IRB_HISTCONTROL
or IRB_HISTIGNORE
like you would (more or less) for Bash:
IRB_HISTIGNORE=ignoreboth IRB_HISTCONTROL='\Aq!:foo' irb
This does the following:
q!
(a custom method of mine) or containing foo
will not be added to historyUpvotes: 2
Reputation: 498
This will eliminate duplicates after closing IRB console. But it works only for IRBs using Readline
(mac users warned).
# ~/.irbrc
require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
deduplicate_history = Proc.new do
history = Readline::HISTORY.to_a
Readline::HISTORY.clear
history.reverse!.uniq!
history.reverse!.each{|entry| Readline::HISTORY << entry}
end
IRB.conf[:AT_EXIT].unshift(deduplicate_history)
And this monkey patch will eliminate duplicates on the fly if your IRB is using Readline
:
require 'irb/ext/save-history'
IRB.conf[:SAVE_HISTORY] = 1000
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb_history"
class IRB::ReadlineInputMethod
alias :default_gets :gets
def gets
if result = default_gets
line = result.chomp
history = HISTORY.to_a
HISTORY.clear
history.each{|entry| HISTORY << entry unless entry == line}
HISTORY << line
end
result
end
end
Any suggestion on how to improve it?
Upvotes: 0