JoosepAlviste/nvim-ts-context-commentstring

Add `utils.get_visual_end_location`

RaafatTurki opened this issue ยท 4 comments

Currently we have utils.get_visual_start_location and it would be great if we've had its pair so one could compare comment strings at the start and end of a visual selection and abort commenting if they don't match.

More info about this use case can be found in this issue

Hey @RaafatTurki!

It does make sense to have this function in this plugin. I created a PR: #45 Could you try it out and see if it works correctly for your use case?

Also, if you don't mind, could you show your final solution as well? ๐Ÿ˜„

It worked pretty well, here's the final Comment.nvim pre_hook I ended up with

pre_hook = function(ctx)
  local comment_utils = require 'Comment.utils'
  local tsctxcs_utils = require 'ts_context_commentstring.utils'
  local tsctxcs_internal = require 'ts_context_commentstring.internal'
  
  local comment_strings = {}
  local cs_type = ctx.ctype == comment_utils.ctype.line and '__default' or '__multiline'

  local calc_cs = function (posision)
    return tsctxcs_internal.calculate_commentstring({
      key = cs_type,
      location = posision
    })
  end

  local abort_cs = function (msg)
    vim.notify(msg)
    return '%s'
  end

  -- visual commenting
  if ctx.cmotion == comment_utils.cmotion.v or ctx.cmotion == comment_utils.cmotion.V then
    table.insert(comment_strings, calc_cs(tsctxcs_utils.get_visual_start_location()))
    table.insert(comment_strings, calc_cs(tsctxcs_utils.get_visual_end_location()))
  -- block commenting
  elseif ctx.ctype == comment_utils.ctype.block then
    table.insert(comment_strings, calc_cs(tsctxcs_utils.get_cursor_location()))
  -- linewise commenting
  else
    table.insert(comment_strings, calc_cs(nil))
  end

  -- compare comment_strings and return one
  local last_cs = nil
  for i, cs in ipairs(comment_strings) do
    if i > 1 and cs ~= last_cs then
      return abort_cs('Commenting aborted due to mismatching comment strings')
    end
    last_cs = cs
  end

  return last_cs
end

One thing I'd like it to do better is not register something in the undo history when aborting but that's a Comment.nvim issue that I'll look further into (will post new snippet here when resolved).

I'm thinking that maybe it would make sense to maintain the pre_hook integration inside this plugin (or perhaps inside Comment.nvim). Then people wouldn't need to copy-paste a lot of unnecessary code into their configuration and we could maintain the integration in one of the plugins, keeping it always up-to-date, adding features, etc.

Then, the users could import it easily:

require('Comment').setup {
  pre_hook = require('ts_context_commentstring.integrations.comment_nvim').pre_hook,
}

Maybe once you're happy with your solution you could make a PR to this plugin or to Comment.nvim?

I very much appreciate the care you take in user experience!

In order for this to get implemented correctly an aborting mechanism is needed in the pre_hook (to avoid things like comment string parsing and inserting a change that does nothing in the undo history). Currently there is no such thing in Comment.nvim and its author wouldn't accept a PR to implement it so I'll look into other commenting plugins

Once I come up with a decent solution I'll PR an integration here.