]> git.mxchange.org Git - flightgear.git/commitdiff
replaced the outdated bash completion script with a completely rewritten version
authorRaphael Dümig <duemig@in.tum.de>
Wed, 8 Oct 2014 12:36:39 +0000 (14:36 +0200)
committerRaphael Dümig <duemig@in.tum.de>
Wed, 8 Oct 2014 12:36:39 +0000 (14:36 +0200)
The new script is documented in the flightgear wiki (see "bash completion") and adds functionality such as advanced detection of FG_ROOT and other paths, and many completions not available before.
The list of possible command line options is automatically generated from "fgfs --help --verbose".

The author of the original script (mfranz) has agreed to replace this script.

scripts/completion/fg-completion.bash

index fe55f167922421499cb2f602b27e7b79bd8580a0..4bd70f35a8956695bfb87d4ffca146d57131bf41 100755 (executable)
-#!/bin/bash
-# Tab completion for FlightGear command line options. To use it put
-# this in your ~/.bashrc file:
-#
-#   export FG_HOME=$HOME/.fgfs/
-#   [ -e $FG_HOME/fg-completion.bash ] && source $FG_HOME/fg-completion.bash
-#
-# Defining FG_HOME is only required if you don't like the default
-# "$HOME/.fgfs/". The script doesn't offer all available airports
-# for the --airport option, but only those listed in a file
-# $FG_HOME/airport.list if available, or a short default list otherwise.
-#
-# After installing new aircraft you have to rebuild the aircraft list
-# by typing   $ fgfs --aircraft=?<TAB>
+# © 2014 Raphael Dümig ( duemig at in dot tum dot de ) forum handle: "hamster"
+# distributed under the terms of the GPLv3
 
-__fgfs_root=${FG_ROOT:-/usr/local/share/FlightGear}
-__fgfs_home=${FG_HOME:-$HOME/.fgfs}
-[ -d "$__fgfs_home" ] || mkdir -p "$__fgfs_home"
+local_config_file="$HOME/.fgfsrc"
 
