package provide stead 2.0


#f fichier electricAlias.tcl : gstion des abbréviation statiques
# 
########################################################################
# Comment utiliser les electricalias
########################################################################
# 
# Voici les procédure utiles à l'intérieur d'une spécification d'alias
# 
# defAlias 
#   (option  -sol si declenchable seulement en début de ligne)
#   crée la définition de l'alias. Cette définition pourra
#   faire appel au commandes suivante
#   
# askVar <string> <varName>: 
#   demande et mémorise par exemple le nom d'une chaine de caractere
#   en vue de son utilisation dans l'alias expansé
#   
# getVar <varName> : 
#   retourne la valeur de la "variable" créée sous ce nom
#   
# setStop : 
#   crée un marque de stop dans l'alias (pour passer d'un champs à l'autre 
#   apres l'expansion de l'alias)
#   
# i :
#   Extrait la chaine d'indentation actuelle de l'utilisateur
# 
# Exemple de définition d'un alias avec dialogue (extrait du mode TCL)
# ----------------------------------------------
# 
#     set    tmp {[askVar "procedure name" NAME]}
#     append tmp {## [getVar NAME] -- [setStop]\n}
#     append tmp {# \n}
#     append tmp {# arguments:\n}
#     append tmp {# \n}
#     append tmp {#   - \n}
#     append tmp {# \n}
#     append tmp {# results:\n}
#     append tmp {# \n}
#     append tmp {# \n}
#     append tmp {# \n}
#     append tmp {# examples\n}
#     append tmp {# \n}
#     append tmp {# \n}
#     append tmp {# \n}
#     append tmp {proc [getVar NAME] { [setStop] } \{\n}
#     append tmp {[i][setStop]\n}
#     append tmp {\}\n}
#     append tmp {[setStop]}
#     defAlias -sol  tcl proc2 $tmp
# 
# Exemple de définition d'un alias simple
#     defAlias -sol gvt if      {if ([setStop]) then\n[i]endif [setStop]}
# 
########################################################################
# Historique 
# 
# 18/08/00 diam : refonte (pas fini !
# 24/11/02 diam : ajout proc defAlias
# 
# A faire :
# 
# - renommer electricAlias en sabbrev ou salias (voir sab ou sal)
# - conserver la compatibité par création d' "alias au sens tcl"
# - maintenir doc utilisateur
# - créer une procédure à inserer dans les alias, ou bien une option
#   à passer à electricAlias-def pour que l'alias soit expensé en début 
#   de ligne.
#   Puis virer le ${M} au début du nom de l'alias.
# 
# 
# Conventions (provisoire et souple :-) pour les noms de procedure :
# 
# - un tiret dans le nom => procédure exportée (ou plutot
#   déja utilisée à l'extérieure => ne pas changer son nom à la légère)
# - pas de tiret dans le nom => utilisation interne à ce fichier
# 
########################################################################
# 
# Ce fichier est conçu à partir du travail initial de David C. Black
# 
#    Copyright © 1992,1993 by David C. Black
#    Internet: black@mpd.tandem.com (preferred)
#
########################################################################


## electricAlias-init -- initialise quelques globales
# 
# Doit être appelée avant toutes autre procédure des electricAlias.
# 
# 17/08/00 (diam) : création
# 
# A FAIRE : accepter un parametre $w et créer un tableau global
# par document
# 
# proc electricAlias-init {w} {
#     uplevel #0 electricAlias-$w alias
#     ...
# }
proc electricAlias-init {} {
    global ALIAS

    # Define global array for state/alias data
    if {![info exists ALIAS(active)]} {
            if {[info exists ALIAS]} {
                    # Its scalar and we need an array
                    unset ALIAS
            }
            set ALIAS(active) 1
            set ALIAS(mode)   "tcl"
            set ALIAS(modes)  [list tcl]
    }

    # Initialisation des quatre caractères 8 bits spéciaux aux alias
    # 
    # initialisent les 4 caracteres spéciaux 8 bits utilisée
    # pour créer des alias statiques
    # 
    # modif :
    #   diam  02/12/99 : création
    #   diam  21/08/00 : utlisation du tableau ALIAS au lieu de globale
    #                    séparée et cleanup (dans tous les modes)
    # 
    # ATTENTION : NE PAS CHANGER LA VALEUR DE CES CARACTERES 8 BITS
    #             CAR ELLES SONT EN DUR DANS CE FICHIER ET DANS LA PLUS 
    #             PART DES MODES !
    # 
    # variable d'insertion d'une marque temporaire et d'indication
    # d'extension de l'alias en debut de ligne uniquement
    set ALIAS(8bit_mark) [format %c 165]  ;# caractere : "¥"
    
    # début de postcommande Tcl dans l'alias
    set ALIAS(8bit_begin) [format %c 164][format %c 199] ;# cars : "¤Ç"
    
    # fin de postcommande Tcl dans l'alias
    set ALIAS(8bit_end) [format %c 200]  ;# car : "È"
    
    # Inclusion d'une variable TCL dans l'alias
    set ALIAS(8bit_var) [format %c 164]  ;# caractere : "¤"
    
}

## electricAlias-use8bitsCars -- déclare les globales contenant les 4 
##                               caracteres spéciaux
# 
# 
# 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
# 
proc electricAlias-use8bitsCars {} {
    uplevel 1 {        
        upvar #0  ALIAS(8bit_mark)   M ;# Marque temporaire
        upvar #0  ALIAS(8bit_begin)  B ;# début de postcommande 
        upvar #0  ALIAS(8bit_end)    E ;# fin de postcommande
        upvar #0  ALIAS(8bit_var)    V ;# Inclusion d'une variable TCL
    }
}

## electricAlias -- for compatibility with old version
# 
# Ne semble pas utilisé, mais à conserver !
# 
proc electricAlias {cmd args} {
    switch -exact [llength $args] {
        0 {electricAlias-$cmd}
        1 {electricAlias-$cmd [lindex $args 0]}
        2 {electricAlias-$cmd [lindex $args 0] [lindex $args 1]}
        3 {electricAlias-$cmd [lindex $args 0] [lindex $args 1] [lindex $args 2]}
    } ;# endswitch
    
   electricAlias-$cmd $args
}

## electricAliasOn -- turns on (enables) electricAlias-expand
# 
# non utilisé 
# A conserver pour usage interne éventuel (non utilisé)
# 
# 
proc electricAliasOn {} {
    global ALIAS
    set ALIAS(active) 1
}

## electricAliasOff -- turns off (disables) electricAlias-expand
# 
# non utilisé 
# A conserver pour usage interne éventuel (non utilisé)
# 
# 
proc electricAliasOff {} {
    global ALIAS
    set ALIAS(active) 0
}


## electricAlias-def       -- creates an electricAlias definition
# 
#  electricAlias-def MODE NAME ?DEFINITION?
# 
#      Defines or displays an alias template.  If DEFINITION
#      is omitted and the alias exists, then the current
#      definition is returned per TCL 'return'.
#      
#      Aliases may have embedded variables, TCL commands, stops,
#      line-ends and deletes as described under TEMPLATES below.
# 
#      If MODE begins with a bullet ($M), then the alias is only effective
#      when used as the first token on a line.
# 
# A FAIRE : 
# gérer une option -startline ou -sol pour indiquer qu'on veux ne 
# declancher cet alias qu'en début de ligne (une proc par exemple)
# Acuellement, l'utilisateur de cette proc doir indiquer cette info
# par un car 8bit_mark devant le mode !
# 
proc electricAlias-def {aliasmode name {def ""} } {
    global ALIAS
    set aliasmode [string tolower $aliasmode]
    
    if {[regexp {,} $aliasmode]} {
        error "Alias modes may not include commas"
    }
    
    if {[string length $def]} {
        regsub -all "\r" $ "\n" defdef
        
        # diam 21/08/00 => 
        # envisager à terme (suivant definition (i.e. cmd) ou var) :
        #    set ALIAS(defcmd,$aliasmode,$name) $def
        #    set ALIAS(defvar,$aliasmode,$name) $def
        # 
        set ALIAS($aliasmode,$name) $def
        
        if {[lsearch $ALIAS(modes) $aliasmode] < 0} {
                lappend ALIAS(modes) $aliasmode
        }
    } else {
        return [electricAliasDump $aliasmode $name]
    }
} ;#endproc electricAlias-def



## electricAlias-var  -- creates an electricAlias variable
# 
#   Defines an alias variable for use in templates.  If the pattern
#   [set V](NAME) (i.e. ¤{NAME}) is found during template insertion, it 
#   is replaced with the DEFINITION.  
#   This allows a single template to have multiple uses.
#   
#   If the DEFINITION is omitted, then the current definition
#   is returned.
# 
# A FAIRE : à renomme en electricAlias-defVar ?
# 
# Usage: electricAlias-var MODE NAME ?DEFINITION?
# 
#      Extrait de l'utilisation de electricAlias-var :
#         modes/c-mode.tcl:electricAlias-var C bb "\{"
#         modes/c-mode.tcl:electricAlias-var C eb "\}"
#         modes/c-mode.tcl:electricAlias-var C bc "/*"
#         modes/c-mode.tcl:electricAlias-var C ec "*/"
#         modes/csh-mode.tcl:electricAlias-var csh bc "#"
#         modes/csh-mode.tcl:electricAlias-var csh ec ""
#         modes/make-mode.tcl:   electricAlias-var $stead(mode) bb "\{" ;# Begin Bloc
#         modes/make-mode.tcl:   electricAlias-var $stead(mode) eb "\}" ;# End Bloc
#         modes/pascal-mode.tcl:electricAlias-var pascal bb "begin"
#         modes/pascal-mode.tcl:electricAlias-var pascal eb "end"
#         modes/pascal-mode.tcl:electricAlias-var pascal bc "\{"
#         modes/pascal-mode.tcl:electricAlias-var pascal ec "\}"
#         modes/tcl-mode.tcl:electricAlias-var tcl bb "\{"
#         modes/tcl-mode.tcl:electricAlias-var tcl eb "\}"
#         modes/tcl-mode.tcl:electricAlias-var 	tcl bc "# "
#         modes/tcl-mode.tcl:electricAlias-var tcl ec ""
#         modes/tcl-mode.tcl:electricAlias-var tcl sep $t1
# 
proc electricAlias-var {aliasmode name {defn ""} } {
    global ALIAS
    set aliasmode [string tolower $aliasmode]

    if {[regexp {,} $aliasmode]} {
        error "Alias modes may not include commas"
    }
    
    if {[string length $defn]} {
        regsub -all "\r" $defn "\n" defn
        
        # diam 21/08/00 => 
        # envisager à terme (suivant definition (i.e. cmd) ou var) :
        #    set ALIAS(defcmd,$aliasmode,$name) $defn
        #    set ALIAS(defvar,$aliasmode,$name) $defn
        # 
        # set ALIAS($aliasmode,¤\{$name\}) $defn
        set "ALIAS($aliasmode,$ALIAS(8bit_var){$name})" $defn

        if {[lsearch $ALIAS(modes) $aliasmode] < 0} {
                lappend ALIAS(modes) $aliasmode
        }
    } else {
        return [electricAliasDump $aliasmode $name]
    }
}


## electricAliasExists  -- Returns 1 if alias NAME exists; otherwise 0
# 
# Usage: electricAliasExists MODE NAME
# 
# non utilisé en externe ni en interne 
# mais à conserver pour l'instant
# 
proc electricAliasExists {aliasMode name} {
    global ALIAS
    set aliasMode [string tolower $aliasMode]
    
    # envisager de la structure interne mémorisant les alias de commande
    # et les alias de variables 
    # 
    #  [info exists ALIAS(defcmd,$aliasMode,$name)]
    #  [info exists ALIAS(defvar,$aliasMode,$name)]
    # 
    # Mais attention car les noms de variable d'alias sont 
    # actuellement de la forme $V{bb} dans  ALIAS(tcl,$V{bb})
    # 
    return [info exists ALIAS($aliasMode,$name)]
}


