File indexing completed on 2024-04-28 16:49:43
0001 #compdef kscreen-doctor 0002 0003 # SPDX-FileCopyrightText: 2022 ivan tkachenko <me@ratijas.tk> 0004 # 0005 # SPDX-License-Identifier: GPL-2.0-or-later 0006 0007 local curcontext="$curcontext" state expl ret=1 0008 0009 _kscreen-doctor-check-jq() { 0010 local tag=$1 descr=$2 0011 0012 if (( $+commands[jq] )); then 0013 return 0 0014 else 0015 local -a empty # Is there a better way to print description? 0016 _describe -t "$tag" "$descr (completions unavailable, please install jq)" empty 0017 return 1 0018 fi 0019 } 0020 0021 _kscreen-doctor-outputs() { 0022 local -a outputs # array of triples: id, name, enabled status (true/false) 0023 0024 _kscreen-doctor-check-jq outputs output || return 1 0025 0026 data=(${(f)"$( 0027 kscreen-doctor --json | 0028 jq --raw-output ' 0029 .outputs 0030 | map(select(.connected)) 0031 | sort_by((.enabled | not), .name) 0032 | map(.id, .name, .enabled) 0033 | .[] 0034 ' 0035 )"}) 0036 0037 local id name enabled desc 0038 for id name enabled in $data ; do 0039 if [[ "$enabled" == true ]]; then 0040 enabled="[Enabled] " # a bit of right padding, like git does for recent commits list 0041 else 0042 enabled="[Disabled]" 0043 fi 0044 desc="$enabled Output ID $id, connected as $name" 0045 # Duplicate completions for id and name. But given identical description, 0046 # they will occupy the same row. 0047 outputs+=( "$id:$desc" "$name:$desc" ) 0048 done 0049 0050 _describe -t outputs "output" outputs "$@" -V unsorted 0051 } 0052 0053 _kscreen-mode-fmt() { 0054 local dst="$1" mode="$2" 0055 local size refresh_rate 0056 0057 size=${mode%@*} 0058 refresh_rate=${mode#*@} 0059 # WWWWxHHHH @ RRR, (l:n:) is padding with spaces on the left 0060 printf -v $dst " ${(l:9:)size} @ ${(l:3:)refresh_rate} " 0061 } 0062 0063 _kscreen-doctor-mode() { 0064 local ret=1 output="$1" 0065 0066 _kscreen-doctor-check-jq modes mode || return $ret 0067 0068 # 'top_comp' is a list of current and preferred mode IDs (literal completions). 0069 # 'top_descr' is a list of pretty-printed version of top_comp and their descriptions. 0070 # 'rest_comp' is a list of mode IDs, and 'rest_fmt' is pretty-printed version of rest (without descriptions). 0071 local -a stdout top_comp top_descr rest_comp rest_fmt 0072 stdout=(${(f)"$( 0073 kscreen-doctor --json | 0074 jq --raw-output --arg output "$output" ' 0075 .outputs[] 0076 # note about "\(.id)": stringifying known-to-be integer sounds safer 0077 # than parsing untrusted input as an int. 0078 | select("\(.id)" == $output or .name == $output) 0079 | [ 0080 .preferredModes as $pref 0081 | .currentModeId as $curr 0082 | .modes 0083 | map({ 0084 id: .id, 0085 w: .size.width, 0086 h: .size.height, 0087 r: (.refreshRate | round), 0088 }) 0089 # Some names may be duplicated after rounding refresh rates. 0090 # Group them by what going to be part of a name, 0091 # while keeping a list of IDs to be able to determine which ones are "current" and/or "preferred". 0092 | group_by(.w, .h, .r) 0093 | map({ # flatten back 0094 p: any( 0095 # this is how you do a nested loop 0096 .id as $id | $pref[] as $p | $id == $p 0097 ), 0098 c: any(.id == $curr), 0099 # Just take the first mode`s data. They are identical, and there will always be at least one. 0100 w: .[0].w, 0101 h: .[0].h, 0102 r: .[0].r 0103 }) 0104 | sort_by(.w, .h, .r) 0105 | reverse 0106 | map({ name: "\(.w)x\(.h)@\(.r)", p: .p, c: .c }) 0107 # show current mode on top, then preferred, then the rest. 0108 # Second line is a flag that indicates whether current mode is also the preferred one. 0109 | map(select(.c) | "\(.name);\(.p)")[], 0110 "--", 0111 map(select((.c | not) and .p) | .name)[], 0112 "++", 0113 map(select((.c | not) and (.p | not)) | .name)[] 0114 ][] 0115 ' 0116 )"}) 0117 # sample result: 0118 # 4096x2160@60;false 0119 # -- 0120 # 1920x1080@60 0121 # ++ 0122 # 4096x2160@50 0123 # 4096x2160@30 0124 # 3840x2160@60 0125 # 3840x2160@50 0126 # 3840x2160@30 0127 # 1920x1080@50 0128 # 1920x1080@30 0129 # 1920x1080@25 0130 # ... 0131 # The 'false' on a first line indicates that current is not also a 0132 # preferred one. If it were, it would not appear in the list of preferred 0133 # modes below. 0134 0135 local current label formatted line parser=current # then "preferred" and "rest" 0136 for line in $stdout ; do 0137 case $line in 0138 --) 0139 parser=preferred 0140 continue 0141 ;; 0142 ++) 0143 parser=rest 0144 continue 0145 esac 0146 case $parser in 0147 current) 0148 current=${line%;*} 0149 _kscreen-mode-fmt formatted "$current" 0150 label="Current" 0151 # current is also preferred 0152 if [[ "${line#*;}" != "false" ]]; then 0153 label="$label & Preferred" 0154 fi 0155 top_comp+=( "$current" ) 0156 top_descr+=( "${formatted}:${label} mode" ) 0157 ;; 0158 preferred) 0159 _kscreen-mode-fmt formatted "$line" 0160 top_comp+=( "$line" ) 0161 top_descr+=( "${formatted}:Preferred mode" ) 0162 ;; 0163 rest) 0164 _kscreen-mode-fmt formatted "$line" 0165 rest_comp+=( $line ) 0166 rest_fmt+=( $formatted ) 0167 esac 0168 done 0169 0170 ret=1 0171 # Resetting expl to avoid it 'leaking' from one line to the next. 0172 expl=() 0173 _describe -V -t notable-modes 'notable modes' top_descr top_comp && ret=0 0174 expl=() 0175 _wanted all-modes expl 'other available modes' \ 0176 compadd -o nosort -d rest_fmt -a rest_comp \ 0177 && ret=0 0178 return $ret 0179 } 0180 0181 _kscreen-doctor-priorities() { 0182 local connected_count 0183 if (( $+commands[jq] )); then 0184 connected_count="$( 0185 kscreen-doctor --json | 0186 jq --raw-output ' 0187 .outputs 0188 | map(select(.connected)) 0189 | length 0190 ')" 0191 else 0192 # best effort fallback 0193 connected_count="$(kscreen-doctor --outputs | wc -l)" 0194 fi 0195 _alternative "priority::( {0..${connected_count}} )" 0196 } 0197 0198 _arguments -C \ 0199 '(-h --help)'{-h,--help}'[Displays help on commandline options]' \ 0200 '--help-all[Displays help including Qt specific options]' \ 0201 '(-i --info)'{-i,--info}'[Show runtime information: backends, logging, etc]' \ 0202 '(-j --json)'{-j,--json}'[Show configuration in JSON format]' \ 0203 '(-o --outputs)'{-o,--outputs}'[Show outputs]' \ 0204 '(DPMS)'{-d=,--dpms=}'[(Wayland only) Display power management]:status:(on off)' \ 0205 '--dpms-excluded=[Do not apply the dpms change to the output with said model names]:output:_kscreen-doctor-outputs' \ 0206 '(-l --log)'{-l=,--log=}'[Write a comment to the log file]:comment' \ 0207 '*: :->settings' && ret=0 0208 0209 case $state in 0210 settings) 0211 if compset -P 'output.' ; then 0212 0213 if compset -P 1 '*.' ; then 0214 local output; output="${${IPREFIX#*.}%.}" 0215 0216 if compset -P 1 'mode.' ; then 0217 _kscreen-doctor-mode "$output" && ret=0 0218 elif compset -P 1 'priority.' ; then 0219 _kscreen-doctor-priorities && ret=0 0220 elif compset -P 1 'position.' ; then 0221 _arguments '1::x,y:' && ret=0 0222 elif compset -P 1 'rgbrange.' ; then 0223 _alternative 'rgbrange::(automatic full limited)' && ret=0 0224 elif compset -P 1 'rotation.' || compset -P 1 'orientation.' ; then 0225 _alternative 'rotation::(none normal left right inverted)' && ret=0 0226 elif compset -P 1 'overscan.' ; then 0227 local -a overscan_descr overscan_comp 0228 overscan_descr=( 0229 ' 0%:Disable overscan (Default)' 0230 ' 3%:Action safe area (Vertical, round down)' 0231 ' 4%:Action safe area (Vertical, round up)' 0232 '10%:Action safe area (Horizontal, 14:9 displayed on 16:9)' 0233 '15%:Action safe area (Horizontal, 4:3 displayed on 16:9)' 0234 '17%:Title safe area (Horizontal, 4:3 displayed on 16:9)' 0235 ) 0236 overscan_comp=('0' '3' '4' '10' '15' '17') 0237 _describe -t overscan "(Wayland only) output overscan, 0%%..100%%" \ 0238 overscan_descr overscan_comp -o nosort && ret=0 0239 elif compset -P 1 'scale.' ; then 0240 local -a scale_descr scale_comp 0241 scale_descr=('100%' '125%' '150%' '175%' '200%' '225%' '250%' '275%' '300%' ) 0242 scale_comp=( '1' '1,25' '1,5' '1,75' '2' '2,25' '2,5' '2,75' '3' ) 0243 _describe -t scale "(Wayland only) per-output scaling" scale_descr scale_comp -o nosort && ret=0 0244 elif compset -P 1 'vrrpolicy.' ; then 0245 _alternative 'vrrpolicy::(never always automatic)' && ret=0 0246 else 0247 # two groups: first without suffix, and second with '.' at the end 0248 _describe -t subcommands 'subcommand' '( 0249 enable:"Toggle output" 0250 disable:"Toggle output" 0251 primary:"Make this output primary (same as priority.1)" 0252 )' -- '( 0253 mode:"Resolution and refresh rate" 0254 orientation:"Display orientation" 0255 overscan:"(Wayland only) Overscan area size" 0256 position:"x and y coordinates" 0257 priority:"Set output priority" 0258 rgbrange:"RGB range" 0259 rotation:"Display orientation" 0260 scale:"(Wayland only) Per-output scaling" 0261 vrrpolicy:"(Wayland only) Variable refresh rate" 0262 )' -S '.' && ret=0 0263 fi 0264 else 0265 _kscreen-doctor-outputs -S '.' && ret=0 0266 fi 0267 else 0268 _sep_parts '(output)' . && ret=0 0269 fi 0270 ;; 0271 esac 0272 0273 return $ret