# groovy-main.tcl - mode for editing groovy code
# 
# Modif :
# diam (13/06/01) : rajout alias foreach (=forall) pour itérer sur une List
# diam (13/01/97) : modifs colorisation : super des deux type de
#                   commentaires /* .. */ et // 
# diam (05/12/96) : création
# 
######################################################################

global stead

proc groovyMain {} {
   
   global stead 
   global MODE EDITPREFS FILENAME
   global TE_MODE_SEARCH_STRING TE_MODE_NAVIG_SHOW_TEXT

   # On utilisera de plus en plus stead(mode) a la place de MODE.
   set stead(mode) $MODE 
   
   if [info exists FILENAME] {
       set stead(fileToCompile) $FILENAME
   } else {
       set stead(fileToCompile) ""
   }

   
   # Quelques préférences globales :
   set EDITPREFS(autobreak)     0
   set EDITPREFS(autoindent)    1          ;# Force l'auto indent
   
   # define the prefix for c mode
   set EDITPREFS(prefix) "// "
   set EDITPREFS(suffix) " //"
   
   
   # Définition du menu de navigation
   set TE_MODE_NAVIG_SHOW_TEXT "objects_methods"
   # set method "\n\[ \t\]*(public|abstract|class|static|private)\[^\n\]+"
   set method "\n\[ \t\]*(public|abstract|class|static|private)\[^\n\]+"
   set TE_MODE_SEARCH_STRING $method
   
   # cette variable contient une liste de fichiers à éditer dans ce mode
   if ![info exists stead(modeGROOVY,sampleFiles)] {
       set stead(modeGROOVY,sampleFiles) {
          /insert/here/you/favorite/list/of
          /groovy/modeles.groovy
       }
   }
   
   
   groovyDefineAlias
   groovyBuildMenus
   mode_groovy_defineStyles
   
} ;# endproc groovyMain


########################################################################
# procédure de définition des couleurs des couleurs
########################################################################
proc mode_groovy_defineStyles {} {
    global stead
    upvar #0 stead(text) w
    
    # "keylist1"  définit une patterne de reconnaissance des mots clé 
    # "important" (i.e. modif de structure et autre...)
    # 
    xtext_style $w define groovy keylist1 {
        -type wordListLight
        -config {-foreground red}
        -values {
            public protected private abstract static final
            main class interface package import 
            return break continue catch try throw throws
        }
    }
    
    # "keylist2"  définit une patterne de reconnaissance des mots clé 
    # "courants" du groovy :
    # 
    xtext_style $w define groovy keylist2 {
        -type wordListLight
        -config {-foreground blue}
        -values {
            Object extends implements synchronized 
            if else while do for switch 
            new this
            assert
        }
    }
    
    # "keylist3"  définit une patterne de reconnaissance des mots clé 
    # correspondant à des types ou classes couramment prédéfinis :
    # 
    xtext_style $w define groovy keylist3 {
        -type wordListLight
        -config {-foreground blue}
        -values {
            byte short int long real float double char boolean 
            Byte Short Integer Long Real Float Double Character Boolean 
            String SringBuffer List ArrayList LinkedList Thread Event
            void null true false
            Iterator
        }
    }
        
    # Traitement des guillemets
    # 
    xtext_style $w define groovy {
        quotes {
            -type regexpLight
            -config {-foreground #700}
            -pat {(".*?")}
        }
        singleQuotes {
            -type regexpLine
            -config {-foreground red -font bold}
            -pat {^(?:[^"]*)(")(?:[^"]*)$}
        }
    }


    # erreur légère (rose claire)
    # J'en ai mare des tabulations qu'on trouve dans le code source
    # et qui perturbe l'indentation
    set COLOR_TAB 1
    if {$COLOR_TAB} {
        xtext_style $w define $stead(mode) {
            tabulation {
                -type regexpLight
                -pat {\t}
                -config {
                    -background "#FDD"
                }
            }
        }
    }
    

    set stead(commentConfig) {-foreground #060}
    # set config  "-background green -foreground red"
    # Pour balance stead /*
    set stead(tagSpec,c_comment) [list  \
        -type    regexpPair             \
        -prePat  {/\*}                  \
        -postPat {\*/}                  \
        -config  $stead(commentConfig)   \
    ]
    xtext_style $w define groovy c_comment  $stead(tagSpec,c_comment)
    
    xtext_style $w define groovy cc_comment [list \
        -type regexpLight  \
        -pat {//.*$}       \
        -config $stead(commentConfig)
    ]
    
    xtext_style $w enable groovy
}



###########################################################################
# aide sur le mode groovy :
###########################################################################

proc groovy_GetHelp {} {
  set help {
    aide du mode GROOVY prototype :
    
    Les electric alias sont des raccourcis qu'on peut lancer en tapant 
    l'abbreviation suivie de <Meta-Space>
    La liste complète de ces abbréviation est définie dans le sous-menu 
    "alias" du menu Template.
    
    Quelques exemples d'alias prédéfinis :
      bb             Begin Bloc :{..} avec indentation
      for            boucle for
      while          boucle while
      do             boucle while ... do
      if             if
      ife            if ...else 
      switch         switch
    
    Le menu "Template" propose quelques macros prédéfinies. Vous pouvez
    en rajouter d'autres dans le fichier de mode utilisateur (voir menu
    "Help/xxx") 
    
    
    Le menu "objects_methods" permet d'accéder rapidement à une procédure 
    du fichier.
    
    raccourci clavier      résultat
    ^^^^^^^^^^^^^^^^^      ^^^^^^^^
    <meta-1>               insertion d'un séparateur "////..."
    <Control-c>            rafrechit les couleurs
    
  }
  return $help
}

########################################################################
# groovyDefineAlias --
# Aliases for groovy mode
# 
proc groovyDefineAlias {} {

  global stead MODE 
  
  # Pour simplifier l'écriture des electricAlias : on déclare
  # les variables M, B, E et V au niveau local pour 
  # 
  #      M :  Marque temporaire
  #      B :  début de postcommande 
  #      E :  fin de postcommande
  #      V :  Inclusion d'une variable TCL
  # 
  electricAlias-use8bitsCars  
    
  # Quelques petites abbrév courantes
  
  # bloc d'instruction
  electricAlias-def     groovy bb {\{\n[i][setStop]\n\}\n}

  electricAlias-def groovy pub  "public "
  electricAlias-def groovy p    "public "
  electricAlias-def groovy pri "private "
  electricAlias-def groovy m  "main "
  electricAlias-def groovy v  "void "
  electricAlias-def groovy p  "public "
  electricAlias-def groovy s  "static "
  electricAlias-def groovy psfv  "public static final void "
  electricAlias-def groovy psv  "public static void "
  electricAlias-def groovy psf  "public static final "
  electricAlias-def groovy pf  "public final "
  electricAlias-def groovy ps  "public static "
  electricAlias-def groovy pv  "public void "
  electricAlias-def groovy const  "public static final "
  
  electricAlias-def groovy S  "String "
  electricAlias-def groovy b  "boolean "
  electricAlias-def groovy B  "Boolean "
  
  
  electricAlias-def groovy sy "synchronized"
  
  electricAlias-def groovy pr "print([setStop]);\n[setStop]"
  electricAlias-def groovy pn "println([setStop]);\n[setStop]"

  set    tmp {import groovy.io.*;\n}
  append tmp {import groovy.util.*;\n}
  electricAlias-def ${M}groovy imp  $tmp

  # insertion de documentation (pour javadoc)
  set    tmp {/**\n}
  append tmp {   [setStop]\n}
  append tmp {*/}
  append tmp {[setStop]}
  electricAlias-def ${M}groovy doc $tmp
  electricAlias-def ${M}groovy d   $tmp
  
  # Déclaration de classe  TODO
  set    tmp {[askVar "class name" NAME]}
  append tmp {/**\n}
  append tmp {     La classe [getVar NAME] ...[setStop]\n}
  append tmp {   [setStop] \n}
  append tmp {*/ \n}
  append tmp {class [getVar NAME]  \{\n}
  append tmp {[i][setStop]\n}
  append tmp {\}\n}
  append tmp {[setStop]}
  electricAlias-def ${M}groovy class $tmp
  electricAlias-def ${M}groovy c $tmp
  
  
  
  # Classe  Main contenant une fonction main()
  # Il faudrait pouvoir réutiliser les abréviations "class" et "main"
  set    tmp {/** \n}
  append tmp {[i]Classe principale de l'application\n}
  append tmp {[i][setStop] \n}
  append tmp {*/ \n}
  append tmp {public final static class Main  \{\n}
  append tmp {[i]\n}
  append tmp {[i]public static void main(String\[\] args) \{\n}
  append tmp {[i]\n}
  append tmp {[i][i][setStop]\n}
  append tmp {[i]\}\n}
  append tmp {\}\n}
  append tmp {[setStop]}
  electricAlias-def ${M}groovy Main $tmp
  
  # fonction  main
  set    tmp {public static void main(String\[\] args) \{\n[i][setStop]\n\} }
  append tmp { // main\n[setStop]}
  electricAlias-def ${M}groovy main $tmp
  
  # fonction  top
  set    tmp {def top(argl) \{\n[i][setStop]\n\} }
  append tmp { // top\n[setStop]}
  electricAlias-def ${M}groovy top $tmp
  
  # fonction  def
  set    tmp {def [setStop] \{\n[i][setStop]\n\} }
  append tmp { // top\n[setStop]}
  electricAlias-def ${M}groovy def $tmp
  
  # structure switch
  set    tmp {switch ([setStop]) \{\n}
  append tmp {[i]case : [setStop]\n}
  append tmp {[i]case : [setStop]\n}
  append tmp {[i]       break;\n}
  append tmp {[i]default : [setStop]\n\} }
  append tmp {\n[setStop]}
  electricAlias-def ${M}groovy switch $tmp
  electricAlias-def ${M}groovy swi    $tmp
  
  
  # structure if
  set    tmp {if ([setStop]) \{\n[i][setStop]\n\}}
  append tmp {\n[setStop]}
  electricAlias-def ${M}groovy if $tmp
  
  # structure if avec else
  set    tmp {if ([setStop]) \{\n[i][setStop]\n\}}
  append tmp { else \{\n}
  append tmp {[i][setStop]\n}
  append tmp {\}\n[setStop]}
  electricAlias-def ${M}groovy ife $tmp
  
  
  # boucle while
  set    tmp {while ([setStop]) \{\n[i][setStop]\n\} }
  append tmp {\n[setStop]}
  electricAlias-def ${M}groovy while $tmp
  electricAlias-def ${M}groovy w     $tmp
  
  # boucle do
  set    tmp {do \{\n[i][setStop]\n}
  append tmp {\} while ([setStop]);\n}
  append tmp {\n[setStop]}
  electricAlias-def ${M}groovy do $tmp
  
  # boucle for
  # set    tmp {for ([setStop];[setStop];[setStop]) \{\n}
  set    tmp {for ([setStop]) \{\n}
  append tmp {[i][setStop]\n}
  append tmp {\}\n[setStop]}
  electricAlias-def ${M}groovy for $tmp
  
  # alias foreach = fe
  # Iteration sur une collection par un Iterator
  # 
  set    tmp {[askVar "iterator name" IT_NAME]}
  append tmp {[askVar "local variable name" VAR_NAME]}
  append tmp {[askVar "collection name" LIST_NAME]}
  append tmp {\n}
  append tmp {// foreach ([getVar VAR_NAME], [getVar LIST_NAME]) \{...\}\n}
  append tmp {Iterator [getVar IT_NAME] = [getVar LIST_NAME].iterator();\n}
  append tmp {while ( [getVar IT_NAME].hasNext() ) \{\n}
  append tmp {[i][getVar VAR_NAME] = ([setStop VARTYPE])[getVar IT_NAME].next(); \n}
  append tmp {[i]\n}
  append tmp {[i][setStop]\n}
  append tmp {[i]\n}
  append tmp {\}\n}
  append tmp {\n}
  append tmp {[setStop]}
  electricAlias-def ${M}groovy fe      $tmp
  electricAlias-def ${M}groovy foreach $tmp
  
  # alias forall = fa
  # Iteration sur une ArrayList par boucle for
  # 
  set    tmp {[askVar "local variable name" VAR_NAME]}
  append tmp {[askVar "ArrayList name" LIST_NAME]}
  append tmp {\n}
  append tmp {// foreach ([getVar VAR_NAME], [getVar LIST_NAME]) \{...\}\n}
  append tmp {for(int i = 0; i < [getVar LIST_NAME].size(); i++) \{\n}
  append tmp {[i][getVar VAR_NAME] = ([setStop VARTYPE])[getVar LIST_NAME].get(i); \n}
  append tmp {[i][setStop]\n}
  append tmp {\}\n}
  append tmp {\n}
  append tmp {[setStop]}
  electricAlias-def ${M}groovy fa      $tmp
  electricAlias-def ${M}groovy forall  $tmp
  
  

} ;# endproc groovyDefineAlias



##################################################################
# definit le libelle des elements de navigation pour le mode groovy
##################################################################

proc te:mode:navig_sort_hook {l} {
  return [lsort -command te:mode:sort_command $l]
}
 
#################################################################
# te:tcl:cmd:search_node - recherche la procedure selectionnee   
#################################################################

proc te:tcl:cmd:search_node {{w .main.t}} {

  set sel [xtext_getSel $w]
  if {"x$sel" == "x"} {
    stead:log -title "Tcl" -text "Please select procedure name"
  } else {
    te:tcl:cmd:go_to_node $sel $w
  }
}

#######################################################################
# te:tcl:cmd:go_to_node - selectionne la procedure $p dans le texte $t

proc te:tcl:cmd:go_to_node {p {t .main.t}} {

  global  auto_index
  set methodPat "\n\[ \t\]*(public|class|final|protected|private)$p\[ \t\]\[^\n\]*"

  stead:log -text "Searching procedure $p" -title "Tcl"
  set text [$t get 1.0 end]
  if {[regexp -indices "$methodPat" $text n]} {
    stead:log -text "procedure $p found." -title "Tcl"
    $t mark set insert "1.0 + [lindex $n 1] chars"
    catch {$t tag remove sel sel.first sel.last}    
    $t tag add sel "1.0 + [lindex $n 1] chars linestart" \
    "1.0 + [lindex $n 1] chars lineend"
    $t yview -pickplace insert
    xtext_updateFocusIn $t
    # A FAIRE :
    # xtext_applyShortHighlight $t \
    #                           "1.0 + [lindex $n 1] chars" \
    #                           "1.0 + [lindex $n 1] chars lineend"

  } else {
    stead:log -text "procedure $p not found" -title "Tcl"
    set file {}
    catch {set file [lindex $auto_index($p) 1]}
    if {"x$file" != "x"} {
      stead:log "Opening file $file"
      exec $stead(exe) $file -command "te:tcl:cmd:go_to_node $p" &
    }
  }
}
# blink
 
######################################################################
# define the groovy menu:
proc groovyBuildMenus {} {
global stead MODE 

  te:mode:make_menu $MODE
  
  .menu.$MODE.m add command -label {make} \
        -command {te:cmd:make_file}
        
  .menu.$MODE.m add separator
  .menu.$MODE.m add command -label {g++ File} \
        -command {te:cmd:gcc_file}
  .menu.$MODE.m add command -label {g++ -g File} \
        -command {te:cmd:gcc_debug_file}
  .menu.$MODE.m add command -label {execute File} \
        -command {te:cmd:exe_file}
  .menu.$MODE.m add command -label {debug File} \
        -command {te:cmd:debug_file}
        
  .menu.$MODE.m add separator
  .menu.$MODE.m add command -label {File to Process. . .} \
        -command {te:cmd:change_c_file}
       


  .menu.$MODE.m add command -label {search selected method} \
     -command {te:tcl:cmd:search_node }
     
  .menu.$MODE.m add separator
  .menu.$MODE.m add command -label {Refresh Colors} \
     -command {refresh_colors} \
     -accelerator {<Control-c>}
  .menu.$MODE.m add command -label {Cancel Colors} \
     -command {cancel_colors}
     
  .menu.$MODE.m add separator
  .menu.$MODE.m add command -label "Aide du mode $MODE"  \
     -command {stead -r 1  -text [groovy_GetHelp] }  
  .menu.$MODE.m add cascade -label {Files sample}  \
     -menu ".menu.$MODE.m.files"
     
  menu .menu.$MODE.m.files
  foreach {file} $stead(modeGROOVY,sampleFiles) {
     .menu.$MODE.m.files add command -label $file \
        -command "exec $stead(exe) $file &"
  } ;# endforeach
  
    
  
  ###########################################################################
  # Création et remplissage de menu template
  ###########################################################################
  
  te:mode:make_menu {templates}
  
  .menu.templates.m add command -label "Insérer un separateur" \
                        -command {separator 1}
  
  .menu.templates.m add command -label {main...} \
                                -command {electricAlias-wrap main}
  
  .menu.templates.m add separator
  
  .menu.templates.m add command -label {Boucle for} \
                                -command {electricAlias-wrap for}
  .menu.templates.m add command -label {Boucle while} \
                                -command {electricAlias-wrap while}
  .menu.templates.m add command -label {Boucle "do...while"} \
                                -command {electricAlias-wrap do}
  .menu.templates.m add command -label {Structure switch} \
                                -command {electricAlias-wrap switch}
                                
  .menu.templates.m add command -label {Structure if} \
                                -command {electricAlias-wrap if}
  .menu.templates.m add command -label {Structure if...else} \
                                -command {electricAlias-wrap ife}
    
  
  .menu.templates.m add separator
  .menu.templates.m add cascade -label Alias -menu .menu.templates.m.alias
  menu .menu.templates.m.alias
  
  foreach alias [electricAlias-softNames] {
     .menu.templates.m.alias add command \
         -label $alias \
         -command "electricAlias-insert $stead(text) [te:no_interp $alias]"
  }

} ;# endproc groovyBuildMenus

###########################################################################
# proc separator {number_of_lines textwidget}
# retourne une chaine correspondant au separateur souhaité 
# 
proc separator {{NbLines 1} } {
   
   insert_fill_lines "/" $NbLines 

} ;# endproc separator


########################################################################
########################################################################
# Autre procédure utiles (a deplacer plus tard)


###########################################################################
# te:cmd:change_groovy_file - change le fichier a compiler
#
proc te:cmd:change_groovy_file {} {

  global stead
  
   set prompt_result [te:prompt -text "Enter Main File" \
   -default $stead(fileToCompile) -title "groovy file to compil"]
   
   if { [file isfile $prompt_result] } {
     set stead(fileToCompile) $prompt_result
   } else {
     stead:log -text "invalid File Name" -title "groovy"
   }
}

######################################################################
# te:cmd:gcc_file - gcc file
######################################################################

proc te:cmd:gcc_file {} {
  global stead
  
  if {("x$stead(fileToCompile)" == "x") || [xtext_isDirty .main.t]} {
  
    stead:log -text "please save file first" -title "g++"
    
  } else {

    exec xterm -e g++ -o \
       [file rootname $stead(fileToCompile)].out $stead(fileToCompile) 
  }
}

######################################################################
# te:cmd:make_file - make file
######################################################################

proc te:cmd:make_file {} {
  global stead
  if {("x$stead(fileToCompile)" == "x") || [xtext_isDirty .main.t]} {
    stead:log -text "please save file first" -title "g++"
  } else {

    exec xterm -e make& 
  }
}

######################################################################
# te:cmd:gcc_debug_file - gcc file with symbolic info for debugg
######################################################################

proc te:cmd:gcc_debug_file {} {
  global stead
  if {("x$stead(fileToCompile)" == "x") || [xtext_isDirty .main.t]} {
    stead:log -text "please save file first" -title "g++ -g"
  } else {

    exec xterm -e g++ -g -o \
      [file rootname $stead(fileToCompile)].out $stead(fileToCompile) 
  }
}

######################################################################
# te:cmd:debug_file - debug the executable file with xxgdb
######################################################################

proc te:cmd:debug_file {} {
  global stead
  if {("x$stead(fileToCompile)" == "x") || [xtext_isDirty .main.t]} {
    stead:log -text "please save file first" -title "g++"
  } else {
    if [file exists [file rootname $stead(fileToCompile)].out] {
      exec xxgdb [file rootname $stead(fileToCompile)].out &
      stead:log -text "Running Command" \
               -title "xxgdb [file tail [file rootname $stead(fileToCompile)]]"
    } else {
      stead:log -text "No out File" \
               -title "xxgdb [file tail [file rootname $stead(fileToCompile)]]" 
    }
  }
}
######################################################################
# te:cmd:exe_file -  executes the output file 
######################################################################

proc te:cmd:exe_file {} {
  global stead 
  if {("x$stead(fileToCompile)" == "x") || [xtext_isDirty .main.t]} {
    stead:log -text "please save file first" -title "g++"
  } else {
    if [file exists [file rootname $stead(fileToCompile)].out] {
      exec xterm -e [file rootname $stead(fileToCompile)].out &
    } else {
      stead:log -text "No out File" \
               -title "xxgdb [file tail [file rootname $stead(fileToCompile)]]" 
    }
  }
}



######################################################################
# cleanup for groovy mode
######################################################################

proc stead:modeCleanup {} {
    global stead
    upvar 0 stead(text) w
    te:mode:destroy_menu $stead(mode)
    te:mode:destroy_menu templates
    xtext_style $w delete $stead(mode)    
}

groovyMain