## electricAliasModes -- return the list of all "alias modes"
# 
# 
# Pas encore utilisée (mais le sera si on acceptre la notions de 
# "jeu" ou ensemble d'alias (je n'aime pas le terme mode qui est utilisé à 
# cause de l'ambigüité avec le mode de stead
# 
proc electricAliasModes {} {
    global ALIAS
    return $ALIAS(modes)
}


########################################################################
########################################################################
########################################################################
########################################################################

## electricAlias-hardNames    -- returns a list of some electricAliases 
# 
# Usage: electricAlias-hardNames ?MODE?"
# 
# argument
#   mode : sélectionne les noms (hard) des alias concernant ce mode
#          en cas d'abscence de mode, retourne tous les hardName
#          
# 
# Les hardNames sont des noms de la forme "latex,item" ou encore 
# "tcl,${M}proc" ou "tcl,${V}{proc}" avec généralement des 
# caracteres spéciaux dedans, alors que les softNames sont des noms de la 
# forme "item"  ou "proc
# 

# Tout cela sera profondément transformé quand la structure
# interne du tableau ALIAS sera refondu.
# En attendant, je préfére cette organisation pour cette procédure
# 
# - non utilisé à l'extérieure de ce fichier
# 
# bug (?) En fait le parametre MODE ne sert pas à grand chose car il
# XXXXXXXXXXXX je corrige
# 
proc electricAlias-hardNames { {mode "" }} {
    global ALIAS
        
    set mode [string tolower $mode]
    if {[regexp {,} $mode]} {
        error "Alias modes may not include commas"
    }

    # La liste des indices sélectionnés du tableau dont on extraira
    # les sous-chaines formant les noms recherchés
    set arrayIndexes [list]
    # 
    # on elimine les index du style ALIAS(modes) ou ALIAS(8bit_mark)
    # # # # foreach arrayIndex [array names ALIAS] { xxx }
    foreach arrayIndex [array names ALIAS *,*] {
    
        set idx [string first "," $arrayIndex]
        set theMode [string range $arrayIndex 0 [expr $idx-1] ]
        set theName [string range $arrayIndex [expr $idx+1] end]
        # # puts "arrayIndex=$arrayIndex idx=$idx theMode=$theMode theName=$theName"

        # On ne traite un alias que si :
        #  - mode n'est pas précisé, donc on garde tous les modes
        #  - l'alias est une commande d'alias normal : "tcl" 
        #  - c'est une cmde d'alias de début de ligne "${M}tcl"
        # 
        if {   [string equal $mode  ""] \
                || [string equal $theMode  $mode ] \
                || [string equal $theMode \
                        "[set ALIAS(8bit_mark)]$mode" ]  } {
            lappend arrayIndexes $arrayIndex
        }
        
        
        
    }

    return [lsort $arrayIndexes]

} ;#endproc electricAlias-hardNames


## electricAlias-softNames -- renvoie la liste des alias connus (sans les variables)
# 
# les softNames sont des noms de la forme "item" par opposition aux hardNames
# qui sont de la forme "latex,item" avec généralement des caractere spéciaux 
# en plus.
# De plus, les softName ne contiennent pas les "variable" dont le hardName 
# est de la forme tcl,${V}{proc}" 
# 
# 
# diam 21/08/00 : création (à partir de l'ancienne te:liste_alias)
# 
proc electricAlias-softNames { {mode "" } } {
  
     global ALIAS
     # # # electricAlias-use8bitsCars
   
     # Pourquoi faire ? pour ne pas mémoriser les alias de type vr on
     # devant débuter une ligne 
     # 
     # # # set pat "\[$V$M\]"
     set pat "\[$ALIAS(8bit_var)$ALIAS(8bit_mark)\]"
     
     set softNames [list]
     
     foreach hardName [electricAlias-hardNames $mode] {
          set softName [lindex [split $hardName ,] 1]
          if {![regexp $pat $softName]} {
               lappend softNames $softName
          }
     }
     return [lsort $softNames]
}

## electricAliasDump -- returns a "ready to eval" alias definition
# 
# exemple  la commande  : 
#       electricAliasDump tcl = 
# retourne : 
#       electricAlias-def "tcl"    "="        {==}
# 
# Mais attention les parametres aliasMode et name contiennent généralement 
# les caracteres 8bits spéciaux !
# 
# non utilisé en externe
# 
proc electricAliasDump {aliasMode name} {
    global ALIAS
    if {![info exists ALIAS($aliasMode,$name)]} {
        # on passe souvent par ici  (avec aliasMode=tcl name=ec) ! 
        stead:log "electricAliasDump: ?$aliasMode $name?"
        return ""
    }

    # On traite différement les alias de type variable ( ${V}{bb} )
    # et de type def ( proc ou ${M}proc )
    # 
    # aliasType vaut "def" ou "var" 
    set aliasType "var" 
    # 
    set pat "^$ALIAS(8bit_var)"
    append pat {{.*}$}
    # 
    if { [regexp $pat $name]} {
        set aliasType "var"
    } else {
      set aliasType "def"
    }

    set theDef "$ALIAS($aliasMode,$name)"
    
    
    # Ceci sera à vérifier, puis simplifier !
    
    # Attention : ceci ne PEUT PAS fonctionner car on  veux rempler
    # l'unique caractere "\n" pas deux caracteres "\" et "n" qui n'ont aucun
    # rapport !
    # regsub -all {(\r\n\t\b\$\{\})}  $theDef {\\\1}  theDef
    # 
    regsub -all {\r} "$theDef" "\\r"   theDef
    regsub -all {\n} "$theDef" "\\n"   theDef
    regsub -all {\t} "$theDef" "\\t"   theDef
    regsub -all {\b} "$theDef" "\\b"   theDef
    regsub -all {\$} "$theDef" "\\\$"  theDef
    regsub -all {\{} "$theDef" "\\\{"  theDef
    regsub -all {\}} "$theDef" "\\\}"  theDef
    
    # utilité de ce qui suit : 
    # au cas ou l'utilisateur souhaite déclancher un alias à partie
    # d'un caractere spécial  !
    # De plus les names peuvent etre de la forme "$V{bb}" (i.e beginbloc)
    regsub -all {\$} "$name"   "\\\$"  name
    regsub -all {\{} "$name"   "\\\{"  name
    regsub -all {\}} "$name"   "\\\}"  name
    regsub -all {\[} "$name"   "\\\["  name
    regsub -all {\]} "$name"   "\\\]"  name
    
    set name "\"$name\""


    set fmt "electricAlias-%s %-8s %-10s \{%s\}"
    return [format $fmt $aliasType "\"$aliasMode\"" $name $theDef]

} ;#endproc electricAliasDump

## electricAlias-dumpAll -- affiche des alias à partir d'une patterne
# 
# regexp : une pattern que doit satisfaire (partiellement) chaque dump 
#          complet
# 
proc electricAlias-dumpAll { {regexp {.*}} } {
    
    set dumpList [list]
    foreach hardName [electricAlias-hardNames] {
        set idx [string first "," $hardName]
        set theMode [string range $hardName 0 [expr $idx-1] ]
        set theName [string range $hardName [expr $idx+1] end]
        # puts "hardName=$hardName idx=$idx theMode=$theMode theName=$theName"
        set theDump [electricAliasDump $theMode $theName]
        
        if { ! [regexp -- $regexp $theName]}  { 
            continue 
        }
        
        lappend dumpList $theDump
    }
    return [join [lsort $dumpList] \n]
}


## electricAlias-setMode -- set/list current electricAlias mode
# 
# Usage: electricAlias-setMode ?NAME?
# 
#   Sets the current alias mode.  This is used to determine
#   which alias to use in a given situation.  Leading bullet ($M),
#   if any, is removed.  This forces use of the MODE field when
#   defining aliases that must occur as the first token of a line.
#   
#   If the NAME is missing, then the current mode is returned.
# 
proc electricAlias-setMode { {theMode ""} } {
    global ALIAS

    if {![string length $theMode]} {
        return $ALIAS(mode)
    }
    set theMode [string tolower $theMode]
    if {[regexp {,} $theMode]} {
        error "Alias modes may not include commas"
    }
    set ALIAS(active) 1

    # transformation éventuelle de "${M}tcl" en "tcl"
    regsub "^$ALIAS(8bit_mark)"  $theMode  "" theMode
    set ALIAS(mode) "$theMode"

    if {[lsearch $ALIAS(modes) $theMode] < 0} {
            lappend ALIAS(modes) $theMode
    }
}

## electricAlias-removeall -- removes all electricAlias definitions
# 
# 
# Usage: electricAlias-removeall ?MODE?
# 
#   Removes all alias definitions and variables
#   Specifying a MODE will restrict the returned list to
#   that mode.
# 
# utilisé dans stead/main.tcl
# 
proc electricAlias-removeAll { {theMode ""} } {
    global ALIAS


    set theMode [string tolower [lindex $theMode 0]]
    if {[regexp {,} $theMode]} {
        error "Alias modes may not include commas"
    }
    
    foreach hardName [electricAlias-hardNames $theMode] {
        unset ALIAS($hardName)
    }
} ;#endproc electricAlias-removeall


## electricAlias-undefine  -- removes an electricAlias definition
# 
# 
# 
# utilisé dans modes/latex-mode.tcl !
# 
proc electricAlias-undefine {aliasmode name} {
    global ALIAS
    set aliasmode [string tolower $aliasmode]
    if {[regexp {,} $aliasmode]} {
        error "Alias modes may not include commas"
    }
    if {[info exists ALIAS($aliasmode,$name)] == 0} {
        error "electricAlias does not exist!"
    }
    unset ALIAS($aliasmode,$name)
}


