nanozuki / tabby.nvim

A declarative, highly configurable, and neovim style tabline plugin. Use your nvim tabs as a workspace multiplexer!
MIT License
563 stars 21 forks source link

[Help wanted]: Current working directory instead of buffer name #138

Closed diegodario88 closed 2 months ago

diegodario88 commented 2 months ago

Hey, thanks for putting effort into this plugin.

I really like the default values; they're nice. The only thing I would like to change is (as the title suggests) instead of displaying the buffer name (which is already in my statusline), I would like to display the current working directory (cwd) while keeping the other options as they are.

nanozuki commented 2 months ago

Because the target of "tabby.nvim" is to be highly configurable, the preset just provides default and example configs. So, there is no simple way to modify a component in preset configs. But we can write our customer config from the preset's example. I want to write a step-by-step guide here in case someone else needs help.

We can find the default preset's config here: function preset.active_wins_at_tail(opt). The config is:

function preset.active_wins_at_tail(opt)
  local o = vim.tbl_deep_extend('force', default_preset_option, opt or {})
  tabline.set(function(line)
    return {
      preset_head(line, o),
      line.tabs().foreach(function(tab)
        return preset_tab(line, tab, o)
      end),
      line.spacer(),
      line.wins_in_tab(line.api.get_current_tab()).foreach(function(win)
        return preset_win(line, win, o)
      end),
      preset_tail(line, o),
      hl = o.theme.fill,
    }
  end, o)
end

By replacing the local function and default opt, we can get the following:

  tabline.set(function(line)
    return {
      {
        { '  ', hl = opt.theme.head },
        line.sep(right_sep(opt), opt.theme.head, opt.theme.fill),
      },
      line.tabs().foreach(function(tab)
        local hl = tab.is_current() and opt.theme.current_tab or opt.theme.tab
        local status_icon = opt.nerdfont and { '', '󰆣' } or { '+', '' }
        return {
          line.sep(left_sep(opt), hl, opt.theme.fill),
          tab.is_current() and status_icon[1] or status_icon[2],
          tab.number(),
          tab.name(),
          tab.close_btn(opt.nerdfont and '' or '(x)'),
          line.sep(right_sep(opt), hl, opt.theme.fill),
          hl = hl,
          margin = ' ',
        }
      end),
      line.spacer(),
      line.wins_in_tab(line.api.get_current_tab()).foreach(function(win)
        local status_icon = opt.nerdfont and { '', '' } or { '*', '' }
        return {
          line.sep(left_sep(opt), opt.theme.win, opt.theme.fill),
          win.is_current() and status_icon[1] or status_icon[2],
          win.buf_name(),
          line.sep(right_sep(opt), opt.theme.win, opt.theme.fill),
          hl = opt.theme.win,
          margin = ' ',
        }
      end),
      {
        line.sep(left_sep(opt), opt.theme.tail, opt.theme.fill),
        { opt.nerdfont and '  ' or ' ', hl = opt.theme.tail },
      },
      hl = o.theme.fill,
    }
  end)

If you want to use cwd to replace the filenames, you can replace the line.wins_in_tab part. We can use vim.fn.getcwd() to get cwd, and use vim.fn.fnamemodify() to get relative/absolute path, or tail of the path.

So the config may be this:

  tabline.set(function(line)
    local cwd = ' ' .. vim.fn.fnamemodify(vim.fn.getcwd(), ':t') .. ' '
    return {
      {
        { '  ', hl = opt.theme.head },
        line.sep(right_sep(opt), opt.theme.head, opt.theme.fill),
      },
      line.tabs().foreach(function(tab)
        local hl = tab.is_current() and opt.theme.current_tab or opt.theme.tab
        local status_icon = opt.nerdfont and { '', '󰆣' } or { '+', '' }
        return {
          line.sep(left_sep(opt), hl, opt.theme.fill),
          tab.is_current() and status_icon[1] or status_icon[2],
          tab.number(),
          tab.name(),
          tab.close_btn(opt.nerdfont and '' or '(x)'),
          line.sep(right_sep(opt), hl, opt.theme.fill),
          hl = hl,
          margin = ' ',
        }
      end),
      line.spacer(),
      {
        line.sep(left_sep(opt), opt.theme.win, opt.theme.fill),
        cwd,
        line.sep(right_sep(opt), opt.theme.win, opt.theme.fill),
        hl = opt.theme.win,
      },
      {
        line.sep(left_sep(opt), opt.theme.tail, opt.theme.fill),
        { opt.nerdfont and '  ' or ' ', hl = opt.theme.tail },
      },
      hl = o.theme.fill,
    }
  end)

I think these texts will help you. It's welcome to receive more feedback.

diegodario88 commented 2 months ago

Thank you, @nanozuki. Your assistance was very helpful. However, I'm still not quite there yet. Here is a video demonstrating what I'm trying to achieve:

Video Link

I would like it to function like switching projects, but so far, I haven't been able to find a way to save the "current working directory for the current tab."

nanozuki commented 2 months ago

I realize you want to display cwd in the tab label. So, we should get cwd paths in each tab. The vim fn getcwd([{winnr} [, {tabnr}]]) can receive two optional parameters, winnr and tabnr, and we can pass winnr = -1 to ignore it. So, we can do this:

line.tabs().foreach(tab)
  return {
    -- previous configs
    vim.fn.fnamemodify(vim.fn.getcwd(-1, tab.number()))
    -- next configs
  }
end
diegodario88 commented 2 months ago

Thanks a million!