-
-__fgfs_ac_list="$__fgfs_home/aircraft.list"
-__fgfs_apt_list="$__fgfs_home/airport.list"
-
-__fgfs_options="
-       --help
-       --verbose
-       --disable-intro-music
-       --enable-intro-music
-       --units-feet
-       --units-meters
-       --disable-sound
-       --enable-sound
-       --disable-panel
-       --enable-panel
-       --disable-hud
-       --enable-hud
-       --disable-anti-alias-hud
-       --enable-anti-alias-hud
-       --disable-hud-3d
-       --enable-hud-3d
-       --hud-tris
-       --hud-culled
-       --disable-random-objects
-       --enable-random-objects
-       --disable-ai-models
-       --enable-ai-models
-       --disable-freeze
-       --enable-freeze
-       --disable-fuel-freeze
-       --enable-fuel-freeze
-       --disable-clock-freeze
-       --enable-clock-freeze
-       --disable-splash-screen
-       --enable-splash-screen
-       --disable-mouse-pointer
-       --enable-mouse-pointer
-       --fog-disable
-       --fog-fastest
-       --fog-nicest
-       --disable-enhanced-lighting
-       --enable-enhanced-lighting
-       --disable-distance-attenuation
-       --enable-distance-attenuation
-       --disable-specular-highlight
-       --enable-specular-highlight
-       --disable-fullscreen
-       --enable-fullscreen
-       --disable-game-mode
-       --enable-game-mode
-       --shading-flat
-       --shading-smooth
-       --disable-skyblend
-       --enable-skyblend
-       --disable-textures
-       --enable-textures
-       --disable-wireframe
-       --enable-wireframe
-       --notrim
-       --on-ground
-       --in-air
-       --enable-auto-coordination
-       --disable-auto-coordination
-       --show-aircraft
-       --time-match-real
-       --time-match-local
-       --disable-real-weather-fetch
-       --enable-real-weather-fetch
-       --disable-horizon-effect
-       --enable-horizon-effect
-       --enable-clouds
-       --disable-clouds
-       --enable-clouds3d
-       --disable-clouds3d
-       --atc610x
-       --enable-save-on-exit
-       --disable-save-on-exit
-       --ai-scenario=
-       --fg-root=
-       --fg-scenery=
-       --language=
-       --browser-app=
-       --config=
-       --failure=
-       --bpp=
-       --fov=
-       --callsign=
-       --aspect-ratio-multiplier=
-       --geometry=
-       --view-offset=
-       --aircraft=
-       --min-status=
-       --fdm=
-       --aero=
-       --model-hz=
-       --speed=
-       --aircraft-dir=
-       --timeofday=
-       --time-offset=
-       --start-date-sys=
-       --start-date-gmt=
-       --start-date-lat=
-       --airport=
-       --runway=
-       --carrier=
-       --parkpos=
-       --vor=
-       --ndb=
-       --fix=
-       --offset-distance=
-       --offset-azimuth=
-       --lon=
-       --lat=
-       --altitude=
-       --heading=
-       --roll=
-       --pitch=
-       --uBody=
-       --vBody=
-       --wBody=
-       --vc=
-       --mach=
-       --glideslope=
-       --roc=
-       --wp=
-       --flight-plan=
-       --nav1=
-       --nav2=
-       --adf=
-       --dme=
-       --visibility=
-       --visibility-miles=
-       --wind=
-       --turbulence=
-       --ceiling=
-       --multiplay=
-       --proxy=
-       --httpd=
-       --telnet=
-       --jpg-httpd=
-       --generic=
-       --garmin=
-       --joyclient=
-       --jsclient=
-       --native-ctrls=
-       --native-fdm=
-       --native=
-       --nmea=
-       --opengc=
-       --props=
-       --pve=
-       --ray=
-       --rul=
-       --log-level=
-       --trace-read=
-       --trace-write=
-       --season=
-       --vehicle=
-       --prop:
-"
-
-
-if [ ${BASH_VERSINFO[0]} -eq 2 ] && [[ ${BASH_VERSINFO[1]} = "05b" ]] \
-               || [ ${BASH_VERSINFO[0]} -gt 2 ]; then
-       __fgfs_nospace="-o nospace"
-fi
-
-shopt -s progcomp
-
-
-__fgfs_write_ac_list() {
-       rm -f $__fgfs_ac_list
-       for i in $__fgfs_root/Aircraft/*/*-set.xml; do
-               i=${i%-set.xml}
-               echo ${i##*/} >>$__fgfs_ac_list
-       done
+_get_opt()
+{
+    local opt len
+    opt=$1
+    len=`expr ${#opt} + 3`
+    
+    if [ -e "$local_config_file" ]
+    then
+        stored_opts="$(cat "$local_config_file")"
+    fi
+    
+    for word in $stored_opts "${words[@]}"
+    do
+        if [ "${word:0:$len}" == "--$opt=" ]
+        then
+            # TODO: we have to get rid of at least the most important escape sequences!!!
+            value="$(echo "${word:$len}" | sed 's/\\ / /g')"
+        fi
+    done
 }
 
-
-[ -e $__fgfs_ac_list ] || __fgfs_write_ac_list
-
-
-__fgfs_ai_scenario() {
-       local i
-       for i in $__fgfs_root/AI/*.xml; do
-               i=${i%.xml}
-               echo ${i##*/}
-       done
+_get_opts()
+{
+    local opt len
+    opt=$1
+    len=`expr ${#opt} + 3`
+    value=""
+    
+    if [ -e "$local_config_file" ]
+    then
+        stored_opts="$(cat "$local_config_file")"
+    fi
+    
+    for word in "$stored_opts ${words[@]}"
+    do
+        if [ "${word:0:$len}" == "--$opt=" ]
+        then
+            value+="$(echo "${word:$len}" | sed 's/\\ / /g') "
+        fi
+    done
 }
 
