ding-an-sich / history

An improved history for the Elixir IEx shell

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

history

Saves shell history and optionally variable bindings between shell sessions.

Allows the user to display history, and re-issue historic commands, made much easier since the variable bindings are saved.

Some screen shots can be found here: Images

For ease History can be enabled in ~/.iex.exs for example:

Code.append_path("~/github/history/_build/dev/lib/iex_history/ebin")
History.initialize(history_limit: 200, scope: :local, show_date: true, colors: [index: :red])

Of course Code.append_path may not be required depending on how the project is imported.

The following options can be set:

[
  scope: :local,
  history_limit: :infinity,
  hide_history_commands: true,
  prepend_identifiers: true,
  command_display_width: int,
  save_invalid_results: false,
  key_buffer_history: true,
  show_date: true,
  save_bindings: true,
  colors: [
    index: :red,
    date: :green,
    command: :yellow,
    label: :red,
    variable: :green
  ]
]

:hide_history_commands This will prevent all calls to History.* from been saved.

NOTE: History.x/1 is always hidden. Scope of :global will only hide them from output, otherwise they will not be saved.

:save_invalid_results If set to false, the default, commands that were evaluated incorrectly will not be saved.

:key_buffer_history If set to true will allow the user to scroll up (ctrl+u) or down (ctrl+k) through history. Unlike the standard up/down arrow history this is command based not line based. So pasting of a large structure will only require 1 up or down. This mechanism also saves commands that were not properly evaluated; however there is a buffer limit of 75 lines, although this can be changed by updating @history_buffer_size in events_server.ex. This will also not duplicate back to back identical commands.

:prepend_identifiers If this is enabled it will prepend identifiers when a call to x = History(val) is issued.

For example:

    enabled:
        iex> time = Time.utc_now().second
        14
        iex> new_time = History.x(1)
        22

        iex> new_time
        22                  # New time is assigned to variable time
        iex> time
        13                  # However, the original date variable is unchanged

        iex> History.h()
        1: 2021-09-01 17:13:13: time = Time.utc_now().second
        2: 2021-09-01 17:13:22: new_time =  time = Time.utc_now().second    # We see the binding to new_time

      disabled:
        iex> time = Time.utc_now().second
        43
        iex> new_time = History.x(1)
        50

        iex> new_time       # New time is assigned to variable time
        50
        iex> time
        50                  # However, this time the original time variable has also changed

        iex> History.h
        1: 2021-09-01 17:17:43: time = Time.utc_now().second
        2: 2021-09-01 17:17:50: time = Time.utc_now().second      # We do not see the binding to new_time

:scope can be one of :local, :global or a node() name

If scope is :local (the default) history will be active on all shells, even those that are remotely connected, but the history for each shell will be unique

If scope is node() (e.g. :mgr@localhost) history will only be active on that shell

If scope is :global history will be shared between all shells. However the saving of variable bindings will be disabled along with the date/time in history

Furthermore, if a scope of :global is selected following kernel option must be set, either directly as VM options or via an environment variable:

    export ERL_AFLAGS="-kernel shell_history enabled"

    --erl "-kernel shell_history enabled"

A word about aliases. Rather than using something like alias History, as: H, please use History.alias(H) instead.

Functions

History.h()

Displays the entire history.

    iex> History.h()
    1: 2021-09-01 17:29:27: time = Time.utc_now().second
    2: 2021-09-01 17:29:31: time = Time.utc_now().second
    3: 2021-09-01 17:29:36: time
    4: 2021-09-01 17:29:41: new_time
    5: 2021-09-01 17:50:10: Process.info self
    6: 2021-09-01 17:50:33: r = o
    7: 2021-09-01 17:52:36: Process.get(:iex_history)

History.h(val)

If the argument is a string it displays the history that contain or match entirely the passed argument. If the argument is a positive integer it displays the command at that index. If the argument is a negative number it displays the history that many items from the end.

    iex> History.h(2)
    2: 2021-09-01 17:29:31: time = Time.utc_now().second
    
    iex> History.h("Applic")
    34: 2021-09-01 18:10:39: Application.put_env(:kernel, :shell_history, :disabled)
    41: 2021-09-01 18:11:30: Application.get_env(:kernel, :shell_history)
    48: 2021-09-01 18:14:02: Application.put_env(:kernel, :shell_history, 0)
    101: 2021-09-01 19:01:15: :rpc.call(:erlang.node(Process.group_leader()), Application, :put_env, [:kernel, :shell_history, :disabled])
    103: 2021-09-01 19:01:30: :rpc.call(:erlang.node(Process.group_leader()), Application, :put_env, [:kernel, :shell_history, :enabled])
    
    iex> History.h(-3)
    5: 2021-09-01 17:50:10: Process.info self
    6: 2021-09-01 17:50:33: r = o
    7: 2021-09-01 17:52:36: Process.get(:iex_history)

History.h(start, stop)

Specify a range, the atoms :start and :stop can also be used.

History.x(idx)

Invokes the command at index 'i'.

    iex> History.h(114)
    114: 2021-09-01 19:30:14: Enum.count([1, 2, 3])
    
    iex> History.x(114)
    3

History.c(idx)

Copies the command at index 'i' and pastes it to the shell.

    iex> History.h(114)
    114: 2021-09-01 19:30:14: Enum.count([1, 2, 3])
    
    iex> History.c(114)
    :ok
    iex> Enum.count([1, 2, 3])

History.initialize(opts)

Initializes the History app. Takes the following parameters:

      [
        scope: :local,
        history_limit: :infinity,
        prepend_identifiers: true,
        show_date: true,
        save_invalid_results: false,
        key_buffer_history: true,
        save_bindings: true,
        colors: [
          index: :red,
          date: :green,
          command: :yellow,
          label: :red,
          variable: :green
        ]
      ]

History.state()

Displays the current state:

    History version 4.0 is 
    enabled:
      Current history is 199 commands in size.
      Current bindings are 153 variables in size.

History.clear()

Clears the history and bindings. If scope is :global the IEx session needs restarting for the changes to take effect.

History.clear_history(range)

Clears the history only, if no argument all history is cleared, else history from 1 to value is cleared

History.clear_bindings()

Clears bindings only

History.unbind(vars)

Unbinds a variable or list of variables, varibales should be expressed as atoms

History.stop_clear()

Clears the history and bindings then stops the service. If scope is :global the IEx session needs restarting for the changes to take effect.

History.configuration()

Displays the current conifuration

History.save_config(filename)

Saves the configuration to filename

History.load_config(filename)

Loads the configuration from filename. NOTE: All changes may not be applied, to do this specify the filename in History.initialize/1 instead of a config keyword list

History.configure/2

Allows the following options to be changed, but not saved:

    :show_date
    :history_limit
    :hide_history_commands,
    :prepend_identifiers,
    :command_display_width,
    :save_invalid_results,
    :key_buffer_history,
    :save_bindings,
    :colors

Examples:

    History.configure(:colors, [index: :blue])
    History.configure(:prepend_identifiers, true)

History.get_bindings()

Displays the current shell bindings.

History.is_enabled?()

Returns true or false is History is enabled

History.alias/1

If you want to setup an alias like alias History, as: H, rather than using alias/2 from the shell, please use this function instead. So to create an alias of H use History.alias(H). This allows aliased functions to be handled correctly.

About

An improved history for the Elixir IEx shell

License:MIT License


Languages

Language:Elixir 100.0%