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

feat: support for statuscolumn #1037

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Super fast git decorations implemented purely in Lua.
- Live intra-line word diff
- Ability to display deleted/changed lines via virtual lines.
- Support for detached working trees.
- Support for `'statuscolumn'`.

## Requirements

Expand Down
13 changes: 13 additions & 0 deletions doc/gitsigns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ setup({cfg}) *gitsigns.setup()*
{cfg} (table|nil): Configuration for Gitsigns.
See |gitsigns-usage| for more details.

statuscolumn() *gitsigns.statuscolumn()*
Function that can be used in the 'statuscolumn' option.

Note calling this function will automatically disable
|gitsigns-config-signcolumn|.

e.g. >lua
vim.o.statuscolumn = "%s%l%C%{%v:lua.require'gitsigns'.statuscolumn()%} "
<

Returns: ~
(string)

attach({bufnr}, {ctx}, {callback?}) *gitsigns.attach()*
Attach Gitsigns to the buffer.

Expand Down
19 changes: 16 additions & 3 deletions gen_help.lua
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,19 @@ local function parse_param(x)
return name, ty, des
end

--- @param x string
--- @return string? type
--- @return string? name
--- @return string? description
local function parse_return(x)
local ty, name, des = x:match('([^ ]+) +([^ ]+) *(.*)')
if ty then
return ty, name, des
end
ty = x:match('([^ ]+)')
return ty
end

--- @param x string[]
--- @return string[]
local function trim_lines(x)
Expand Down Expand Up @@ -207,11 +220,11 @@ local function render_param_or_return(name, ty, desc, name_pad)
ty = ty:gsub('Gitsigns%.%w+', 'table')

name_pad = name_pad and (name_pad + 3) or 0
local name_str --- @type string
local name_str = '' --- @type string

if name == ':' then
name_str = ''
else
elseif name then
local nf = '%-' .. tostring(name_pad) .. 's'
name_str = nf:format(string.format('{%s} ', name))
end
Expand Down Expand Up @@ -266,7 +279,7 @@ local function process_doc_comment(state, doc_comment, desc, params, returns)
end

if emmy_type == 'return' then
local ty, name, rdesc = parse_param(emmy_str)
local ty, name, rdesc = parse_return(emmy_str)
returns[#returns + 1] = { name, ty, { rdesc } }
return 'in_return'
end
Expand Down
35 changes: 26 additions & 9 deletions lua/gitsigns.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
local async = require('gitsigns.async')
local log = require('gitsigns.debug.log')

local gs_config = require('gitsigns.config')
local config = gs_config.config

local api = vim.api
local uv = vim.uv or vim.loop
Expand Down Expand Up @@ -101,6 +97,7 @@ local update_cwd_head = async.create(function()
{},
async.create(function(err)
local __FUNC__ = 'cwd_watcher_cb'
local log = require('gitsigns.debug.log')
if err then
log.dprintf('Git dir update error: %s', err)
return
Expand All @@ -125,13 +122,16 @@ local function setup_cli()
})
end

local function setup_debug()
--- @param config Gitsigns.Config
local function setup_debug(config)
local log = require('gitsigns.debug.log')
log.debug_mode = config.debug_mode
log.verbose = config._verbose
end

--- @async
local function setup_attach()
--- @param config Gitsigns.Config
local function setup_attach(config)
if not config.auto_attach then
return
end
Expand All @@ -146,6 +146,7 @@ local function setup_attach()
local bufnr = args.buf --[[@as integer]]
if attach_autocmd_disabled then
local __FUNC__ = 'attach_autocmd'
local log = require('gitsigns.debug.log')
log.dprint('Attaching is disabled')
return
end
Expand Down Expand Up @@ -199,11 +200,25 @@ local function setup_cwd_head()
})
end

--- Function that can be used in the 'statuscolumn' option.
---
--- Note calling this function will automatically disable
--- |gitsigns-config-signcolumn|.
---
--- e.g. >lua
--- vim.o.statuscolumn = "%s%l%C%{%v:lua.require'gitsigns'.statuscolumn()%} "
--- <
--- @return string
function M.statuscolumn()
return require('gitsigns.manager').statuscolumn()
end

--- Setup and start Gitsigns.
---
--- @param cfg table|nil Configuration for Gitsigns.
--- See |gitsigns-usage| for more details.
function M.setup(cfg)
local gs_config = require('gitsigns.config')
gs_config.build(cfg)

if vim.fn.executable('git') == 0 then
Expand All @@ -213,10 +228,12 @@ function M.setup(cfg)

api.nvim_create_augroup('gitsigns', {})

setup_debug()
local config = gs_config.config

setup_debug(config)
setup_cli()
require('gitsigns.highlight').setup()
setup_attach()
setup_attach(config)
setup_cwd_head()
end

