helix-editor / helix

A post-modern modal text editor.
https://helix-editor.com
Mozilla Public License 2.0
33.78k stars 2.51k forks source link

Align backup system to Neovim's #12074

Open kirawi opened 2 hours ago

kirawi commented 2 hours ago

I've looked through and written down the algorithm that Neovim follows. Looking to see what should be excluded from it for Helix.

Neovim backup path function:
- If a backup is desired (would be disabled by a user if using a file watcher):
    - Checks if user explicitly requested a copy
    - Or automatically choose whether to copy or rename
    - Offers options for:
        - Breaking symlinks or hardlinks (not offered in Helix)
    - Offers the ability to have a list of directories where the backup file is written:
        - Default is: ".,$XDG_STATE_HOME/nvim/backup//"
    - Offers ability to set backup extension
- For copy backup:
    - If the file is a link, then the backup will have the name of the link
- Auto backup:
    - Immediately set copy if:
        - Is hardlink or symlink
    - Then, tries to:
        - Create a temporary file with the same permissions as the file to test if its ok to rename later
            - If it fails, then set copy
        - fchown created file
            - If it fails or perms weren't copied, then set copy
        - Delete test file
    - Otherwise, will rename
- Break symlink/hardlink if requested
- Copy backup:
    - If there is an error while creating the file, it will be propogated unless force write is true
    - Try to create backup path in bdir:
        - Tries first directory where this is possible
        - If no directory exists, the last directory is created
        - Filename is escaped and extension applied
    - Check if backup already exists:
        - Check if pre-existing file is a symlink to the original file (and don't attempt to create one)
        - Dunno what p_bk is, but if false, it tries to create a different backup file path where each character before the extension is changed (if all attempts fail, then error)
    - Copies file with UV_FS_COPYFILE_FICLONE
    - Sets perm as os_setperm(*backupp, perm & 0777);
    - On Unix:
        - Attempts to set gid via chown:
            - os_setperm(*backupp, (perm & 0707) | ((perm & 07) << 3) if fails
        - Sets file time:
            os_file_settime(*backupp,
                        (double)file_info_old->stat.st_atim.tv_sec,
                        (double)file_info_old->stat.st_mtim.tv_sec);
    - On Windows, sets ACL
    - Attempts to copy xattr if exists
- Rename backup:
    - Backup is created by renaming original file:
        - Don't if file is read-only and cpoptions has "W" flag
    - Tries to find backup file name w/ bdir (similar to copy)
    - Checks if a file with that name already exists:
        - Attempts same method as copy backup to create a different filename

Neovim write:
- On Unix:
    - If using :w! and file was read-only, make it writable (if process uid is same as file):
- Reset read-only flag if overwriting
- Executes fsync (will not propogate error if storage does not support op)
- Copies xattr for non-copy backups
- If a rename backup is being performed:
    - Check if uid and gid are same as original file, and set if they aren't
    - Set perms
- Either way, copy perms from old file to new file
- Either way, if not a backup copy, also set ACL (method seems to not do anything?)
- On failure:
    - If a copy, copy contents from copy to original file
    - Otherwise, rename backup back to original path
kirawi commented 2 hours ago

It involves quite a few config options. I think we should include:

backup_type : { None, Copy, Auto }
backup_directories : [Path]
backup_extension : String