Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add trim of changed lines only #23

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ local default_config = {
trim_trailing = true,
trim_last_line = true,
trim_first_line = true,
trim_changed_only = false, -- Trim only lines changed from last save
highlight = false,
highlight_bg = '#ff0000', -- or 'red'
highlight_ctermbg = 'red',
Expand Down
1 change: 1 addition & 0 deletions doc/trim.nvim.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ HOW TO SETUP *trim.nvim-trim.nvim-how-to-setup*
trim_trailing = true,
trim_last_line = true,
trim_first_line = true,
trim_changed_only = false, -- Trim only lines changed from last save
highlight = false,
highlight_bg = '#ff0000', -- or 'red'
highlight_ctermbg = 'red',
Expand Down
8 changes: 8 additions & 0 deletions lua/trim/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ local default_config = {
trim_trailing = true,
trim_last_line = true,
trim_first_line = true,
trim_changed_only = false,
highlight = false,
highlight_bg = '#ff0000',
highlight_ctermbg = 'red',
Expand All @@ -23,6 +24,13 @@ function M.setup(opts)
opts.ft_blocklist = opts.disable
end

if opts.trim_changed_only and vim.fn.executable('diff') == 0 then
vim.notify('`trim_changed_only` cannot function without a `diff` binary available in PATH. Disabling trimming.', { title = 'trim.nvim' })
opts.trim_first_line = false
opts.trim_last_line = false
opts.trim_trailing = false
end

M.config = vim.tbl_deep_extend('force', default_config, opts)

if M.config.trim_trailing then
Expand Down
74 changes: 72 additions & 2 deletions lua/trim/trimmer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,81 @@ local api = vim.api

local trimmer = {}

local format_line_endings = {
unix = "\n",
dos = "\r\n",
mac = "\r",
}

function trimmer.changed_blocks()
local filename = vim.api.nvim_buf_get_name(0)

if vim.fn.filereadable(filename) == 0 then
return {{1, vim.fn.line('$')}}
end

if vim.bo.modified then
local diff_bits = {
"diff",
"-a",
"--unchanged-group-format=",
"--old-group-format=",
"--new-group-format=%dF,%dL ",
"--changed-group-format=%dF,%dL ",
filename,
"-"
}

local format = vim.api.nvim_buf_get_option(0, 'fileformat')
local line_ending = format_line_endings[format]

local file_content = table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, true), line_ending) .. line_ending
local call_result = vim.system(diff_bits, {stdin = file_content, text = true}):wait()

local trimmed_output = vim.fn.trim(call_result.stdout)
local changes_list = vim.split(trimmed_output, ' ')
local split_fn = function(val)
return vim.split(val, ",")
end

return vim.tbl_map(split_fn, changes_list)
end

return {}
end

function trimmer.trim()
local config = require('trim.config').get()
local save = vim.fn.winsaveview()
for _, v in ipairs(config.patterns) do
api.nvim_exec(string.format('keepjumps keeppatterns silent! %s', v), false)
if config.trim_changed_only then
local line_trailing_pattern = [[s/\s\+$//e]]
local changed_blocks = trimmer.changed_blocks()

-- Trim ends of all changed lines
local num_changed_blocks = 0
for _, range in ipairs(changed_blocks) do
local command = string.format('keepjumps keeppatterns silent! %s,%s%s', range[1], range[2], line_trailing_pattern)
api.nvim_exec2(command, {output = false})
num_changed_blocks = num_changed_blocks + 1
end

-- NOTE: order is important, do trailing first, then leading, otherwise the
-- line ranges might not be accurate anymore
local line_count = vim.api.nvim_buf_line_count(0)
if config.trim_last_line and num_changed_blocks > 0 and tonumber(changed_blocks[num_changed_blocks][2]) == line_count then
-- Last changed range extends to EOF -> We can trim trailing lines
api.nvim_exec2([[keepjumps keeppatterns silent! %s/\($\n\s*\)\+\%$//]], {output = false})
end

if config.trim_first_line and num_changed_blocks > 0 and tonumber(changed_blocks[1][1]) == 1 then
-- First changed range starts at first line -> We can trim leading lines
api.nvim_exec2([[keepjumps keeppatterns silent! %s/\%^\n\+//]], {output = false})
end
else
-- Trim globally
for _, v in ipairs(config.patterns) do
api.nvim_exec2(string.format('keepjumps keeppatterns silent! %s', v), {output = false})
end
end
vim.fn.winrestview(save)
end
Expand Down