February 2026

Timescale DB NixOS

Strange bug.... cannot rebuild nixos with timescale DB as postgresql-setup.service hangs.. (never comples).

Have to:

  1. go into localhost postgres and drop timescaledb and timescaledb_toolkit extensions
  2. rebuild nixos
  3. go back into localhost and re-install extensions

Autoformat enabling and disabling

because i always forget, to enable and disable auto-formatting (conform) for a specific buffer

:FormatDisable!
:FormatEnable!

Vim mode ZSH

Well after many hours of searching, i found out why by default a docker container does NOT support vim mode in ZSH (I never installed the zsh vi mode plugin as it's glitchy).

Turns out we need the EDITOR variable if its set to vim or something like vi ZSH will enable vim bindings... 😆

Docer here: https://zsh.sourceforge.io/Doc/Release/Zsh-Line-Editor.html

Migration to taskfile

Need to update my readme at some point, have moved from utility script to Taskfile

Recap on magic mode replacements

gosh. i alwasy forget this. the magic modes by deafult escape most (except brackets and stuff. definitely star * symbol)

So for an example i wanted to do - replace all non star with star (realised i could have just replaced all chars would have been simpler but whatever, skill issue)

ModeCommand SyntaxThe "Magic" Logic
Very Magic (\v):%s/\v[^*]/*/gHigh Octane: No backslash needed. Inside [], the * is assumed to be literal. The \v at the start makes the brackets "live" automatically.
Magic (\m):%s/[^*]/*/gThe Default: This is what you used. Brackets are special by default, but the * inside them is treated as a literal character.
Nomagic (\M):%s/\[^*\]/*/gOld School: You have to escape the brackets \[ \] to make them act as a "set." Otherwise, Vim looks for a literal [ character.
Very Nomagic (\V):%s/\V[^*]/*/gLiteral Mode: Almost everything is literal. Surprisingly, [ ] still work as a set here, but the * is strictly a character.

Nvim prev pos

Wow.... how have i never known this.... To go back to previous cursor positoin

  • ''
  • ``

` conflicts with my lua console so can use ''

Revisiting folding

So can do it like this (with LSP)

vim.o.foldmethod = 'expr'
vim.o.foldexpr = 'v:lua.vim.lsp.foldexpr()'

See :h vim.lsp.foldexpr() for more details on how it works

An interactive way to see it for current line is

:echo v:lua.vim.lsp.foldexpr(line('.'))

Whereby line('.') is current line (see :h :line()) and the vim.lsp.foldexpr() takes an arg of the current line number

To use treesitter it must be

vim.opt.foldmethod = "expr"
vim.opt.foldexpr = "v:lua.vim.treesitter.foldexpr()"

see https://neovim.io/doc/user/treesitter.html#vim.treesitter.foldexpr()

Similarly, can test it with

echo v:lua.vim.treesitter.foldexpr(line('.'))

foldlevel / foldlevelstart

foldlevel is the active threshold for a buffer — folds deeper than N are closed.

foldlevel=0   → all folds closed
foldlevel=1   → only level-1 folds open
foldlevel=99  → everything open

foldlevelstart sets the initial foldlevel when a buffer opens. Default is 0 (all closed).

vim.opt.foldlevelstart = 99  -- start with all folds open

Treesitter and folding

Ok so claude came up with a very interesting note about treesitter and how it supports folding.

Treesitter has flags for types of treesitter (nodes?) on which to do folds. For SQL this is https://github.com/nvim-treesitter/nvim-treesitter/blob/master/queries/sql/folds.scm here where it is JUST statement notes. (WITH, SELECT) i believe but not including union selects?

So if i go into a sql file with select * .... union all select the second select is NOT a statement hence can't fold on it!

So have some options:

  • use LSP for SQL?
  • override treesitter to add fold commands for union/select?

also need to add fallback to indent for :LspInfo which is of filetype checkhealth no supported by treesitter or LSP (i assume)

Also.... trying out the sqls and sqlls couldnt get folding to work?

Well.... checking out https://neovim.io/doc/user/lsp.html it says you need "textDocument/foldingRange" to support folding?

And with sqlls I tried:

:redir >pls.txt
:lua =vim.lsp.get_active_clients()[1].server_capabilities
:redir END

And couldnt see it there....

Claude wrote me this a custom fallback function for folding myself?

function CustomFoldExpr()
  local lnum = vim.v.lnum
  local buf = vim.api.nvim_get_current_buf()
  local ts_ok, ts_result = pcall(vim.treesitter.foldexpr)
  if ts_ok and ts_result ~= '0' and ts_result ~= 0 then
    vim.b[buf].fold_provider = 'treesitter'
    return ts_result
  end
  vim.b[buf].fold_provider = 'indent'
  local indent = vim.fn.indent(lnum)
  local sw = vim.bo[buf].shiftwidth
  if sw == 0 then
    sw = vim.bo[buf].tabstop
  end
  return math.floor(indent / sw)
end

function ShowFoldProvider()
  local provider = vim.b.fold_provider or 'unknown'
  vim.notify('fold provider: ' .. provider, vim.log.levels.INFO)
  return provider
end

vim.opt.foldmethod = 'expr'
vim.opt.foldexpr = 'v:lua.CustomFoldExpr()'

Nvim glitching after zellij layout change

Symptoms

Intermittent nvim corruption after changing zellij pane layout:

  1. Display glitch - lines duplicating/overlapping when navigating up/down, :redraw! doesnt fix, only nvim restart
  2. Cmdline completion broken - :Lazy subcommands no longer complete (native :e <Tab> still works)
  3. LSP completion broken - <C-Space> stops triggering blink.cmp completions
  4. Which-key popup gone - <Space> (leader) moves cursor instead of showing which-key menu, but actual leader bindings like <Space>tv still work

All symptoms appear together in the same session, always after a zellij layout change (resize/relayout sends SIGWINCH to nvim).

Debugging process

  1. Initially suspected satellite.nvim (scrollbar redraws on cursor move) - disabled it, issue persisted
  2. Tried :redraw! - no effect, ruling out simple terminal redraw issue
  3. Tried narrowing to blink.cmp cmdline config - but native completion worked fine
  4. Noticed leader key "broken" but actual bindings still worked -> isolated to which-key popup specifically
  5. Ran :checkhealth on both a working and broken nvim session, diffed the outputs

Root cause - lspsaga crashing inside which-key

The broken session's checkhealth had stack traces not present in the working session:

- stack traceback:
    /home/joelyboy/.local/share/nvim/lazy/lspsaga.nvim/lua/lspsaga/symbol/head.lua:89
    /home/joelyboy/.local/share/nvim/lazy/lspsaga.nvim/lua/lspsaga/symbol/head.lua:57
    [C]:-1
    [C]:-1
    /home/joelyboy/.local/share/nvim/lazy/which-key.nvim/lua/which-key/state.lua:262
    /home/joelyboy/.local/share/nvim/lazy/which-key.nvim/lua/which-key/state.lua:346
    /home/joelyboy/.local/share/nvim/lazy/which-key.nvim/lua/which-key/state.lua:115
- stack traceback:
    ...lspsaga/symbol/head.lua:89
    ...lspsaga/symbol/head.lua:57
    [C]:-1
    [C]:-1
    ...which-key/state.lua:262
    ...which-key/state.lua:346
    ...which-key/triggers.lua:44

The chain: zellij layout change -> VimResized/WinResized -> which-key triggers re-evaluate (triggers.lua:44) -> which-key processes state (state.lua) -> calls into lspsaga's symbol/head.lua:89 which errors -> corrupts which-key's internal state -> popup dies, and the cascading error likely breaks blink.cmp's handlers too.

The broken session also had deprecation warnings (client.supports_method is deprecated, removed in Nvim 0.13) that lspsaga is triggering, suggesting it hasnt been updated for nvim 0.11.5 APIs.

Action taken

Disabled lspsaga for now to see if the issue reoccurs:

{ 'nvimdev/lspsaga.nvim', enabled = false }

If the glitch stops, lspsaga is confirmed as the root cause and needs updating or replacing.

Treesitter folding quirk with multi-line signatures

vim.treesitter.foldexpr() breaks fold hierarchy when a function has a multi-line signature. Example:

    def parse_st8_bet_data(   # foldexpr: >3 (starts level 3 fold)
        self,                  # foldexpr: 3
        record: ArchiveRecord, # foldexpr: 3
    ) -> ParseResult:          # foldexpr: 3
        try:                   # foldexpr: >3 (starts NEW level 3 fold)

The parameters treesitter node spans multiple lines, inflating the fold level to 3 (class > func > parameters). When parameters ends, the foldexpr never drops back to level 2 before try_statement starts its own >3. Vim sees two separate level-3 folds rather than a level-2 fold containing a level-3 fold.

Result: closing the function fold only collapses the signature (lines 108-111), not the body. The try block is a separate fold at the same level.

Key foldexpr syntax (:h fold-expr):

  • >N = start a new fold at level N
  • N = continue at level N
  • <N = end a fold at level N

Useful built-in level commands:

  • zm/zr = increment/decrement foldlevel by 1
  • zM/zR = close/open all folds
  • :set foldlevel=N = close all folds deeper than N

Single-line signatures fold correctly. This is not a treesitter parser bug - the parser correctly nests try_statement inside function_definition. The bug is in neovim's vim.treesitter.foldexpr() which translates the tree into fold levels. It counts parameters as a foldable multi-line node at the same depth as try_statement (both direct children of function_definition), so it assigns them the same level instead of treating the function body as deeper than the signature. LSP folding (vim.lsp.foldexpr()) may handle it better but LSP fold support varies by server.