diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2024-05-02 16:00:54 +0200 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2024-05-02 16:00:54 +0200 |
| commit | aead994af26e91c3a094b010fcba3d45453c8940 (patch) | |
| tree | 5841d69f14d24f7239d6d1c7edd9d5e48c735f49 /init.lua | |
| download | vis-lockfiles-aead994af26e91c3a094b010fcba3d45453c8940.tar.gz vis-lockfiles-aead994af26e91c3a094b010fcba3d45453c8940.zip | |
initial commit
Diffstat (limited to 'init.lua')
| -rw-r--r-- | init.lua | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..02fee0d --- /dev/null +++ b/init.lua @@ -0,0 +1,121 @@ +-- Copyright (c) 2024 Florian Fischer. All rights reserved. +-- +-- vis-lockfiles is free software: you can redistribute it and/or modify it under +-- the terms of the GNU General Public License as published by the Free Software +-- Foundation, either version 3 of the License, or (at your option) any later +-- version. +-- +-- vis-lockfiles is distributed in the hope that it will be useful, but WITHOUT +-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +-- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with +-- vis-lockfiles found in the LICENSE file. +-- If not, see <https://www.gnu.org/licenses/>. +local M = {} +M.directory = '${XDG_CACHE_HOME:-${HOME}/.local/share}/vis/locks' + +-- Helper to execute a command and capture its output +local function capture_cmd(cmd) + local p = assert(io.popen(cmd, 'r')) + local s = assert(p:read('*a')) + local success, _, status = p:close() + if not success then + local err = cmd .. ' failed with exit code: ' .. status + vis:info('vis-lockfiles: ' .. err) + end + return s +end + +local function lock_file_path(path) + local filename = path:gsub('/', '%%') + assert(os.execute('mkdir -p "' .. M.directory .. '"')) + local lfile_path = capture_cmd('echo "' .. M.directory .. '/' .. filename .. '.lock"') + return lfile_path:sub(1, #lfile_path - 1) -- trim newline from path +end + +-- determine vis' pid +local vis_pid +do + local vis_proc_file = io.open('/proc/self/stat', 'r') + if vis_proc_file then + vis_pid = vis_proc_file:read('*n') + vis_proc_file:close() + + else -- fallback if /proc/self/stat is not available + local out = capture_cmd('sh -c "echo $PPID"') + vis_pid = tonumber(out) + end +end +assert(vis_pid) + +-- get a user confirmation +-- return true if user selected yes, false otherwise +local function confirm(path) + local choices = 'no\nyes' + local prompt = path .. ' exists. Edit anyway:' + local cmd = 'printf "' .. choices .. '" | vis-menu -b -p \'' .. prompt .. '\'' + + local choice = nil + -- local status, output = vis:pipe(nil, {start = 0, finish = 0}, cmd) + local menu = assert(io.popen(cmd)) + local output = menu:read('*a') + local _, _, status = menu:close() + if status == 0 then + -- trim newline from selection + if output:sub(-1) == '\n' then + choice = output:sub(1, -2) + else + choice = output + end + end + vis:redraw() + return choice == 'yes' +end + +local created_locks = {} +local function create_lock_file(lfile_path) + local already_locked = os.execute('test -e ' .. '"' .. lfile_path .. '"') + if already_locked then + return false + end + + -- create the lock file with our pid + local cmd = 'echo ' .. vis_pid .. ' > "' .. lfile_path .. '"' + assert(os.execute(cmd)) + + -- detect a possible race + local lock_file = io.open(lfile_path) + assert(lock_file) + local lock_pid = lock_file:read('*n') + lock_file:close() + local locked = tonumber(lock_pid) == vis_pid + + -- remember we created the lock file + if locked then + created_locks[lfile_path] = true + end + + return locked +end + +local function delete_lock_file(lfile_path) + os.execute('rm ' .. '"' .. lfile_path .. '"') + created_locks[lfile_path] = nil +end + +vis.events.subscribe(vis.events.FILE_OPEN, function(file) + local lfile_path = lock_file_path(file.path) + if not create_lock_file(lfile_path) and not confirm(lfile_path) then + os.exit(1) + end +end) + +vis.events.subscribe(vis.events.FILE_CLOSE, function(file) + local lfile_path = lock_file_path(file.path) + if created_locks[lfile_path] then + delete_lock_file(lfile_path) + end +end) + +return M |
