Skip to content

Commit

Permalink
Version 5.4 (#14)
Browse files Browse the repository at this point in the history
* Permit standard up/down arrow keys

* Permit standard up/down arrow keys

* Permit standard up/down arrow keys

* Update README.md

* Permit standard up/down arrow keys

---------

Co-authored-by: nhpip <nhpip@github.com>
  • Loading branch information
nhpip and nhpip authored Feb 8, 2024
1 parent 0a09ef5 commit c1c6211
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 53 deletions.
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,44 @@ The default navigation keys are defined below. They can however be configured to
ctrl^[ - Reset navigation, returns to the prompt.
```
NOTE: To use `ctrl^l` the environment variable EDITOR must be set to point to your editor:
### Text Editor
To use `ctrl^l` the environment variable EDITOR must be set to point to your editor:
```
export EDITOR="vim"
```

### Standard Arrow Keys

If you want to use the regular up / down arrow (and backspace) keys:

1. Create the following file in your `HOME` directory:
```
~/.erlang_keymap.config
```
```
[{stdlib,
[{shell_keymap,
\#{ normal => \#{ "\\e\[A" => none, "\\e\[B" => none } }
}]
}].
```

2. Set the following environment variable:
```
ERL_FLAGS='-config $HOME/.erlang_keymap.config'
```
3. Add the following to `IExHistory2` configuration:
```
standard_arrow_keys: true
```
or
```
IExHistory2.initialize(standard_arrow_keys: true, ....)
```

4. Restart your VM

## Shortcut Search and Edit Functions
Key history navigation functions are automatically imported into the shell.
```
Expand Down
112 changes: 84 additions & 28 deletions lib/iex_history2.ex
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,60 @@ defmodule IExHistory2 do
export EDITOR="vim"
### Examples
## Navigation Keys
The application uses a different set of keys for navigation, and attempts to present multi-line
terms and other items as a single line:
ctrl^u (21) - move up through history (see below).
ctrl^k (11) - move down through history (see below).
ctrl^h (08) - allows the currently displayed item to be modified.
ctrl^l (12) - opens the currently displayed item in an editor.
ctrl^[ (27) - reset navigation, returns to the prompt.
### Text Editor
To use `ctrl^l` the environment variable `EDITOR` must be set to your editor of choice:
export EDITOR=vim
### Standard Arrow Keys
If you want to use the regular up / down arrow (and backspace) keys:
1. Create the following file in your `HOME` directory:
```
~/.erlang_keymap.config
```
```
[{stdlib,
[{shell_keymap,
\#{ normal => \#{ "\\e\[A" => none, "\\e\[B" => none } }
}]
}].
```
2. Set the following environment variable:
```
ERL_FLAGS='-config $HOME/.erlang_keymap.config'
```
3. Add the following to `IExHistory2` configuration:
```
standard_arrow_keys: true
```
or
```
IExHistory2.initialize(standard_arrow_keys: true, ....)
```
4. Restart your VM
## Examples
Simple listing of last 9 items:
Expand Down Expand Up @@ -158,23 +211,6 @@ defmodule IExHistory2 do
See also `IExHistory2.register/1`.
## Navigation
The application uses a different set of keys for navigation, and attempts to present multi-line
terms and other items as a single line:
ctrl^u (21) - move up through history.
ctrl^k (11) - move down through history.
ctrl^h (08) - allows the currently displayed item to be modified.
ctrl^l (12) - opens the currently displayed item in an editor.
ctrl^[ (27) - reset navigation, returns to the prompt.
**NOTE:** To use `ctrl^e` the environment variable `EDITOR` must be set to your editor:
## Configuration
The following options can be set either as a keyword list in `.iex.exs` (a sample file is
Expand Down Expand Up @@ -202,6 +238,7 @@ defmodule IExHistory2 do
abandon: 27,
enter: 13
],
standard_arrow_keys: false,
paste_eval_regex: ["#Reference", "#PID", "#Function", "#Ecto.Schema.Metadata", "#Port"],
prepend_identifiers: true,
save_bindings: true,
Expand Down Expand Up @@ -256,6 +293,10 @@ defmodule IExHistory2 do
navigation_keys: [editor: 5]
To use standard up/down arrow keys (see `Navigation Keys` above) set:
standard_arrow_keys: true
If this is enabled it will prepend identifiers when a call to `x = hx(val)` is issued.
prepend_identifiers: true
Expand Down Expand Up @@ -356,13 +397,15 @@ defmodule IExHistory2 do

@default_paste_eval_regex ["#Reference", "#PID", "#Function", "#Ecto.Schema.Metadata", "#Port"]

@history_up_key 21 # ctrl+u
@history_down_key 11 # ctrl+k
@history_up_key 21 # ctrl+u (try "\e[A" if overriding default)
@history_down_key 11 # ctrl+k (try "\e[B" if overriding default)
@editor_key 12 # ctrl+l
@modify_key 08 # ctrl+h
@abandon_key 27 # ctrl+[ or esc(ape)
@enter_key 13

@standard_arrow_keys [up: "\e[A", down: "\e[B", modify: "\d"]

@alive_prompt "%prefix(%node)%counter>"
@default_prompt "%prefix(%counter)>"

Expand All @@ -379,6 +422,7 @@ defmodule IExHistory2 do
scope: :local,
history_limit: :infinity,
hide_history_commands: true,
standard_arrow_keys: false,
prepend_identifiers: true,
show_date: true,
save_bindings: true,
Expand Down Expand Up @@ -409,7 +453,8 @@ defmodule IExHistory2 do
show_date: true,
import: true,
paste_eval_regex: [],
navigation_keys: [up: 21, down: 11, ...]
navigation_keys: [up: 21, down: 11, ...],
standard_arrow_keys: false,
save_bindings: true,
colors: [
index: :red,
Expand Down Expand Up @@ -534,10 +579,10 @@ defmodule IExHistory2 do
"""
def configuration() do
cfg = Process.get(:history_config, [])
nav_keys = Keyword.get(cfg, :navigation_keys)
|> Enum.map(fn {k, v} ->
<<nv::8>> = v
{k, nv}
nav_keys = Keyword.get(cfg, :navigation_keys, [])
|> Enum.map(fn
{k, v} when is_bitstring(v ) -> {k, to_string(v)}
kv -> kv
end)
Keyword.put(cfg, :navigation_keys, nav_keys)
|> Keyword.delete(:compiled_paste_eval_regex)
Expand Down Expand Up @@ -1128,7 +1173,13 @@ defmodule IExHistory2 do
colors = Keyword.get(config, :colors, @default_colors)
new_colors = Enum.map(@default_colors, fn {key, default} -> {key, Keyword.get(colors, key, default)} end)
custom_regex = Keyword.get(config, :paste_eval_regex, [])
new_keys = Keyword.get(config, :navigation_keys, @default_navigation_keys)
new_keys =
if Keyword.get(config, :standard_arrow_keys, false) do
Keyword.get(config, :navigation_keys, @default_navigation_keys)
|> Keyword.merge(@standard_arrow_keys)
else
Keyword.get(config, :navigation_keys, @default_navigation_keys)
end
config = Keyword.delete(config, :colors)

new_config =
Expand All @@ -1142,14 +1193,19 @@ defmodule IExHistory2 do
{key, default} -> {key, Keyword.get(config, key, default)}
end
) |> List.flatten()


new_config = if Keyword.get(config, :show_unmapped_keys, false),
do: Keyword.put(new_config, :show_unmapped_keys, true),
else: new_config
Process.put(:history_config, new_config)
new_config
end

defp make_navigation_keys(keys, new_keys) do
Keyword.merge(keys, new_keys)
|> Enum.map(fn {k, v} -> {k, <<v>>} end)
|> Enum.map(fn {k, v} when is_integer(v) -> {k, <<v>>}
kv -> kv
end)
end

defp compile_regex(regex) do
Expand Down
62 changes: 40 additions & 22 deletions lib/iex_history2/events_server.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ defmodule IExHistory2.Events.Server do
@trace_pattern [{{:_, :_, {:_, {:"$1", :_}}}, [{:orelse, {:==, :"$1", :data}, {:==, :"$1", :editor_data}}], []}]
@non_alphanumeric Regex.compile!("^[a-zA-Z0-9]+$")
@start_regex Regex.compile!("defmodule IExHistory2.Random(.*)XX do")

@default_modify 08 # ctrl-h

use GenServer
alias IExHistory2.Bindings

Expand Down Expand Up @@ -238,7 +239,8 @@ defmodule IExHistory2.Events.Server do
Enum.reduce(process_info, process_info, fn
{shell_pid, shell_config}, process_info when is_pid(shell_pid) ->
activity_queue = create_activity_queue(shell_config, true)
activity_pid = keystroke_activity_monitor(shell_parent_node, navigation)
unmapped_keys = Map.get(process_info, :show_unmapped_keys, false)
activity_pid = keystroke_activity_monitor(shell_parent_node, navigation, unmapped_keys)
Map.put(process_info, shell_pid, %{shell_config | queue: activity_queue, keystroke_monitor_pid: activity_pid})

_, process_info ->
Expand Down Expand Up @@ -413,7 +415,8 @@ defmodule IExHistory2.Events.Server do
store_count = IExHistory2.Store.open_store(store_name, shell_config.store_filename, scope, store_count)
Node.monitor(shell_config.node, true)
Process.monitor(shell_pid)
activity_pid = keystroke_activity_monitor(shell_parent_node, navigation)
unmapped_keys = Map.get(process_info, :show_unmapped_keys, false)
activity_pid = keystroke_activity_monitor(shell_parent_node, navigation, unmapped_keys)
:erlang.trace_pattern(:receive, @trace_pattern, [])
activity_queue = create_activity_queue(shell_config, key_buffer_history)
new_process_info = Map.put(process_info, shell_pid, %{shell_config | queue: activity_queue, keystroke_monitor_pid: activity_pid})
Expand All @@ -424,7 +427,7 @@ defmodule IExHistory2.Events.Server do
end
end

defp keystroke_activity_monitor(remote_node, navigation) do
defp keystroke_activity_monitor(remote_node, navigation, unmapped_keys) do
dest = self()
{mod, bin, _file} = :code.get_object_code(__MODULE__)
:rpc.call(remote_node, :code, :load_binary, [mod, :nofile, bin])
Expand All @@ -433,7 +436,9 @@ defmodule IExHistory2.Events.Server do
remote_node,
fn ->
:erlang.trace(Process.whereis(:user_drv), true, [:send, :receive])
do_keystroke_activity_monitor(dest, navigation)
:erlang.trace_pattern(:receive, @trace_pattern, [])
:erlang.trace_pattern(:send, @trace_pattern, [])
do_keystroke_activity_monitor(dest, navigation, unmapped_keys)
end
)
end
Expand All @@ -443,34 +448,42 @@ defmodule IExHistory2.Events.Server do
enter: enter,
editor: editor,
modify: modify,
abandon: abandon} = keys) do
abandon: abandon} = keys, unmapped_keys) do
receive do
{_, pid, :receive, {_, {:data, ^up}}} ->
send(dest, {:up_key, pid})
do_keystroke_activity_monitor(dest, keys)
do_keystroke_activity_monitor(dest, keys, unmapped_keys)

{_, pid, :receive, {_, {:data, ^down}}} ->
send(dest, {:down_key, pid})
do_keystroke_activity_monitor(dest, keys)
do_keystroke_activity_monitor(dest, keys, unmapped_keys)

{_, pid, :receive, {_, {:data, ^editor}}} ->
send(dest, {:editor_key, pid})
do_keystroke_activity_monitor(dest, keys)
do_keystroke_activity_monitor(dest, keys, unmapped_keys)

{_, pid, :receive, {_, {:data, ^modify}}} ->
send(dest, {:modify_key, pid})
do_keystroke_activity_monitor(dest, keys)

do_keystroke_activity_monitor(dest, keys, unmapped_keys)

{_, pid, :receive, {_, {:data, @default_modify}}} ->
send(dest, {:modify_key, pid})
do_keystroke_activity_monitor(dest, keys, unmapped_keys)

{_, pid, :receive, {_, {:data, ^abandon}}} ->
send(dest, {:abandon_key, pid})
do_keystroke_activity_monitor(dest, keys)
do_keystroke_activity_monitor(dest, keys, unmapped_keys)

{_, pid, :receive, {_, {:data, ^enter}}} ->
send(dest, {:enter_key, pid})
do_keystroke_activity_monitor(dest, keys)

do_keystroke_activity_monitor(dest, keys, unmapped_keys)

{_, _, :receive, {_, {:data, key}}} when unmapped_keys ->
IO.inspect(key)
do_keystroke_activity_monitor(dest, keys, unmapped_keys)

_ ->
do_keystroke_activity_monitor(dest, keys)
do_keystroke_activity_monitor(dest, keys, unmapped_keys)
end
end

Expand Down Expand Up @@ -535,6 +548,10 @@ defmodule IExHistory2.Events.Server do
send(user_driver, {user_driver_group, {:requests, [{:move_line, -1}]}})
end

defp send_to_shell(%{user_driver: user_driver, user_driver_group: user_driver_group}, :delete_left) do
send(user_driver, {user_driver_group, {:requests, [{:delete_chars, -1}]}})
end

defp send_to_shell(%{user_driver: user_driver, user_driver_group: user_driver_group}, command) do
send(user_driver_group, {user_driver, {:data, String.replace(command, ~r/\s+/, " ")}})
end
Expand Down Expand Up @@ -583,15 +600,15 @@ defmodule IExHistory2.Events.Server do
%{process_info | shell_pid => %{shell_config | queue: {0, queue}, last_scan_command: "", paste_buffer: "", last_direction: :none}}
end

defp handle_cursor_action(shell_pid, %{queue: {_, queue}, last_scan_command: command} = shell_config, process_info, :modify)
when byte_size(command) > 0 do
defp handle_cursor_action(shell_pid, %{queue: {_, queue}, last_scan_command: command, last_direction: last_dir} = shell_config, process_info, :modify)
when byte_size(command) > 0 and last_dir in [:up, :down] do
send_to_shell(shell_config, "", :scan_action)
send_to_shell(shell_config, command)
%{process_info | shell_pid => %{shell_config | queue: {0, queue}, last_scan_command: "", last_direction: :none}}
end

defp handle_cursor_action(_, _, process_info, :modify) do
process_info
defp handle_cursor_action(shell_pid, shell_config, process_info, :modify) do
%{process_info | shell_pid => %{shell_config | last_direction: :none}}
end

defp handle_cursor_action(shell_pid, %{queue: {_, queue}, server_pid: server_pid, last_scan_command: command, paste_buffer: ""} = shell_config, process_info, :editor) do
Expand Down Expand Up @@ -647,7 +664,7 @@ defmodule IExHistory2.Events.Server do
%{shell_config | queue: {search_pos, queue}, last_direction: :none, last_scan_command: command}
end

defp do_handle_cursor_action(search_pos, %{queue: {pos, queue}} = shell_config, :up) when pos < length(queue)-1 do
defp do_handle_cursor_action(search_pos, %{queue: {pos, queue}} = shell_config, :up) when pos < (length(queue) - 1) do
command = Enum.at(queue, search_pos)
send_to_shell(shell_config, command, :scan_action)
%{shell_config | queue: {search_pos, queue}, last_direction: :up, last_scan_command: command}
Expand Down Expand Up @@ -772,8 +789,9 @@ defmodule IExHistory2.Events.Server do
case Code.string_to_quoted(fun_string) do
{:ok, {:def, _, [{fun, _, args} | _]}} ->
key = {Atom.to_string(fun), Enum.count(args)}
Map.get_and_update(solo_functions, key, fn
mod -> if not is_nil(mod), do: {mod, mod}, else: {new_module, new_module}
Map.get_and_update(solo_functions, key,
fn mod when not is_nil(mod) -> {mod, mod}
_ -> {new_module, new_module}
end)
_ ->
{new_module, solo_functions}
Expand Down
Loading

0 comments on commit c1c6211

Please sign in to comment.