Last active
June 19, 2024 09:39
-
-
Save sushant12/38c8e01ab7a3673ca45abe82d1ffe3c0 to your computer and use it in GitHub Desktop.
list or search through your iex history
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The bash command `history | grep abc` is a neat tool. I abuse it alot. | |
# So, I wrote a module that would list or search through iex history. | |
# https://dev.to/sushant12/list-all-history-in-iex-408b | |
# I prefer to put this module in my .iex.exs file and then import the .iex.exs file into my project. | |
defmodule History do | |
def search do | |
load_history() | |
|> Enum.with_index(1) | |
|> Enum.each(fn {value, index} -> | |
IO.write("#{index} #{value}") | |
end) | |
end | |
def search(term) do | |
load_history() | |
|> Enum.filter(&String.match?(&1, ~r/#{term}/)) | |
|> Enum.with_index(1) | |
|> Enum.each(fn {value, index} -> | |
IO.write("#{index} ") | |
IO.write(String.replace(value, term, "#{IO.ANSI.red()}#{term}#{IO.ANSI.default_color()}")) | |
end) | |
end | |
def search(term, opts) do | |
history = load_history() | |
history_count = Enum.count(history) | |
history | |
|> get_match_indices(term) | |
|> maybe_add_contexts(opts, history_count) | |
|> group_ranges() | |
|> Enum.each(fn range_list -> | |
parse_range(range_list) | |
|> Enum.each(fn match_index -> | |
if match_index < history_count do | |
txt = Enum.at(history, match_index) | |
IO.write("#{match_index} ") | |
IO.write(String.replace(txt, term, "#{IO.ANSI.red()}#{term}#{IO.ANSI.default_color()}")) | |
end | |
end) | |
IO.write("#{IO.ANSI.red()}--- #{IO.ANSI.default_color()} \n") | |
end) | |
end | |
defp group_ranges([head | rest]) do | |
Enum.reduce(rest, {head, [], []}, fn current, {prev, group, grouped} -> | |
if Range.disjoint?(current, prev) do | |
{current, [current], [Enum.reverse(group) | grouped]} | |
else | |
{current, [current | group], grouped} | |
end | |
end) | |
|> elem(2) | |
|> Enum.reverse() | |
end | |
defp get_match_indices(history, term) do | |
history | |
|> Enum.with_index() | |
|> Enum.flat_map(fn {element, index} -> | |
case String.match?(element, ~r/#{term}/) do | |
true -> [index] | |
false -> [] | |
end | |
end) | |
end | |
defp maybe_add_contexts(match_indices, opts, history_count) do | |
context_a = Keyword.get(opts, :A, 0) | |
context_b = Keyword.get(opts, :B, 0) | |
match_indices | |
|> Enum.map(fn index -> | |
upper_bound(index, context_b)..lower_bound(index, context_a, history_count) | |
end) | |
end | |
defp upper_bound(index, 0), do: index | |
defp upper_bound(index, context_b) do | |
potential_index = index - context_b | |
if potential_index < 0 do | |
0 | |
else | |
potential_index | |
end | |
end | |
defp lower_bound(index, 0, _), do: index | |
defp lower_bound(index, context_a, history_count) do | |
potential_index = index + context_a | |
if potential_index > history_count do | |
history_count | |
else | |
potential_index | |
end | |
end | |
defp parse_range(range_list) do | |
Enum.map(range_list, &Enum.to_list/1) | |
|> List.flatten() | |
|> Enum.uniq() | |
end | |
defp load_history do | |
:group_history.load() | |
|> Enum.map(&List.to_string/1) | |
|> Enum.reverse() | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@eksperimental
Yes, I did think about it but I could not convince myself regarding its usefulness as a package.