diff --git a/lib/livebook/intellisense.ex b/lib/livebook/intellisense.ex index 8d13e3030..f423b02e2 100644 --- a/lib/livebook/intellisense.ex +++ b/lib/livebook/intellisense.ex @@ -127,21 +127,21 @@ defmodule Livebook.Intellisense do defp include_in_completion?(_), do: true - defp format_completion_item({:variable, name, value}), + defp format_completion_item({:variable, name, _value}), do: %{ label: name, kind: :variable, detail: "variable", - documentation: value_snippet(value, @line_length), + documentation: nil, insert_text: name } - defp format_completion_item({:map_field, name, value}), + defp format_completion_item({:map_field, name, _value}), do: %{ label: name, kind: :field, detail: "field", - documentation: value_snippet(value, @line_length), + documentation: nil, insert_text: name } @@ -336,18 +336,9 @@ defmodule Livebook.Intellisense do end end - defp format_details_item({:variable, name, value}) do - join_with_divider([ - code(name), - value_snippet(value, @extended_line_length) - ]) - end + defp format_details_item({:variable, name, _value}), do: code(name) - defp format_details_item({:map_field, _name, value}) do - join_with_divider([ - value_snippet(value, @extended_line_length) - ]) - end + defp format_details_item({:map_field, name, _value}), do: code(name) defp format_details_item({:module, _module, display_name, documentation}) do join_with_divider([ @@ -403,14 +394,6 @@ defmodule Livebook.Intellisense do """ end - defp value_snippet(value, line_length) do - """ - ``` - #{inspect(value, pretty: true, width: line_length)} - ```\ - """ - end - defp format_signatures([], _module), do: nil defp format_signatures(signatures, module) do diff --git a/lib/livebook/intellisense/identifier_matcher.ex b/lib/livebook/intellisense/identifier_matcher.ex index 94defe41d..0f8ea6d40 100644 --- a/lib/livebook/intellisense/identifier_matcher.ex +++ b/lib/livebook/intellisense/identifier_matcher.ex @@ -341,7 +341,7 @@ defmodule Livebook.Intellisense.IdentifierMatcher do defp valid_alias_rest?(rest), do: valid_alias_piece?(rest) defp usable_as_unquoted_module?(mod) do - Code.Identifier.classify(mod) != :other + macro_classify_atom(mod) in [:identifier, :unquoted] end defp get_matching_modules(hint, ctx) do @@ -484,4 +484,70 @@ defmodule Livebook.Intellisense.IdentifierMatcher do ctx.matcher.(name, hint), do: {:module_attribute, name, {"text/markdown", info.doc}} end + + # --- + + # TODO use Macro.classify_atom/1 on Elixir 1.14 + + def macro_classify_atom(atom) do + case macro_inner_classify(atom) do + :alias -> :alias + :identifier -> :identifier + type when type in [:unquoted_operator, :not_callable] -> :unquoted + _ -> :quoted + end + end + + defp macro_inner_classify(atom) when is_atom(atom) do + cond do + atom in [:%, :%{}, :{}, :<<>>, :..., :.., :., :"..//", :->] -> + :not_callable + + atom in [:"::"] -> + :quoted_operator + + Macro.operator?(atom, 1) or Macro.operator?(atom, 2) -> + :unquoted_operator + + true -> + charlist = Atom.to_charlist(atom) + + if macro_valid_alias?(charlist) do + :alias + else + case :elixir_config.identifier_tokenizer().tokenize(charlist) do + {kind, _acc, [], _, _, special} -> + if kind == :identifier and not :lists.member(?@, special) do + :identifier + else + :not_callable + end + + _ -> + :other + end + end + end + end + + defp macro_valid_alias?('Elixir' ++ rest), do: macro_valid_alias_piece?(rest) + defp macro_valid_alias?(_other), do: false + + defp macro_valid_alias_piece?([?., char | rest]) when char >= ?A and char <= ?Z, + do: macro_valid_alias_piece?(macro_trim_leading_while_valid_identifier(rest)) + + defp macro_valid_alias_piece?([]), do: true + defp macro_valid_alias_piece?(_other), do: false + + defp macro_trim_leading_while_valid_identifier([char | rest]) + when char >= ?a and char <= ?z + when char >= ?A and char <= ?Z + when char >= ?0 and char <= ?9 + when char == ?_ do + macro_trim_leading_while_valid_identifier(rest) + end + + defp macro_trim_leading_while_valid_identifier(other) do + other + end end diff --git a/test/livebook/intellisense_test.exs b/test/livebook/intellisense_test.exs index 34a60080a..e3d1b6c08 100644 --- a/test/livebook/intellisense_test.exs +++ b/test/livebook/intellisense_test.exs @@ -112,6 +112,13 @@ defmodule Livebook.IntellisenseTest do assert lists_item in Intellisense.get_completion_items(" :", binding, env) end + @tag :erl_docs + test "Erlang completion doesn't include quoted atoms" do + {binding, env} = eval(do: nil) + + assert [] = Intellisense.get_completion_items(~s{:Elixir}, binding, env) + end + @tag :erl_docs test "Erlang module completion with 'in' operator in spec" do {binding, env} = eval(do: nil) @@ -589,21 +596,21 @@ defmodule Livebook.IntellisenseTest do label: "bar_1", kind: :field, detail: "field", - documentation: ~s{```\n~r/pattern/\n```}, + documentation: nil, insert_text: "bar_1" }, %{ label: "bar_2", kind: :field, detail: "field", - documentation: ~s{```\ntrue\n```}, + documentation: nil, insert_text: "bar_2" }, %{ label: "foo", kind: :field, detail: "field", - documentation: ~s{```\n1\n```}, + documentation: nil, insert_text: "foo" } ] = Intellisense.get_completion_items("map.", binding, env) @@ -613,7 +620,7 @@ defmodule Livebook.IntellisenseTest do label: "foo", kind: :field, detail: "field", - documentation: ~s{```\n1\n```}, + documentation: nil, insert_text: "foo" } ] = Intellisense.get_completion_items("map.f", binding, env) @@ -639,18 +646,7 @@ defmodule Livebook.IntellisenseTest do label: "nested", kind: :field, detail: "field", - documentation: """ - ``` - %{ - deeply: %{ - bar_1: 23, - bar_2: 14, - foo: 1, - mod: System - } - } - ```\ - """, + documentation: nil, insert_text: "nested" } ] = Intellisense.get_completion_items("map.nest", binding, env) @@ -660,7 +656,7 @@ defmodule Livebook.IntellisenseTest do label: "foo", kind: :field, detail: "field", - documentation: ~s{```\n1\n```}, + documentation: nil, insert_text: "foo" } ] = Intellisense.get_completion_items("map.nested.deeply.f", binding, env) @@ -787,7 +783,7 @@ defmodule Livebook.IntellisenseTest do label: "numbats", kind: :variable, detail: "variable", - documentation: ~s{```\n["numbat", "numbat"]\n```}, + documentation: nil, insert_text: "numbats" } ] = Intellisense.get_completion_items("numba", binding, env) @@ -797,14 +793,14 @@ defmodule Livebook.IntellisenseTest do label: "numbats", kind: :variable, detail: "variable", - documentation: ~s{```\n["numbat", "numbat"]\n```}, + documentation: nil, insert_text: "numbats" }, %{ label: "number", kind: :variable, detail: "variable", - documentation: ~s{```\n3\n```}, + documentation: nil, insert_text: "number" } ] = Intellisense.get_completion_items("num", binding, env) @@ -814,7 +810,7 @@ defmodule Livebook.IntellisenseTest do label: "nothing", kind: :variable, detail: "variable", - documentation: ~s{```\nnil\n```}, + documentation: nil, insert_text: "nothing" }, %{label: "node/0"},