# bash_completion_ordbanken – bash-basert autofullføring for skriptet ordbanken.
#
# Copyright © 2008, 2009, 2010, 2018–2020 Karl Ove Hufthammer <karl@huftis.org>.
#
#     This file is part of Ordbanken.
#
#     Ordbanken is free software: you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation, either version 3 of the License, or
#     (at your option) any later version.
#
#     This program is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#     GNU General Public License for more details.
#
#     You should have received a copy of the GNU General Public License
#     along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Bruk: source bash_completion_ordbanken
#       (og bruk so ordbankskriptet som før)

shopt -s extglob # Nødvendig for testane som brukar @()-syntaksen.

# Finn ut kva språk brukaren har valt.
_ordbanken_finn_sprak()
{
  # Enten har brukaren definert språket på kommandolinja.
  for (( i=0; i < ${#COMP_WORDS[@]}-1; i++ ))
  do
    sprak_arg=${COMP_WORDS[i]}
    case $sprak_arg in
      -snn ) sprak=nn;;
      -snb ) sprak=nb;;
      --sprak|-s ) sprak=${COMP_WORDS[i+1]};;
    esac
  done

  # Eller so har brukaren (forhåpentligvis) definert eit standardspråk.
  if [ -z "$sprak" ]
  then
    if [[ "$SPRAK_ORDBANKEN" == @(nn|nb) ]]
    then
      sprak=$SPRAK_ORDBANKEN
    fi
  fi

  echo "$sprak"
}

# Hent alle orda frå gjeldande språk som begynner med teksten under skrivemerket.
_ordbanken_hent_ord()
{
  # Må først finna ut kva språk me har.
  sprak=$(_ordbanken_finn_sprak)

  # Mappa der ordbankfilene ligg.
  local ordbanken_mappe
  ordbanken_mappe="/usr/local/share/ordbanken"
  
  # Oppslagsordet, der «ord» som "på tvers", 'på tvers'
  # og på\ tvers er utvida/evaluert til «på tvers».
  # Brukar «eval» til å få «kanonisk» form av ordet,
  # der «'», «"», «\ » og liknande er tolka,
  # men må triksa litt viss ordet ikkje inneheld
  # eit avsluttane hermeteikn. (Det er sikkert ein
  # lurare måte å gjera dette på.)
  local oppslagsord
  oppslagsord=$(eval echo "$cur" 2>/dev/null || \
                      eval echo "$cur'" 2>/dev/null || \
                      eval echo "$cur\"" 2>/dev/null || "")
  local forslag

  # Sjekk at ordlistefila finst (språkkoden er rett)
  # og at me ikkje søkjer gjennom heile (tom søkjetekst).
  fil="$ordbanken_mappe/fullform_$sprak.dat"
  if [ -r "$fil" ] && [ -n "$oppslagsord" ]
  then
    LOOK_PROG=$(command -v look) # Sjekk om programmet «look» finst.
    LOOK_FINST=$?
    if [ $LOOK_FINST -eq 0 ] # Bruk «look» om programmet finst, «grep» elles.
    then
      forslag=$(LC_ALL=C $LOOK_PROG -- "$oppslagsord" "$fil")
    else
      forslag=$(LC_ALL=C grep -- "^$oppslagsord" "$fil")
    fi
    echo "$forslag" | cut -f1 | uniq \
    | sed -e "{" -e 's#\\#\\\\#g' -e "s#'#\\\'#g" -e 's#"#\\\"#g' -e "}"
  fi
}

# Hent alle ordklassane (morfologiske skildringar) frå gjeldande
# språk som begynner med teksten under skrivemerket.
_ordbanken_hent_klassar()
{
  # Må først finna ut kva språk me har.
  sprak=$(_ordbanken_finn_sprak)
  
  LOOK_PROG=$(command -v look) # Sjekk om programmet «look» finst.
  LOOK_FINST=$?

  # Mappa der ordbankfilene ligg.
  local ordbanken_mappe="/usr/local/share/ordbanken"

  # Oppslagsordet der «ord» som "på tvers", 'på tvers'
  # og på\ tvers er utvida/evaluert til «på tvers».
  local oppslagsord
  oppslagsord=$(eval echo "$prev" 2>/dev/null || 
  eval echo "$prev'" 2>/dev/null ||
  eval echo "$prev\"" 2>/dev/null || "")

  # Sjekk at ordlistefila finst (språkkoden er rett).
  fil="$ordbanken_mappe/fullform_$sprak.dat"
  if [ -r "$fil" ] && [ -n "$oppslagsord" ]
  then
    if [ $LOOK_FINST -eq 0 ] # Bruk «look» om programmet finst, «gawk» elles.
    then
      oppslag="$(LC_ALL=C $LOOK_PROG -- "$oppslagsord	" "$fil")"
    else
      oppslag="$(LC_ALL=C gawk -F'\t' '{ if ( $1 == '\""$oppslagsord"\"') {print $0}}' "$fil")"
    fi
    # Forklaring:
    #   gawk: Fjern dei to talkodane på slutten av kvar linje
    #         (med litt triksing viss forslagslista er tom, slik
    #          at me ikkje prøver å lesa frå kolonne -1)
    #   cut:  Fjern oppslagsord og tilhøyrande bøying (to første kolonnar)
    #   sed:  Fjern < og >, som nokre kodar har
    #   grep: Sjå berre på forslaga som er i samsvar med gjeldande inntasting
    #   sort: Alfabetisk sortering
    #   uniq: Fjern duplikatar
    echo "$oppslag" \
    | gawk -F'\t' 'BEGIN { OFS="\t" } { $(NF?NF-1:NF)=$NF=""; print $0; }' \
    | cut -f3- -d"	" \
    | sed 's/[<>]//g;s/	/\
/g' \
    | grep "^$cur" \
    | sort \
    | uniq 
  fi
}

