Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accepting a function completion duplicates it when using auto_insert #117

Open
3rd opened this issue Oct 15, 2024 · 6 comments
Open

Accepting a function completion duplicates it when using auto_insert #117

3rd opened this issue Oct 15, 2024 · 6 comments

Comments

@3rd
Copy link

3rd commented Oct 15, 2024

Thank you for the plugin!
Although it's early, it's almost a perfect replacement for cmp for me.

I've been hitting this issue when accepting completions for functions:

blink_fn_commit.mp4

I tried setting insertReplaceSupport=false, is it related to that somehow?
Thank you!

Config: https://github.com/3rd/config/blob/c869af41ab08470fdc169b7873a94c0ae130faff/dotfiles/nvim/lua/modules/completion/blink.lua

@chrisgrieser
Copy link

Can confirm that I also have the issue

@3rd
Copy link
Author

3rd commented Oct 17, 2024

It seems to happen with regular snippets (non-LSP) as well.

@Saghen Saghen closed this as completed in 6e15864 Oct 18, 2024
@3rd
Copy link
Author

3rd commented Oct 18, 2024

Thank you!

@jorgebef
Copy link

Sorry to comment on a closed issue, but I've found that the issue persists on some instances, example images below:

When attempting to complete className from the LSP it is initially correctly displayed as an option, all good so far:
Screenshot 2024-10-18 at 18 49 37

When selecting, then the text is correctly auto inserted, however, the cursor lands after the second quote instead of in between both quotes (unsure if this is an issue at all, just wanted to point it out):
Screenshot 2024-10-18 at 18 49 57

When accepting the option, it proceeds to double the input it should initially produce, however, it correctly positions the cursor in between the last double quotes as shown here:
Screenshot 2024-10-18 at 18 50 07

I'm unsure if I have configured the plugin wrong in any way, but I have confirmed I am on the latest update and I believe I've followed all documentation and instructions.

Brilliant plugin by the way, highly appreciated!!!

My blink.cmp config for reference
local M = {
  "saghen/blink.cmp",
  lazy = false, -- lazy loading handled internally
  -- WARNING
  -- DISABLE
  enabled = true,
  -- optional: provides snippets for the snippet source
  dependencies = {
    { "rafamadriz/friendly-snippets", lazy = true },
    { "onsails/lspkind-nvim", lazy = true },
  },

  -- use a release tag to download pre-built binaries
  -- OR build from source, requires nightly: https://rust-lang.github.io/rustup/concepts/channels.html#working-with-nightly-rust
  build = "cargo build --release",
  -- On musl libc based systems you need to add this flag
  -- build = 'RUSTFLAGS="-C target-feature=-crt-static" cargo build --release',
}

