Merge pull request #2556 from chrisant996/clink-async-prompt

This commit is contained in:
Benjamin Staneck 2021-07-18 09:58:41 +02:00 committed by GitHub
commit b8760e4d04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 103 additions and 7 deletions

101
vendor/clink.lua vendored
View File

@ -63,6 +63,32 @@ local function get_folder_name(path)
end end
---
-- Forward/backward compatibility for Clink asynchronous prompt filtering.
-- With Clink v1.2.10 and higher this lets git status run in the background and
-- refresh the prompt when it finishes, to eliminate waits in large git repos.
---
local io_popenyield
local clink_promptcoroutine
local cached_info = {}
if clink.promptcoroutine and io.popenyield then
io_popenyield = io.popenyield
clink_promptcoroutine = clink.promptcoroutine
else
io_popenyield = io.popen
clink_promptcoroutine = function (func)
return func(false)
end
end
---
-- Global variable so other Lua scripts can detect whether they're in a Cmder
-- shell session.
---
CMDER_SESSION = true
--- ---
-- Setting the prompt in clink means that commands which rewrite the prompt do -- Setting the prompt in clink means that commands which rewrite the prompt do
-- not destroy our own prompt. It also means that started cmds (or batch files -- not destroy our own prompt. It also means that started cmds (or batch files
@ -113,6 +139,10 @@ local function set_prompt_filter()
prompt_singleLine = false prompt_singleLine = false
end end
if prompt_includeVersionControl == nil then
prompt_includeVersionControl = true
end
if prompt_type == 'folder' then if prompt_type == 'folder' then
cwd = get_folder_name(cwd) cwd = get_folder_name(cwd)
end end
@ -133,7 +163,12 @@ local function set_prompt_filter()
if env ~= nil then env = "("..env..") " else env = "" end if env ~= nil then env = "("..env..") " else env = "" end
prompt = get_uah_color() .. "{uah}" .. get_cwd_color() .. "{cwd}{git}{hg}{svn}" .. get_lamb_color() .. cr .. "{lamb} \x1b[0m" if uah ~= '' then uah = get_uah_color() .. uah end
if cwd ~= '' then cwd = get_cwd_color() .. cwd end
local version_control = prompt_includeVersionControl and "{git}{hg}{svn}" or ""
prompt = "{uah}{cwd}" .. version_control .. get_lamb_color() .. cr .. "{lamb} \x1b[0m"
prompt = string.gsub(prompt, "{uah}", uah) prompt = string.gsub(prompt, "{uah}", uah)
prompt = string.gsub(prompt, "{cwd}", cwd) prompt = string.gsub(prompt, "{cwd}", cwd)
prompt = string.gsub(prompt, "{env}", env) prompt = string.gsub(prompt, "{env}", env)
@ -308,7 +343,7 @@ end
-- @return {bool} -- @return {bool}
--- ---
local function get_git_status() local function get_git_status()
local file = io.popen("git --no-optional-locks status --porcelain 2>nul") local file = io_popenyield("git --no-optional-locks status --porcelain 2>nul")
for line in file:lines() do for line in file:lines() do
file:close() file:close()
return false return false
@ -323,7 +358,7 @@ end
-- @return {bool} indicating true for conflict, false for no conflicts -- @return {bool} indicating true for conflict, false for no conflicts
--- ---
function get_git_conflict() function get_git_conflict()
local file = io.popen("git diff --name-only --diff-filter=U 2>nul") local file = io_popenyield("git diff --name-only --diff-filter=U 2>nul")
for line in file:lines() do for line in file:lines() do
file:close() file:close()
return true; return true;
@ -363,11 +398,36 @@ local function get_svn_status()
return true return true
end end
---
-- Use a prompt coroutine to get git status in the background.
-- Cache the info so we can reuse it next time to reduce flicker.
---
local function get_git_info_table()
local info = clink_promptcoroutine(function ()
return { status=get_git_status(), conflict=get_git_conflict() }
end)
if not info then
info = cached_info.git_info or {}
else
cached_info.git_info = info
end
return info
end
--- ---
-- Get the status of working dir -- Get the status of working dir
-- @return {bool} -- @return {bool}
--- ---
local function get_git_status_setting() local function get_git_status_setting()
-- When async prompt filtering is available, check the
-- prompt_overrideGitStatusOptIn config setting for whether to ignore the
-- cmder.status and cmder.cmdstatus git config opt-in settings.
if clink.promptcoroutine and io.popenyield and settings.get("prompt.async") then
if prompt_overrideGitStatusOptIn then
return true
end
end
local gitStatusConfig = io.popen("git --no-pager config cmder.status 2>nul") local gitStatusConfig = io.popen("git --no-pager config cmder.status 2>nul")
for line in gitStatusConfig:lines() do for line in gitStatusConfig:lines() do
@ -392,6 +452,11 @@ end
local function git_prompt_filter() local function git_prompt_filter()
-- Don't do any git processing if the prompt doesn't want to show git info.
if not clink.prompt.value:find("{git}") then
return false
end
-- Colors for git status -- Colors for git status
local colors = { local colors = {
clean = get_clean_color(), clean = get_clean_color(),
@ -406,15 +471,26 @@ local function git_prompt_filter()
if git_dir then if git_dir then
local branch = get_git_branch(git_dir) local branch = get_git_branch(git_dir)
if branch then if branch then
-- If in a different repo or branch than last time, discard cached info.
if cached_info.git_dir ~= git_dir or cached_info.git_branch ~= branch then
cached_info.git_info = nil
cached_info.git_dir = git_dir
cached_info.git_branch = branch
end
-- Use git status if allowed.
if cmderGitStatusOptIn then if cmderGitStatusOptIn then
-- if we're inside of git repo then try to detect current branch -- if we're inside of git repo then try to detect current branch
-- Has branch => therefore it is a git folder, now figure out status -- Has branch => therefore it is a git folder, now figure out status
local gitStatus = get_git_status() local gitInfo = get_git_info_table()
local gitConflict = get_git_conflict() local gitStatus = gitInfo.status
local gitConflict = gitInfo.conflict
color = colors.dirty if gitStatus == nil then
if gitStatus then color = colors.nostatus
elseif gitStatus then
color = colors.clean color = colors.clean
else
color = colors.dirty
end end
if gitConflict then if gitConflict then
@ -435,6 +511,11 @@ end
local function hg_prompt_filter() local function hg_prompt_filter()
-- Don't do any hg processing if the prompt doesn't want to show hg info.
if not clink.prompt.value:find("{hg}") then
return false
end
local result = "" local result = ""
local hg_dir = get_hg_dir() local hg_dir = get_hg_dir()
@ -474,6 +555,12 @@ local function hg_prompt_filter()
end end
local function svn_prompt_filter() local function svn_prompt_filter()
-- Don't do any svn processing if the prompt doesn't want to show svn info.
if not clink.prompt.value:find("{svn}") then
return false
end
-- Colors for svn status -- Colors for svn status
local colors = { local colors = {
clean = get_clean_color(), clean = get_clean_color(),

View File

@ -29,6 +29,15 @@ prompt_useUserAtHost = false
-- default is false -- default is false
prompt_singleLine = false prompt_singleLine = false
-- OPTIONAL. If true then always ignore the cmder.status and cmder.cmdstatus git config settings and run the git prompt commands in the background.
-- default is false
-- NOTE: This only takes effect if using Clink v1.2.10 or higher.
prompt_overrideGitStatusOptIn = false
-- OPTIONAL. If true then Cmder includes git, mercurial, and subversion status in the prompt.
-- default is true
prompt_includeVersionControl = true
-- Prompt Attributes -- Prompt Attributes
-- --
-- Colors -- Colors