aboutsummaryrefslogtreecommitdiffstats
path: root/config/hypr/scripts/KeyBinds.sh
blob: 4158b762132649b1d31e7c7010427f34e2f59c75 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/env bash
# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */  ##
# searchable enabled keybinds using rofi (supports bindd descriptions)

# kill yad to not interfere with this binds
pkill yad || true

# check if rofi is already running
if pidof rofi > /dev/null; then
  pkill rofi
fi

# define the config files
keybinds_conf="$HOME/.config/hypr/configs/Keybinds.conf"
user_keybinds_conf="$HOME/.config/hypr/UserConfigs/UserKeybinds.conf"
laptop_conf="$HOME/.config/hypr/UserConfigs/Laptops.conf"
rofi_theme="$HOME/.config/rofi/config-keybinds.rasi"
msg='☣️ NOTE ☣️: Clicking with Mouse or Pressing ENTER will have NO function'

# collect raw bind lines (strip end-of-line comments) from available files
files=("$keybinds_conf" "$user_keybinds_conf")
[[ -f "$laptop_conf" ]] && files+=("$laptop_conf")

# Parse binds/unbinds from files, detect overrides, and keep unique effective binds
declare -A binding_map        # combo -> bind line (effective)
declare -A source_map         # combo -> source file
declare -A user_bind_map      # combo -> user bind line
declare -A unbound_user       # combo -> 1 if explicitly unbound in user file
declare -A seen_any_bind      # combo -> 1 if any bind seen (for iteration)
declare -A default_seen       # combo -> 1 if default bind exists
declare -a missing_unbind_suggestions_arr

normalize_combo() { echo "$1" | sed -E 's/[[:space:]]//g'; }

extract_combo() {
  # arg: a bind/unbind line; returns "mods,key" via echo
  local s="$1"
  s="$(echo "$s" | sed -E 's/[[:space:]]+#.*$//')"
  if [[ "$s" =~ = ]]; then
    local rhs="${s#*=}"
    local mods="$(echo "$rhs" | awk -F',' '{gsub(/^[ \t]+|[ \t]+$/,"",$1); print $1}')"
    local key="$(echo "$rhs"  | awk -F',' '{gsub(/^[ \t]+|[ \t]+$/,"",$2); print $2}')"
    echo "${mods},${key}"
  fi
}

for file in "${files[@]}"; do
  [[ ! -f "$file" ]] && continue
  while IFS= read -r line; do
    [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue

    if [[ "$line" =~ ^[[:space:]]*bind[a-z]*[[:space:]]*= ]]; then
      combo_raw="$(extract_combo "$line")"
      [[ -z "$combo_raw" ]] && continue
      combo="$(normalize_combo "$combo_raw")"
      seen_any_bind["$combo"]=1

      if [[ "$file" != "$user_keybinds_conf" ]]; then
        default_seen["$combo"]=1
      fi

      # prefer user bind, else first seen
      if [[ -z "${source_map[$combo]}" ]]; then
        binding_map["$combo"]="$line"
        source_map["$combo"]="$file"
      fi
      if [[ "$file" == "$user_keybinds_conf" ]]; then
        user_bind_map["$combo"]="$line"
        binding_map["$combo"]="$line"
        source_map["$combo"]="$file"
      fi

    elif [[ "$line" =~ ^[[:space:]]*unbind[[:space:]]*= ]]; then
      combo_raw="$(extract_combo "$line")"
      [[ -z "$combo_raw" ]] && continue
      combo="$(normalize_combo "$combo_raw")"
      if [[ "$file" == "$user_keybinds_conf" ]]; then
        unbound_user["$combo"]=1
      fi
    fi
  done < "$file"
done

# Build raw_keybinds for display and collect missing unbind suggestions
raw_keybinds=""
for combo in "${!seen_any_bind[@]}"; do
  eff_line="${binding_map[$combo]}"
  src="${source_map[$combo]}"
  [[ -z "$eff_line" ]] && continue
  raw_keybinds+="$eff_line"$'\n'

  # If user overrides a default but didn't unbind in user file, suggest unbind
  if [[ "$src" == "$user_keybinds_conf" && -n "${default_seen[$combo]}" && -z "${unbound_user[$combo]}" ]]; then
    suggest="$(echo "$eff_line" | sed -E 's/^[[:space:]]*bind[a-z]*/unbind/')"
    missing_unbind_suggestions_arr+=("$suggest")
  fi
done

# If there are missing unbinds, write suggestions to a temp file and note in message
if (( ${#missing_unbind_suggestions_arr[@]} > 0 )); then
  suggestions_file="$(mktemp -t hypr-unbind-suggestions.XXXX.conf)"
  printf '%s\n' "${missing_unbind_suggestions_arr[@]}" > "$suggestions_file"
  msg="$msg | Overrides missing unbind: ${#missing_unbind_suggestions_arr[@]} (suggestions: $suggestions_file)"
fi

# check for any keybinds to display
if [[ -z "$raw_keybinds" ]]; then
    echo "no keybinds found."
    exit 1
fi

# transform into a readable list: MODS+KEY — DESCRIPTION (for bindd) or DISPATCHER [PARAMS] (for bind)
display_keybinds=$(echo "$raw_keybinds" | awk -F'=' '
  function trim(s){ gsub(/^[ \t]+|[ \t]+$/,"",s); return s }
  /^[[:space:]]*bind/ {
    binder=$1; gsub(/[ \t]/, "", binder);
    hasdesc = (index(binder, "d")>0);

    rhs=$2; rhs=trim(rhs);
    n=split(rhs, a, /[ \t]*,[ \t]*/);

    mods=trim(a[1]); key=(n>=2?trim(a[2]):"");
    desc=""; dispatcher=""; params="";

    if (hasdesc) {
      desc=(n>=3?trim(a[3]):"");
      dispatcher=(n>=4?trim(a[4]):"");
      start=5;
    } else {
      dispatcher=(n>=3?trim(a[3]):"");
      start=4;
    }

    for(i=start;i<=n;i++){ if(length(a[i])){ p=trim(a[i]); if(p!="") params = (params?params", ":"") p } }

    gsub(/\$mainMod/,"SUPER",mods);
    gsub(/[ \t]+/,"+",mods);

    combo = (mods && key) ? mods "+" key : (key?key:mods);

    if (hasdesc && desc != "") {
      print combo, " — ", desc;
    } else {
      if (dispatcher != "" && params != "")
        print combo, " — ", dispatcher, " ", params;
      else if (dispatcher != "")
        print combo, " — ", dispatcher;
      else
        print combo;
    }
  }
')

# use rofi to display the keybinds
printf '%s\n' "$display_keybinds" | rofi -dmenu -i -config "$rofi_theme" -mesg "$msg"
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage