Skip to content

Instantly share code, notes, and snippets.

@hibiyasleep
Created August 21, 2026 07:56
Show Gist options
  • Select an option

  • Save hibiyasleep/de584f9479568ae81043e9d3e36f415f to your computer and use it in GitHub Desktop.

Select an option

Save hibiyasleep/de584f9479568ae81043e9d3e36f415f to your computer and use it in GitHub Desktop.
#!/usr/bin/env zsh
#
# hanfix.zsh — fix commands that were typed with the Korean (2-beolsik)
# keyboard layout switched on by mistake, e.g.:
#
# $ ㅣㄴ -미ㅗ
# -> ls -alh
#
# It works by reversing the standard 2-beolsik key mapping: every Hangul
# syllable is decomposed into its jamo (초성/중성/종성), and each jamo is
# mapped back to the Latin key that produces it. Anything that isn't
# Hangul (already-correct English, digits, symbols, spaces, filenames
# typed in Korean on purpose, etc.) is left completely untouched, so
# mixed input is handled fine.
#
# USAGE
# As a one-off converter/runner:
# ./hanfix.zsh 'ㅣㄴ -미ㅗ'
#
# For automatic correction of "command not found" errors, source this
# file from your .zshrc:
# source /path/to/hanfix.zsh
# After that, mistyped Hangul commands are retried automatically.
emulate -L zsh
# ---------------------------------------------------------------------
# 2-beolsik keymap tables
# ---------------------------------------------------------------------
# 19 initial consonants (초성), in Unicode decomposition order
typeset -ga _CHO=(r R s e E f a q Q t T d w W c z x v g)
# 21 vowels (중성), in Unicode decomposition order. Compound vowels
# (ㅘㅙㅚㅝㅞㅟㅢ) are just two keystrokes typed back to back.
typeset -ga _JUNG=(k o i O j p u P h hk ho hl y n nj np nl b m ml l)
# 28 final consonants (종성); index 1 = "no final consonant"
typeset -ga _JONG=(
"" r R rt s sw sg e f fr
fa fq ft fx fv fg a q qt t
T d w c z x v g
)
# Standalone compatibility jamo (U+3131-U+3163), for jamo that never got
# combined into a full syllable, e.g. a lone ㄴ or ㅣ.
typeset -ga _JAMO=(
r R rt s sw sg e E f fr fa fq ft fx fv fg a q Q qt t T d w W c z x v g
k o i O j p u P h hk ho hl y n nj np nl b m ml l
)
# ---------------------------------------------------------------------
# qwerty_from_hangul <string>
# Prints <string> with every Hangul character replaced by the QWERTY
# keystrokes that would have produced it on a 2-beolsik layout.
# ---------------------------------------------------------------------
qwerty_from_hangul() {
emulate -L zsh
local input="$1" out="" ch
local -i cp cho jung jong idx
for ch in "${(@s::)input}"; do
cp=$(( #ch )) # codepoint of this single character
if (( cp >= 0xAC00 && cp <= 0xD7A3 )); then
# Composed syllable (가-힣): decompose into 초성/중성/종성
idx=$(( cp - 0xAC00 ))
jong=$(( idx % 28 ))
idx=$(( idx / 28 ))
jung=$(( idx % 21 ))
cho=$(( idx / 21 ))
out+="${_CHO[cho+1]}${_JUNG[jung+1]}${_JONG[jong+1]}"
elif (( cp >= 0x3131 && cp <= 0x3163 )); then
# Standalone jamo, not (yet) part of a composed syllable
out+="${_JAMO[cp-0x3131+1]}"
else
# Not Hangul at all -- leave mixed-in input exactly as typed
out+="$ch"
fi
done
print -r -- "$out"
}
# ---------------------------------------------------------------------
# Optional: auto-retry unknown commands after converting them.
# Add `source /path/to/hanfix.zsh` to your .zshrc to enable this.
# ---------------------------------------------------------------------
command_not_found_handler() {
local original="$*" converted
converted="$(qwerty_from_hangul "$original")"
if [[ -n "$converted" && "$converted" != "$original" ]]; then
print -u2 "zsh: command not found: $1 -- retrying as: $converted"
eval "$converted"
return $?
fi
print -u2 "zsh: command not found: $1"
return 127
}
# ---------------------------------------------------------------------
# Direct execution mode: `./hanfix.zsh 'ㅣㄴ -미ㅗ'` converts and runs it.
# When this file is `source`d instead, this block is skipped and only
# the functions above (plus command_not_found_handler) get defined.
# ---------------------------------------------------------------------
if [[ "$ZSH_EVAL_CONTEXT" == "toplevel" ]]; then
if (( $# == 0 )); then
print -u2 "usage: $0 <mistyped command>"
exit 1
fi
typeset converted
converted="$(qwerty_from_hangul "$*")"
print -r -- "-> $converted"
eval "$converted"
exit $?
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment