-- :RString strip white psace from right of all lines, ranges supported
vim.api.nvim_create_user_command('RStrip', function(opts)
  local pos = vim.fn.getcurpos(vim.api.nvim_get_current_win())
  local range = opts.line1 .. ',' .. opts.line2
  vim.cmd.execute("'" .. range .. 's/\\s\\+$//e' .. "'")
  vim.cmd.nohlsearch()
  vim.fn.setpos('.', pos)
end, { range = '%' })

-- :TabWidth set the tab width for the current buffer
vim.api.nvim_create_user_command('TabWidth', function(opts)
  -- Set the tab width for the current filetype
  local width = tonumber(opts.args)
  vim.opt.tabstop = width
  vim.opt.shiftwidth = width
  vim.opt.softtabstop = width
end, { nargs = 1 })

-- :Remove the file associated with the current buffer, bang to delete buffer
vim.api.nvim_create_user_command('Remove', function(opts)
  local path = vim.fn.expand('%:p')
  -- Using opts.bang in the callback can cause a SEGFAULT, instead use it
  -- before invoking the async unlink to select which callback should be called
  -- on completion.
  local callback = nil
  if opts.bang then
    -- Invoked as :Remove! so also delete the buffer.
    callback = function(err, success)
      if success then
        vim.schedule(function()
          vim.api.nvim_buf_delete(vim.api.nvim_get_current_buf(), {})
        end)
      else
        error(err)
      end
    end
  else
    -- Invoked as :Remove so don't delete the buffer.
    callback = function(err, success)
      if not success then
        error(err)
      end
    end
  end
  -- Actually remove the file using the selecte callback.
  vim.loop.fs_unlink(path, callback)
end, { bang = true })

-- :Move the file associated with the current buffer
vim.api.nvim_create_user_command('Move', function(opts)
  local source = vim.fn.expand('%:p')
  local dest = opts.args
  if vim.fn.isdirectory(dest) ~= 0 then
    dest = vim.fn.resolve(dest .. '/' .. vim.fn.expand('%:t'))
  end
  vim.loop.fs_rename(source, dest, function(err, success)
    if success then
      vim.schedule(function()
        vim.cmd.edit(dest)
      end)
    else
      error(err)
    end
  end)
end, {
  nargs = 1,
  complete = 'file',
})

-- :Rename the file associated with current buffer
vim.api.nvim_create_user_command('Rename', function(opts)
  local source = vim.fn.expand('%')
  local dest = nil
  local dir = vim.fn.expand('%:h')
  if dir == '.' then
    dest = opts.args
  else
    dest = vim.fn.resolve(dir .. '/' .. opts.args)
  end
  local buffer = vim.api.nvim_get_current_buf()
  vim.loop.fs_rename(source, dest, function(err, success)
    if not success then
      error(err)
    else
      vim.schedule(function()
        vim.cmd.edit(dest)
        vim.api.nvim_buf_delete(buffer, {})
      end)
    end
  end)
end, {
  nargs = 1,
  complete = function()
    return { vim.fn.expand('%:t') }
  end
})

-- :Chmod change file mode bits
if vim.fn.executable('chmod') == 1 then
  vim.api.nvim_create_user_command('Chmod', function(opts)
    local file = vim.fn.expand('%:p')
    vim.fn.system('chmod ' .. opts.args .. ' ' .. file)
  end, { nargs = '+' })
end

-- :Mkdir create a directory, bang to create intermediate directories
vim.api.nvim_create_user_command('Mkdir', function(opts)
  local flags = nil
  if opts.bang then
    flags = 'p'
  end
  vim.fn.mkdir(opts.args, flags)
end, {
  bang = true,
  nargs = 1,
  complete = 'file',
})

-- :Rg grep for the given string, word under the cursor, or visual selection
-- then fuzzy find the results. Bang to enable regex in given string.
vim.api.nvim_create_user_command('Rg', function(opts)
  local search = opts.args
  if opts.range == 2 then
    local lines = vim.fn.getline(vim.fn.line("'<"), vim.fn.line("'>"))
    local start_col = vim.fn.col("'<")
    local end_col = vim.fn.col("'>")
    if #lines == 1 then
      lines[1] = string.sub(lines[1], start_col, end_col)
    else
      lines[1] = string.sub(lines[1], start_col)
      lines[#lines] = string.sub(lines[#lines], 1, end_col)
    end
    search = table.concat(lines, "\n")
  elseif #search == 0 then
    search = vim.fn.expand('<cword>')
  end
  local grep_opts = { search = search}
  if opts.bang then
    grep_opts['use_regex'] = true
  end
  require('telescope.builtin').grep_string(grep_opts)
end, { bang = true, range = true, nargs = '*' })

vim.api.nvim_create_user_command('PreProcIfWrap', function(opts)
  local buffer = vim.api.nvim_get_current_buf()
  vim.api.nvim_buf_set_lines(
    buffer, opts.line2, opts.line2, true, { '#endif' })
  vim.api.nvim_buf_set_lines(
    buffer, opts.line1 - 1, opts.line1 - 1, true, { '#if 0' })
  local window = vim.api.nvim_get_current_win()
  vim.api.nvim_win_set_cursor(window, { opts.line1, 5 })
end, { range = true })