Fix cmderdev/cmder#3020; hg prompt is slow.

Cmder's hg prompt didn't use async prompt filtering yet.
Cmder's svn prompt only used async prompt filtering if a special config
variable was set (the commit which contributed it seems to have
misunderstood the git config settings for the git async prompt).

This commit makes the following changes:
1.  Adds async prompt filtering for hg.
2.  Makes async prompt filtering for svn the default.
3.  Removes the prompt_overrideSvnStatusOptIn variable.
4.  Fixes a bug where any errors during `svn status` in the svn prompt
    accidentally show up in the terminal.
5.  Fixes a bug where any errors during `hg branch` in the hg prompt
    turn into Lua errors.
6.  Simplifies the code for colors in the hg and svn prompts.
7.  Clean up the svn prompt code and make it consistent with the git
    and hg prompt code.
This commit is contained in:
Chris Antos
2025-09-04 10:41:08 -07:00
parent 43ab19a74d
commit 8ec4789e35
2 changed files with 83 additions and 74 deletions

152
vendor/clink.lua vendored
View File

@@ -7,7 +7,7 @@
-- luacheck: globals uah_color cwd_color lamb_color clean_color dirty_color conflict_color unknown_color -- luacheck: globals uah_color cwd_color lamb_color clean_color dirty_color conflict_color unknown_color
-- luacheck: globals prompt_homeSymbol prompt_lambSymbol prompt_type prompt_useHomeSymbol prompt_useUserAtHost -- luacheck: globals prompt_homeSymbol prompt_lambSymbol prompt_type prompt_useHomeSymbol prompt_useUserAtHost
-- luacheck: globals prompt_singleLine prompt_includeVersionControl -- luacheck: globals prompt_singleLine prompt_includeVersionControl
-- luacheck: globals prompt_overrideGitStatusOptIn prompt_overrideSvnStatusOptIn -- luacheck: globals prompt_overrideGitStatusOptIn
-- luacheck: globals clink io.popenyield os.isdir settings.get -- luacheck: globals clink io.popenyield os.isdir settings.get
-- At first, load the original clink.lua file -- At first, load the original clink.lua file
@@ -350,13 +350,8 @@ end
-- @return {false|mercurial branch information} -- @return {false|mercurial branch information}
--- ---
local function get_hg_branch() local function get_hg_branch()
-- Return the branch information. The default is to get just the -- Return the branch information.
-- branch name, but you could e.g. use the "hg-prompt" extension to local file = io.popen("hg branch 2>nul")
-- get more information, such as any applied mq patches. Here's an
-- example of that:
-- local cmd = "hg prompt \"{branch}{status}{|{patch}}{update}\""
local cmd = "hg branch 2>nul"
local file = io.popen(cmd)
if not file then if not file then
return false return false
end end
@@ -424,12 +419,33 @@ local function get_git_status()
return { status = is_status, conflict = conflict_found } return { status = is_status, conflict = conflict_found }
end end
---
-- Get the status of working dir
-- @return {bool}
---
local function get_hg_status()
-- The default is to just use the branch name, but you could e.g. use the
-- "hg-prompt" extension to get more information, such as any applied mq
-- patches. Here's an example of that:
-- "hg prompt \"{branch}{status}{|{patch}}{update}\""
local pipe = io_popenyield("hg status -amrd 2>&1")
if not pipe then
return { error = true }
end
local output = pipe:read('*all')
pipe:close()
local dirty = (output ~= nil and output ~= "")
return { clean = not dirty }
end
--- ---
-- Get the status of working dir -- Get the status of working dir
-- @return {bool} -- @return {bool}
--- ---
local function get_svn_status() local function get_svn_status()
local file = io_popenyield("svn status -q") local file = io_popenyield("svn status -q 2>nul")
if not file then if not file then
return { error = true } return { error = true }
end end
@@ -520,14 +536,6 @@ local function git_prompt_filter()
return false return false
end end
-- Colors for git status
local colors = {
clean = get_clean_color(),
dirty = get_dirty_color(),
conflict = get_conflict_color(),
nostatus = get_unknown_color()
}
local git_dir = get_git_dir() local git_dir = get_git_dir()
local color local color
if git_dir then if git_dir then
@@ -547,18 +555,19 @@ local function git_prompt_filter()
local gitConflict = gitInfo.conflict local gitConflict = gitInfo.conflict
if gitStatus == nil then if gitStatus == nil then
color = colors.nostatus color = get_unknown_color()
elseif gitStatus then elseif gitStatus then
color = colors.clean color = get_clean_color()
else else
color = colors.dirty color = get_dirty_color()
end end
if gitConflict then if gitConflict then
color = colors.conflict color = get_conflict_color()
end end
clink.prompt.value = gsub_plain(clink.prompt.value, "{git}", " "..color.."("..branch..")") local result = " "..color.."("..branch..")"
clink.prompt.value = gsub_plain(clink.prompt.value, "{git}", result)
return false return false
end end
end end
@@ -568,6 +577,18 @@ local function git_prompt_filter()
return false return false
end end
local function get_hg_info_table()
local info = clink_promptcoroutine(function ()
return get_hg_status() or {}
end)
if not info then
info = cached_info.hg_info or {}
else
cached_info.hg_info = info
end
return info
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. -- Don't do any hg processing if the prompt doesn't want to show hg info.
@@ -577,33 +598,34 @@ local function hg_prompt_filter()
local hg_dir = get_hg_dir() local hg_dir = get_hg_dir()
if hg_dir then if hg_dir then
-- Colors for mercurial status local output = get_hg_branch() or ""
local colors = {
clean = get_clean_color(),
dirty = get_dirty_color(),
nostatus = get_unknown_color()
}
local output = get_hg_branch()
-- strip the trailing newline from the branch name -- strip the trailing spaces and newline from the branch name
local n = #output local branch = output:gsub("%s+$", "")
while n > 0 and output:find("^%s", n) do n = n - 1 end
local branch = output:sub(1, n)
if branch ~= nil and if branch ~= nil and
string.sub(branch,1,7) ~= "abort: " and -- not an HG working copy string.sub(branch,1,7) ~= "abort: " and -- not an HG working copy
(not string.find(branch, "is not recognized")) then -- 'hg' not in path (not string.find(branch, "is not recognized")) then -- 'hg' not in path
local color = colors.clean -- If in a different repo or branch than last time, discard cached info
if cached_info.hg_dir ~= hg_dir or cached_info.hg_branch ~= branch then
local pipe = io.popen("hg status -amrd 2>&1") cached_info.hg_info = nil
if pipe then cached_info.hg_dir = hg_dir
output = pipe:read('*all') cached_info.hg_branch = branch
pipe:close()
if output ~= nil and output ~= "" then color = colors.dirty end
end end
local result = color .. "(" .. branch .. ")" local hgInfo = get_hg_info_table()
clink.prompt.value = gsub_plain(clink.prompt.value, "{hg}", " "..result)
local color
if not hgInfo or hgInfo.error then
color = get_unknown_color()
elseif hgInfo.clean then
color = get_clean_color()
else
color = get_dirty_color()
end
local result = " "..color.."("..branch..")"
clink.prompt.value = gsub_plain(clink.prompt.value, "{hg}", result)
return false return false
end end
end end
@@ -612,6 +634,18 @@ local function hg_prompt_filter()
clink.prompt.value = gsub_plain(clink.prompt.value, "{hg}", "") clink.prompt.value = gsub_plain(clink.prompt.value, "{hg}", "")
end end
local function get_svn_info_table()
local info = clink_promptcoroutine(function ()
return get_svn_status() or {}
end)
if not info then
info = cached_info.svn_info or {}
else
cached_info.svn_info = info
end
return info
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. -- Don't do any svn processing if the prompt doesn't want to show svn info.
@@ -619,13 +653,6 @@ local function svn_prompt_filter()
return false return false
end end
-- Colors for svn status
local colors = {
clean = get_clean_color(),
dirty = get_dirty_color(),
nostatus = get_unknown_color()
}
local svn_dir = get_svn_dir() local svn_dir = get_svn_dir()
if svn_dir then if svn_dir then
-- if we're inside of svn repo then try to detect current branch -- if we're inside of svn repo then try to detect current branch
@@ -637,29 +664,16 @@ local function svn_prompt_filter()
cached_info.svn_dir = svn_dir cached_info.svn_dir = svn_dir
cached_info.svn_branch = branch cached_info.svn_branch = branch
end end
-- Get the svn status using coroutine if available and option is enabled. Otherwise use a blocking call
local svnStatus local svnInfo = get_svn_info_table()
if clink.promptcoroutine and io.popenyield and settings.get("prompt.async") and prompt_overrideSvnStatusOptIn then -- luacheck: no max line length
svnStatus = clink_promptcoroutine(function ()
return get_svn_status()
end)
-- If the status result is pending, use the cached version instead, otherwise store it to the cache
if svnStatus == nil then
svnStatus = cached_info.svn_info
else
cached_info.svn_info = svnStatus
end
else
svnStatus = get_svn_status()
end
local color local color
if not svnStatus or svnStatus.error then if not svnInfo or svnInfo.error then
color = colors.nostatus color = get_unknown_color()
elseif svnStatus.clean then elseif svnInfo.clean then
color = colors.clean color = get_clean_color()
else else
color = colors.dirty color = get_dirty_color()
end end
clink.prompt.value = gsub_plain(clink.prompt.value, "{svn}", " "..color.."("..branch..")") clink.prompt.value = gsub_plain(clink.prompt.value, "{svn}", " "..color.."("..branch..")")

View File

@@ -38,11 +38,6 @@ prompt_includeVersionControl = true
-- NOTE: This only takes effect if using Clink v1.2.10 or higher. -- NOTE: This only takes effect if using Clink v1.2.10 or higher.
prompt_overrideGitStatusOptIn = false prompt_overrideGitStatusOptIn = false
-- OPTIONAL. If true then always ignore the cmder.status and cmder.cmdstatus svn config settings and run the svn prompt commands in the background.
-- default is false
-- NOTE: This only takes effect if using Clink v1.2.10 or higher.
prompt_overrideSvnStatusOptIn = false
-- Prompt Attributes -- Prompt Attributes
-- --
-- Colors: https://github.com/cmderdev/cmder/wiki/Customization#list-of-colors -- Colors: https://github.com/cmderdev/cmder/wiki/Customization#list-of-colors