Code Monkey home page Code Monkey logo

Comments (29)

kusayuzayushko avatar kusayuzayushko commented on August 23, 2024 4

word by word and line by line. I second this as well

from codeium.vim.

xmready avatar xmready commented on August 23, 2024 3

I second this request. I have found myself needing this feature many times.

from codeium.vim.

szilu avatar szilu commented on August 23, 2024 2

Hello guys,

I have implemented a quick and dirty solution for NeoVim in lua. I've been using it for several weeks, it handles word and line completion quite well (line completion has some indentation problems with auto indenting).
I thought I share it with you, maybe someone has some more time to clear it up a bit.

use {
    'Exafunction/codeium.vim',
    config = function ()
        vim.g.codeium_no_map_tab = true
        vim.keymap.set('i', '<M-BS>', function () return vim.fn['codeium#Accept']() end, { expr = true })
        vim.keymap.set('i', '<M-Right>', function () return vim.fn['codeium#CycleCompletions'](1) end, { expr = true })
        vim.keymap.set('i', '<M-Left>', function () return vim.fn['codeium#CycleCompletions'](-1) end, { expr = true })
        vim.keymap.set('i', '<M-Esc>', function () return vim.fn['codeium#Clear']() end, { expr = true })

        -- Line completion
        vim.keymap.set('i', '<M-Enter>', function ()
            local fullCompletion = vim.api.nvim_eval("b:_codeium_completions.items[b:_codeium_completions.index].completionParts[0].text")
            local cursor = vim.api.nvim_win_get_cursor(0)
            local line = vim.api.nvim_get_current_line()
            local completion = string.gsub(fullCompletion, '\n.*$', '')
            if (completion ~= '') then
                vim.defer_fn(function ()
                    local nline = line:sub(0, cursor[2]) .. completion .. line:sub(cursor[2] + 1)
                    vim.api.nvim_set_current_line(nline)
                    vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + #completion })
                    print('pre enter ' .. vim.inspect(cursor))
                    vim.api.nvim_feedkeys('\n', 'i', true)
                end, 0)
            end
        end, { expr = true })

        -- Word completion
        vim.keymap.set('i', '<M-Space>', function ()
            local fullCompletion = vim.api.nvim_eval("b:_codeium_completions.items[b:_codeium_completions.index].completionParts[0].text")
            local cursor = vim.api.nvim_win_get_cursor(0)
            local line = vim.api.nvim_get_current_line()
            local completion = string.match(fullCompletion, '[ ,;.]*[^ ,;.]+')
            vim.defer_fn(function ()
                if (string.match(completion, '^\t')) then
                    vim.api.nvim_buf_set_lines(0, cursor[1], cursor[1], true, { completion })
                    vim.api.nvim_win_set_cursor(0, { cursor[1] + 1, #completion })
                else
                    local nline = line:sub(0, cursor[2]) .. completion .. line:sub(cursor[2] + 1)
                    vim.api.nvim_set_current_line(nline)
                    vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + #completion })
                end
            end, 0)
        end, { expr = true })
    end
}

from codeium.vim.

klew avatar klew commented on August 23, 2024 1

Me too :)

The more I work with codeium the more I see useless suggestions in another lines. Accepting partial completion word-by-word or by-line would be nice.

from codeium.vim.

pqn avatar pqn commented on August 23, 2024 1

As a small update, we've confirmed that per-word/per-line is something we could probably do across all editors. Before we figure out what it looks like, I want to ask anyone who is familiar with the copilot.lua, etc., what are the word boundaries that we should be using to make this most useful?

from codeium.vim.

LeonardoMor avatar LeonardoMor commented on August 23, 2024 1

Hello guys,

I have implemented a quick and dirty solution for NeoVim in lua. I've been using it for several weeks, it handles word and line completion quite well (line completion has some indentation problems with auto indenting). I thought I share it with you, maybe someone has some more time to clear it up a bit.

use {
    'Exafunction/codeium.vim',
    config = function ()
        vim.g.codeium_no_map_tab = true
        vim.keymap.set('i', '<M-BS>', function () return vim.fn['codeium#Accept']() end, { expr = true })
        vim.keymap.set('i', '<M-Right>', function () return vim.fn['codeium#CycleCompletions'](1) end, { expr = true })
        vim.keymap.set('i', '<M-Left>', function () return vim.fn['codeium#CycleCompletions'](-1) end, { expr = true })
        vim.keymap.set('i', '<M-Esc>', function () return vim.fn['codeium#Clear']() end, { expr = true })

        -- Line completion
        vim.keymap.set('i', '<M-Enter>', function ()
            local fullCompletion = vim.api.nvim_eval("b:_codeium_completions.items[b:_codeium_completions.index].completionParts[0].text")
            local cursor = vim.api.nvim_win_get_cursor(0)
            local line = vim.api.nvim_get_current_line()
            local completion = string.gsub(fullCompletion, '\n.*$', '')
            if (completion ~= '') then
                vim.defer_fn(function ()
                    local nline = line:sub(0, cursor[2]) .. completion .. line:sub(cursor[2] + 1)
                    vim.api.nvim_set_current_line(nline)
                    vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + #completion })
                    print('pre enter ' .. vim.inspect(cursor))
                    vim.api.nvim_feedkeys('\n', 'i', true)
                end, 0)
            end
        end, { expr = true })

        -- Word completion
        vim.keymap.set('i', '<M-Space>', function ()
            local fullCompletion = vim.api.nvim_eval("b:_codeium_completions.items[b:_codeium_completions.index].completionParts[0].text")
            local cursor = vim.api.nvim_win_get_cursor(0)
            local line = vim.api.nvim_get_current_line()
            local completion = string.match(fullCompletion, '[ ,;.]*[^ ,;.]+')
            vim.defer_fn(function ()
                if (string.match(completion, '^\t')) then
                    vim.api.nvim_buf_set_lines(0, cursor[1], cursor[1], true, { completion })
                    vim.api.nvim_win_set_cursor(0, { cursor[1] + 1, #completion })
                else
                    local nline = line:sub(0, cursor[2]) .. completion .. line:sub(cursor[2] + 1)
                    vim.api.nvim_set_current_line(nline)
                    vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + #completion })
                end
            end, 0)
        end, { expr = true })
    end
}

These are the coolest bindings I've seen

from codeium.vim.

LeonardoMor avatar LeonardoMor commented on August 23, 2024 1

Does anyone feel confident enough to make a PR that adds native support for this

Almost there. I've been working on this and pretty happy with the results so far. I'll submit a PR soon.

from codeium.vim.

pqn avatar pqn commented on August 23, 2024

This is an interesting one. Do you have an example of a situation recently where you found yourself really wishing for this?

from codeium.vim.

luiz00martins avatar luiz00martins commented on August 23, 2024

I see no inconvenience just follow the ghost text and type the next word(~10 chars on average) ourselves.

There's also no issue in pressing 10 times, but we tend to prefer db. That's kind of the point of using Vim/Neovim. Saving a few keystrokes over a long period of time to preserve our sanity (and our fingers) in the long run.

When most plugins don't provide a feature, we probably need to think about why they don't, too.

copilot.lua does implement this.

In fact, in implements both a 'by word' completion (complete the current word, leaving the rest of the completion intact), and a 'by line' completion (complete the current line, leaving the rest of the completion intact). I find myself using the line completion quite more often than the 'full' completion.

That would mean the ghost text will become a requirement for this feature, then it will conflict with the on-the-plan feature proposed in #3.

It doesn't have to conflict with support for a completion engine, if you keep the functionalities separate.

I use both copilot.lua and copilot-cmp. copilot-cmp has nothing that we are discussing in here, nor is it aware of any of it, and just hooks to nvim-cmp. copilot.lua on the other hand, which provides the ghost text, provides the functionality of 'by-word' and 'by-line' completion.

That is, disabling ghost-text (and just using nvim-cmp for completions) would just disable this feature.

from codeium.vim.

luiz00martins avatar luiz00martins commented on August 23, 2024

I heavily third this request. I'd go further and also suggest adding a 'line-by-line' completion.

It's quite common for codeium.vim to have a completion that is perfect for the current line, but also attaches 1-to-3 unnecessary (or wrong) lines extra. I constantly find myself completing everything, and then deleting the extra lines, keeping only one. Having a feature for that would be great.

copilot.lua has this feature, and I tend to use it a lot.

from codeium.vim.

luiz00martins avatar luiz00martins commented on August 23, 2024

An opinion about the line-by-line completion (which is mostly a critique of copilot.lua's implementation):

When you complete the current line on copilot.lua, the cursor automatically jumps to the next line (i.e. it adds a newline in the end of the completion). It's quite common to find myself completing, and then removing the superfluous empty line added. However, I understand why this is the case: It's mostly so you can 'chain complete' (i.e. repeatedly press the mapping to complete the next lines if you wish).

Here's my proposed solution:

  • If there's some completion in the current line, complete the current line (without adding a newline, keeping the cursor at the end of the completion).
  • If there's nothing to complete in the current line, but there is a remaining completion below, complete the next line (so the cursor would land at the end of the next completion).
  • If there's no completion at all, do nothing.

This implementation makes possible to chain complete, without adding a superfluous line in the case where you only want one line.

from codeium.vim.

klew avatar klew commented on August 23, 2024

Vim has build in meaning of "word" and "WORD". First one is build of letters, digits and underscores. Second one is a sequence of non-blank chars. See :help word, :help WORD

I think that those options will be most intuitive for vim users.

Altenarnative way may be something like this: when completion is accepted, mode is changed to Visual and it allows to use standard Vim movement commands to select as much of suggestion as we want, and then another "tab" confirms accepted part.

from codeium.vim.

luiz00martins avatar luiz00martins commented on August 23, 2024

I second klew's idea of using the built-in 'word' and/or 'WORD' from vim.

Specially because most users will be familiar with them, and each user can already customize the definition themselves (e.g. the iskeyword option).

from codeium.vim.

pidgeon777 avatar pidgeon777 commented on August 23, 2024

It would be nice to implement an option to let the user choose between an autocomplete based on "word" or "WORD".

from codeium.vim.

aranc avatar aranc commented on August 23, 2024

This seems to be working:

function! CompleteNextWord()
  let dict = copilot#GetDisplayedSuggestion()
  let text = dict['text']
  let first = split(text, ' ')[0]
  return first . ' '
endfunction

inoremap <silent><expr> <C-J> CompleteNextWord()

from codeium.vim.

dpetka2001 avatar dpetka2001 commented on August 23, 2024

@aranc In which file did you put that function?

from codeium.vim.

aranc-pix avatar aranc-pix commented on August 23, 2024

@aranc In which file did you put that function?

Hi, I added it to my .vimrc

from codeium.vim.

dpetka2001 avatar dpetka2001 commented on August 23, 2024

@aranc-pix Are your dotfiles public? Also i see that you use copilot in the function. Is this working with codeium?

from codeium.vim.

aranc-pix avatar aranc-pix commented on August 23, 2024

@aranc-pix Are your dotfiles public? Also i see that you use copilot in the function. Is this working with codeium?

Oops, seems like I thought this was an "nvim copilot" discussion and not codeium

not public. I only added those lines for word-by-word copilot support. but it's probably not relevant to codeium

from codeium.vim.

fwy avatar fwy commented on August 23, 2024

I wrote a version of line and word completion in vimscript based on the lua implementation by @szilu, with a few changes and my own preferred key mappings. After a few days of use, it is also working OK for me. During autocompletion there is sometimes a lag with a race condition, where my typing will get ahead of codeium and some characters (usually parentheses) are placed before the completed text instead of after it. However, this is intermittent and may be general codeium behavior on my workstation, I am not sure. It might not happen on a faster machine.

`
" Line completion
imap <C-.> call CompleteLine()
function! CompleteLine() abort
let fullCompletion = b:_codeium_completions.items[b:_codeium_completions.index].completionParts[0].text
let curpos = getcurpos()
let line = getline(".")
let completion = substitute(fullCompletion, "\n.*$", "", "")
if completion != ''
let nline = line[0:curpos[2]] . completion . line[curpos[2] + 1:]
call setline(curpos[1], nline)
call cursor(line, len(nline) + 1)
endif
endfunction

" Word completion
imap <C-,> call CompleteWord()
function! CompleteWord() abort
let fullCompletion = b:_codeium_completions.items[b:_codeium_completions.index].completionParts[0].text
let curpos = getcurpos()
let line = getline(".")
let completion = matchstr(fullCompletion, '[ ,;.\t]*[^ ,;.\t]+')
if completion != ''
let nline = line[0:curpos[2]] . completion . line[curpos[2] + 1:]
call setline(curpos[1], nline)
call cursor(line, len(nline) + 1)
endif
endfunction
`

BTW, I am running codeium.vim on Windows 10. I mention this because I haven't noticed other postings from Windows users.

from codeium.vim.

xmready avatar xmready commented on August 23, 2024

@pqn what is the status of getting this feature implemented? Very excited to see this supported without .vimrc tweaks

from codeium.vim.

LeonardoMor avatar LeonardoMor commented on August 23, 2024

For those that use whichkey, I've made a version of the mappings suggested by @fwy with some error handling for when there are no completions:

-- Executes a normal key presses. Used to fallback to the normal behavior of the keys in the keymap
local function fallback(key)
  vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<C-g>u" .. key .. "<C-g>u", true, true, true), "n", true)
end

-- See if there are Codeium completions. If there are, return them
local function getCodeiumCompletions()
  local status, completions = pcall(function()
    return vim.api.nvim_eval "b:_codeium_completions.items[b:_codeium_completions.index].completionParts[0].text"
  end)
  if status then
    return completions
  else
    return nil
  end
end

M.codeium = {
  i = {
    ["<A-l>"] = {
      function()
        return vim.fn["codeium#Accept"]()
      end,
      "Accept completion",
      opts = { expr = true, silent = true },
    },
    ["<A-Bslash>"] = {
      function()
        return vim.fn["codeium#Complete"]()
      end,
      "Manually trigger suggestion",
      opts = { expr = true, silent = true },
    },
    ["<A-]>"] = {
      function()
        return vim.fn["codeium#CycleCompletions"](1)
      end,
      "Cycle completions forwards",
      opts = { expr = true, silent = true },
    },
    ["<A-[>"] = {
      function()
        return vim.fn["codeium#CycleCompletions"](-1)
      end,
      "Cycle completions backwards",
      opts = { expr = true, silent = true },
    },
    ["<A-BS>"] = {
      function()
        return vim.fn["codeium#Clear"]()
      end,
      "Clear completion",
      opts = { expr = true },
    },
    ["<C-Right>"] = {
      function()
        local fullCompletion = getCodeiumCompletions()
        local cursor = vim.api.nvim_win_get_cursor(0)
        local line = vim.api.nvim_get_current_line()
        if not fullCompletion then
          return fallback "<C-Right>"
        end
        local completion = fullCompletion:match "[ ,;.]*[^ ,;.]+"
        vim.defer_fn(function()
          if string.match(completion, "^\t") then
            vim.api.nvim_buf_set_lines(0, cursor[1], cursor[1], true, { completion })
            vim.api.nvim_win_set_cursor(0, { cursor[1] + 1, #completion })
          else
            local nline = line:sub(0, cursor[2]) .. completion .. line:sub(cursor[2] + 1)
            vim.api.nvim_set_current_line(nline)
            vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + #completion })
          end
        end, 0)
      end,
      "Accept next word in completion",
      opts = { expr = true },
    },
    ["<Right>"] = {
      function()
        local fullCompletion = getCodeiumCompletions()
        local cursor = vim.api.nvim_win_get_cursor(0)
        local line = vim.api.nvim_get_current_line()
        if not fullCompletion then
          return fallback "<Right>"
        end
        local completion = fullCompletion:gsub("\n.*$", "")
        if completion == "" then
          return fallback "<Right>"
        end
        vim.defer_fn(function()
          local nline = line:sub(0, cursor[2]) .. completion .. line:sub(cursor[2] + 1)
          vim.api.nvim_set_current_line(nline)
          vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + #completion })
          fallback "<CR>"
        end, 0)
      end,
      "Accept next line in completion",
      opts = { expr = true },
    },
  },
}

from codeium.vim.

joakin avatar joakin commented on August 23, 2024

I had this in copilot and I'm trying codeium and I find it super important. Here is how I've done it which seems to work well (inspired by the two snippets above) and is a lot shorter:

    local expr_opts = {
      noremap = true,
      silent = true,
      expr = true,
      -- With expr = true, replace_keycodes is set to true. See https://github.com/orgs/community/discussions/29817
      -- We need to set it to false to avoid extraneous caracters when accepting a suggestion.
      replace_keycodes = false,
    }

    local function getCodeiumCompletions()
      local status, completion = pcall(function()
        return vim.api.nvim_eval("b:_codeium_completions.items[b:_codeium_completions.index].completionParts[0].text")
      end)
      if status then
        return completion
      else
        return ""
      end
    end
    local function accept_one_line()
      local text = getCodeiumCompletions()
      return vim.fn.split(text, [[[\n]\zs]])[1] .. "\n"
    end
    local function accept_one_word()
      local text = getCodeiumCompletions()
      return vim.fn.split(text, [[\(\w\+\|\W\+\)\zs]])[1]
    end

    vim.keymap.set("i", "<C-L>", accept_one_line, expr_opts)
    vim.keymap.set("i", "<C-G><C-L>", accept_one_word, expr_opts)

There is some wonkiness with indentation and completing at the end of a line, maybe someone else can figure out something simple to fix that.

from codeium.vim.

LeonardoMor avatar LeonardoMor commented on August 23, 2024

I had this in copilot and I'm trying codeium and I find it super important. Here is how I've done it which seems to work well (inspired by the two snippets above) and is a lot shorter:

    local expr_opts = {
      noremap = true,
      silent = true,
      expr = true,
      -- With expr = true, replace_keycodes is set to true. See https://github.com/orgs/community/discussions/29817
      -- We need to set it to false to avoid extraneous caracters when accepting a suggestion.
      replace_keycodes = false,
    }

    local function getCodeiumCompletions()
      local status, completion = pcall(function()
        return vim.api.nvim_eval("b:_codeium_completions.items[b:_codeium_completions.index].completionParts[0].text")
      end)
      if status then
        return completion
      else
        return ""
      end
    end
    local function accept_one_line()
      local text = getCodeiumCompletions()
      return vim.fn.split(text, [[[\n]\zs]])[1] .. "\n"
    end
    local function accept_one_word()
      local text = getCodeiumCompletions()
      return vim.fn.split(text, [[\(\w\+\|\W\+\)\zs]])[1]
    end

    vim.keymap.set("i", "<C-L>", accept_one_line, expr_opts)
    vim.keymap.set("i", "<C-G><C-L>", accept_one_word, expr_opts)

There is some wonkiness with indentation and completing at the end of a line, maybe someone else can figure out something simple to fix that.

Pretty neat. Thanks

from codeium.vim.

LeonardoMor avatar LeonardoMor commented on August 23, 2024

I had this in copilot and I'm trying codeium and I find it super important. Here is how I've done it which seems to work well (inspired by the two snippets above) and is a lot shorter:

    local expr_opts = {
      noremap = true,
      silent = true,
      expr = true,
      -- With expr = true, replace_keycodes is set to true. See https://github.com/orgs/community/discussions/29817
      -- We need to set it to false to avoid extraneous caracters when accepting a suggestion.
      replace_keycodes = false,
    }

    local function getCodeiumCompletions()
      local status, completion = pcall(function()
        return vim.api.nvim_eval("b:_codeium_completions.items[b:_codeium_completions.index].completionParts[0].text")
      end)
      if status then
        return completion
      else
        return ""
      end
    end
    local function accept_one_line()
      local text = getCodeiumCompletions()
      return vim.fn.split(text, [[[\n]\zs]])[1] .. "\n"
    end
    local function accept_one_word()
      local text = getCodeiumCompletions()
      return vim.fn.split(text, [[\(\w\+\|\W\+\)\zs]])[1]
    end

    vim.keymap.set("i", "<C-L>", accept_one_line, expr_opts)
    vim.keymap.set("i", "<C-G><C-L>", accept_one_word, expr_opts)

There is some wonkiness with indentation and completing at the end of a line, maybe someone else can figure out something simple to fix that.

One thing with this is that, if the next thing in the completion is a space, you have to accept it and then accept it again to get the next non-space thing.

One way to fix that is by ending that function like this:

        local word_delimeters = " %(%)%[%]%{%}',\"`|%.%%"
        local nextword_pattern = "[" .. word_delimeters .. "]*[^" .. word_delimeters .. "]+"
        return full_completion:match(nextword_pattern)

Populate the word delimiters with whatever you prefer. This has been working well.

from codeium.vim.

teocns avatar teocns commented on August 23, 2024

This proved to work well for me, no funny spacing behavior.

    local function accept_one_word()
      local text = getCodeiumCompletions()
      -- Adjusting the pattern to consider a broader range of non-whitespace characters, including punctuation.
      local first_non_space = text:find "%S" -- Find the index of the first non-space character.

      if not first_non_space then return "" end -- If there's no non-space character, return an empty string.

      -- Capture the first word along with any immediately preceding spaces.
      -- The pattern looks for any leading spaces, followed by a sequence of non-space characters.
      local captured = text:match("^(%s*%S+)", first_non_space)
      if not captured then return "" end -- Safety check, though at this point captured should always be non-nil.

      -- Look ahead for any syntactically significant characters that should be included with the word.
      local next_char_index = first_non_space + #captured
      local next_char = text:sub(next_char_index, next_char_index)
      if next_char:match "[%s,{}%[%]\"']" then captured = captured .. next_char end

      return captured
    end

from codeium.vim.

JohnRigoni avatar JohnRigoni commented on August 23, 2024

Here's my hacky/fragile attempt, though I can't break it anymore: https://github.com/JohnRigoni/codeium.vim

I apologize to the devs as it needs to ignore call codeium#server#Request('AcceptCompletion', {'metadata': codeium#server#RequestMetadata(), 'completion_id': current_completion.completion.completionId}), but hopefully we can see this feature officially rolled out soon.

This is prone to breakage with updates and no promises I keep the repo updated.

from codeium.vim.

LeonardoMor avatar LeonardoMor commented on August 23, 2024

I find @fwy approach superior because it works even if there's existing text already in front of the cursor. It still breaks on some circumstances but less often than other solutions.

from codeium.vim.

fortenforge avatar fortenforge commented on August 23, 2024

Does anyone feel confident enough to make a PR that adds native support for this

from codeium.vim.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.