-
-
Save sushant12/38c8e01ab7a3673ca45abe82d1ffe3c0 to your computer and use it in GitHub Desktop.
| # 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 |
I think an options argument being it a keyword list is the best aproach.
History.search("Repo", A: 5)
Also if you make an alias named history/2 that resolves to search/2,
we can add it as a helper in an .iexs files.
import History
iex> history "Enum.reduce", C: 5acknowledged. I will implement this and I will ping back when I am done with one of the flag. π¨βπ»
finished implementing for -A flag. I will add the new changes here after I am done with some code changes. βοΈ
My apologies for updating you about the progress after months. Life just happened so I couldn't focus.
I have finally finished adding contexts to History.search/2 and please note that I didn't add the -C flag because I got too damn lazy π
You can now use it like this
History.search("Repo.get!", A: 2, B: 2)
Awesome.
I will use it and get back to you.
BTW, have you consider the possibility of having this as a repository? I will be easier to contribute to, and maybe release it as an Elixir package.
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.
@eksperimental I have went through the docs for those flags and I found those flags to be very useful.
Do you think this approach is okay?
History.search("Repo", "-A 5")I will then pattern match on the 2nd param like.
"-A " <> num,"-B" <> numLet me know what you think of this.