Skip to content
This repository was archived by the owner on Aug 30, 2025. It is now read-only.

Crash with invalid String.slice length if file has emoji #865

@nshafer

Description

@nshafer

Dorgan asked me in Discord to report bugs with Lexical, since Expert may have the same problem. This is a weird one I experience in a Phoenix app I'm working on, where when typing just d when I start to type def will crash lexical with:

2025-08-04 12:04:19.717 [info] [Error - 12:04:19 PM] Request textDocument/completion failed.
2025-08-04 12:04:19.717 [info]   Message: ** (FunctionClauseError) no function clause matching in String.slice/3
    (elixir 1.18.3) lib/string.ex:2333: String.slice("  d", 0, -1)
    (lx_common 0.7.2) lib/lexical/code_unit.ex:23: LXical.CodeUnit.utf8_position_to_utf16_offset/2
    (lx_protocol 0.7.2) lib/lexical/protocol/conversions.ex:146: LXical.Protocol.Conversions.extract_lsp_character/1
    (lx_protocol 0.7.2) lib/lexical/protocol/conversions.ex:120: LXical.Protocol.Conversions.to_lsp/1
    (lx_protocol 0.7.2) lib/lexical/protocol/conversions.ex:98: LXical.Protocol.Conversions.to_lsp/1
    (lx_protocol 0.7.2) lib/lexical/protocol/convertibles/lexical.document.edit.ex:11: LXical.Convertible.Lexical.Document.Edit.to_lsp/1
    (lx_lexical_shared 0.5.0) lib/lexical/convertible.ex:9: anonymous fn/3 in LXical.Convertible.Helpers.apply/2
    (elixir 1.18.3) lib/enum.ex:4968: Enumerable.List.reduce/3

  Code: -32603 

I was able to reproduce this in a new project created with mix phx.new lxtest (1.8.0-rc.4). After install and dep install/compile so everything is happy, in VS Code, create a new file, "lib/testlx_web/components/test_component.ex" and paste:

defmodule TestlxWeb.Components.TestComponent do
  use TestlxWeb, :live_component

  def render(assigns) do
    ~H"""
    <div>
      <h1>Hello, {@name}! ⚠️</h1>
    </div>
    """
  end
end

Now try to create a new function, as soon as you type d it will crash. If you remove the emoji, then it works as expected. I'm guessing this is due to counting codepoints instead of graphemes, as that emoji is 2 codepoints.

iex(6)> s = "Hello⚠️"
"Hello⚠️"
iex(7)> s
"Hello⚠️"
iex(8)> String.codepoints(s)
["H", "e", "l", "l", "o", "⚠", ""]
iex(9)> String.graphemes(s)
["H", "e", "l", "l", "o", "⚠"]

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions