Skip to content

Instantly share code, notes, and snippets.

@sushant12
Last active June 19, 2024 09:39
Show Gist options
  • Save sushant12/38c8e01ab7a3673ca45abe82d1ffe3c0 to your computer and use it in GitHub Desktop.
Save sushant12/38c8e01ab7a3673ca45abe82d1ffe3c0 to your computer and use it in GitHub Desktop.
list or search through your iex history
# 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
@sushant12
Copy link
Author

sushant12 commented Feb 19, 2022

@eksperimental

have you consider the possibility of having this as a repository?

Yes, I did think about it but I could not convince myself regarding its usefulness as a package.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment