autoload -Uz chpwd_recent_dirs cdr add-zsh-hook
add-zsh-hook chpwd chpwd_recent_dirs
zstyle ':chpwd:*' recent-dirs-max 50

cdselect() {
  local dirs=("${(@f)$(cdr -l 2>/dev/null | sed 's/^[0-9]* *//')}")
  [[ ${#dirs} -eq 0 ]] && return
  local query="" cursor=1 selected=""
  while true; do
    local filtered=()
    for d in "${dirs[@]}"; do
      local match=1
      for word in ${(s: :)query}; do
        [[ "${d:l}" != *"${word:l}"* ]] && match=0 && break
      done
      [[ $match -eq 1 ]] && filtered+=("$d")
    done
    # sort by path length (shortest first)
    local sorted=()
    for f in "${filtered[@]}"; do sorted+=("${#f} $f"); done
    sorted=(${(n)sorted})
    filtered=()
    for s in "${sorted[@]}"; do filtered+=("${s#* }"); done
    [[ $cursor -gt ${#filtered} ]] && cursor=${#filtered}
    [[ $cursor -lt 1 ]] && cursor=1
    clear
    echo "cd> $query"
    local i=1
    for d in "${filtered[@]}"; do
      if [[ $i -eq $cursor ]]; then
        printf "\e[7m  %s\e[0m\n" "$d"
      else
        printf "  %s\n" "$d"
      fi
      ((i++))
      [[ $i -gt 20 ]] && break
    done
    read -k1 key 2>/dev/null
    if [[ "$key" == $'\x1b' ]]; then
      read -k1 -t 0.1 k2 2>/dev/null
      if [[ "$k2" == "[" ]]; then
        read -k1 -t 0.1 k3 2>/dev/null
        case "$k3" in
          A) ((cursor--)) ;;  # up
          B) ((cursor++)) ;;  # down
        esac
        continue
      else
        break  # plain ESC
      fi
    fi
    case "$key" in
      $'\n'|$'\r') [[ ${#filtered} -gt 0 ]] && selected="${filtered[$cursor]}"; break ;;
      $'\x0e') ((cursor++)) ;;  # C-n
      $'\x10') ((cursor--)) ;;  # C-p
      $'\x7f'|$'\b') query="${query%?}"; cursor=1 ;;
      *) query+="$key"; cursor=1 ;;
    esac
  done
  clear
  if [[ -n "$selected" ]]; then
    selected="${selected/#\~/$HOME}"
    selected="${selected//\\ / }"
    cd "$selected"
  fi
  zle reset-prompt
}
zle -N cdselect
bindkey '^j' cdselect
