### Copyright (C) 1995-1997 Jesper K. Pedersen
### This program 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 2 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, write to the Free Software
### Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


######################################################################
###                     User defined completion
######################################################################
proc completion_user {} {
  # completion / userdefined

  Desc "Here you can configure a very smart feature of tcsh: user defined"\
      "completion. User defined completion lets you complete from different"\
      "list of possibilities depending on the command you are typing."\
      "Normally, you can only complete on filenames and directories. Here"\
      "you have the possibility to complete on things like process Id's,"\
      "usernames, aliases, pre defined lists, and even on output from a"\
      "program."
  
  ShortDesc "user defined completion"

  ############################### Widgets ##############################
  Entry command \
      -text "Command name" 

  ### I cant find out what this option does!
#   CheckBox ambiguous \
#       -text "Use only this command when completion is ambiguous"

  ################# Which word to complete on ##########################
  Radio type -text "How to define completion" -entries position pattern \
      -packFrame:fill x

  ### Position ###
  Header posHead -text "Position depend completion"
  for {set i 1} {$i < 31} {incr i} {
    lappend num $i
  }
  eval ComboBox from -text From: -entries All $num \
      -width 4 -noedit 1 -default All -packFrame:fill x -packFrame:expand 1
  eval ComboBox to -text To: -entries Rest $num \
      -width 4 -noedit 1 -default Rest -packFrame:fill x -packFrame:expand 1
  Frame posFrame -entries from to -packFrame:fill x -packFrame:pady 10

  ### Pattern ###
  Header patHead -text "Pattern depend definition"
  set s1 [Space 10]
  Entry pattern -text "Pattern to match"
  Radio word -text "Word this pattern shall match" \
      -entries {current previous "2x prev"}
  CheckBox include -text "Include pattern in completion"
  Frame patFrame -entries pattern $s1 word include -orient top -packFrame:pady 10
  
  Window pos -text "Position definition" \
      -entries type posHead posFrame patHead patFrame \
      -pageEnd {
        if {$type(name) == "position"} {
          if {$from == "All"} {
            set posLabel "position: All"
          } else {
            set posLabel "position: $from - $to"
          }
        } else {
          set posLabel "pattern \"$pattern\" on $word(name) word"
        }
      }
  
  Label posLabel -text ( -textafter ) -default "position: All"
  Frame posFrm -entries pos posLabel

  ################## List to complete from #############################

  ### Internal
  Header h1 -text Internal -background gray 
  CheckBox c1 -text Alias -default 1
  CheckBox c2 -text Editor commands
  CheckBox c3 -text Limits
  CheckBox c4 -text Shell var names
  CheckBox c5 -text Environment var names
  CheckBox c6 -text Shell & Environment var names
  Frame f1 -entries c1 c4 -orient top
  Frame f2 -entries c2 c5 -orient top
  Frame f33 -entries c3 c6 -orient top
  Frame f3 -entries f1 f2 f33

  ### files and diectories
  Header h2 -text Files and Directories -background gray

  CheckBox c7 -text Commands
  CheckBox c8 -text Directories
  CheckBox c9 -text FileNames
  CheckBox c10 -text Text files
  Frame f4 -entries c7 c8 c9 c10 -orient top
  
  Dir-Browser com  -text "From Directory:"
  Dir-Browser dir  -text "From Directory:"
  Dir-Browser file -text "From Directory:"
  Dir-Browser text -text "From Directory:"
  Frame f5 -entries frame_com frame_dir frame_file frame_text -orient top \
      -packFrame:expand 1 -packFrame:fill x

  Frame f6 -entries f4 f5

  ### System
  Header h3 -text System -background gray
  CheckBox c11 -text Signal Names
  CheckBox c12 -text Groupnames
  CheckBox c13 -text Jobs
  CheckBox c14 -text Usernames
  Frame f7 -entries c11 c13 -orient top
  Frame f8 -entries c12 c14 -orient top
  Frame f9 -entries f7 f8

  ### From variable
  Header h4 -text Content of variable -background gray
  CheckBox c15 -text Content of Variable:
  Entry content -packEntry:fill x -packEntry:expand 1\
      -packFrame:fill x -packFrame:expand 1
  Frame f10 -entries c15 content 

  ### From List
  Header h5 -text "Predefined List" -background gray
  CheckBox c16 -text "Predefined list:"
  Entry predef -packEntry:fill x  -packEntry:expand 1\
      -packFrame:fill x -packFrame:expand 1
  Frame f11 -entries c16 predef

  ### Output from command
  Header h6 -text Output From Command -background gray
  CheckBox c17 -text "Command: "
  Entry out_com  -packEntry:fill x  -packEntry:expand 1\
      -packFrame:fill x -packFrame:expand 1
  Frame f12 -entries c17 out_com
  
  ### Misc
  Header h7 -text Misc -background gray
  CheckBox c18 -text No completion
  CheckBox c19 -text Message:
  Entry message  -packEntry:fill x -packEntry:expand 1 \
      -packFrame:fill x -packFrame:expand 1 -width 50
  Frame f13 -entries c19 message

  Window list -text "List" \
      -entries h1 f3 h2 f6 h3 f9 h4 f10 h5 f11 h6 f12 h7 c18 f13\
      -pageEnd {
        set elm 1
        for {set i 1} {$i <= 19} {incr i} {
          if {[set c$i]} {
            set elm $i
            break
          }
        }
        switch $elm {
          1 {set listLabel "Alias"}
          2 {set listLabel "Editor Command"}
          3 {set listLabel "Limits"}
          4 {set listLabel "Shell var names"}
          5 {set listLabel "Environment var names"}
          6 {set listLabel "Shell & Env. var names"}
          7 {
            set listLabel "Commands"
            if { $com != ""} {
              append listLabel " from \"$com\""
            }
          }
          8 {set listLabel "Directories"
            if { $dir != ""} {
              append listLabel " from \"$dir\""
            }
          }
          9 {
            set listLabel "FileNames"
            if { $file != ""} {
              append listLabel " from \"$file\""
            }
          }
          10 {set listLabel "Text files"
            if { $text != ""} {
              append listLabel " from \"$text\""
            }
          }
          11 {set listLabel "Signals"}
          12 {set listLabel "Groupnames"}
          13 {set listLabel "Jobs"}
          14 {set listLabel "Usernames"}
          15 {
            if {$content == ""} {
              error "Error in window \"List\": No variable name given!"
            }
            set listLabel "Content of Variable \"$content\""}
          16 {
            if {$predef == ""} {
              error "Error in window \"List\":No list given!"
            }
            set listLabel "Predefined list"}
          17 {
            if {$out_com == ""} {
              error "Error in window \"List\": No command given!"
            }
            set listLabel "Output from command"
          }
          18 {set listLabel "No completion"}
          19 {
            if {$message == ""} {
              error "Error in window \"List\": No message given!"
            }
            set listLabel "Message"
          }
        }
      }

  Label listLabel -text ( -textafter ) -default Alias 
  Frame listFrame -entries list listLabel

  Entry suffix \
      -text additional suffix \
      -entry:width 2

  ### Restriction
  Entry restrict -text "Restrict to pattern:" -packEntry:fill x\
      -packEntry:expand 1 -packFrame:fill x -packFrame:expand 1

  ExtEntry complete \
      -entries command posFrm listFrame suffix restrict\
      -count 2 \
      -lines 1\
      -orient top \
      -index command \
      -packFrame:fill x

  ################################ Help ################################

  Help command \
      "This may be a full command name or a glob-pattern."\
      "Glob-patterns are build of the following elements:\n * - Match"\
      "an arbitrary length sequence of characters\n ? - Match a single"\
      "character\n \[...\] - Match any character named between"\
      "brackets\n \[^...\] - Match any character not named between"\
      "brackets\n ^pattern - Match filenames not matching pattern\n"\
      "{file1,file2,...} - List elements\n\n Example:\n"\
      "{ls,less,mv,rm}\n a2* match a2ps a2dvi etc."

#   Help ambiguous \
#       "I Need Help here!"

  Help type \
      "Select wether you want this completion to be chosen from a"\
      "position or a pattern"

  foreach elm {posFrame from to posHead} {
    Help $elm "Select the argument number this completion should work for."
  }

  Help pattern "This is the pattern, which the word specified with the"\
      "radio buttons have to match before the the completion is"\
      "selected from the list, this completion specify."

  Help word \
      "Here you select which word the pattern shall match. (examples in"\
      "help text for each radio button)"

  EntryHelp word current \
      "If this radio button is selected, the text, which is to be"\
      "completed, must match the pattern given"\
      "above.\n\nExample:\n\"find\" have a lot of switched, these can"\
      "be completed, if the pattern matched is \"-\", and the list of"\
      "switches is given.\nIf the user types \"-n\" and press the tab"\
      "key, then \"-n\" will match - on the current word, and this"\
      "completion apply."

  EntryHelp word previous \
      "If this radio button is selected, the word before the text,"\
      "which is to be completed, must match the pattern given"\
      "above.\n\nExample:\nIf the previous word on the command line"\
      "to \"find\" is \"-user\" the word shall be completed with a user"\
      "name. I.e. the pattern shall be \"-user\" and this radio button"\
      "should be selected."

  EntryHelp word "2x prev" \
      "If a program have a switch, which takes two argument, this radio"\
      "button should be selected.\n\nExample:\nImagine we have a"\
      "program with a -test switch, which takes a username as the first"\
      "argument, and a directory as the second (ie. -test Jesper"\
      "/dev/), then a completion may be set up to complete a directory"\
      "if the 2x previous word is \"-test\"."

  Help include \
      "When completing on the current word, you may wish either to"\
      "include the pattern, which selected this completion or to"\
      "complete without the pattern.\n\nExample:\nThe program kill"\
      "may either take a process id, as the job to kill (ie. 123) or a"\
      "percent sign and the command line, which the job has been"\
      "started with (ie. %emacs).\nIf the current word matches \"%\","\
      "then the completion should be done without the pattern matched,"\
      "and with job names. Otherwise if the curent word matched \[0-9\]*,"\
      "the the completion should be done with process id's, and the"\
      "pattern should be included in the completion."
  
  Help pos \
      "You can define when a given completion is to be used in terms of"\
      "either a position or a pattern to be matched.\nThe position is"\
      "given in word on the command line, i.e. the first argument is"\
      "position 1, the second is position 2 etc.\nThe pattern can match"\
      "the current word (i.e. the word which is being completed), the"\
      "word before the word being completed or the before the previous"\
      "word."

  Help c1 \
      "This is the list of all the aliases, which are defined for the"\
      "current user. (type alias in the prompt to see their definition)"

  Help c2 \
      "This is a list of builtin editor commands. See the section \"The"\
      "command-line editor \" in the tcsh man page."

  Help c3 \
      "This is a list of limit names. type \"limit\" in the prompt to"\
      "see these names."

  setArgs help \
      "The deference between a shell variable name and an environment"\
      "variable name is, that programs which are started in the shell"\
      "may read environment variables but not shell variables. Shell"\
      "variables are often used to configure tcsh with, or in scripts"\
      "where they contain information, which will be used later in the"\
      "script."
  
  Help c4 "This is a list of all defined shell variable names." $help
  Help c5 "This is a list of all defined environment variable names." $help
  Help c6 "This is a list of all defined variables." $help

  setArgs help \
      "If a \"from directory\" is given, the completion is done from"\
      "this directory. Otherwise the completion is done with offset in"\
      "the current working directory.\n\nExample:\nIf elm is given an"\
      "equal sign, and a name, the name is the name of a file in the"\
      "~/mail directory. In this example the completion should complete"\
      "to a text file with offset \"~/mail\""

  foreach elm {c7 com com_com} {
    Help $elm \
        "This is a list of commands (either built-in or executable files)" $help
  }
  foreach elm {c8 dir com_dir} {
    Help $elm "This is a list of directories." $help
  }
  foreach elm {c9 file com_file} {
    Help $elm "This is a list of files." $help
  }
  foreach elm {c10 text com_text} {
    Help $elm "This is a list of plain text files, (ie filese, which"\
        "you can see with less ort cat)" $help
  }

  Help c11 "This is a list of signal names, Ie. HUP KILL etc."
  Help c12 "This is a list of group available on the system"
  Help c13 "This is a list of all jobs started in the fiven shell"
  Help c14 "This is a list of all users at the given system"
  foreach elm {c15 content} {
    Help $elm "The variable given here shall contain a list, which to"\
        "complete from."
  }
  foreach elm {c16 predef} {
    Help $elm "Here you can type a list of word, which to complete from"
  }
  foreach elm {c17 out_com} {
    Help $elm "Here you can type a command, which returns a space"\
      "delimited list of element, which to complete from. This command"\
      "is invoked each time completions is done.\nNote I'm not 100%"\
      "sure that this will work all the time, so if you find a"\
      "situation, in which this doesn't work I would very much like to"\
      "hear about it."
  }
  foreach elm {c19 message} {
    Help $elm "No completion is done, but the message is echoed each time"\
        "completion is invoked."
  }
  Help restrict \
    "Here you can type an aditional pattern, an element"\
    "have to fullfill to be inserted in the completion list."\
    "Patterns are build of the following elements:\n * - Match an"\
    "arbitrary length sequenjce of characters\n ? - Match a single"\
    "character\n \[...\] - Match any character named between"\
    "brackets\n \[^...\] - Match any character not named between"\
    "brackets\n ^pattern - Match filenames not matching pattern\n"\
    "{file1,file2,...} - List elements\n\n Example:\n"\
    "{ls,less,mv,rm}\n a2* match a2ps a2dvi etc.\n"\
    "^{*.dvi,*.ps} - match anything, which does not match *.dvi or *.ps"
    
  
  Help list \
      "On this page you select which list the completion shall be done"\
      "from. You can select:\n Things which are local to tcsh, like the"\
      "name of its aliases. Names of files or directories, or you can"\
      "create the list yourself either static or on the fly."

  Help suffix "This is a single character to  be appended to a successful"\
      "completion.  If omitted a slash is appended to directories and a"\
      "space to other words."

  ############################### Change ###############################
  Change {
    switch -glob $changeElm {
      from {
        if {$from == "All"} {
          Disable to
        } else {
          Enable to
          if {$from != "All" && $to != "Rest" && $to < $from} {
            set from 1
            error "\"To entry\" less than \"from entry\""
          }
        }
      }
      to {
        if {$from != "All" && $to != "Rest" && $to < $from} {
          set to Rest
          error "To entry less than from entry"
        }
      }
      type {
        if {$type(name) == "position"} {
          Enable posFrame posHead
          if {$from == "All"} {Disable to}
          Disable patHead pattern word include
        } else {
          Disable posHead posFrame
          Enable patHead pattern word include
          if {$word(name) != "current"} {
            Disable include
          }
        }
      }
      word {
        if {$word(name) == "current" && $type(name) == "pattern"} {
          Enable include
        } else {
          Disable include
        }
      }
      c[0-9]* {
        if {[set $changeElm]} {
          for {set i 1} {$i <= 19} {incr i} {
            if {"c$i" != $changeElm} {
              set c$i 0
            }
          }
          foreach elm {frame_com frame_dir frame_file frame_text
            content predef out_com message} {
            Disable $elm
          }
          Enable restrict
          switch $changeElm {
            c7 {
              Enable frame_com
              if {$com != ""} {Disable restrict}
            }
            c8 {
              Enable frame_dir
              if {$dir != ""} {Disable restrict}
            }
            c9 {
              Enable frame_file
              if {$file != ""} {Disable restrict}
            }
            c10 {
              Enable frame_text
              if {$text != ""} {Disable restrict}
            }
            c15 {Enable content;Disable restrict}
            c16 {Enable predef;Disable restrict}
            c17 {Enable out_com;Disable restrict}
            c19 {Enable message;Disable restrict}
          }
        } else {
          set found 0
          for {set i 1} {$i <= 19} {incr i} {
            if {[set c$i]} {
              set found 1
              break
            }
          }
          if {!$found} {
            set $changeElm 1
          }
        }
      }
    }
  }

  ################################ Save ################################
  Save {
    catch "unset completeList"
    forevery complete {
      if {$command == ""} continue

      if {$type(name) == "position"} {
        ### Position
        set part1 p
        if {$from == "All"} {
          set part2 *
        } elseif {$to == $from} {
          set part2 $from
        } elseif {$to == "Rest"} {
          set part2 ${from}-
        } else {
          set part2 ${from}-$to
        }
      } else {
        ### Pattern
        set part2 $pattern
        if {$word(index) == 0} {
          if {$include} {
            set part1 C
          } else {
            set part1 c
          }
        } elseif {$word(index) == 1} {
          set part1 n
        } else {
          set part1 N
        }
      }

      ### find the selected element
      for {set i 1} {$i <= 19} {incr i} {
        if {[set c$i]} {
          break
        }
      }
      
      switch $i {
        1 {set part3 a}
        2 {set part3 b}
        3 {set part3 l}
        4 {set part3 s}
        5 {set part3 e}
        6 {set part3 v}
        7 {
          if {$com == ""} {
            set part3 "c"
          } else {
            set part3 "C:$com"
          }
        }
        8 {
          if {$dir == ""} {
            set part3 d
          } else {
            set part3 "D:$dir"
          }
        }
        9 {
          if {$file == ""} {
            set part3 f
          } else {
            set part3 "F:$file"
          }
        }
        10 {
          if {$text == ""} {
            set part3 t
          } else {
            set part3 "T:$text"
          }
        }
        11 {set part3 S}
        12 {set part3 g}
        13 {set part3 j}
        14 {set part3 u}
        15 {set part3 \$$content}
        16 {set part3 ($predef)}
        17 {
          regsub -all ' $out_com {'"'"'} com
          set part3 `$com`
        }
        18 {set part3 n}
        19 {set part3 x:$message}
      }

      if {[lsearch -exact {a b c d e f g j l s S t v u} $part3] != -1 \
              && $restrict != ""} {
        append part3 ":$restrict"
      }

      # search for an appropriate delimiter
      set alltext $part1$part2$part3
      foreach del {/ @ \# % * - _ = + | &} {
        if {[string first $del $alltext] == -1} {
          break
        }
      }

      append completeList($command) " '$part1$del$part2$del$part3$del'"
    }
    foreach var [array names completeList] {
      print "complete $var $completeList($var)"
    }
#     foreach var [array names ambiguousList] {
#       print "-complete $var $ambiguousList($var)"
#     }
  }
}