# Hovudfunksjonen som autofullfører for oss.
_ordbanken()
{
  local cur prev prevprev

  # Ikkje del på mellomrom, berre tabulator og linjeskift.
  local IFS
  IFS=$(printf '\n\t')

  COMPREPLY=()
  cur="${COMP_WORDS[COMP_CWORD]}"
  prev="${COMP_WORDS[COMP_CWORD-1]}"

  # Finn òg fram ordet før, om det finst.
  if [ "$COMP_CWORD" -gt 1 ]
  then
    prevprev="${COMP_WORDS[COMP_CWORD-2]}"
  fi

  # Viss me er etter «--», er me på argumentsida
  # og alle ord skal reknast som oppslagsord og
  # ikkje som argument, sjølv om det startar med
  # «-» (som «-aktig»). Returner derfor ordklassane
  # til førre ord, altså ordet etter «--».
  if [ "$prevprev" = "--" ]
  then
      COMPREPLY=( $( compgen -W "$(_ordbanken_hent_klassar)" -- ) )
  else # Elles kan me ha både argument og oppslagsord …

  # Viss me berre på første ord (programnamnet),
  # er det ingenting å fullføra. Sørg for at dette
  # fungerer sjølv om brukaren har endra namnet
  # på programfila, eller har laga eit alias til ho.
  if [ "$COMP_CWORD" -eq 1 ]
  then
    prev="ordbanken"
  fi

  # Tips om gyldige språkkodar eller ordkodar.
  while true; do
    case "$prev" in
      --sprak | -s) # Tips om språkkodar.
      COMPREPLY=( $( compgen -W 'nb	nn' -- "$cur" ) )
      return 0
      ;;
      nn | nb ) break;; # Førre ord var ein språkkode.
      ordbanken) break;; # Me er berre på første ord.
      -*) break;; # Førre ord var eit val.
      *) # Førre ord var eit oppslagsord. Føreslå derfor ordkodar.
      COMPREPLY=( $( compgen -W "$(_ordbanken_hent_klassar)" -- ) )
      return 0;;
    esac
  done

  # Tips om gyldige argument som startar med «-».
  if [[ "$cur" == -* ]] && [ "$prev" != "--" ]; then
    local strekargument
    strekargument='--sprak	-snn	-snb	-e	--eksempel	-f	--fargekod	'
    strekargument+='-F	--ikkje-fargekod	-g	--grupper-ord	-G	--ikkje-grupper-ord	'
    strekargument+='-p	--grupper-paradigme	-P	--ikkje-grupper-paradigme	-r	'
    strekargument+='--regulært-uttrykk	--tekst	--html	'
    strekargument+='-h	--hjelp	-v	--versjon'  
    COMPREPLY=( $( compgen -W "$strekargument" -- "$cur") )
  else
    # Sjå om brukaren alt har valt språk,
    # anten ved at han/ho har definert standardspråk …
    local sprakvald
    if [[ "$SPRAK_ORDBANKEN" == @(nn|nb) ]]
    then
      sprakvald="ja"
    else # … eller ved å definera det på kommandolinja
      for (( i=0; i < ${#COMP_WORDS[@]}-1; i++ ))
      do
        if [[ "${COMP_WORDS[i]}" == @(--sprak|-s|-snn|-snb|--sprak=nn|--sprak=nb) ]]
        then
          sprakvald="ja"
        fi
      done
    fi
    if [ -z "$sprakvald" ] # Viss språket ikkje er valt, legg til «--sprak» …
    then
      COMPREPLY=( "--sprak" )
    else # … elles hent oversikt over ord som begynner med vald tekst.
      COMPREPLY=( $( compgen -W "$(_ordbanken_hent_ord)" -- ) )
      # "cur" på slutten her er uødvendig, og fører til problem med
      # hermeteikna ", ' og mellomrom.
      # Løysing basert på http://stackoverflow.com/questions/1146098/properly-handling-spaces-and-quotes-in-bash-completion
      local hermeteikn="'\''"
      local i=0
      for entry in ${COMPREPLY[*]}
      do
        if [[ "${cur:0:1}" == "'" ]]
        then
          # Starta med '. Skriv dei andre hermeteikna som '\''.
          # [']bla'bla"bla\bla bla → [']bla'\''bla"bla\bla bla
          COMPREPLY[$i]="${entry//\'/${hermeteikn}}"
        elif [[ "${cur:0:1}" == "\"" ]]
        then
          # Starta med ". Skriv " som \" og \ som \\.
          # ["]bla'bla"bla\bla bla → ["]bla'bla\"bla\\bla bla
          entry="${entry//\\/\\\\}"
          COMPREPLY[$i]="${entry//\"/\\\"}"
        else
          # Starta ikkje med hermeteikn. Skriv ", ' og \ som \", \' og \\.
          # [ ]bla'bla"bla\bla bla → [ ]bla\'bla\"bla\\bla\ bla
          entry="${entry//\\/\\\\}"
          entry="${entry//\'/\'}"
          entry="${entry//\"/\\\"}"
          COMPREPLY[$i]="${entry// /\\ }"
        fi
        (( i++ ))
      done
    fi
  fi
  fi
}

# Legg til slutt til støtte for autofullføring.
complete -F _ordbanken ordbanken