-
-__fgfs_aircraft() {
-       while read i; do
-               echo $i
-       done <$__fgfs_ac_list
+_get_fg_root()
+{
+    local value
+    _get_opt "fg-root"
+    
+    # value on the command line?
+    if [ -n "$value" ]
+    then
+        root="$value"
+        return 0
+    # value stored in environment variable $FG_ROOT?
+    else if [ -n "$FG_ROOT" ]
+    then
+        root="$FG_ROOT"
+        return 0
+    # no clue! search at the most common places
+    else
+        for path in /usr{/local,}/share{/games,}/{F,f}light{G,g}ear{/data,} {~,}/Applications/FlightGear.app/Contents/Resources/data
+        do
+            if [ -e "$path" ]
+            then
+                root="$path"
+                break
+            fi
+        done
+    fi
+    fi
 }
 
-
-__fgfs_offer() {
-       local i
-       for i in "$@"; do
-               [ "$i" == "${i%=}" ] && i="$i "
-               echo "$i"
-       done
+_get_fg_scenery()
+{
+    local value
+    _get_opt "fg-scenery"
+    
+    # value on command line?
+    if [ -n "$value" ]
+    then
+        scenery="$value"
+    # value stored in environment variable $FG_SCENERY?
+    else if [ -n "$FG_SCENERY" ]
+    then
+        scenery="$FG_SCENERY"
+    # no clue! try default:
+    else
+        local root
+        _get_fg_root
+        scenery="$root/Scenery"
+    fi
+    fi
+    
+    return 0
 }
 
+_get_fg_aircraft()
+{
+    local value
+    _get_opt "fg-aircraft"
+    
+    # value on command line?
+    if [ -n "$value" ]
+    then
+        aircraft_dir="$value"
+    # value stored in environment variable $FG_AIRCRAFT?
+    else if [ -n "$FG_AIRCRAFT" ]
+    then
+        aircraft_dir="$FG_AIRCRAFT"
+    # no clue! try default:
+    else
+        local root
+        _get_fg_root
+        aircraft_dir="$root/Aircraft"
+    fi
+    fi
+}
 
-__fgfs_options=$(__fgfs_offer $__fgfs_options)
-
-
-__fgfs() {
-       COMPREPLY=()
-       local IFS=$'\n'$'\t' cur=${COMP_WORDS[COMP_CWORD]} alt
+_get_airport()
+{
+    local value
+    _get_opt "airport"
+    
+    if [ -z "$value" ]
+    then
+        airport="KSFO"
+    else
+        airport=$value
+    fi
+}
 
-       case "$cur" in
-       --ai-scenario=*)
-               alt=$(__fgfs_offer $(__fgfs_ai_scenario))
-               ;;
-       --aircraft=\?)
-               __fgfs_write_ac_list
-               ;;
-       --aircraft=*|--vehicle=*)
-               alt=$(__fgfs_offer $(__fgfs_aircraft))
-               ;;
-       --airport=*)
-               if [ -e "$__fgfs_apt_list" ]; then
-                       alt=$(cat "$__fgfs_apt_list")
-               else
-                       alt=$(__fgfs_offer khaf kpao koak kmry knuq ksjc kccr ksns krhv klvk o62 lpma)
-               fi
-               ;;
-       --carrier=*)
-               alt=$(__fgfs_offer Nimitz Eisenhower Foch)
-               ;;
-       --failure=*)
-               alt=$(__fgfs_offer pitot static vacuum electrical)
-               ;;
-       --fdm=*)
-               alt=$(__fgfs_offer jsbsim yasim uiuc larcsim ufo magic)
-               ;;
-       --geometry=*)
-               alt=$(__fgfs_offer 640x480 800x600 1024x768 1152x864 1600x1200)
-               ;;
-       --log-level=*)
-               alt=$(__fgfs_offer bulk debug info warn alert)
-               ;;
-       --min-status=*)
-               alt=$(__fgfs_offer alpha beta early-production production)
-               ;;
-       --parkpos=*)
-               alt=$(__fgfs_offer cat-1 cat-2 cat-3 cat-4 park-1)
-               ;;
-       --season=*)
-               alt=$(__fgfs_offer summer winter)
-               ;;
-       --timeofday=*)
-               alt=$(__fgfs_offer real dawn morning noon afternoon dusk evening midnight)
-               ;;
-       --prop:*)
-               return
-               ;;
-       *)
-               alt="$__fgfs_options"
-               ;;
-       esac
+_get_carrier()
+{
+    local value
+    _get_opt "carrier"
+    
+    carrier=$value
+}
 
