From b3acf0c2f15ffca3df587e817575fee13babae3b Mon Sep 17 00:00:00 2001 From: Steffen Deusch Date: Wed, 12 Feb 2025 16:19:50 +0100 Subject: [PATCH] don't try to lex sigils inside iex prompts --- lib/makeup/lexers/elixir_lexer.ex | 14 +++++++++++ mix.exs | 5 +++- .../elixir_lexer_sigil_lexer_test.exs | 24 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/makeup/lexers/elixir_lexer.ex b/lib/makeup/lexers/elixir_lexer.ex index a86f09c..2f12c0a 100644 --- a/lib/makeup/lexers/elixir_lexer.ex +++ b/lib/makeup/lexers/elixir_lexer.ex @@ -506,6 +506,20 @@ defmodule Makeup.Lexers.ElixirLexer do do: [{:comment, attrs, text} | postprocess_helper(tokens)] # Custom sigil lexers + # special case: sigil inside iex prompt + defp postprocess_helper([ + {:generic_prompt, %{language: :elixir}, ["iex" | _]} = first, + # in the iex case, we don't get the whole sigil content in one token + {:string_sigil, _, ["~", _sigil_char, _separator]} = second | rest + ]) do + # we don't handle this case, because it would require some special inside + # and outside lexing, similar to what makeup_eex is doing + {extra_tokens, [end_sigil | rest]} = + Enum.split_while(rest, fn token -> not match?({:string_sigil, _, _}, token) end) + + [first, second | extra_tokens ++ [end_sigil | postprocess_helper(rest)]] + end + defp postprocess_helper([{:string_sigil, attrs, content} | tokens]) do # content is a list of the format ["~", sigil_char, separator, ... sigil_content ..., end_separator] sigil = diff --git a/mix.exs b/mix.exs index 072fdbe..b92baa8 100644 --- a/mix.exs +++ b/mix.exs @@ -13,7 +13,10 @@ defmodule MakeupElixir.Mixfile do deps: deps(), package: package(), description: description(), - aliases: aliases() + aliases: aliases(), + test_ignore_filters: [ + &String.starts_with?(&1, "test/generators/") + ] ] end diff --git a/test/makeup/lexers/elixir_lexer/elixir_lexer_sigil_lexer_test.exs b/test/makeup/lexers/elixir_lexer/elixir_lexer_sigil_lexer_test.exs index d3b2789..a7c0ae5 100644 --- a/test/makeup/lexers/elixir_lexer/elixir_lexer_sigil_lexer_test.exs +++ b/test/makeup/lexers/elixir_lexer/elixir_lexer_sigil_lexer_test.exs @@ -20,5 +20,29 @@ defmodule ElixirLexerSigilLexerTest do after Application.put_env(:makeup_elixir, :sigil_lexers, %{}) end + + test "does not lex inside iex prompts" do + # does not exist, but should also not be invoked + Makeup.Lexers.ElixirLexer.register_sigil_lexer("PY", DoesNotExist, foo: :bar) + + # if it tried to use the sigil lexer, it would crash + assert lex(""" + iex> import Pythonx + iex> x = 1 + iex> ~PY\""" + ...> y = 10 + ...> x + y + ...> \""" + #Pythonx.Object< + 11 + > + iex> x + 1 + iex> y + #Pythonx.Object< + 10 + > + """) + end end end