kevinhwang91 / nvim-ufo

Not UFO in the sky, but an ultra fold in Neovim.
BSD 3-Clause "New" or "Revised" License
2.16k stars 37 forks source link

go if err != nil, fold to the back of the previous line #207

Closed kackerx closed 3 months ago

kackerx commented 3 months ago

Feature description

Great job! I implemented foldingif _, err := foo()based on your plugin, err != nil { to _, err := foo() or ... that's cool, but I don't know how to do it for a new line of if err != nil
WechatIMG5567

Describe the solution you'd like

Is it possible to do this, if err != nil to the end of the line above it, 'err := foo() or return err'

Additional context

No response

kackerx commented 3 months ago
local handler = function(virtText, lnum, endLnum, width, truncate)
  local line = vim.fn.getline(lnum)
  if line:find("if%s+err%s*!= nil") then
      local prevLine = vim.api.nvim_buf_get_lines(0, lnum - 2, lnum - 1, false)[1]
      local indent = string.match(prevLine, "^%s*") or "" 
      local startLine = lnum
      local endLine = endLnum
      local lines = vim.api.nvim_buf_get_lines(0, startLine, endLine - 1, false)
      for i, l in ipairs(lines) do
          lines[i] = l:gsub("^%s*", ""):gsub("return", "..") 
      end
      local newText = indent .. table.concat(lines, "; ")
      virtText = { { newText, "@comment" } }
      return virtText
  end
  if line:find("if%s+[^;]+;[^;]+!= nil") then
      -- local startLine = lnum
      -- local endLine = endLnum
      -- local content = table.concat(vim.api.nvim_buf_get_lines(0, startLine, endLine - 1, false), "")
      local startLine = lnum
      local endLine = endLnum
      local lines = vim.api.nvim_buf_get_lines(0, startLine, endLine - 1, false)
      for i, l in ipairs(lines) do
          lines[i] = l:gsub("^%s*", "")
      end
      local content = table.concat(lines, "; ")

      local newVirtText = {}
      -- local suffix = ('  %d '):format(endLnum - lnum)
      local suffix = " ? " .. content
      local sufWidth = vim.fn.strdisplaywidth(suffix)
      local targetWidth = width - sufWidth
      local curWidth = 0
      local errCount = 0
      for _, chunk in ipairs(virtText) do
          local chunkText = chunk[1]
          local chunkWidth = vim.fn.strdisplaywidth(chunkText)

          if targetWidth > curWidth + chunkWidth then
              -- chunkText = chunkText:gsub("!=", "")
              if chunkText == "err" then
                  errCount = errCount + 1
                  if errCount ~= 2 then
                      table.insert(newVirtText, { chunkText, chunk[2] })
                  end
              end

              if chunkText ~= ";" and chunkText ~= "err" and chunkText ~= "!=" and chunkText ~= "nil" and chunkText ~= "{" and chunkText ~= "if" and chunkText ~= " " then
                  if chunkText == ":=" or chunkText == "=" then
                      chunkText = " " .. chunkText .. " "
                      table.insert(newVirtText, { chunkText, chunk[2] })
                  elseif chunkText == "," then
                      chunkText = "," .. " "
                      table.insert(newVirtText, { chunkText, chunk[2] })
                  else
                      table.insert(newVirtText, { chunkText, chunk[2] })
                  end
              end
          end
          curWidth = curWidth + vim.fn.strdisplaywidth(chunkText)
      end
      -- newVirtText = newVirtText:gsub("if ", ""):gsub("; err != nil {", "")
      table.insert(newVirtText, { suffix, 'k.bracket' })
      return newVirtText
  end

  local newVirtText = {}
  -- local suffix = ('  %d '):format(endLnum - lnum)
  local suffix = ('...%d '):format(endLnum - lnum)
  local sufWidth = vim.fn.strdisplaywidth(suffix)
  local targetWidth = width - sufWidth
  local curWidth = 0
  for _, chunk in ipairs(virtText) do
      local chunkText = chunk[1]
      local chunkWidth = vim.fn.strdisplaywidth(chunkText)
      if targetWidth > curWidth + chunkWidth then
          table.insert(newVirtText, chunk)
      else
          chunkText = truncate(chunkText, targetWidth - curWidth)
          local hlGroup = chunk[2]
          table.insert(newVirtText, { chunkText, hlGroup })
          chunkWidth = vim.fn.strdisplaywidth(chunkText)
          -- str width returned from truncate() may less than 2nd argument, need padding
          if curWidth + chunkWidth < targetWidth then
              suffix = suffix .. (' '):rep(targetWidth - curWidth - chunkWidth)
          end
          break
      end
      curWidth = curWidth + vim.fn.strdisplaywidth(chunkText)
  end
  table.insert(newVirtText, { suffix, 'k.bracket' })

  return newVirtText
end
kackerx commented 3 months ago

This is my rough implementation of the effect as shown in the figure, the fly in the ointment is, if err! = nil {can only collapse on the current line, and collapsing at the end of the previous line would be the perfect plugin for the go language

kevinhwang91 commented 3 months ago

Must hack in two parts:

  1. fold_virt_text_handler;
  2. provider_selector;

I think the first part you have already mastered like the code you provided. For the second part, you can reference https://github.com/kevinhwang91/nvim-ufo/issues/125, get the LSP fold ranges, and forward search the if err, finally rebuild the new range.

kevinhwang91 commented 3 months ago

Add the get_fold_kind function in fold_virt_text_handler, no plan to write doc, maybe a new API should be better.

You can add a kind for new ranges when your rebuild your ranges and get them inside fold_virt_text_handler

kackerx commented 3 months ago

Add the get_fold_kind function in fold_virt_text_handler, no plan to write doc, maybe a new API should be better.在 fold_virt_text_handler 里面加上 get_fold_kind 函数,没有计划写文档,也许一个新的API应该更好。

You can add a kind for new ranges when your rebuild your ranges and get them inside fold_virt_text_handler当您重建范围并将它们放入其中 fold_virt_text_handler 时,您可以为新范围添加一种

我草, 原来是中国的大佬啊我还费劲去翻译😅, 哈哈哈, 感谢插件, 虽然没折腾明白, 看不太懂lua代码, 目前实现的效果是能用的, 如果能语法糖到上一行末尾, 真的是完美了, go2来到了

kevinhwang91 commented 3 months ago

lua就是js和go的混合,你wrap一下获取lsp ranges向前搜索重构range并自定义kind,在渲染函数中根据kind提取重构的range就行了

kackerx commented 3 months ago

lua就是js和go的混合,你wrap一下获取lsp ranges向前搜索重构range并自定义kind,在渲染函数中根据kind提取重构的range就行了

好的感谢老哥大概明白, 回头研究下

BrunoKrugel commented 1 week ago

mind share your updated version?