-       COMPREPLY=($(compgen -W "$alt" -- ${cur#*=}))
+_get_scenarios()
+{
+    local value
+    _get_opts "ai-scenario"
+    
+    scenarios="$value nimitz_demo"
 }
 
 
-complete -o default $__fgfs_nospace -F __fgfs fgfs signs fgfsterra
+_fgfs() 
+{
+    local cur prev words cword split
+    _init_completion -s || return
 
+    local root airport aircraft_dir carrier scenarios scenery value
+    
+    # auto-completion for values of keys ( --key=value )
+    case "$prev" in
+        --fg-aircraft|--fg-root|--fg-scenery|--flight-plan|--terrasync-dir|--materials-file|--config|--browser-app)
+            # completion of filesystem path
+            _filedir
+            return 0 ;;
+        --ai-scenario)
+            # list of scenarios in $FG_ROOT/AI
+            _get_fg_root
+            scenarios="$(find "$root/AI" -maxdepth 1 -iname *.xml -printf '%f\n' | sed -e 's/.xml$//')"
+            
+            COMPREPLY=( $(compgen -W "${scenarios}" -- ${cur}) )
+            return 0 ;;
+        --aircraft|--vehicle)
+            # list of aircrafts in $FG_AIRCRAFT
+            _get_fg_aircraft
+            aircrafts="$(find "$aircraft_dir" -maxdepth 2 -mindepth 2 -iname *-set.xml -printf '%f\n' | sed -e 's/-set.xml$//')"
+            
+            COMPREPLY=( $(compgen -W "${aircrafts}" -- ${cur}) )
+            return 0 ;;
+        --airport)
+            _get_fg_root
+            _get_fg_scenery
+            # is an index file present in the scenery?
+            if [ -e "$scenery/Airports/index.txt" ]
+            then
+                COMPREPLY=( $(compgen -W "$(awk 'BEGIN { FS="|"; } { print $1 }' "$scenery/Airports/index.txt")" -- ${cur}) )
+                return 0
+            # or at least the apt.dat file?
+            else if [ -e "$root/Airports/apt.dat.gz" ]
+            then
+                COMPREPLY=( $(compgen -W "$(zcat "$root/Airports/apt.dat.gz" | awk '/^1 / { print $5 }')" -- ${cur}) )
+                return 0
+            fi
+            fi
+            
+            return 0 ;;
+        --carrier)
+            _get_fg_root
+            _get_scenarios
+            
+            carriers=""
+            
+            for scenario in $scenarios
+            do
+                carriers+="$(awk -- '
+BEGIN { carrier=0; name=""; }
+/<type>/ {
+    a=index($0,"<type>")+6; s=index(substr($0,a),"</type>")-1;
+    if(substr($0,a,s) == "carrier") carrier=1;
+}
+/<name>/ {
+    if(carrier) {
+        a=index($0,"<name>")+6; s=index(substr($0,a),"</name>")-1;
+        print substr($0,a,s);
+        carrier=0;
+    }
+}
+/<\/entry>/ {
+    carrier=0;
+    name="";
+}' "$root/AI/$scenario.xml") "
+            done
+            
+            COMPREPLY=( $(compgen -W "${carriers}" ${cur}) )
+            return 0 ;;
+        --runway)
+            _get_fg_scenery
+            _get_airport
+            
+            # try to find a thresholds file
+            path="$scenery/Airports/${airport:0:1}/${airport:1:1}/${airport:2:1}"
+            
+            if [ -e "$path/$airport.threshold.xml" ]
+            then
+                runways="$(awk -- '
+/<rwy>/ {
+    a=index($0,"<rwy>")+5;
+    s=index(substr($0,a),"</rwy>")-1;
+    print substr($0,a,s)
+}' "$path/$airport.threshold.xml")"
+            fi
+            
+            COMPREPLY=( $(compgen -W "${runways}" -- ${cur}) )
+            return 0 ;;
+        --parkpos)
+            # try to find out the name of the carrier or the ID of the airport
+            _get_carrier
+            
+            if [ -n "$carrier" ]
+            then
+                _get_fg_root
+                _get_scenarios
+                
+                for scenario in $scenarios
+                do
+                    positions="$(awk -v carrier_name="$carrier" '
+BEGIN { carrier=0; name=0; parkpos=0; }
+/<type>/ {
+    a=index($0,"<type>")+6; s=index(substr($0,a),"</type>")-1;
+    if(substr($0,a,s) == "carrier") carrier=1;
+}
+/<parking-pos>/ {
+    parkpos=(carrier && name);
+}
+/<name>/ {
+    a=index($0,"<name>")+6; s=index(substr($0,a),"</name>")-1;
+    if(parkpos) print substr($0,a,s);
+    else if(carrier) name=(substr($0,a,s) == carrier_name);
+}
+/<\/parking-pos>/ {
+    parkpos=0;
+}
+/<\/entry>/ {
+    carrier=name=parkpos=0;
+}' "$root/AI/$scenario.xml")"
+                    
+                    if [ -n "$positions" ]
+                    then
+                        break
+                    fi
+                done
+                
+            else
+                _get_fg_scenery
+                _get_airport
+                
+                # search for the groundnet or parking file
+                path="$scenery/Airports/${airport:0:1}/${airport:1:1}/${airport:2:1}"
+                
+                if [ -e "$path/$airport.groundnet.xml" ]
+                then
+                    file="$airport.groundnet.xml"
+                else if [ -e "$path/$airport.parking.xml" ]
+                then
+                    file="$airport.parking.xml"
+                else
+                    # no file found => do not try to analyze it!
+                    return 0
+                fi
+                fi
+                
+                # build a list of the parking positions at that airport
+                positions="$(awk -- '
+/<Parking/ {
+    pos_active=1;
+    name=number="";
+}
+/name="/ {
+    if(pos_active) {
+        a=index($0,"name=\"")+6;
+        s=index(substr($0,a),"\"")-1;
+        name=substr($0,a,s);
+    }
+}
+/number="/ {
+    if(pos_active) {
+        a=index($0,"number=\"")+8;
+        s=index(substr($0,a),"\"")-1;
+        number=substr($0,a,s);
+    }
+}
+/\/>/ {
+    if(pos_active == 1 && (name!="" || number!="")) print name number;
+    pos_active=0;
+    name=number="";
+}' "$path/$file")"
+            fi
+            
+            COMPREPLY=( $(compgen -W "${positions}" -- ${cur}) )
+            return 0 ;;
+        --control)
+            COMPREPLY=( $(compgen -W "joystick keyboard mouse" -- ${cur}) )
+            return 0 ;;
+        --failure)
+            COMPREPLY=( $(compgen -W "pitot static vacuum electrical" -- ${cur}) )
+            return 0 ;;
+        --fix)
+            _get_fg_root
+            COMPREPLY=( $(compgen -W "$(zcat "$root/Navaids/fix.dat.gz" | awk '{ print substr($3,0,5) }')" -- ${cur}) )
+            return 0 ;;
+        --fdm)
+            COMPREPLY=( $(compgen -W "jsb larcsim yasim magic balloon ada external null" -- ${cur}) )
+            return 0 ;;
+        --min-status)
+            COMPREPLY=( $(compgen -W "alpha beta early-production production" -- ${cur}) )
+            return 0 ;;
+        --log-class)
+            COMPREPLY=( $(compgen -W "ai environment flight general io network sound terrain" -- ${cur}) )
+            return 0 ;;
+        --log-level)
+            COMPREPLY=( $(compgen -W "bulk debug info warn alert" -- ${cur}) )
+            return 0 ;;
+        --ndb)
+            _get_fg_root
+            COMPREPLY=( $(compgen -W "$(zcat "$root/Navaids/nav.dat.gz" | awk '/^2 / { print $8 }')" -- ${cur}) )
+            return 0 ;;
+        --ndb-frequency)
+            _get_fg_root
+            _get_opt "ndb"
+            COMPREPLY=( $(compgen -W "$(zcat "$root/Navaids/nav.dat.gz" | awk -v nav=$value '/^2 / { if($8 == nav) print $5 }')" -- ${cur}) )
+            return 0 ;;
+        --season)
+            COMPREPLY=( $(compgen -W "summer winter" -- ${cur}) )
+            return 0 ;;
+        --texture-filtering)
+            COMPREPLY=( $(compgen -W "1 2 4 8 16" -- ${cur}) )
+            return 0 ;;
+        --timeofday)
+            COMPREPLY=( $(compgen -W "real dawn morning noon afternoon dusk evening midnight" -- ${cur}) )
+            return 0 ;;
+        --view-offset)
+            COMPREPLY=( $(compgen -W "LEFT RIGHT CENTER" -- ${cur}) )
+            return 0 ;;
+        --vor)
+            _get_fg_root
+            COMPREPLY=( $(compgen -W "$(zcat "$root/Navaids/nav.dat.gz" | awk '/^3 / { print $8 }')" -- ${cur}) )
+            return 0 ;;
+        --vor-frequency)
+            _get_fg_root
+            _get_opt "vor"
+            COMPREPLY=( $(compgen -W "$(zcat "$root/Navaids/nav.dat.gz" | awk -v nav=$value '/^3 / { if($8 == nav) print substr($5,0,3) "." substr($5,4) }')" -- ${cur}) )
+            return 0 ;;
+    esac
+    
+    case "${cur}" in
+        -*)
+            # auto completion for options
+            COMPREPLY=( $(compgen -W "$(_parse_help fgfs "--help --verbose")" -- ${cur}) )
+            # no whitespace after keys
+            [[ $COMPREPLY == *= ]] && compopt -o nospace ;;
+        *)
+            _filedir
+    esac
+    
+    return 0
+}
+complete -F _fgfs fgfs