mirror of
				https://github.com/cmderdev/cmder.git
				synced 2025-11-04 19:32:13 +08:00 
			
		
		
		
	Holding ^C made git.exe hang while cmd.exe (Clink) updated the prompt.
The prompt script had three problems:
1.  It invoked `git config` every time a prompt was displayed, to
    figure out where to skip invoking `git status`.  But it even did
    that if the current directory wasn't part of a git repo.
2.  It invoked `git config` two times for every single prompt, to
    attempt to improve performance if the user disables `git status`
    coloring.  But two times for every single prompt is expensive, so
    it has the opposite effect in the general case, and noticeably
    degrades performance.
3.  It invoked `git config` using a blocking call, instead of using the
    async prompt support in Clink.  That significantly reduced the
    benefit of having used async prompt filtering for `git status`.
Now the `git config` invocations use async prompt filtering, which lets
the prompt display instantaneously.  It also now uses a timer to avoid
invoking `git config` repeatedly when new prompts show up in rapid
succession.
Also, the `cmderGitStatusOptIn` variable is no longer leaked into the
Lua global namespace.
These changes resolve the issue: holding ^C is very fast and no longer
causes git.exe to hang.
			
			
This commit is contained in:
		
							
								
								
									
										98
									
								
								vendor/clink.lua
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										98
									
								
								vendor/clink.lua
									
									
									
									
										vendored
									
									
								
							@@ -408,13 +408,63 @@ local function get_svn_status()
 | 
			
		||||
    return true
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
-- Get the status of working dir
 | 
			
		||||
-- @return {bool}
 | 
			
		||||
---
 | 
			
		||||
local last_git_status_time = nil
 | 
			
		||||
local last_git_status_setting = true
 | 
			
		||||
local function get_git_status_setting()
 | 
			
		||||
    local time = os.clock()
 | 
			
		||||
    local last_time = last_git_status_time
 | 
			
		||||
    last_git_status_time = time
 | 
			
		||||
    if last_time and time >= 0 and time - last_time < 10 then
 | 
			
		||||
        return last_git_status_setting
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    -- 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
 | 
			
		||||
            last_git_status_setting = true
 | 
			
		||||
            return true
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local gitStatusConfig = io_popenyield("git --no-pager config cmder.status 2>nul")
 | 
			
		||||
    for line in gitStatusConfig:lines() do
 | 
			
		||||
        if string.match(line, 'false') then
 | 
			
		||||
            gitStatusConfig:close()
 | 
			
		||||
            last_git_status_setting = false
 | 
			
		||||
            return false
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    gitStatusConfig:close()
 | 
			
		||||
 | 
			
		||||
    local gitCmdStatusConfig = io_popenyield("git --no-pager config cmder.cmdstatus 2>nul")
 | 
			
		||||
    for line in gitCmdStatusConfig:lines() do
 | 
			
		||||
        if string.match(line, 'false') then
 | 
			
		||||
            gitCmdStatusConfig:close()
 | 
			
		||||
            last_git_status_setting = false
 | 
			
		||||
            return false
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    gitCmdStatusConfig:close()
 | 
			
		||||
 | 
			
		||||
    last_git_status_setting = true
 | 
			
		||||
    return true
 | 
			
		||||
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 get_git_status()
 | 
			
		||||
        -- Use git status if allowed.
 | 
			
		||||
        local cmderGitStatusOptIn = get_git_status_setting()
 | 
			
		||||
        return cmderGitStatusOptIn and get_git_status() or {}
 | 
			
		||||
    end)
 | 
			
		||||
    if not info then
 | 
			
		||||
        info = cached_info.git_info or {}
 | 
			
		||||
@@ -424,42 +474,6 @@ local function get_git_info_table()
 | 
			
		||||
    return info
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
-- Get the status of working dir
 | 
			
		||||
-- @return {bool}
 | 
			
		||||
---
 | 
			
		||||
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")
 | 
			
		||||
 | 
			
		||||
    for line in gitStatusConfig:lines() do
 | 
			
		||||
        if string.match(line, 'false') then
 | 
			
		||||
            gitStatusConfig:close()
 | 
			
		||||
            return false
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    local gitCmdStatusConfig = io.popen("git --no-pager config cmder.cmdstatus 2>nul")
 | 
			
		||||
    for line in gitCmdStatusConfig:lines() do
 | 
			
		||||
        if string.match(line, 'false') then
 | 
			
		||||
            gitCmdStatusConfig:close()
 | 
			
		||||
            return false
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    gitStatusConfig:close()
 | 
			
		||||
    gitCmdStatusConfig:close()
 | 
			
		||||
 | 
			
		||||
    return true
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
local function git_prompt_filter()
 | 
			
		||||
 | 
			
		||||
    -- Don't do any git processing if the prompt doesn't want to show git info.
 | 
			
		||||
@@ -477,7 +491,6 @@ local function git_prompt_filter()
 | 
			
		||||
 | 
			
		||||
    local git_dir = get_git_dir()
 | 
			
		||||
    local color
 | 
			
		||||
    cmderGitStatusOptIn = get_git_status_setting()
 | 
			
		||||
    if git_dir then
 | 
			
		||||
        local branch = get_git_branch(git_dir)
 | 
			
		||||
        if branch then
 | 
			
		||||
@@ -487,9 +500,8 @@ local function git_prompt_filter()
 | 
			
		||||
                cached_info.git_dir = git_dir
 | 
			
		||||
                cached_info.git_branch = branch
 | 
			
		||||
            end
 | 
			
		||||
            -- Use git status if allowed.
 | 
			
		||||
            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
 | 
			
		||||
            local gitInfo = get_git_info_table()
 | 
			
		||||
            local gitStatus = gitInfo.status
 | 
			
		||||
@@ -506,9 +518,7 @@ local function git_prompt_filter()
 | 
			
		||||
            if gitConflict then
 | 
			
		||||
                color = colors.conflict
 | 
			
		||||
            end
 | 
			
		||||
            else
 | 
			
		||||
                color = colors.nostatus
 | 
			
		||||
            end
 | 
			
		||||
 | 
			
		||||
            clink.prompt.value = string.gsub(clink.prompt.value, "{git}", " "..color.."("..verbatim(branch)..")")
 | 
			
		||||
            return false
 | 
			
		||||
        end
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user