Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
c5c4480
Replace custom error recovery with the toxic2 tolerant parser
lukaszsamson Jun 13, 2026
6622efa
Add public parse_to_neutralized_ast/2 with keep_range option
lukaszsamson Jun 13, 2026
726938b
Add SurroundContext.Toxic seam; route nav locators through it (stage 0)
lukaszsamson Jun 13, 2026
e1dd521
SurroundContext.Toxic: classify symbol under cursor from toxic2 ranges
lukaszsamson Jun 14, 2026
f4d0030
Source.bitstring_options: detect bitstring context via AST, drop Norm…
lukaszsamson Jun 14, 2026
b3cf330
Port elixir-ls completion subsystem (commit 98e983d) wholesale
lukaszsamson Jun 14, 2026
5ed9a66
SurroundContext.Toxic: fix 3 classification bugs (gpt-5.5 adversarial…
lukaszsamson Jun 14, 2026
0675b4f
SurroundContext.Toxic: classify atoms from the parse tree via literal…
lukaszsamson Jun 14, 2026
b5b40c2
surround_context/toxic: classify keyword keys and nil/true/false via …
lukaszsamson Jun 14, 2026
1a3bea5
surround_context/toxic: classify step-range `..//` as `..` to match C…
lukaszsamson Jun 14, 2026
a454552
surround_context/toxic: add AST-accepting arity; tidy literal classify
lukaszsamson Jun 14, 2026
b928399
deps: use published toxic2 git dep; require Elixir ~> 1.19
lukaszsamson Jun 14, 2026
a2b0e59
completion_engine: fix compiler/credo warnings from the wholesale port
lukaszsamson Jun 14, 2026
38a29d5
Address PR review: parser_options, struct-field grouping, perf, dead …
lukaszsamson Jul 4, 2026
99570b9
Restore Elixir 1.16-1.18 support
lukaszsamson Jul 4, 2026
f7bbb71
test: make version-sensitive parser tests pass on Elixir 1.16/1.17
lukaszsamson Jul 4, 2026
89eda3f
completion: restore state-based bitstring modifier filtering
lukaszsamson Jul 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .dialyzer_ignore.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@
{"lib/elixir_sense/core/compiler/fn.ex", :pattern_match},
{"lib/elixir_sense/core/normalized/macro/env.ex", :pattern_match},

# 2. Pre-existing peripheral logic (vendored tokenizer/parser, normalized helpers)
{"lib/elixir_sense/core/normalized/tokenizer.ex", :contract_supertype},
{"lib/elixir_sense/core/normalized/tokenizer.ex", :pattern_match},
{"lib/elixir_sense/core/parser.ex", :guard_fail}
# 3. Completion engine ported wholesale from elixir-ls (commit 98e983d). The unreachable `:error`
# clauses in expand_dot_path/expand_aliases are upstream-faithful defensive fallbacks.
{"lib/elixir_sense/providers/completion/completion_engine.ex", :pattern_match}
]
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
strategy:
fail-fast: false
matrix:
# Same matrix as mix_test (Linux). See above for compatibility notes.
# Same matrix as mix_test (Linux).
include:
- elixir: 1.16.x
otp: 26.x
Expand Down
2 changes: 1 addition & 1 deletion lib/elixir_sense.ex
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ defmodule ElixirSense do
...> end
...> '''
iex> ElixirSense.string_to_quoted(code, 1)
{:ok, {:defmodule, [do: [line: 1, column: 11], end: [line: 2, column: 1], line: 1, column: 1], [[do: {:__block__, [], []}]]}}
{:ok, {:defmodule, [do: [line: 1, column: 11], end: [line: 2, column: 1], line: 1, column: 1], [[do: {:__block__, [line: 1, column: 11], []}]]}}
"""
@spec string_to_quoted(
String.t(),
Expand Down
127 changes: 0 additions & 127 deletions lib/elixir_sense/core/bitstring.ex

This file was deleted.

15 changes: 15 additions & 0 deletions lib/elixir_sense/core/compiler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,21 @@ defmodule ElixirSense.Core.Compiler do
{Enum.reverse(ast), %{state | protocol: nil}, env}
end

defp expand_macro(
meta,
Kernel,
:defmodule,
[alias, {:__cursor__, _, cursor_args} = cursor],
callback,
state,
env
)
when is_list(cursor_args) do
# tolerant parsers may produce a cursor in place of the do block
# expand as if the cursor was the module body
expand_macro(meta, Kernel, :defmodule, [alias, [do: cursor]], callback, state, env)
end

defp expand_macro(
meta,
Kernel,
Expand Down
72 changes: 11 additions & 61 deletions lib/elixir_sense/core/metadata.ex
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,6 @@ defmodule ElixirSense.Core.Metadata do
}
end

if Version.match?(System.version(), "< 1.18.0-dev") do
def container_cursor_to_quoted_options(_trailing_fragment) do
[columns: true, token_metadata: true]
end
else
def container_cursor_to_quoted_options(trailing_fragment) do
[columns: true, token_metadata: true, trailing_fragment: trailing_fragment]
end
end

def get_cursor_env(
metadata,
position,
Expand All @@ -95,57 +85,17 @@ defmodule ElixirSense.Core.Metadata do
{line, column},
surround
) do
{{prefix, needle, suffix}, source_with_cursor} =
case surround do
{{begin_line, begin_column}, {end_line, end_column}} ->
[prefix, needle, suffix] =
ElixirSense.Core.Source.split_at(metadata.source, [
{begin_line, begin_column},
{end_line, end_column}
])

source_with_cursor = prefix <> "__cursor__(#{needle})" <> suffix

{{prefix, needle, suffix}, source_with_cursor}

nil ->
[prefix, suffix] =
ElixirSense.Core.Source.split_at(metadata.source, [
{line, column}
])

source_with_cursor = prefix <> "__cursor__()" <> suffix

{{prefix, "", suffix}, source_with_cursor}
end

{meta, cursor_env} =
case Code.string_to_quoted(source_with_cursor,
columns: true,
token_metadata: true,
emit_warnings: false
) do
{:ok, ast} ->
MetadataBuilder.build(ast).cursor_env || {[], nil}

_ ->
{[], nil}
end

{_meta, cursor_env} =
if cursor_env != nil do
{meta, cursor_env}
else
# IO.puts(prefix <> "|")
options = container_cursor_to_quoted_options(needle <> suffix)

case Code.Fragment.container_cursor_to_quoted(prefix, options) do
{:ok, ast} ->
MetadataBuilder.build(ast).cursor_env || {[], nil}

_ ->
{[], nil}
end
# the cursor environment is derived by marking the AST node at the cursor
# (located via toxic2's source ranges) - a separate parse from the one that
# produced `metadata`, so the marker never pollutes the calls/vars/references
# metadata. A `surround` range means the caller is navigating an existing
# symbol (definition/hover/references), so we keep that token in the tree.
opts = if surround == nil, do: [], else: [preserve_token: true]

cursor_env =
case ElixirSense.Core.Parser.cursor_env(metadata.source, {line, column}, opts) do
{_meta, env} -> env
nil -> nil
end

if cursor_env != nil do
Expand Down
45 changes: 0 additions & 45 deletions lib/elixir_sense/core/normalized/tokenizer.ex

This file was deleted.

Loading
Loading