From 4674d633ce9f18e5f9f1159af00a1233aae86e37 Mon Sep 17 00:00:00 2001 From: David Chen Date: Tue, 27 Aug 2024 18:35:55 -0500 Subject: [PATCH] added git.yazi --- yazi/plugins/git.yazi/LICENSE | 21 +++ yazi/plugins/git.yazi/README.md | 43 +++++++ yazi/plugins/git.yazi/init.lua | 219 ++++++++++++++++++++++++++++++++ 3 files changed, 283 insertions(+) create mode 100644 yazi/plugins/git.yazi/LICENSE create mode 100644 yazi/plugins/git.yazi/README.md create mode 100644 yazi/plugins/git.yazi/init.lua diff --git a/yazi/plugins/git.yazi/LICENSE b/yazi/plugins/git.yazi/LICENSE new file mode 100644 index 0000000..85c5dfd --- /dev/null +++ b/yazi/plugins/git.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 DreamMaoMao + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/yazi/plugins/git.yazi/README.md b/yazi/plugins/git.yazi/README.md new file mode 100644 index 0000000..e999026 --- /dev/null +++ b/yazi/plugins/git.yazi/README.md @@ -0,0 +1,43 @@ +# git.yazi +git message prompt plugin for Yazi, + +Asynchronous task loading without blocking the rendering of other components + +![image](https://gitee.com/DreamMaoMao/git.yazi/assets/30348075/3a95e25a-cf0e-4f03-8d92-e7c9cc0767bb) + + + + +https://gitee.com/DreamMaoMao/git.yazi/assets/30348075/f827dd33-8e51-4f8a-9069-0affc2f7aab8 + + + +# Install + +### Linux + +```bash +git clone https://gitee.com/DreamMaoMao/git.yazi.git ~/.config/yazi/plugins/git.yazi +``` + +# Dependcy +- git + +# Usage + +Add this to ~/.config/yazi/init.lua + +``` +require("git"):setup{ +} +``` +if you want listen for file changes to automatically update the status. +Add this to ~/.config/yazi/yazi.toml, `below the exists [plugin] modules`, like this +``` +[plugin] + +fetchers = [ + { id = "git", name = "*", run = "git", prio = "normal" }, + { id = "git", name = "*/", run = "git", prio = "normal" }, +] +``` diff --git a/yazi/plugins/git.yazi/init.lua b/yazi/plugins/git.yazi/init.lua new file mode 100644 index 0000000..4307c62 --- /dev/null +++ b/yazi/plugins/git.yazi/init.lua @@ -0,0 +1,219 @@ +local function string_split(input,delimiter) + + local result = {} + + for match in (input..delimiter):gmatch("(.-)"..delimiter) do + table.insert(result, match) + end + return result +end + +local function set_status_color(status) + if status == nil then + return "#6cc749" + elseif status == "M" then + return "#ec613f" + elseif status == "A" then + return "#ec613f" + elseif status == "." then + return "#ae96ee" + elseif status == "?" then + return "#D4BB91" + elseif status == "R" then + return "#ec613f" + else + return "#ec613f" + end + +end + +local function fix_str_ch(str) + local chinese_chars, num_replacements = str:gsub("\\(%d%d%d)", function (s) + return string.char(tonumber(s, 8)) + end) + return num_replacements > 0 and chinese_chars:sub(2,-2) or chinese_chars +end + +local function make_git_table(git_status_str) + local file_table = {} + local git_status + local is_dirty = false + local filename + local multi_path + local is_ignore_dir = false + local is_untracked_dir = false + local convert_name + local split_table = string_split(git_status_str:sub(1,-2),"\n") + for _, value in ipairs(split_table) do + split_value = string_split(value," ") + if split_value[#split_value - 1] == "" then + split_value = string_split(value," ") + end + + if split_value[#split_value - 1] == "??" then + git_status = "?" + is_dirty = true + elseif split_value[#split_value - 1] == "!!" then + git_status = "." + elseif split_value[#split_value - 1] == "->" then + git_status = "R" + is_dirty = true + else + git_status = split_value[#split_value - 1] + is_dirty = true + end + if split_value[#split_value]:sub(-2,-1) == "./" and git_status == "." then + is_ignore_dir = true + return file_table,is_dirty,is_ignore_dir,is_untracked_dir + end + + if split_value[#split_value]:sub(-2,-1) == "./" and git_status == "?" then + is_untracked_dir = true + return file_table,is_dirty,is_ignore_dir,is_untracked_dir + end + + multi_path = string_split(split_value[#split_value],"/") + if (multi_path[#multi_path] == "" and #multi_path == 2) or git_status ~= "." then + filename = multi_path[1] + else + filename = split_value[#split_value] + end + + convert_name = fix_str_ch(filename) + file_table[convert_name] = git_status + end + + return file_table,is_dirty,is_ignore_dir,is_untracked_dir +end + +local save = ya.sync(function(st, cwd, git_branch,git_file_status,git_is_dirty,git_status_str,is_ignore_dir,is_untracked_dir) + if cx.active.current.cwd == Url(cwd) then + st.git_branch = git_branch + st.git_file_status = git_file_status + st.git_is_dirty = git_is_dirty and "*" or "" + st.git_status_str = git_status_str + st.is_ignore_dir = is_ignore_dir + st.is_untracked_dir= is_untracked_dir + ya.render() + end +end) + +local clear_state = ya.sync(function(st) + st.git_branch = "" + st.git_file_status = "" + st.git_is_dirty = "" + ya.render() +end) + +local function update_git_status(path) + ya.manager_emit("plugin", { "git", args = ya.quote(tostring(path))}) +end + +local is_in_git_dir = ya.sync(function(st) + return (st.git_branch ~= nil and st.git_branch ~= "") and cx.active.current.cwd or nil +end) + +local flush_empty_folder_status = ya.sync(function(st) + local cwd = cx.active.current.cwd + local folder = cx.active.current + if #folder.window == 0 then + clear_state() + ya.manager_emit("plugin", { "git", args = ya.quote(tostring(cwd))}) + end +end) + +local handle_path_change = ya.sync(function(st) + local cwd = cx.active.current.cwd + if st.cwd ~= cwd then + st.cwd = cwd + clear_state() + ya.manager_emit("plugin", { "git", args = ya.quote(tostring(cwd))}) + end +end) + + +local M = { + setup = function(st,opts) + + local function linemode_git(self) + local f = self._file + local git_span = {} + local git_status + if st.git_branch ~= nil and st.git_branch ~= "" then + local name = f.name:gsub("\r", "?", 1) + if st.is_ignore_dir then + git_status = "." + elseif st.is_untracked_dir then + git_status = "?" + elseif st.git_file_status and st.git_file_status[name] then + git_status = st.git_file_status[name] + else + git_status = nil + end + + local color = set_status_color(git_status) + if f:is_hovered() then + git_span = (git_status ) and ui.Span(git_status .." ") or ui.Span("✓ ") + else + git_span = (git_status) and ui.Span(git_status .." "):fg(color) or ui.Span("✓ "):fg(color) + end + end + return git_span + end + Linemode:children_add(linemode_git,8000) + + local function header_git(self) + return (st.git_branch and st.git_branch ~= "") and ui.Line {ui.Span(" <".. st.git_branch .. st.git_is_dirty .. ">"):fg("#f6a6da")} or ui.Line {} + end + Header:children_add(header_git,1400,Header.LEFT) + + ps.sub("cd",handle_path_change) + ps.sub("delete",flush_empty_folder_status) + ps.sub("trash",flush_empty_folder_status) + end, + + entry = function(_, args) + local output + local git_is_dirty + local is_ignore_dir,is_untracked_dir + + local git_branch + local command = "git symbolic-ref HEAD 2> /dev/null" + local file = io.popen(command, "r") + output = file:read("*a") + file:close() + + if output ~= nil and output ~= "" then + local split_output = string_split(output:sub(1,-2),"/") + + git_branch = split_output[3] + elseif is_in_git_dir() then + git_branch = nil + else + return + end + + local git_status_str = "" + local git_file_status = nil + local command = "git status --ignored -s --ignore-submodules=dirty 2> /dev/null" + local file = io.popen(command, "r") + output = file:read("*a") + file:close() + + if output ~= nil and output ~= "" then + git_status_str = output + git_file_status,git_is_dirty,is_ignore_dir,is_untracked_dir = make_git_table(git_status_str) + end + save(args[1], git_branch,git_file_status,git_is_dirty,git_status_str,is_ignore_dir,is_untracked_dir) + end, +} + +function M:fetch() + local path = is_in_git_dir() + if path then + update_git_status(path) + end + return 3 +end + +return M \ No newline at end of file