Salome HOME
menage
[tools/eficas.git] / generator / Formatage.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2013   EDF R&D
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20 """
21     Ce module contient la classe Formatage qui permet le formatage d'une 
22     liste de chaines de caractères dans une syntaxe représentative d'un
23     jeu de commandes en un texte présentable
24 """
25 import types,string,re
26 from Extensions.i18n import tr
27 filePattern="'[^\(\)]([^\(\)]*\([^\(\)]*\))*[^\(\)]*'"
28 filePattern2='"[^\(\)]([^\(\)]*\([^\(\)]*\))*[^\(\)]*"'
29
30 class Formatage :
31   """ 
32      Cette classe contient toutes les méthodes nécessaires au formatage
33      de la chaine de caracteres issue d'un generator en un fichier
34      'lisible' ie avec indentations
35
36      L'objet attend en parametre du constructeur (argument l_jdc) une representation
37      du jeu de commandes sous la forme d'une liste.
38
39      Chaque element de la liste est la representation d'une etape.
40
41      La representation d'une etape est une liste dont le premier element est une chaine de
42      caracteres donnant le debut de la commande ("xxx=lire_maillage(", par exemple).
43      Les elements suivants sont les representations des mots cles simples et facteurs.
44      Elle se termine avec un element de fin : ");"
45
46      La representation d'un mot cle simple est une chaine de caracteres (info=2, par exemple).
47
48      La representation d'un mot cle facteur est semblable à celle de l'étape : premier element
49      caracteristique du mot cle facteur suivi d'elements representatifs des mots cles simples.
50      Elle se termine avec un element de fin : ")" ou "),".
51   """
52   def __init__(self,l_jdc,code=None,mode=None,sep='=',l_max=72):
53     # l_jdc représente le jeu de commandes brut sous forme de liste
54     self.l_jdc = l_jdc
55     self.jdc_fini =''
56     self.count = 0
57     self.sep=sep
58     self.l_max=l_max
59     if mode == '.py':
60        self.sep = '='
61        self.l_max = 132 
62     elif code == 'ASTER':
63        self.sep = ':'
64        self.l_max = 72
65
66   def formate_jdc(self):
67     comment=re.compile("\n#")
68     commentaireavant=0
69     for etape in self.l_jdc:
70       self.count = self.count+1
71       self.texte_etape = ''
72       if type(etape)==types.ListType:
73         # L'etape est sous la forme d'une liste dont le premier element est une chaine
74         self.indent=[]
75         self.indent.append(len(etape[0]))
76         self.indent_courant = self.indent[0]
77         self.texte_etape = '\n' + etape[0]
78         if len(etape)>1 :
79           self.formate_etape(etape[1:])
80       else :
81         # L'etape est deja sous forme de chaine de caracteres
82         self.indent=[]
83         self.texte_etape = etape
84
85       m=comment.match(self.texte_etape)
86       # si ce n est pas la premiere ligne
87       if self.jdc_fini != ""  : 
88         # si il n y avait pas de commentaire avant on met un saut de ligne
89         if commentaireavant == 0 :
90            self.jdc_fini = self.jdc_fini + '\n' + self.texte_etape
91         else :
92            self.jdc_fini = self.jdc_fini + self.texte_etape
93       # si c est la premiere ligne
94       else :
95         # on ne met pas de saut de ligne avant la premiere ligne 
96         # si c est un commentaire on enleve le saut de ligne precedent
97         if m : self.texte_etape=self.texte_etape[1:]
98         self.jdc_fini = self.texte_etape
99       if m : 
100         commentaireavant=1 
101       else :
102         commentaireavant=0 
103
104     return self.jdc_fini
105   
106   
107
108   def formate_etape(self,liste):
109     """
110         Enrichissement de la chaine de caracteres representant l'etape (attribut
111         texte_etape de l'objet Formatage).
112         Les elements a ajouter sont dans l'argument liste de la methode.
113         L'objet "liste" à traiter a été produit par le module generator. En particulier
114         les parenthèses et les virgules ont été produites par ce module
115     """
116     l_patterns_fin_etape = ( ');' , ');\n' )
117     l_patterns_fin_mcf   = ( ')'  , '),'   )
118
119     ind = 0
120     for element in liste :
121       if type(element) == types.ListType:
122
123         # il s'agit d'un mot-clé facteur
124         # on écrit son nom (element[0])
125         longueur = self.longueur(self.texte_etape)
126         try:
127           increment = len(('\n'+self.indent_courant*' ')*ind + element[0])
128         except:
129           print (tr('ERREUR'))
130           print (liste)
131           print (element)
132         self.texte_etape = self.texte_etape + (u'\n'+self.indent_courant*' ')*ind + element[0]
133         length = len(self.indent)
134         self.indent.insert(length,self.indent[length-1]+len(element[0]))
135         self.indent_courant = self.indent[length]
136         # on écrit ses fils
137         self.formate_etape(element[1:])
138       elif type(element) == types.StringType:
139
140         # il s'agit d'un mot-clé simple ou de ')' ou ');' ou '),' ou ');\n'
141
142         if element in l_patterns_fin_mcf :
143               self.traite_mcfact(s_mcfact=element,ind=ind)
144         elif element in l_patterns_fin_etape :
145               self.traite_etape(s_etape=element,ind=ind)
146         else :
147               self.traite_mcsimp(s_mcsimp=element,ind=ind)
148
149       ind = 1
150
151   def traite_etape(self,s_etape,ind) :
152       """
153           Traite une partie du jdc formaté : s_etape, une chaîne de caractères
154           contenant une étape
155           L'attribut self.texte_etape est modifié (complété) par le traitement
156           L'attribut self.indent est modifié par le traitement
157           L'attribut self.indent_courant est modifié par le traitement
158       """
159       length = len(self.indent)
160       if length > 1:
161           last = self.indent[length-1]
162           self.indent.remove(last)
163           self.indent_courant=self.indent[length-2]
164       else :
165           self.indent_courant=self.indent[0]
166       self.texte_etape = self.texte_etape + string.strip(s_etape)
167
168   def traite_mcfact(self,s_mcfact,ind) :
169       """
170           Traite une partie du jdc formaté : s_mcfact, une chaîne de caractères
171           contenant un mot-clef facteur.
172           L'attribut self.texte_etape est modifié (complété) par le traitement
173           L'attribut self.indent est modifié par le traitement
174           L'attribut self.indent_courant est modifié par le traitement
175       """
176       self.texte_etape = self.texte_etape + string.strip(s_mcfact)
177       length = len(self.indent)
178       if length > 1:
179            last = self.indent[length-1]
180            self.indent.remove(last)
181            self.indent_courant=self.indent[length-2]
182       else :
183            self.indent_courant=self.indent[0]
184       return
185
186
187   def traite_mcsimp(self,s_mcsimp,ind) :
188       """
189           Traite une partie du jdc formaté : s_mcsimp, une chaîne de caractères
190           contenant un mot-clef simple.
191           L'attribut self.texte_etape est modifié (complété) par le traitement
192       """
193       #
194       # Ajout PN pour defi_fonction
195       if self.texte_etape.find("DEFI_FONCTION") > 1 :
196           bool_fonction=1
197           if s_mcsimp.find("\n")  > 1:
198               txt=""; bool = 0; numident=1
199               for l in s_mcsimp.splitlines() :
200                  if bool == 0 :
201                     bool = 1
202                     numident=s_mcsimp.find("=")+2
203                     txt=l
204                  else :
205                     txt=txt+('\n'+self.indent_courant*' '+numident*' ')*ind+l
206               s_mcsimp = txt
207       else : 
208           bool_fonction=0
209       longueur = self.longueur(self.texte_etape)
210       increment = len((u'\n'+self.indent_courant*' ')*ind + string.strip(s_mcsimp))
211       if (bool_fonction == 1 ) :
212           self.texte_etape = self.texte_etape+'\n'+self.indent_courant*' ' +s_mcsimp
213       elif ( ((1-ind)*longueur+increment) <= self.l_max ) :
214           self.texte_etape = self.texte_etape + ('\n'+self.indent_courant*' ')*ind + string.strip(s_mcsimp)
215       else :
216           # il faut couper ...
217           nom,valeur = string.split(s_mcsimp,self.sep,1)
218           chaine = self.creer_chaine(nom,valeur,'\n'+self.indent_courant*' ',ind)
219           #self.jdc_fini = self.jdc_fini + ('\n'+self.indent_courant*' ')*ind + string.strip(s_mcsimp)
220           self.texte_etape = self.texte_etape + chaine
221       return
222
223
224   def longueur(self,texte):
225     """ 
226        texte est une string qui peut contenir des retours chariots
227        Cette méthode retourne la longueur de la dernière ligne de texte 
228     """
229     liste = string.split(texte,'\n')
230     return len(liste[-1])
231
232   def creer_chaine(self,nom,valeur,increment,ind):
233     """
234         La methode creer_chaine reconstitue un objet Eficas à partir de
235              - son nom,
236              - sa valeur.
237     """
238     s=''
239     if len(increment + nom + self.sep) <= self.l_max:
240       texte = increment*ind
241       label = nom + self.sep
242       s=texte + label
243       longueur = len(increment + label)
244
245       if ('(' not in valeur) or (valeur[0:3]=='"""') :
246         # il s'agit d'une vraie chaîne de caractères
247         val = len(valeur)
248         texte = (self.l_max-2-val)*' '+valeur
249         s=s+'\n'+texte
250       elif re.match(filePattern,valeur) or re.match(filePattern2,valeur):
251         val = len(valeur)
252         texte = (self.l_max-2-val)*' '+valeur
253         s=s+'\n'+texte
254       elif ',' in valeur:
255         # il s'agit d'une liste de tuple
256         # c est trop complique on ne splitte pas
257         if valeur[0:2]=='((' or valeur[0:2]=='[(':
258            s=s+valeur
259            return s
260         # il s'agit d'une liste
261         liste = string.split(valeur,',')
262         i=0
263         for arg in liste :
264           ajout = string.strip(arg)
265           if len(ajout) == 0 : continue
266           longueur = self.longueur(texte = (texte + label)) + len(ajout +',') + (1-i)*len(increment)
267           if longueur  <= self.l_max:
268               if ajout[-1] != ')':
269                 texte = texte + ajout +','
270               else :
271                 texte = texte + ajout
272           else :
273             i=1
274             if ajout[-1] != ')':
275               texte = texte  + increment + (len(label)+2)*' ' + ajout  + ','
276             else :
277               texte = texte  + increment + (len(label)+2)*' ' + ajout
278
279         s=s+texte
280         s =  s + ','
281
282       else :
283         # On a une ( mais pas de , . On passe la chaine sans modification
284         val = len(valeur)
285         texte = (self.l_max-2-val)*' '+valeur
286         s=s+'\n'+texte
287
288     return s
289
290 class FormatageLigne(Formatage) :
291   def __init__(self,l_jdc,code=None,mode=None,sep='=',l_max="**"):
292       Formatage.__init__(self,l_jdc,code=None,mode=None,sep='=',l_max="**")
293       
294   def formate_jdc(self):
295       texte1=Formatage.formate_jdc(self)
296       newText=""
297       lignes=texte1.split("\n")
298       texte=""
299       pattern_debut_blanc  = re.compile(r"^ \s*.*")
300       pattern_commentaire   = re.compile(r"^\s*#.*")
301       pattern_vide=re.compile(r"\s*^$")
302       for l in lignes :
303           if pattern_commentaire.match(l) or pattern_vide.match(l): 
304              newText+=l+"\n"
305              continue
306           if not pattern_debut_blanc.match(l) : texte=l 
307           else : texte+=re.sub(r'^ \s*',' ',l)
308           if texte[-1]==";" :
309              newText+=texte+"\n"
310              texte=""
311       return newText
312
313