joshuadanpeterson / typewriter.nvim

A Neovim plugin that emulates a typewriter, keeping the cursor centered on the screen for a focused writing experience.
MIT License
23 stars 0 forks source link

Preserve Column Position When Moving Between Lines of Different Lengths #17

Closed joshuadanpeterson closed 1 month ago

joshuadanpeterson commented 1 month ago

Description:

This pull request introduces a new feature to preserve the cursor's column position when navigating between lines of varying lengths in Neovim. The change addresses the issue where the cursor position would reset or not be preserved correctly when moving between lines, particularly handling edge cases such as blank lines and shorter lines.

Changes Made:

  1. New Autocommand:

    • Added a CursorMoved autocommand to handle cursor position preservation.
    • The autocommand is triggered whenever the cursor is moved, ensuring real-time adjustment of the cursor position.
  2. Target Column Management:

    • Introduced target_col to store the desired column position across line movements.
    • The target_col is initially set to the current column when moving to a new line and updated when moving within the same line.
  3. Line Length Handling:

    • If the new line is shorter than target_col, the cursor is moved to the end of the line.
    • If the new line is long enough, the cursor is moved to target_col.
  4. Lateral Movements:

    • Ensured that lateral movements (h, l) within the same line update the target_col correctly, preserving the cursor's horizontal position.
  5. Blank Lines:

    • Correctly managed cursor position for blank lines, ensuring it does not reset to 0 unexpectedly.
  6. Cursor Centering:

    • Called commands.center_cursor() after each movement to keep the cursor centered, enhancing the user experience.

Fixes Issue:

This PR fixes issue #16 where:

When moving between lines with j and k, if the next line is shorter than the current column, the cursor moves to the end of the line.

When moving to the next line, which has enough columns for the original cursor position, Vim sets it to that column instead of the max length of the previous line.

Broken Step: When moving back to the original line, the cursor was incorrectly set, leading to an unexpected cursor path.

This change ensures the cursor maintains the correct column position as expected, preserving the original column when moving between lines of different lengths.

Example Code:

-- lua/typewriter/autocommands.lua
-- Preserve column position when moving between lines of different lengths
local target_col = nil
local last_line = nil

vim.api.nvim_create_autocmd("CursorMoved", {
  pattern = "*",
  callback = function()
    local current_line, current_col = unpack(vim.api.nvim_win_get_cursor(0))
    local line_length = vim.fn.col('$') - 1 -- Get the actual length of the current line

    -- If we've moved to a new line
    if last_line ~= current_line then
      -- If target_col is not set, use the current column
      if target_col == nil then
        target_col = current_col
      end

      -- If the current line is shorter than target_col, move to the end of the line
      if line_length < target_col then
        vim.api.nvim_win_set_cursor(0, { current_line, line_length })
      -- If the current line is long enough, move to the target column
      elseif current_col ~= target_col then
        vim.api.nvim_win_set_cursor(0, { current_line, target_col })
      end
    else
      -- If we're on the same line, update the target column
      target_col = current_col
    end

    last_line = current_line

    -- Center the cursor
    commands.center_cursor()
  end
})

Benefits:

Testing: