Skip to content

Commit

Permalink
feat: support for statuscolumn
Browse files Browse the repository at this point in the history
  • Loading branch information
lewis6991 committed Jun 11, 2024
1 parent 4a143f1 commit 87dec80
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 23 deletions.
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,
})
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 }, {})
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#')
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

0 comments on commit 87dec80

Please sign in to comment.