Packages
grizzly
8.0.1
9.1.4
9.1.2
9.1.1
9.1.0
9.0.0
8.15.3
8.15.2
8.15.1
8.15.0
8.14.0
8.13.0
8.12.0
8.11.3
8.11.2
8.11.1
8.11.0
8.10.0
8.9.0
8.8.1
8.8.0
8.7.1
8.7.0
8.6.12
8.6.11
8.6.10
8.6.9
8.6.8
8.6.7
retired
8.6.6
8.6.5
8.6.4
8.6.3
8.6.2
8.6.1
8.6.0
8.5.3
8.5.2
8.5.1
8.5.0
8.4.0
8.3.0
8.2.3
8.2.2
8.2.1
8.2.0
8.1.0
8.0.1
8.0.0
7.4.3
7.4.2
7.4.1
7.4.0
7.3.0
7.2.0
7.1.4
7.1.3
7.1.2
7.1.1
7.1.0
7.0.4
7.0.3
7.0.2
7.0.1
7.0.0
6.8.8
6.8.7
6.8.6
6.8.5
6.8.4
6.8.3
6.8.2
6.8.1
6.8.0
6.7.1
6.7.0
6.6.1
6.6.0
6.5.1
6.5.0
6.4.0
6.3.0
6.2.0
6.1.1
6.1.0
6.0.1
6.0.0
5.4.1
5.4.0
5.3.0
5.2.8
5.2.7
5.2.6
5.2.5
5.2.4
5.2.3
5.2.2
5.2.1
5.2.0
5.1.2
5.1.1
5.1.0
5.0.2
5.0.1
5.0.0
4.0.1
4.0.0
3.0.0
2.1.0
2.0.0
1.0.1
1.0.0
0.22.7
0.22.6
0.22.5
0.22.4
0.22.3
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.2
0.16.1
0.16.0
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.9.0-rc.4
0.9.0-rc.3
0.9.0-rc.2
0.9.0-rc.1
0.9.0-rc.0
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
Elixir Z-Wave library
Current section
Files
Jump to
Current section
Files
lib/grizzly/autocomplete.ex
defmodule Grizzly.Autocomplete do
@moduledoc """
Adds command completion to the default IEx autocomplete.
This module augments the IEx autocompletion logic to complete Grizzly
command names inside of `Grizzly.send_command/4` calls.
Call `Grizzly.Autocomplete.set_expand_fun()` (or put it in your `.iex.exs`) to
enable this feature.
"""
require Logger
def expand(expr) do
str = Enum.reverse(expr) |> to_string()
with {:unquoted_atom, partial_command_name} <- Code.Fragment.cursor_context(str),
{:ok, ast} = Code.Fragment.container_cursor_to_quoted(str),
true <- in_send_command_call?(ast) do
partial_command_name
|> to_string()
|> expand_command()
else
_ ->
IEx.Autocomplete.expand(expr)
end
rescue
err ->
Logger.error("""
Error during autocomplete expansion: #{inspect(err)}
Ejecting `Grizzly.Autocomplete` and restoring default IEx autocomplete.
""")
gl = Process.group_leader()
_ = :io.setopts(gl, expand_fun: &IEx.Autocomplete.expand/1)
end
defp expand_command(command_prefix) do
expansions =
Enum.reduce(Grizzly.list_commands(), [], fn command, acc ->
command_str = Atom.to_string(command)
if String.starts_with?(command_str, command_prefix) do
[command_str | acc]
else
acc
end
end)
prefix_len = String.length(command_prefix)
case expansions do
[] ->
{:no, ~c"", []}
[^command_prefix] ->
{:no, ~c"", []}
[unique] ->
completion = unique |> String.to_charlist() |> Enum.drop(prefix_len)
{:yes, completion, []}
list ->
list = Enum.map(list, &String.to_charlist/1)
completion = list |> Enum.reduce(&common_prefix/2) |> Enum.drop(prefix_len)
{:yes, completion, list}
end
end
# Find the common prefix for two charlists
defp common_prefix(a, b, acc \\ [])
defp common_prefix([h | t1], [h | t2], acc) do
common_prefix(t1, t2, [h | acc])
end
defp common_prefix(_, _, acc) do
Enum.reverse(acc)
end
defp in_send_command_call?(ast) do
{_, yes?} =
Macro.postwalk(ast, false, fn
{{:., _, [{:__aliases__, _, [:Grizzly]}, :send_command]}, _, [_, {:__cursor__, _, _}]},
acc ->
{ast, acc || true}
ast, acc ->
{ast, acc || false}
end)
yes?
end
# The following are adapted from IEx.Autocomplete
# Provides a helper function that is injected into connecting remote nodes to
# properly handle autocompletion.
@doc false
def remsh(node) do
fn e ->
case :rpc.call(node, Grizzly.Autocomplete, :expand, [e]) do
{:badrpc, _} -> {:no, ~c"", []}
r -> r
end
end
end
@spec set_expand_fun() :: :ok | {:error, any}
def set_expand_fun() do
gl = Process.group_leader()
expand_fun =
if node(gl) != node() do
Grizzly.Autocomplete.remsh(node())
else
&Grizzly.Autocomplete.expand/1
end
# expand_fun is not supported by a shell variant
# on Windows, so we do two IO calls, not caring
# about the result of the expand_fun one.
_ = :io.setopts(gl, expand_fun: expand_fun)
:io.setopts(gl, binary: true, encoding: :unicode)
end
end