## electricAlias-expand  -- on-the-fly template insertion of alias
# 
# (the real guts of this thing)
# 
#   Invokes alias template insertion.  Text is scanned from
#   the current cursor position to the beginning of the line.
#   If the non-whitespace text immediately adjacent has an
#   alias entry, then template insertion proceeds.
# 
# utilisé dans : electricAlias.tcl build.tcl xtext.tcl
# 
# argument :
# 
# W : le widget text
# bindkey : le caractere déclencheur de cette procedure (<Space>)
#     ce caractere doit etre insérer si l'abbreviation n'existait pas
# checkPoint : 1 si on doit ou non effectuer un checkPoint intermédiaire
#     entre l'insertion de l'espace et l'insertion de l'alias 
#     (pour pouvoir faire un undo intermédire)
#     Remarque : ce checkpoint n'est pas effectué si cette procédure est  
#     declenché par une menu (il insère alors artificiellement l'alias  
#     puis appelle cette procédure.
# 
# autres arguments (à documenter : car PAS CLEAN !!! et PAS CLAIR !!!)
#   - si plus d'autres arguments : cette proc doit extaire l'alias du texte
#   - argument supplémentaire peut-etre un des caracteres spéciaux 
#   - exemple d'appel :
#        - depuis  electricAlias-insert
#                       electricAlias-expand .main.t " " 0
#        - dans le menu principal ("Config/Abbreviation")
#                       electricAlias-expand .main.t " " 1
#        - depuis xtext.tcl (binding)
#                       electricAlias-expand %W      " " 1
# 
# REMARQUE de diam (19/08/00) :
# 
# Cette procédure fait beaucoup (trop) de choses différentes :
# 
# - détection du dernier mots entre le début de la ligne courante et l'insert
#   (et mémorisation de l'info "premier_mot_de_la_ligne)
# - détection si ce mot est un alias connu (aliasMode courant ou aliasMode 
#   global)
# - lecture de la définition de l'alias (contenant les caractere spéciaux 
#   8 bits propre à ce système d'electricAlias)
# - subtitution de la définition de l'alias par la chaine à insérer
#     - exploitation des caracteres spéciaux
#     - exploitation de l'indentation courant
# - checkPoint éventuelle (option checkpoint de cette procédure) pour mémoriser
#   le contexte alors que l'utilisation vient de taper un nom d'alias
# - suppression du nom d'alias  
# - insertion à cette place du résultat de l'expansion de cet alias
# - création de mark de Stop pour que l'utilsateur puisse sauter d'une marque 
#   à l'autre
# - checkPoint pour mémoriser cette position pour un future undo éventuel
# 
# 
# A FAIRE : 
# - casser cette procédure en plusieurs (et démeleer les spaggetis !)
#   par exemple : 
#       - electricAlias-extract
#       - electricAlias-expand
#       - electricAlias-expand (ou electricAlias-expand ?)
# - remplacer le systeme à base de caracter spéciaux permettant 
#   une substition de commande d'alais et de variable d'alias par les caractere
#   standard TCL ( soit $, [ et ] ) et utiliser subst 
#   Mais ATTENTION : la sémantique sera forcément différente car la substitution 
#   ne sera plus récursive !
#  
#   => **Essayer de garder la compatibilité** si possible (par l'interrmédiair 
#   de procédures spéciales placées dans une fichier du style "compat_staed36.tcl"
# 
# - eclater cette procédure et le fusionner avec la procédure "electricAlias-insert"
# - rien d'autre
# 
# 
proc electricAlias-expand {w bindKey checkpoint } {

    global ALIAS
  
    # report  "electricAlias-expand bindKey='$bindKey' checkpoint=$checkpoint "
    
    # Pour utiliser des variables au lieu des quatres caracteres 8 bits !
    electricAlias-use8bitsCars
      

    # Si la selection est dans le widget
    if {[xtext_hasSel $w]}  then {
        # on insere le caractere tapé
        xtext_insert $w -string $bindKey 
        return
    }

    # Si les electric-alias sont inhibés
    if {$ALIAS(active) == 0} {
        # on insere le caractere tapé
        xtext_insert $w -string $bindKey
        return
    }
    

    ####################################################################
    # 1 - Extraction d'information sans modification du texte
    #     (sauf une insertion d'espace par une xtext_insert à déplacer)
    # 
    #      Créer une proc : electricAlias-extractTextInfo
    # 
    
    # bol : caracteres du debut de la ligne jusqu'au caractere d'insertion
    set bol [$w get   "insert linestart"  insert]

    # eol : du caracteres  d'insertion jusqu'a la fin de la ligne
    set eol [$w get   insert  "insert lineend + 1c" ]
    

    # to do : use this to build the extractPattern1 and extractPattern2
    # set alias(charSeparatorList) {\(\)\[\]\{\}\$'"     }

    # extractPattern1 : First token on the line?
    # 
    # pattern standard (un alias est précédé d'un espace)
    # set alias(extractPattern1)  {^([ \t]*)([^ \t]+)$}
    # pour qu'on puisse definir des alias contenant des caract "[]{}$.."
    set alias(extractPattern1) {^([ \t]*)([^]\[\(\)\{\}\$'" \t]+)$}
      
 
    # extractPattern2 : Word token?
    # 
    # pattern standard (un alias est précédé d'un espace)
    # set alias(extractPattern2)  {([ \t]+)([^ \t]+)$}
    # pour qu'on puisse definir des alias contenant des caract "[]{}.."
    # 
    #  
    set alias(extractPattern2) \
          {([]\[\(\)\{\$'" \t]+)([^]\[\(\)\{\}\$'" \t]+)$}


    set found   0
    set indent  ""
    set name    ""
    
    # diam 08/01/01 : 
    #   - BUG si expansion de (mode java) : MonVecteur () bb<Meta-Space>
    #     L'indent extraite contient les parentheses !!
    # 
    if {[regexp $alias(extractPattern1) $bol all indent name]  \
            &&  [regexp {^[ \t]*[\r\n]?$} $eol all]} {
              
         # si on est en mode d'insertion par les menus ($checkpoint=0) 
         # (et dans le cas "First token on the line")
         # on enleve un espace a l'indentation car celui-ci est rajoute 
         # artificiellement par la procedure electricAlias-insert
         if {!$checkpoint} then {regsub " " $indent "" indent}
         
         set aliasType $ALIAS(8bit_mark)
         set found 1
          
    } elseif { [regexp $alias(extractPattern2) $bol all indent name] == 1} {
    
         set aliasType ""
         set found 1
          
    }
    
    ####################################################################
    # Les variable suivantes sont désormais positionnées :
    # 
    #  - found :  1 si on a trouvé un mot (qui n'est pas forcément un alias 
    #             existant) et on connait les variables suivantes :
    #  - indent : contientient l'indentation de la ligne courante
    #  - name : le nom de l'alias extrait
    #  - aliasType : contient ou non le caractere 8 bit pour un alias de 
    #              "$ALIAS($aliasType$ALIAS(mode),$name)"  debut de ligne
    # 

    
    if {! $found } { 
        xtext_insert $w -string $bindKey
        return 
    }
    
    # Dans la suite :
    # defn : contient la définition de l'alias ; typiquement 
    #         "$ALIAS($aliasType$ALIAS(mode),$name)"
    # 
    
    # match pourra valoir 0 à 4 :
    # 
    #    match : 0  aucun alias n'existe pour ce name
    #    match : 1  pour un alias de début de ligne existant pour
    #               le mode d'alias courant
    #    match : 2  pour un alias de milieu de ligne existant pour
    #               le mode d'alias courant
    #    match : 3  un alias de début de ligne existe pour un mode vide
    #               i.e non spécifique à un mode d'alias particulier
    #    match : 4  un alias de milieu de ligne existe pour un mode vide
    #    
    set match 0
  
    # $M mode template?
    if {$match == 0 \
                && $aliasType == "$ALIAS(8bit_mark)" \
                && [info exists ALIAS($aliasType$ALIAS(mode),$name)] == 1} {
      set defn "$ALIAS($aliasType$ALIAS(mode),$name)"
      set match 1
    }
    
    # embedded word template?
    if {$match == 0 && [info exists ALIAS($ALIAS(mode),$name)] == 1} {
      set defn "$ALIAS($ALIAS(mode),$name)"
      set match 2
    }
    
    # nil mode $M definition matches everything iff non-nil ALIAS(mode)
    if {$match == 0 \
                && $aliasType == "$ALIAS(8bit_mark)" \
                && $ALIAS(mode) != "" \
                && [info exists ALIAS($ALIAS(8bit_mark),$name)] == 1} {
      set defn "$ALIAS($ALIAS(8bit_mark),$name)"
      set match 3
    }
    
    # nil mode matches everything
    if {$match == 0 && [info exists ALIAS(,$name)] == 1} {
      set defn "$ALIAS(,$name)"
      set indent ""
      set match 4
    }
    
    # Next line for debug:
    # stead:log  "$aliasType $ALIAS(mode) $name -> $match"
    
    # return if no aliases found
    if {$match == 0} { 
        xtext_insert $w -string $bindKey
        return
    }
    
    # 
    # Ce qui précède (future procédure electricAlias-extractTextInfo ?) 
    # a positionné les variables suivantes utiles pour la suite
    # 
    #  - indent : contient l'indentation de la ligne courante
    #  - name : le nom de l'alias extrait
    #  - defn : definition de l'alias
    #  - aliasType : (n'est pas utilisé apres) contient ou non le caractere 
    #    mark pour un alias de début le ligne
    #  - match (de 1 à 4) type précis de l'alias
    # 
    ####################################################################
    
    ######################################################################
    # La suite sert à l'extraction, l'expansion et l'insertion de l'alias 
    # trouvé
    ######################################################################
    
    ######################################################################
    # Essai du remplacement du code de substitution des commandes et variable
    # d'alias en utilisant la commande subst de TCL
    # Modif de la spécif des electricAlias car on n'utilise plus les 
    # variable d'alias, mais les variable globale de TCL
    #   => nettoyage supplément de code à faire
    # 
    
    # Variable cablee NON UTILISEE pour l'instant (deviendra une option) !!
    # 
    if {![info exists ALIAS(useTclSubst) ]} {
        set ALIAS(useTclSubst) 1     
    }
    
    
    # On remplace le texte de la définition de l'alais par sa version
    # substituée.
    # La substitution est maintenant faite par un "subst" de TCL, mais un 
    # traitement préalable parmet d'assurer la compatibilité avec la maniere 
    # originale de ce apckage (utilisation de caracteres 8 bit rares)
    # 
    # Principe :
    # 
    # Si on détecte l'existence d'un des trois car 8bit speciaux pour 
    # la substitution dans la définition de l'alias (le 4ieme caractere 
    # 8bits (marquage) étant traiter ailleurs) alors on les exploite pour 
    # garder la compatibilité avec stead36.
    # On les transforme alors en caracteres de substitution standard TCL
    # i.e. [ ] et $ )
    # 
    # Puis, dans tous les cas, on effectue une substitution au sens TCL
    # (par un subst).
    # => INCOMPATIBILITE POTENTIELLE AVEC METHODE OROGINE QUI IGNORAIT LES
    #    CARCATETERES $ [ et ]
    # 
    # 
    # ATTENTION A LA PRESENCE des marques de Stop $M qui est tres utilisée
    # ultérieurement
    # 
    if {[regexp "$B|$E|$V" $defn]} { 
          set NewDefn $defn
      
          # on cache les caracteres spéciaux pour tcl avant interprétation
          regsub -all {([][$\\])} $NewDefn  {\\\1} NewDefn
      
          # on remplace les caracteres de controle 8 bits par les caracateres 
          # TCL correspondant
          # Attention : commencer par le B avant V (car V contenu dans B !)
          regsub -all "$B" $NewDefn {[} NewDefn
          regsub -all "$E" $NewDefn {]} NewDefn
          
          # Version lisant une variable globale (TCL) :
          # 
          # regsub -all "$V" $NewDefn {$} NewDefn
  
          set rpat "$V"
          append rpat {\{(\w+)\}}
  
          regsub -all $rpat $NewDefn {[electricAlias-getVar \1]} NewDefn
          
          set defn $NewDefn
        
    }
    # On a transformé cette définition d'alias en nouveau style
    # 
    # Donc ...
    # On mémorise la position courante de fin et de début d'alias
    # # # set epos [$w index insert]
    # # # set bpos [$w index "$epos - [expr [string length "$name"] + 1] chars"]
    $w mark set epos [$w index insert]
    $w mark set bpos [$w index "epos - [string length $name] chars"]
    $w mark gravity bpos left
    
    # On supprime ici la chaine clée de déclenchement de l'alias
    # On pourra etre amené à ajouter ou supprimer un espace supplémentaire 
    # en fonction d'option, ou du mode d'utilisation de cet alias (electric, 
    # par menu ..)
    # # # # # xtext_delete $w -push $checkpoint  $bpos $epos
    xtext_delete $w -push $checkpoint  bpos epos
    
    # On effectue la subtitution principale
    # ATTENTION : cette substitution peut avoir des effets de bord tels
    # que déplacer le point d'insertion en début de fichier !
    # Il faut donc avoir mémorisé les marques epos et bpos avant cette
    # substitution
    set defn [subst $defn]
  
    # 
    # On va faire quelques autres modif de l'expansion avanr de modifier
    # de widget text 
    # 
      
    # insertion de l'indentation en début de chaque ligne du bloc à insérer
    regsub -all {\n} "$defn" "\n$indent" defn
    
    # On traiter les caracteres "backspace" éventuellement contenus dans le
    # définition de l'alias 
    # - en début de définition, les backspaces sont mémorisés pour exploitation
    #   ultérieure
    # - dans la définition, chaque backspace est traité immédiatement
    # 
    # On extraits les premiers backspace (qui pourront servir à réduire 
    # l'indentation initiale), puis on les supprime 
    set bs ""
    if {[regexp "^\b+" $defn bs]} {
        regsub "^\b+" "$defn" "" defn
    }
    regsub "^\b+" "$defn" "" defn
    
    # on supprime d'une manière itérative tout caractere suivi d'un backspace
    while {[regsub ".\b" "$defn" "" defn]} {}
    #endwhile
  
    # On duplique la définition et on supprime les caracteres "stop"
    # dans la duplacation
    set txtToBeInserted "$defn"
    regsub -all "$ALIAS(8bit_mark)" "$txtToBeInserted" "" txtToBeInserted
    

    # Avant l'insertion, on supprime le nombre de caracteres préciser par 
    # le nombre de backspaces détectés
    $w delete "insert  - [string length $bs]chars" "insert"
    xtext_insert $w -push 0 -- "$txtToBeInserted"
    
    set ALIAS(stopRing) [list]
    
    set defn_tmp "$defn"

    global stead
    
    while {[regexp -indices "$ALIAS(8bit_mark)" $defn_tmp indice]} {
        regsub "$ALIAS(8bit_mark)" "$defn_tmp" "" defn_tmp
        set stopMarkName "_electricalais_stop[xtcl_uid]"
        $w mark set $stopMarkName \
                    [$w index "bpos  + [lindex $indice 0] chars"]
        lappend ALIAS(stopRing) $stopMarkName
    }
    if { [ llength $ALIAS(stopRing) ] } {
        $w mark set insert [lindex $ALIAS(stopRing) 0]
    }
    xtext_setCursor $w insert  

} ;# end proc electricAlias-expand




## electricAlias-nextStop -- finds the next template stop
# 
# 
# 
# utilsé dans : latex-mode.tcl elecAlias_menu.tcl
# 
proc electricAlias-nextStop {{w .main.t}} {
    global ALIAS
    set first [lindex $ALIAS(stopRing) 0]
    set ALIAS(stopRing) [lreplace $ALIAS(stopRing) 0 0]
    lappend ALIAS(stopRing) $first
    set next [lindex $ALIAS(stopRing) 0]
    $w mark set insert $next
    $w see insert

}

## electricAlias-prevStop -- finds the previous template 
# 
# 
# 
# utilsé dans : latex-mode.tcl elecAlias_menu.tcl
# 
proc electricAlias-prevStop {{w .main.t}} {
    global ALIAS
    set end [expr {[llength $ALIAS(stopRing)] - 1}]
    set last [lindex $ALIAS(stopRing) $end]
    set ALIAS(stopRing) [lreplace $ALIAS(stopRing) $end $end]
    set ALIAS(stopRing) [linsert $ALIAS(stopRing) 0 $last]
    $w mark set insert $last
    $w see insert
}


## electricAlias-askVar -- prompts the user for a value to set an alias variable
# 
# prompt : question à poser 
# name : nom de la variable à affecter
# ?value values ...? : valeurs autorisées par la variable name 
#        Si une seule valeur : ce sera la valeur par défaut
#        Si plus d'une valeur proposée, un popmenu permet à l'utilisateur 
#        de choisir la valeur parmi elles
# 
# Utilisée dans les alias interactifs (pour demander le nom de la 
# procédure TCL, de façon à pour utiliser plusieurs fois ce nom dans 
# une meme expansion.
# 
# utilisé dans tous les modes !
# 
proc electricAlias-askVar {prompt name  args} {
    global stead    
    
    set defaultValue [lindex $args 0]
    
    switch -exact -- [llength $args] {
      
        0 -
        1 {
             set defaultValue [lindex $args 0]
             electricAlias-var $stead(mode)  $name \
                        [te:prompt -text $prompt -default $defaultValue]
        } 
        default {
             set default [lindex $args 0]
             set title [lindex $args 1]
             set list [lrange $args 2 end]
             electricAlias-var $stead(mode)  $name \
                   [xtk_listPrompt -text $prompt \
                                  -default $defaultValue \
                                  -title $title \
                                  -values $list \
                   ]
        }
    } ;# endswitch    

    return ""
} ;#endproc electricAlias-askVar



## electricAlias-getVar -- retourne la valeur de la variable d'alias
# 
# aliasVarName: nom solft de la variable (i.e. "NAME" et non pas "$V{NAME}")
# aliasMode : nom du mode ( $ALIAS(mode) par défaut) 
# 
# Cette procédure est plus "tolérante" que electricAlias-var ; car en cas
# d'inexistence du nom  aliasVarName pour le mode aliasMode (demandé ou 
# par défaut): elle suppose que c'est un alias globale (i.e indépendante 
# de tout mode) 
# Cette procédure sera utilisée par tous les modes
# 
# prend un nom de variable simple NAME au lieu de $V{NAME}
proc electricAlias-getVar {aliasVarName {aliasMode {}}} {

    global ALIAS
    

    if {[string equal $aliasMode ""]} {
        set aliasMode $ALIAS(mode)
    }
    
    set value ""
    
    
    set varName1 "ALIAS($aliasMode,[set ALIAS(8bit_var)]\{$aliasVarName\})"
    set varName2 "ALIAS(,[set ALIAS(8bit_var)]\{$aliasVarName\})"    
    if {[info exists $varName1] } {
        set value [set $varName1]
    } else {
        # Does a global version of the variable exist?
        if {[info exists $varName2 ] } {
            set value [set $varName2]
      } else {
            # Si variable inexistante : on retourne son non
            set value "$aliasVarName (NOT EXIST)"
        }
    }
        
    return $value

} ;# electricAlias-getVar


## electricAlias-setStop -- postion un stop dans une definition d'alias
# 
# Pour l'instant, se contente de retourner le caractere 8bit
# réservé à cet effet.
# 
# Plus tard : acceptera un parametre chaine qui sera insérée 
# à la position de ce stop pour donnéer une indication de ce 
# que doit insérer l'utilsateur à ce stop
# Cette chaine devra etre sélection pour etre remplacée par ce que
# tapera l'utilisateur. 
# 
# modif :
#    diam 21/08/00 : création NON TESTEE POUR L'INSTANT
# 
proc electricAlias-setStop { {templateString "" } } {

    # # global ALIAS
        
    return $::ALIAS(8bit_mark)

} ;# electricAlias-setStop

########################################################################
# 
# Quelques commandes d'alias abbrégée 
# 
# - soit ce sont des commandes (appelées à être) utilisées tres fréquement
#   par exmpel des tous les mode
# - soit elle sont dépréciées et appelées à disparaitre
# 
########################################################################

## setStop -- alias à electricAlias-setStop
# 
# sera tres utilisée dans tous les modes
# 
# A terme, on pourra passer une chaine template qui devra etre selection 
# leorseque la marque (le tag?) sera activer par l'utilisation (nextStop 
# et prevStop)
# 
proc setStop { {templateString "" } } {
    return [electricAlias-setStop $templateString ]
}


## getVar -- alias à electricAlias-getVar
# 
# sera tres utilisé dans tous les modes
# 
proc getVar {aliasVarName {aliasMode {}} } {
    return [electricAlias-getVar  $aliasVarName $aliasMode]
}


## askVar -- alias à electricAlias-askVar
# 
# sera tres utilisé dans tous les modes
# 
proc askVar {prompt name args} {
    return [eval electricAlias-askVar [list $prompt $name] $args]
}

## askalias --  alias à electricAlias-askVar (sera obsolete)
# 
# Utiliser partout, mais sera remplacé par askVar
# A conserver pour raison de compatibilité importante
# 
proc askalias {prompt name args} {
    return [eval electricAlias-askVar [list $prompt $name] $args]
}

## defAlias -- surcouche à electricAlias-def 
# 
# Ajoute une option (flag) 
#   -sol : si présent, l'alias n'est effectif que s'il apparait en début de ligne
# Tres utilisé dans tous les modes
# 
proc defAlias {args} {
    # 1 - intialisation des options
    set opt(-sol)     0
    
    # 2 - analyse de la ligne de commande
    while {[llength $args]} {
        switch -glob -- [lindex $args 0] {
          -- {
                set args [lreplace $args 0 0]
                break
          }
          -sol {
                set opt(-sol) 1
                set args [lreplace $args 0 0]
                continue
          }
          -* {
                puts stdout "unknow option [lindex $args 0]"
                exit 1
          }
          default { break  ;# no more options}
        }
    }
    
    # 3 - exploitation des options
    if {$opt(-sol)} {
        set aliasmode "$::ALIAS(8bit_mark)[lindex $args 0]"
    } else {
        set aliasmode [lindex $args 0]
    }
    set name [lindex $args 1]
    set def  [lindex $args 2]
    
    # 4 - construction et exécution de la commande
    set cmd  [list electricAlias-def            \
                ${aliasmode} \
                $name                           \
                $def                            \
    ]
    # report -v  aliasmode name def cmd
    uplevel $cmd
}

########################################################################
# 
# Ce qui suit était dans un fichier séparé "elecAlias_menu.tcl"
# J'au fusionner pour faciliter les modification !
# 
# fichier elecAlias_menu.tcl 
#   creation d'un menu avec des alias pour les modes
#   plus des procedures concernant les electricAlias rajoutes
# 
########################################################################




# electricAlias-wrap -- place la selection dans un champ de l'electric alias
# 
# num : numéro du stop ou on doit insérer la sélection
# 
# A FAIRE : VIRER LE DERNIER RETURN DE LA SELECTION SI EXISTE, ET
# LE RAJOUTER APRES L'ALIAS
# 
# utilisé dans les modes
# 
proc electricAlias-wrap { alias {num 0} {w .main.t}} {

    set selTxt ""
    if {[xtext_hasSel $w]} {
        set selTxt [string trimright [xtext_getSel $w]]
        xtext_delete $w sel
    }
    electricAlias-insert $w $alias
    
    # on se position sur le nieme stop en vue d'y insérer la selection
    for {set i 1} {$i <= $num} {incr i} {
         electricAlias-nextStop
    }
    
    if {[string length $selTxt]} {
        xtext_insert $w -string $selTxt
    }
}        


##  electricAlias-insert -- etend l'alias "Alias"
# 
# Utilisé dans TOUS LES modes pour la construction du menu proposant
# l'exécution de tous les alias dispo pour un mode stead donné.!!
# 
#       foreach alias [electricAlias-softNames] {
#          .menu.templates.m.alias add command -label $alias \
#               -command "electricAlias-insert $w  [te:no_interp $alias]"
#       }
# 
# A FAIRE : 
# - Créer une procédure de plus haut niveau pour simplifier
#   la création du menu "allAliases" dans les modes.
# - améliorer (casser) la procédure avec electricAlias-expand et
#   prevoir une option plus parlante dans electricAlias-expand pour 
#   supprimer l'espace artificiel avant le nom de l'alias inséré
#         -removePrefixSpace 1  
# - adapter tous les fichiers de mode stead pour supprimer cette procédure
# 
# 
proc electricAlias-insert { w alias  } {

    $w mark set  beforePrefixIndex insert
    $w mark gravity beforePrefixIndex left
    
    # on insere un espace avant d'etendre
    set prefix " "
    xtext_insert $w -string "$prefix$alias"

    electricAlias-expand $w " " 0
    if {$prefix == " "} {
         $w delete beforePrefixIndex
    }
    $w mark unset beforePrefixIndex
}

# ./