function M.config()
  local ui = require("config.ui")
  local lspkind = require("lspkind")
  local blink = require("blink.cmp")

  lspkind.init({
    mode = "symbol_text",
    preset = "default",
    symbol_map = {
      Text = "",
      Method = "󰆧 ",
      Function = "󰆧 ",
      Constructor = "󰆧 ",
      Field = "",
      Variable = "",
      Class = "",
      Interface = "",
      Module = "󰅩 ",
      Property = "",
      Unit = "",
      Value = "",
      Enum = "",
      Keyword = "",
      Snippet = "",
      Color = "",
      File = "",
      Reference = "",
      Folder = "",
      EnumMember = "",
      Constant = "",
      Struct = "",
      Event = "",
      Operator = "",
      TypeParameter = "",
    },
  })

  ---@module 'blink.cmp'
  ---@type blink.cmp.Config
  local opts = {
    -- for keymap, all values may be string | string[]
    -- use an empty table to disable a keymap
    keymap = {
      show = "<C-space>",
      hide = "<C-space>",
      accept = {},
      select_and_accept = "<CR>",
      select_prev = { "<S-Tab>", "<Up>", "<C-p>" },
      select_next = { "<Tab>", "<Down>", "<C-n>" },

      show_documentation = "<C-k>",
      hide_documentation = "<C-k>",
      scroll_documentation_up = "<C-d>",
      scroll_documentation_down = "<C-f>",

      snippet_forward = "<Tab>",
      snippet_backward = "<S-Tab>",
    },

    accept = {
      create_undo_point = false,
      auto_brackets = {
        enabled = false,
        default_brackets = { "(", ")" },
        override_brackets_for_filetypes = {},
        -- Overrides the default blocked filetypes
        force_allow_filetypes = {},
        blocked_filetypes = {},
        -- Synchronously use the kind of the item to determine if brackets should be added
        kind_resolution = {
          enabled = true,
          blocked_filetypes = { "typescriptreact", "javascriptreact", "vue" },
        },
        -- Asynchronously use semantic token to determine if brackets should be added
        semantic_token_resolution = {
          enabled = true,
          blocked_filetypes = {},
          -- How long to wait for semantic tokens to return before assuming no brackets should be added
          timeout_ms = 400,
        },
      },
    },

    trigger = {
      completion = {
        -- regex used to get the text when fuzzy matching
        -- changing this may break some sources, so please report if you run into issues
        -- todo: shouldnt this also affect the accept command? should this also be per language?
        keyword_regex = "[%w_\\-]",
        -- LSPs can indicate when to show the completion window via trigger characters
        -- however, some LSPs (*cough* tsserver *cough*) return characters that would essentially
        -- always show the window. We block these by default
        -- blocked_trigger_characters = { " ", "\n", "\t" },
        blocked_trigger_characters = {},
        -- when true, will show the completion window when the cursor comes after a trigger character when entering insert mode
        show_on_insert_on_trigger_character = true,
        -- list of additional trigger characters that won't trigger the completion window when the cursor comes after a trigger character when entering insert mode
        -- show_on_insert_blocked_trigger_characters = { "'", '"' },
        show_on_insert_blocked_trigger_characters = {},
      },

      signature_help = {
        enabled = false,
        blocked_trigger_characters = {},
        blocked_retrigger_characters = {},
        -- when true, will show the signature help window when the cursor comes after a trigger character when entering insert mode
        show_on_insert_on_trigger_character = true,
      },
    },

    fuzzy = {
      -- frencency tracks the most recently/frequently used items and boosts the score of the item
      use_frecency = true,
      -- proximity bonus boosts the score of items with a value in the buffer
      use_proximity = true,
      max_items = 200,
      -- controls which sorts to use and in which order, these three are currently the only allowed options
      sorts = { "label", "kind", "score" },

      prebuiltBinaries = {
        -- Whether or not to automatically download a prebuilt binary from github. If this is set to `false`
        -- you will need to manually build the fuzzy binary dependencies by running `cargo build --release`
        download = true,
        -- When downloading a prebuilt binary force the downloader to resolve this version. If this is uset
        -- then the downloader will attempt to infer the version from the checked out git tag (if any).
        --
        -- Beware that if the FFI ABI changes while tracking main then this may result in blink breaking.
        forceVersion = nil,
      },
    },

    sources = {
      -- similar to nvim-cmp's sources, but we point directly to the source's lua module
      -- multiple groups can be provided, where it'll fallback to the next group if the previous
      -- returns no completion items
      -- WARN: This API will have breaking changes during the beta
      providers = {
        { "blink.cmp.sources.lsp", name = "LSP" },
        { "blink.cmp.sources.path", name = "Path", score_offset = 3 },
        { "blink.cmp.sources.snippets", name = "Snippets", score_offset = -3 },
        { "blink.cmp.sources.buffer", name = "Buffer", fallback_for = { "LSP" } },
        -- -- FOR REF: full example
        -- -- all of these properties work on every source
        -- {
        --   "blink.cmp.sources.lsp",
        --   name = "LSP",
        --   keyword_length = 0,
        --   score_offset = 0,
        --   trigger_characters = { "", "c", "o", "o" },
        -- },
        -- -- the following two sources have additional options
        -- {
        --   "blink.cmp.sources.path",
        --   name = "Path",
        --   score_offset = 3,
        --   opts = {
        --     trailing_slash = false,
        --     label_trailing_slash = true,
        --     get_cwd = function(context)
        --       return vim.fn.expand(("#%d:p:h"):format(context.bufnr))
        --     end,
        --     show_hidden_files_by_default = true,
        --   },
        -- },
        -- {
        --   "blink.cmp.sources.snippets",
        --   name = "Snippets",
        --   score_offset = -3,
        --   -- similar to https://github.com/garymjr/nvim-snippets
        --   opts = {
        --     friendly_snippets = true,
        --     search_paths = { vim.fn.stdpath("config") .. "/snippets" },
        --     global_snippets = { "all" },
        --     extended_filetypes = {},
        --     ignored_filetypes = {},
        --   },
        -- },
        -- {
        --   "blink.cmp.sources.buffer",
        --   name = "Buffer",
        --   fallback_for = { "LSP" },
        -- },
      },
    },

    windows = {
      autocomplete = {
        min_width = 15,
        max_height = 10,
        border = ui.border.Single,
        winhighlight = "Normal:BlinkCmpMenu,FloatBorder:BlinkCmpMenuBorder,CursorLine:BlinkCmpMenuSelection,Search:None",
        -- keep the cursor X lines away from the top/bottom of the window
        scrolloff = 2,
        -- which directions to show the window,
        -- falling back to the next direction when there's not enough space
        direction_priority = { "s", "n" },
        -- Controls how the completion items are selected
        -- 'preselect' will automatically select the first item in the completion list
        -- 'manual' will not select any item by default
        -- 'auto_insert' will not select any item by default, and insert the completion items automatically when selecting them
        selection = "auto_insert",
        -- Controls how the completion items are rendered on the popup window
        -- 'simple' will render the item's kind icon the left alongside the label
        -- 'reversed' will render the label on the left and the kind icon + name on the right
        -- 'minimal' will render the label on the left and the kind name on the right
        -- 'function(blink.cmp.CompletionRenderContext): blink.cmp.Component[]' for custom rendering
        draw = "simple",
        -- Controls the cycling behavior when reaching the beginning or end of the completion list.
        cycle = {
          -- When `true`, calling `select_next` at the *bottom* of the completion list will select the *first* completion item.
          from_bottom = true,
          -- When `true`, calling `select_prev` at the *top* of the completion list will select the *last* completion item.
          from_top = true,
        },
      },
      documentation = {
        min_width = 10,
        max_width = 60,
        max_height = 20,
        border = ui.border.Single,
        winhighlight = "Normal:BlinkCmpDoc,FloatBorder:BlinkCmpDocBorder,CursorLine:BlinkCmpDocCursorLine,Search:None",
        -- which directions to show the documentation window,
        -- for each of the possible autocomplete window directions,
        -- falling back to the next direction when there's not enough space
        direction_priority = {
          autocomplete_north = { "e", "w", "n", "s" },
          autocomplete_south = { "e", "w", "s", "n" },
        },
        auto_show = true,
        auto_show_delay_ms = 0,
        update_delay_ms = 0,
      },
      signature_help = {
        min_width = 1,
        max_width = 100,
        max_height = 10,
        border = "padded",
        winhighlight = "Normal:BlinkCmpSignatureHelp,FloatBorder:BlinkCmpSignatureHelpBorder",
      },
    },

    -- highlight = {
    --   ns = vim.api.nvim_create_namespace("blink_cmp"),
    --   -- sets the fallback highlight groups to nvim-cmp's highlight groups
    --   -- useful for when your theme doesn't support blink.cmp
    --   -- will be removed in a future release, assuming themes add support
    --   use_nvim_cmp_as_default = false,
    -- },
    --
    -- -- set to 'mono' for 'Nerd Font Mono' or 'normal' for 'Nerd Font'
    -- -- adjusts spacing to ensure icons are aligned
    -- nerd_font_variant = "normal",

    kind_icons = {
      Text = "󰉿",
      Method = "󰊕",
      Function = "󰊕",
      Constructor = "󰒓",

      Field = "󰜢",
      Variable = "󰆦",
      Property = "󰖷",

      Class = "󱡠",
      Interface = "󱡠",
      Struct = "󱡠",
      Module = "󰅩",

      Unit = "󰪚",
      Value = "󰦨",
      Enum = "󰦨",
      EnumMember = "󰦨",

      Keyword = "󰻾",
      Constant = "󰏿",

      Snippet = "󱄽",
      Color = "󰏘",
      File = "󰈔",
      Reference = "󰬲",
      Folder = "󰉋",
      Event = "󱐋",
      Operator = "󰪚",
      TypeParameter = "󰬛",
    },
  }

  blink.setup(opts)
end

return M

@Saghen Saghen reopened this Oct 18, 2024
@Saghen
Copy link
Owner

Saghen commented Oct 18, 2024

Thanks! Sounds like there's still edge cases so I'll keep it open. And yeah, I also thought about correctly positioning the cursor but didn't get around to it yet

@3rd
Copy link
Author

3rd commented Oct 18, 2024

I'm hitting a few other edge cases:

  1. for 1 character snippets, accept doesn't close the menu
  2. accepting any other kind of item clears the current text - 2 but doesn't insert the accepted completion
blink_clear.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants