{ ... }:

let
  normalz = {
    e = "scroll_down";
    i = "scroll_up";
    j = "search_next";
    J = "search_prev";

    k = "no_op";
    n = "no_op";
    N = "no_op";
  };

  normalcw = {
    n = "jump_view_left";
    C-n = "jump_view_left";
    e = "jump_view_down";
    C-e = "jump_view_down";
    i = "jump_view_up";
    C-i = "jump_view_up";
    o = "jump_view_right";
    C-o = "jump_view_right";

    N = "swap_view_left";
    E = "swap_view_down";
    I = "swap_view_up";
    O = "swap_view_right";

    c.C-s = "hsplit_new";
    c.s = "hsplit_new";
    c.C-v = "vsplit_new";
    c.v = "vsplit_new";

    C-l = "wonly";
    l = "wonly";

    h = "no_op";
    C-h = "no_op";
    j = "no_op";
    C-j = "no_op";
    k = "no_op";
    C-k = "no_op";
    H = "no_op";
    J = "no_op";
    K = "no_op";
    L = "no_op";
  };

  selectz = {
    e = "scroll_down";
    i = "scroll_up";
    j = "search_next";
    J = "search_prev";

    k = "no_op";
    n = "no_op";
    N = "no_op";
  };

  selectcw = {
    n = "jump_view_left";
    C-n = "jump_view_left";
    e = "jump_view_down";
    C-e = "jump_view_down";
    i = "jump_view_up";
    C-i = "jump_view_up";
    o = "jump_view_right";
    C-o = "jump_view_right";

    N = "swap_view_left";
    E = "swap_view_down";
    I = "swap_view_up";
    O = "swap_view_right";

    c.C-s = "hsplit_new";
    c.s = "hsplit_new";
    c.C-v = "vsplit_new";
    c.v = "vsplit_new";

    C-l = "wonly";
    l = "wonly";

    h = "no_op";
    C-h = "no_op";
    j = "no_op";
    C-j = "no_op";
    k = "no_op";
    C-k = "no_op";
    H = "no_op";
    J = "no_op";
    K = "no_op";
    L = "no_op";
  };
in
{
  xdg.configFile."helix/themes/edge_neon.toml".source = ./edge_neon.toml;
  programs.helix = {
    enable = true;
    languages = {
      use-grammars.except = [ "gemini" ];
      language-server = {
        rust-analyzer.config.check = {
          command = "clippy";
        };
        typst-lsp = {
          command = "typst-lsp";
        };
      };
      language = [
        {
          name = "typst";
          scope = "source.typst";
          file-types = [
            "typst"
            "typ"
          ];
          indent = {
            tab-width = 2;
            unit = "  ";
          };
          comment-token = "//";
          injection-regex = "typ(st)?";
          language-servers = [ "typst-lsp" ];
          roots = [ "template.typ" ];
          auto-pairs = {
            "(" = ")";
            "{" = "}";
            "[" = "]";
            "$" = "$";
            "\"" = "\"";
          };
        }
      ];
      grammar = [
        {
          name = "typst";
          source = {
            git = "https://github.com/uben0/tree-sitter-typst";
            rev = "master";
          };
        }
      ];
    };
    settings = {
      theme = "edge_neon";
      editor = {
        indent-guides.render = true;

        bufferline = "always";

        cursor-shape = {
          insert = "bar";
          normal = "block";
          select = "underline";
        };

        color-modes = true;
        auto-save = true;

        lsp.display-messages = true;
      };
      keys = {
        normal = {
          n = "move_char_left";
          e = "move_visual_line_down";
          i = "move_visual_line_up";
          o = "move_char_right";

          k = "insert_mode";
          K = "insert_at_line_start";
          h = "open_below";
          H = "open_above";

          l = "goto_first_nonwhitespace";
          L = "goto_line_end";

          E = "keep_selections";
          A-E = "remove_selections";

          j = "search_next";
          J = "search_prev";

          "\\" = "join_selections";
          "A-\\" = "join_selections_space";

          "tab" = "goto_next_buffer";
          "S-tab" = "goto_previous_buffer";

          I = "no_op";
          O = "no_op";
          A-K = "no_op";
          N = "no_op";
          A-J = "no_op";
          b = "no_op";
          W = "no_op";
          B = "no_op";
        };

        normal.w = {
          n = "move_prev_word_start";
          e = "move_prev_word_end";
          i = "move_next_word_start";
          o = "move_next_word_end";

          N = "move_prev_long_word_start";
          E = "move_prev_long_word_end";
          I = "move_next_long_word_start";
          O = "move_next_long_word_end";
        };

        normal.z = normalz;

        normal.Z = normalz;

        normal.g = {
          n = "goto_line_start";
          e = "move_line_down";
          i = "move_line_up";
          o = "goto_line_end";

          I = "goto_implementation";

          E = "goto_last_line";

          h = "no_op";
          j = "no_op";
          k = "no_op";
          l = "no_op";
          p = "no_op";
        };

        normal.C-w = normalcw;
        normal.space.w = normalcw;

        select = {
          n = "extend_char_left";
          e = "extend_visual_line_down";
          i = "extend_visual_line_up";
          o = "extend_char_right";

          j = "extend_search_next";
          J = "extend_search_prev";

          k = "insert_mode";
          K = "insert_at_line_start";
          h = "open_below";
          H = "open_above";

          l = "extend_to_first_nonwhitespace";
          L = "extend_to_line_end";

          E = "keep_selections";
          A-E = "remove_selections";

          "\\" = "join_selections";
          "A-\\" = "join_selections_space";

          "tab" = "goto_next_buffer";
          "S-tab" = "goto_previous_buffer";

          I = "no_op";
          O = "no_op";
          A-K = "no_op";
          N = "no_op";
          A-J = "no_op";
          b = "no_op";
          W = "no_op";
          B = "no_op";
        };

        select.w = {
          n = "extend_prev_word_start";
          e = "extend_prev_word_end";
          i = "extend_next_word_start";
          o = "extend_next_word_end";

          N = "extend_prev_long_word_start";
          E = "extend_prev_long_word_end";
          I = "extend_next_long_word_start";
          O = "extend_next_long_word_end";
        };

        select.z = selectz;

        select.Z = selectz;

        select.g = {
          e = "extend_line_down";
          i = "extend_line_up";
          j = "no_op";
          k = "no_op";
        };

        select.C-w = selectcw;
        select.space.w = selectcw;

        insert.C-c = "normal_mode";
      };
    };
  };
}