diff --git a/dot_config/nvim/init.lua b/dot_config/nvim/init.lua index 2a4d8ee..2eea20a 100644 --- a/dot_config/nvim/init.lua +++ b/dot_config/nvim/init.lua @@ -463,6 +463,9 @@ require('lazy').setup({ local offset_encoding = (client and client.offset_encoding) or 'utf-16' local symbol_under_cursor = vim.fn.expand '' local params = vim.lsp.util.make_position_params(nil, offset_encoding) + if method == 'textDocument/references' then + params.context = { includeDeclaration = true } + end vim.lsp.buf_request(event.buf, method, params, function(err, result, context) if err then vim.notify(string.format('[kotlin] %s request failed: %s', label, err.message or tostring(err)), vim.log.levels.ERROR) @@ -874,12 +877,19 @@ require('lazy').setup({ return end - local saw_jar_target = false - for _, item in ipairs(items) do + local function format_location_item(item) + local filename = item.filename or item.uri or '' + local display = filename + if not is_jar_reference(display) then + display = vim.fn.fnamemodify(display, ':~:.') + end + return string.format('%s:%d:%d', display, item.lnum or 1, item.col or 1) + end + + local function jump_to_item(item) if is_jar_reference(item.filename) or is_jar_reference(item.uri) then - saw_jar_target = true if jump_to_jar_reference(item, label) then - return + return true end else local bufnr = vim.fn.bufnr(item.filename, false) @@ -916,10 +926,31 @@ require('lazy').setup({ new_col = 0 end vim.api.nvim_win_set_cursor(0, { line, new_col }) - return + return true end end end + return false + end + + if method == 'textDocument/references' and #items > 1 then + vim.ui.select(items, { + prompt = '[kotlin] references', + format_item = format_location_item, + }, function(item) + if item and not jump_to_item(item) then + vim.notify(string.format('[kotlin] %s target was not jumpable', label), vim.log.levels.INFO) + end + end) + return + end + + local saw_jar_target = false + for _, item in ipairs(items) do + saw_jar_target = saw_jar_target or is_jar_reference(item.filename) or is_jar_reference(item.uri) + if jump_to_item(item) then + return + end end if saw_jar_target then @@ -969,7 +1000,9 @@ require('lazy').setup({ vim.keymap.set('n', 'grd', safe_jump('textDocument/definition', 'definition'), { buffer = buf, desc = '[Kotlin] [G]oto [D]efinition' }) vim.keymap.set('n', 'gri', safe_jump('textDocument/implementation', 'implementation'), { buffer = buf, desc = '[Kotlin] [G]oto [I]mplementation' }) vim.keymap.set('n', 'grt', safe_jump('textDocument/typeDefinition', 'type definition'), { buffer = buf, desc = '[Kotlin] [G]oto [T]ype Definition' }) - vim.keymap.set('n', 'grr', safe_jump('textDocument/references', 'references'), { buffer = buf, desc = '[Kotlin] [G]oto [R]eferences' }) + vim.keymap.set('n', 'grr', function() + builtin.lsp_references { include_declaration = true, jump_type = 'never' } + end, { buffer = buf, desc = '[Kotlin] [G]oto [R]eferences' }) end end, }) diff --git a/dot_config/nvim/lua/custom/plugins/git.lua b/dot_config/nvim/lua/custom/plugins/git.lua index b62bcf0..9040e76 100644 --- a/dot_config/nvim/lua/custom/plugins/git.lua +++ b/dot_config/nvim/lua/custom/plugins/git.lua @@ -366,6 +366,123 @@ return { return vim.fs.normalize(path:sub(1, #path - #suffix - 1)) end + local jj_signs_base_mode = 'default_branch' + local jj_blame_enabled = true + local jj_blame_ns = vim.api.nvim_create_namespace 'dot-jj-current-line-blame' + local jj_blame_group = vim.api.nvim_create_augroup('dot-jj-current-line-blame', { clear = true }) + + local function resolve_jj_signs_base(root) + if jj_signs_base_mode == 'working_copy' then + return '@-' + end + return find_jj_default_branch(root) or '@-' + end + + local function set_jj_signs_base(root) + local base = resolve_jj_signs_base(root) + require('jjsigns.config').config.base = base + return base + end + + local function toggle_jj_signs_base() + local bufname = vim.api.nvim_buf_get_name(0) + local path = bufname ~= '' and vim.fs.normalize(bufname) or vim.fn.getcwd(0) + local root = vcs.find_root(path) + if not root or not vim.uv.fs_stat(root .. '/.jj') then + vim.notify('Not inside a jj repository.', vim.log.levels.WARN) + return + end + + if jj_signs_base_mode == 'default_branch' then + jj_signs_base_mode = 'working_copy' + else + jj_signs_base_mode = 'default_branch' + if not find_jj_default_branch(root) then + vim.notify('Could not find default branch. Falling back to @-. Set vim.g.dot_vcs_default_branches.', vim.log.levels.WARN) + end + end + + local base = set_jj_signs_base(root) + require('jjsigns.attach').refresh_all() + vim.notify('jjsigns base: ' .. base) + end + + local function default_jj_signs_base() + local root = vcs.find_root(vim.fn.getcwd(0)) + if not root or not vim.uv.fs_stat(root .. '/.jj') then + return '@-' + end + + local base = find_jj_default_branch(root) + if not base then + return + end + return base + end + + local function clear_jj_blame(bufnr) + vim.api.nvim_buf_clear_namespace(bufnr, jj_blame_ns, 0, -1) + end + + local function jj_relative_path(filepath, root) + if filepath:sub(1, #root + 1) == root .. '/' then + return filepath:sub(#root + 2) + end + return nil + end + + local function update_jj_blame(bufnr) + if not jj_blame_enabled or not vim.api.nvim_buf_is_valid(bufnr) then + return + end + + clear_jj_blame(bufnr) + local filepath = vim.api.nvim_buf_get_name(bufnr) + local root = vcs.find_root(filepath) + if not root or not vim.uv.fs_stat(root .. '/.jj') then + return + end + + local relpath = jj_relative_path(filepath, root) + if not relpath then + return + end + + local line = vim.api.nvim_win_get_cursor(0)[1] + local template = 'self.commit().change_id().short(8) ++ " " ++ self.commit().author().name() ++ " " ++ self.commit().description().first_line() ++ "\\n"' + system_async({ 'jj', '--ignore-working-copy', 'file', 'annotate', '-r', '@', '-T', template, relpath }, root, function(lines, code) + if code ~= 0 or not vim.api.nvim_buf_is_valid(bufnr) or not jj_blame_enabled then + return + end + + local blame = lines[line] + if not blame or blame == '' then + return + end + + clear_jj_blame(bufnr) + vim.api.nvim_buf_set_extmark(bufnr, jj_blame_ns, line - 1, 0, { + virt_text = { { ' ' .. blame, 'Comment' } }, + virt_text_pos = 'eol', + hl_mode = 'combine', + }) + end) + end + + local function toggle_jj_blame() + jj_blame_enabled = not jj_blame_enabled + if not jj_blame_enabled then + for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do + if vim.api.nvim_buf_is_loaded(bufnr) then + clear_jj_blame(bufnr) + end + end + else + update_jj_blame(vim.api.nvim_get_current_buf()) + end + vim.notify('jj line blame: ' .. (jj_blame_enabled and 'on' or 'off')) + end + local function map_jj_change_navigation(bufnr) if vcs.workspace_kind(bufnr) ~= 'jj' then return @@ -414,6 +531,7 @@ return { vim.keymap.set('n', '[c', function() jump_to_jj_change 'prev' end, { buffer = bufnr, desc = 'jj: previous change' }) + vim.keymap.set('n', 'tb', toggle_jj_blame, { buffer = bufnr, desc = 'Toggle jj line blame' }) end local attach = require 'jjsigns.attach' @@ -424,6 +542,10 @@ return { if filepath:match '^jar://' then return end + local root = vcs.find_root(filepath) + if root and vim.uv.fs_stat(root .. '/.jj') then + set_jj_signs_base(root) + end orig_attach_to_buffer(bufnr) if attach.is_attached(bufnr) then map_jj_change_navigation(bufnr) @@ -432,6 +554,7 @@ return { end require('jjsigns').setup { + base = default_jj_signs_base(), signs = { add = { text = '+' }, change = { text = '~' }, @@ -464,6 +587,17 @@ return { end end, }) + + vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI', 'BufEnter' }, { + group = jj_blame_group, + callback = function(args) + if vcs.workspace_kind(args.buf) == 'jj' then + update_jj_blame(args.buf) + end + end, + }) + + vim.keymap.set('n', 'tJ', toggle_jj_signs_base, { desc = 'Toggle jj signs base' }) end, }, diff --git a/dot_tmux.conf b/dot_tmux.conf index dec84d9..cec7003 100644 --- a/dot_tmux.conf +++ b/dot_tmux.conf @@ -50,7 +50,9 @@ bind % split-window -h -c "#{pane_current_path}" # Quick config reload and scrollback clear. bind-key r source-file ~/.tmux.conf \; display-message "tmux config reloaded" bind-key b send-keys -R \; clear-history -bind-key s choose-tree -sZ +# Use explicit choose-tree shortcuts so sessions after 9 use plain letters. +# tmux's default Meta-letter shortcuts can be swallowed by terminal settings. +bind-key s choose-tree -sZ -K "#{?#{==:#{line},0},0,#{?#{==:#{line},1},1,#{?#{==:#{line},2},2,#{?#{==:#{line},3},3,#{?#{==:#{line},4},4,#{?#{==:#{line},5},5,#{?#{==:#{line},6},6,#{?#{==:#{line},7},7,#{?#{==:#{line},8},8,#{?#{==:#{line},9},9,#{?#{==:#{line},10},a,#{?#{==:#{line},11},b,#{?#{==:#{line},12},c,#{?#{==:#{line},13},d,#{?#{==:#{line},14},e,#{?#{==:#{line},15},g,#{?#{==:#{line},16},i,#{?#{==:#{line},17},o,#{?#{==:#{line},18},p,#{?#{==:#{line},19},u,}}}}}}}}}}}}}}}}}}}}" bind-key w choose-tree -wZ # Neovim-aware pane switching (no prefix; -n).