From be09c53934f6e5a6209f711abe1d0514b2966c6f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 15 Feb 2026 02:01:26 +0000 Subject: [PATCH] feat: add walking cat animation in terminal using floating windows This change implements a walking cat animation directly in the terminal using Neovim's floating windows, providing a more convenient alternative to the previous GLFW-based approach. Key changes: - Created `lua/pawtocomplete/walk.lua` for ASCII cat animation logic. - Integrated `PawWalk` and `PawStop` commands into the plugin. - Added configurable speed and step options for the animation. - Ensured the animation adapts to terminal resizing. - Used `vim.uv` timers with `vim.schedule_wrap` for smooth, safe animation. Co-authored-by: kiddos <9444583+kiddos@users.noreply.github.com> --- lua/pawtocomplete/config.lua | 4 ++ lua/pawtocomplete/init.lua | 10 ++++ lua/pawtocomplete/walk.lua | 101 +++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 lua/pawtocomplete/walk.lua diff --git a/lua/pawtocomplete/config.lua b/lua/pawtocomplete/config.lua index c5c824b..97fd50f 100644 --- a/lua/pawtocomplete/config.lua +++ b/lua/pawtocomplete/config.lua @@ -16,6 +16,10 @@ local config = { max_height = 6, delay = 100, }, + walk = { + speed = 100, + step = 1, + }, } M.merge_option = function(opt) diff --git a/lua/pawtocomplete/init.lua b/lua/pawtocomplete/init.lua index e752be5..0de9836 100644 --- a/lua/pawtocomplete/init.lua +++ b/lua/pawtocomplete/init.lua @@ -1,3 +1,4 @@ +local api = vim.api local M = {} M.setup = function(opts) @@ -9,6 +10,15 @@ M.setup = function(opts) completion.setup() signature.setup() + + api.nvim_create_user_command('PawWalk', function() + local conf = require('pawtocomplete.config').get_config() + require('pawtocomplete.walk').walk(conf.walk) + end, {}) + + api.nvim_create_user_command('PawStop', function() + require('pawtocomplete.walk').stop() + end, {}) end return M diff --git a/lua/pawtocomplete/walk.lua b/lua/pawtocomplete/walk.lua new file mode 100644 index 0000000..718951f --- /dev/null +++ b/lua/pawtocomplete/walk.lua @@ -0,0 +1,101 @@ +local api = vim.api +local uv = vim.uv or vim.loop + +local M = { + timer = nil, + win = nil, + buf = nil +} + +local frames = { +[[ + |\__/,| (`\ +|_ _ |.--.) ) +( T ) / +(((^_((_(((_/ +]], +[[ + |\__/,| (`\ +|_ _ |.--.) ) +( T ) / + ((_((_((_((_/ +]] +} + +function M.stop() + if M.timer then + M.timer:stop() + M.timer:close() + M.timer = nil + end + if M.win and api.nvim_win_is_valid(M.win) then + api.nvim_win_close(M.win, true) + M.win = nil + end +end + +function M.walk(opts) + M.stop() + + opts = opts or {} + local speed = opts.speed or 100 + local step = opts.step or 1 + + M.buf = api.nvim_create_buf(false, true) + api.nvim_set_option_value('bufhidden', 'wipe', { buf = M.buf }) + + local width = 18 + local height = 4 + + local row = api.nvim_get_option('lines') - height - 3 + local col = 0 + + M.win = api.nvim_open_win(M.buf, false, { + relative = 'editor', + row = row, + col = col, + width = width, + height = height, + style = 'minimal', + border = 'none', + zindex = 100, + }) + + api.nvim_set_option_value('winhl', 'Normal:NormalFloat', { win = M.win }) + + local frame_idx = 1 + local current_col = col + + M.timer = uv.new_timer() + M.timer:start(0, speed, vim.schedule_wrap(function() + if not M.win or not api.nvim_win_is_valid(M.win) then + M.stop() + return + end + + local lines = vim.split(frames[frame_idx], '\n') + -- Remove trailing empty line if any + if lines[#lines] == "" then table.remove(lines) end + + api.nvim_buf_set_lines(M.buf, 0, -1, false, lines) + + frame_idx = (frame_idx % #frames) + 1 + current_col = current_col + step + + local max_cols = api.nvim_get_option('columns') + local current_row = api.nvim_get_option('lines') - height - 3 + if current_col > max_cols then + current_col = -width + end + + api.nvim_win_set_config(M.win, { + relative = 'editor', + row = current_row, + col = current_col, + width = width, + height = height + }) + end)) +end + +return M