Expand All @@ -232,7 +249,7 @@ return setmetatable(M, {
return actions[f]
end

if config.debug_mode then
if require('gitsigns.config').config.debug_mode then
local debug = require('gitsigns.debug')
if debug[f] then
return debug[f]
Expand Down
53 changes: 52 additions & 1 deletion lua/gitsigns/manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,52 @@ local signs_staged --- @type Gitsigns.Signs

local M = {}

local statuscolumn_active = false

--- @param bufnr? integer
--- @param top? integer
--- @param bot? integer
local function redraw_statuscol(bufnr, top, bot)
if statuscolumn_active then
api.nvim__redraw({
buf = bufnr,
range = { top, bot },
statuscolumn = true,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you experience that both range and statuscolumn are necessary? The entire window should already be redrawn with statuscolumn = true. But yeah previously placing sign extmarks was what triggered redraws so since that doesn't happen here anymore I think these manual redraws are necessary.

})
end
end

function M.statuscolumn()
if not statuscolumn_active then
config.signcolumn = false
statuscolumn_active = true
end

local res = {}
local res_len = 0
local max_pad = 0
local lnum = vim.v.lnum
for _, signs in pairs({ signs_normal, signs_staged }) do
if next(signs.signs) then
max_pad = 2
end
local marks = api.nvim_buf_get_extmarks(0, signs.ns, { lnum - 1, 0 }, { lnum - 1, -1 }, {})
Copy link

@luukvbaal luukvbaal Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
local marks = api.nvim_buf_get_extmarks(0, signs.ns, { lnum - 1, 0 }, { lnum - 1, -1 }, {})
local buf = api.nvim_win_get_buf(vim.g.statusline_winid)
local marks = api.nvim_buf_get_extmarks(buf, signs.ns, { lnum - 1, 0 }, { lnum - 1, -1 }, {})

I suppose there is no need to change the function signature like I suggested on matrix.

for _, mark in pairs(marks) do
local id = mark[1]
local s = signs.signs[id]
if s then
table.insert(res, '%#' .. s[2] .. '#')
table.insert(res, s[1])
res_len = res_len + vim.str_utfindex(s[1])
table.insert(res, '%#NONE#')
Copy link

@luukvbaal luukvbaal Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want %* here to restore the currently active default statuscolumn highlight (affected by cursorline etc). (Unless this does the same?)

end
end
end

local pad = math.max(0, max_pad - res_len)
return table.concat(res) .. string.rep(' ', pad)
end

--- @param bufnr integer
--- @param signs Gitsigns.Signs
--- @param hunks Gitsigns.Hunk.Hunk[]
Expand Down Expand Up @@ -77,6 +123,9 @@ local function apply_win_signs(bufnr, top, bot, clear)
if signs_staged then
apply_win_signs0(bufnr, signs_staged, bcache.hunks_staged, top, bot, clear, false)
end
if clear then
redraw_statuscol(bufnr, top, bot)
end
end

--- @param blame table<integer,Gitsigns.BlameInfo?>?
Expand Down Expand Up @@ -349,7 +398,7 @@ function M.show_deleted_in_float(bufnr, nsd, hunk, staged)

-- Navigate to hunk
vim.cmd('normal ' .. tostring(hunk.removed.start) .. 'gg')
vim.cmd('normal ' .. vim.api.nvim_replace_termcodes('z<CR>', true, false, true))
vim.cmd('normal ' .. api.nvim_replace_termcodes('z<CR>', true, false, true))
end)

local last_lnum = api.nvim_buf_line_count(bufnr)
Expand Down Expand Up @@ -531,6 +580,7 @@ function M.detach(bufnr, keep_signs)
if signs_staged then
signs_staged:remove(bufnr)
end
redraw_statuscol(bufnr)
end
end

Expand All @@ -542,6 +592,7 @@ function M.reset_signs()
if signs_staged then
signs_staged:reset()
end
redraw_statuscol()
end

--- @param _cb 'win'
Expand Down
22 changes: 12 additions & 10 deletions lua/gitsigns/signs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ local config = require('gitsigns.config').config
--- @field hls table<Gitsigns.SignType,Gitsigns.SignConfig>
--- @field name string
--- @field group string
--- @field signs table<integer,[string,string]>
--- @field config table<string,Gitsigns.SignConfig>
--- @field ns integer
local M = {}
Expand All @@ -32,24 +33,23 @@ end
function M:remove(bufnr, start_lnum, end_lnum)
if start_lnum then
api.nvim_buf_clear_namespace(bufnr, self.ns, start_lnum - 1, end_lnum or start_lnum)
for i = start_lnum - 1, (end_lnum or start_lnum) - 1 do
self.signs[i] = nil
end
else
self.signs = {}
api.nvim_buf_clear_namespace(bufnr, self.ns, 0, -1)
end
end

---@param bufnr integer
---@param signs Gitsigns.Sign[]
function M:add(bufnr, signs)
if not config.signcolumn and not config.numhl and not config.linehl then
-- Don't place signs if it won't show anything
return
end

for _, s in ipairs(signs) do
if not self:contains(bufnr, s.lnum) then
local cs = self.config[s.type]
local text = cs.text
if config.signcolumn and cs.show_count and s.count then
if cs.show_count and s.count then
local count = s.count
local cc = config.count_chars
local count_char = cc[count] or cc['+'] or ''
Expand All @@ -58,20 +58,21 @@ function M:add(bufnr, signs)

local hls = self.hls[s.type]

local ok, err = pcall(api.nvim_buf_set_extmark, bufnr, self.ns, s.lnum - 1, -1, {
id = s.lnum,
local ok, id_or_err = pcall(api.nvim_buf_set_extmark, bufnr, self.ns, s.lnum - 1, -1, {
sign_text = config.signcolumn and text or '',
priority = config.sign_priority,
sign_hl_group = hls.hl,
number_hl_group = config.numhl and hls.numhl or nil,
line_hl_group = config.linehl and hls.linehl or nil,
})

if not ok and config.debug_mode then
if ok then
self.signs[id_or_err] = { text, hls.hl }
elseif config.debug_mode then
vim.schedule(function()
error(table.concat({
string.format('Error placing extmark on line %d', s.lnum),
err,
id_or_err,
}, '\n'))
end)
end
Expand Down Expand Up @@ -129,6 +130,7 @@ function M.new(cfg, name)
self.hls = name == 'staged' and config._signs_staged or config.signs
self.group = 'gitsigns_signs_' .. (name or '')
self.ns = api.nvim_create_namespace(self.group)
self.signs = {}
return self
end

Expand Down
Loading