From 146461f7c6d95f4ba1220559d66eb113418b40a8 Mon Sep 17 00:00:00 2001 From: Morningstar202604 <2516285782@qq.com> Date: Tue, 25 Aug 2026 16:26:23 +0800 Subject: [PATCH] fix(git): force C locale only while matching status regexes (#14006) --- lib/git.zsh | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/lib/git.zsh b/lib/git.zsh index 6d7c2c7ddcf9d..41d01f66eee9c 100644 --- a/lib/git.zsh +++ b/lib/git.zsh @@ -39,16 +39,27 @@ function _omz_git_prompt_info() { echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref//\%/%%}${upstream//\%/%%}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" } -function _omz_git_prompt_status() { - # OHMYZSH-13330: avoid "regex matching error: illegal byte sequence". - # zsh's "=~" operator delegates to the C library regex, which aborts with - # REG_ILLSEQ when the subject contains an invalid byte sequence under a - # multibyte locale (e.g. a filename with non-UTF-8 bytes in `git status` - # output). Forcing the C locale makes every byte a valid character, so the - # regex matching below never fails that way. `git status --porcelain` is - # locale-independent, so this does not change the parsed output. +# Match an extended regular expression against a subject, forcing the C locale +# only for the duration of the call. +# +# OHMYZSH-13330: zsh's "=~" operator delegates to the C library regex, which +# aborts with REG_ILLSEQ when the subject contains an invalid byte sequence +# under a multibyte locale (e.g. a filename with non-UTF-8 bytes in `git +# status` output). Forcing the C locale makes every byte a valid character, +# so the regex matching never fails that way. `git status --porcelain` is +# locale-independent, so this does not change the parsed output. +# +# OHMYZSH-13985: the locale must be scoped to this function and not set for +# the whole caller. Assigning LC_ALL makes zsh re-run setlocale() right away, +# so leaving it set while the rest of the caller runs breaks multibyte +# handling there — most visibly, `echo` refuses to expand Unicode escapes in +# theme prompt symbols ("character not in range"). +function _omz_git_prompt_status_match() { local -x LC_ALL=C + [[ "$1" =~ "$2" ]] +} +function _omz_git_prompt_status() { [[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return # Maps a git status prefix to an internal constant @@ -113,11 +124,11 @@ function _omz_git_prompt_status() { status_lines=("${(@f)${status_text}}") # If the tracking line exists, get and parse it - if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then + if _omz_git_prompt_status_match "$status_lines[1]" "^## [^ ]+ \[(.*)\]"; then local branch_statuses branch_statuses=("${(@s/,/)match}") for branch_status in $branch_statuses; do - if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then + if ! _omz_git_prompt_status_match "$branch_status" "(behind|diverged|ahead) ([0-9]+)?"; then continue fi local last_parsed_status=$prefix_constant_map[$match[1]] @@ -130,7 +141,7 @@ function _omz_git_prompt_status() { local status_constant="${prefix_constant_map[$status_prefix]}" local status_regex=$'(^|\n)'"$status_prefix" - if [[ "$status_text" =~ $status_regex ]]; then + if _omz_git_prompt_status_match "$status_text" "$status_regex"; then statuses_seen[$status_constant]=1 fi done