mirror of
				https://github.com/cmderdev/cmder.git
				synced 2025-11-04 11:22: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
 | 
					    return true
 | 
				
			||||||
end
 | 
					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.
 | 
					-- Use a prompt coroutine to get git status in the background.
 | 
				
			||||||
-- Cache the info so we can reuse it next time to reduce flicker.
 | 
					-- Cache the info so we can reuse it next time to reduce flicker.
 | 
				
			||||||
---
 | 
					---
 | 
				
			||||||
local function get_git_info_table()
 | 
					local function get_git_info_table()
 | 
				
			||||||
    local info = clink_promptcoroutine(function ()
 | 
					    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)
 | 
					    end)
 | 
				
			||||||
    if not info then
 | 
					    if not info then
 | 
				
			||||||
        info = cached_info.git_info or {}
 | 
					        info = cached_info.git_info or {}
 | 
				
			||||||
@@ -424,42 +474,6 @@ local function get_git_info_table()
 | 
				
			|||||||
    return info
 | 
					    return info
 | 
				
			||||||
end
 | 
					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()
 | 
					local function git_prompt_filter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    -- Don't do any git processing if the prompt doesn't want to show git info.
 | 
					    -- 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 git_dir = get_git_dir()
 | 
				
			||||||
    local color
 | 
					    local color
 | 
				
			||||||
    cmderGitStatusOptIn = get_git_status_setting()
 | 
					 | 
				
			||||||
    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
 | 
				
			||||||
@@ -487,9 +500,8 @@ local function git_prompt_filter()
 | 
				
			|||||||
                cached_info.git_dir = git_dir
 | 
					                cached_info.git_dir = git_dir
 | 
				
			||||||
                cached_info.git_branch = branch
 | 
					                cached_info.git_branch = branch
 | 
				
			||||||
            end
 | 
					            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
 | 
					            -- Has branch => therefore it is a git folder, now figure out status
 | 
				
			||||||
            local gitInfo = get_git_info_table()
 | 
					            local gitInfo = get_git_info_table()
 | 
				
			||||||
            local gitStatus = gitInfo.status
 | 
					            local gitStatus = gitInfo.status
 | 
				
			||||||
@@ -506,9 +518,7 @@ local function git_prompt_filter()
 | 
				
			|||||||
            if gitConflict then
 | 
					            if gitConflict then
 | 
				
			||||||
                color = colors.conflict
 | 
					                color = colors.conflict
 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
            else
 | 
					
 | 
				
			||||||
                color = colors.nostatus
 | 
					 | 
				
			||||||
            end
 | 
					 | 
				
			||||||
            clink.prompt.value = string.gsub(clink.prompt.value, "{git}", " "..color.."("..verbatim(branch)..")")
 | 
					            clink.prompt.value = string.gsub(clink.prompt.value, "{git}", " "..color.."("..verbatim(branch)..")")
 | 
				
			||||||
            return false
 | 
					            return false
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user