|
|
|
Même si un fichier de code peut contenir plusieurs langages, le langage de code par défaut est défini par l'extension du nom du fichier. Par exemple, pour le langage Python, les fichiers seront nommés « nom_fichier.py ». Un fichier .html aura le langage HTML par défaut, même s'il peut contenir du code JS ou CSS.
|
|
|
|
Pour ajouter un langage, il est donc nécessaire de développer deux nouveaux plugins : Language et FileType.
|
|
|
|
|
|
|
|
|
|
|
|
# Plugin Language :
|
|
|
|
|
|
|
|
Créez un nouveau module dans le package [tutoring.models.languages.plugins] (https://gitlab.insa-rouen.fr/cip/ubiquity/-/tree/master/ubiquity/tutoring/models/languages/plugins). Ce module devra suivre le template suivant en remplaçant certaines parties par les informations décrivant le langage comme ci-dessous.
|
|
|
|
|
|
|
|
## Template d'un plugin
|
|
|
|
|
|
|
|
```
|
|
|
|
from typing import List, Tuple, Optional
|
|
|
|
|
|
|
|
from ..language_base import Language
|
|
|
|
from ..lexicon import Lexicon, Token
|
|
|
|
|
|
|
|
|
|
|
|
class <Nom du langage>Language(Language):
|
|
|
|
"""A <Nom du langage> language plugin"""
|
|
|
|
|
|
|
|
@property
|
|
|
|
def comments(self) -> List[Tuple[Optional[str], Optional[str]]]:
|
|
|
|
return <Liste des tuples de définition des commentaires>
|
|
|
|
|
|
|
|
@property
|
|
|
|
def prettify_lang(self) -> str:
|
|
|
|
return <Nom du langage dans prettify pour la coloration syntaxique>
|
|
|
|
|
|
|
|
@property
|
|
|
|
def lexicon(self) -> Lexicon:
|
|
|
|
return Lexicon(<Dictionnaire décrivant le lexique du langage>)
|
|
|
|
```
|
|
|
|
|
|
|
|
## Explication du template
|
|
|
|
|
|
|
|
Explication des différentes parties du plugin d'un langage :
|
|
|
|
- [Nom du langage](#LanguageTool)
|
|
|
|
- [Commentaires](#commentaires)
|
|
|
|
- [Coloration syntaxique](#coloration-syntaxique)
|
|
|
|
- [Lexique](#lexique)
|
|
|
|
|
|
|
|
|
|
|
|
### Nom du langage
|
|
|
|
|
|
|
|
```
|
|
|
|
class <Nom du langage>Language(Language):
|
|
|
|
"""A <Nom du langage> language plugin"""
|
|
|
|
```
|
|
|
|
|
|
|
|
Remplacez `<Nom du langage>` simplement par le nom du langage en respectant la syntaxe CamelCase pour le nom de la classe.
|
|
|
|
|
|
|
|
Exemple avec Python:
|
|
|
|
|
|
|
|
```
|
|
|
|
class PythonLanguage(Language):
|
|
|
|
"""A Python language plugin"""
|
|
|
|
```
|
|
|
|
|
|
|
|
### Commentaires
|
|
|
|
|
|
|
|
```
|
|
|
|
@property
|
|
|
|
def comments(self) -> List[Tuple[Optional[str], Optional[str]]]:
|
|
|
|
return <Liste des tuples de définition des commentaires>
|
|
|
|
```
|
|
|
|
|
|
|
|
Remplacez `<Liste des tuples de définition des commentaires>` par la liste des tuples de commentaire. Si un commentaire ne posséde qu'un délimiteur de début sans délimiteur de fin pour le décrire ou inversement, il faut indiquer `None` pour marquer cette absence. Si le langage a une seule façon de décrire un commentaire, alors il y aura un seul tuple dans cette liste.
|
|
|
|
|
|
|
|
Exemple avec Python :
|
|
|
|
|
|
|
|
```
|
|
|
|
@property
|
|
|
|
def comments(self) -> List[Tuple[Optional[str], Optional[str]]]:
|
|
|
|
return [('#', None), ('"""', '"""')]
|
|
|
|
```
|
|
|
|
|
|
|
|
### Coloration syntaxique
|
|
|
|
|
|
|
|
```
|
|
|
|
@property
|
|
|
|
def prettify_lang(self) -> str:
|
|
|
|
return '<Nom du langage dans prettify pour la coloration syntaxique>'
|
|
|
|
```
|
|
|
|
|
|
|
|
Remplacez `<Nom du langage dans prettify pour la coloration syntaxique>` par la valeur de prettify correspondant à ce langage. Hors cas spéciaux, pour trouver cette valeur, allez dans le répertoire [static/tutoring/js/google-code-prettify](https://gitlab.insa-rouen.fr/cip/ubiquity/-/tree/master/ubiquity/tutoring/static/tutoring/js/google-code-prettify) et recherchez le fichier JavaScript correspondant. Il commence par **lang-** et se termine par **.js**. Prenez le nom du fichier et supprimez **lang-** et **.js**.
|
|
|
|
|
|
|
|
Les cas spéciaux sont les suivants :
|
|
|
|
|
|
|
|
- default-code
|
|
|
|
- c, cc, cpp, cxx, cyx, m
|
|
|
|
- coffee
|
|
|
|
- cs
|
|
|
|
- json
|
|
|
|
- perl, pl, pm
|
|
|
|
- rb, ruby
|
|
|
|
- default-markup, mxml, xml, xsl
|
|
|
|
- java
|
|
|
|
- javascript, js, ts, typescript
|
|
|
|
- cv, py, python
|
|
|
|
- bash, bsh, csh, sh
|
|
|
|
|
|
|
|
Exemple avec Python :
|
|
|
|
|
|
|
|
```
|
|
|
|
@property
|
|
|
|
def prettify_lang(self) -> str:
|
|
|
|
return 'py'
|
|
|
|
```
|
|
|
|
|
|
|
|
### Lexique
|
|
|
|
|
|
|
|
```
|
|
|
|
@property
|
|
|
|
def lexicon(self) -> Lexicon:
|
|
|
|
return Lexicon(<Dictionnaire décrivant le lexique du langage>)
|
|
|
|
```
|
|
|
|
|
|
|
|
Le lexique est un dictionnaire dont les clés sont les suivantes avec pour valeur des expressions régulières :
|
|
|
|
| Nom | Description | Valeur par défaut |
|
|
|
|
|-----|-------------|-------------------|
|
|
|
|
| ID | Les noms des variables, classes et méthodes | ``r'[a-zA-Z_]\w*'`` |
|
|
|
|
| DELIMITER | Les caractères de délimitation | ``"\|".join((r"\]", r",", r"\(", r"\[", r"\{", r":", r";", r"\)", r"\}", r"\."))`` |
|
|
|
|
| AFFECTATION | Les opérateurs d'affectation | ``r"="`` |
|
|
|
|
| OPERATOR | Les opérateurs | ``"\|".join((r">", r"==", r"\\|", r"&", r"<", r">=", r"-", r"\*", r"<=", r"!=", r"\^", r"%", r"\+"))`` |
|
|
|
|
| STR | Les chaînes de caractères | ``r"(\".*?\")`` |
|
|
|
|
| NUMBER | Tous les nombres | ``r"\d+(.\d+)?"`` |
|
|
|
|
| COMMENT | Les commentaires | ``None`` |
|
|
|
|
| KEYWORD | Les mots clés du langage | ``None`` |
|
|
|
|
|
|
|
|
\
|
|
|
|
Exemple avec Python :
|
|
|
|
|
|
|
|
```
|
|
|
|
@property
|
|
|
|
def lexicon(self) -> Lexicon:
|
|
|
|
return Lexicon({
|
|
|
|
Token.DELIMITER: "|".join(
|
|
|
|
(r"\]", r",", r"\(", r"\[", r"\{", r"->", r":", r";", r"\)", r"\}", r"\.", r"\\")),
|
|
|
|
Token.AFFECTATION: "|".join((r"[\^\*/:\+\-]=", r"//=", r">>=", r"=", r"\*\*=")),
|
|
|
|
Token.OPERATOR: "|".join(
|
|
|
|
(r">", r"~", r"==", r"\|", r"&", r"<<", r"<", r">=", r"-", r"\*", r"<=", r"!=", r">>",
|
|
|
|
r"\\}", r"\^", r"%", r"\*\*", r"\+")),
|
|
|
|
Token.STR: r"(\"\"\"(.|\s)*?\"\"\")|(\'\'\'(.|\s)*?\'\'\')|(\".*?\")|(\'.*?\')",
|
|
|
|
Token.NUMBER: r"(([1-9](_?\d)*)|0|((\d(_?\d)*)?\.\d(_?\d)*)|((\d(_?\d)*)\.))(e[+-]?\d+)?j?",
|
|
|
|
Token.COMMENT: r"(\#.*)",
|
|
|
|
Token.KEYWORD: r"(" + "|".join(
|
|
|
|
[r"import", r"yield", r"lambda", r"await", r"for", r"with", r"elif", r"continue", r"try", r"else",
|
|
|
|
r"True", r"while", r"is", r"\.\.\.", r"def", r"assert", r"if", r"global", r"from", r"pass", r"del",
|
|
|
|
r"break", r"False", r"return", r"finally", r"raise", r"nonlocal", r"except", r"and", r"class", r"as",
|
|
|
|
r"async", r"and", r"or", r"not", r"in", r"None", r"is"]) + r")[\W$]"
|
|
|
|
})
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
# Plugin FileType :
|
|
|
|
|
|
|
|
Créez un nouveau module dans le package [tutoring.models.filetypes.plugins] (https://gitlab.insa-rouen.fr/cip/ubiquity/-/tree/master/ubiquity/tutoring/models/filetypes/plugins). Ce module devra suivre le modèle suivant en remplaçant certaines parties par les informations décrivant le type de fichier comme ci-dessous.
|
|
|
|
|
|
|
|
## Template d'un plugin
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
from typing import Set
|
|
|
|
from tutoring.models.filetypes.filetype import FileType
|
|
|
|
from tutoring.models.languages.language_base import Language
|
|
|
|
from tutoring.models.languages.plugins.python import <Nom de classe Language>
|
|
|
|
|
|
|
|
|
|
|
|
class FileType<Nom du langage>(FileType):
|
|
|
|
"""A <Nom du langage> file type plugin"""
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_extensions(cls) -> Set[str]:
|
|
|
|
""" Extensions for the file """
|
|
|
|
return {'.<Extension>', '.<Autre Extension possible>', ...}
|
|
|
|
|
|
|
|
@property
|
|
|
|
def default_language(self) -> <Nom de classe Language>:
|
|
|
|
""" Default language """
|
|
|
|
return <Nom de classe Language>()
|
|
|
|
```
|
|
|
|
|
|
|
|
## Explication du template
|
|
|
|
|
|
|
|
Explication des différentes parties du plugin pour un type de fichier :
|
|
|
|
- [Nom du language](#nom-du-language)
|
|
|
|
- [Extension](#extension)
|
|
|
|
- [Nom de classe Language](#nom-de-classe-langage)
|
|
|
|
|
|
|
|
### Nom du langage
|
|
|
|
|
|
|
|
```
|
|
|
|
class FileType<Nom du langage>(FileType):
|
|
|
|
"""A <Nom du langage> file type plugin"""
|
|
|
|
```
|
|
|
|
|
|
|
|
Remplacez `<Nom du langage>` par le nom du langage en respectant la syntaxe CamelCase pour le nom de la classe.
|
|
|
|
|
|
|
|
Exemple avec Python:
|
|
|
|
|
|
|
|
```
|
|
|
|
class FileTypePython(FileType):
|
|
|
|
"""A Pytyon file type plugin"""
|
|
|
|
```
|
|
|
|
|
|
|
|
### Extension
|
|
|
|
|
|
|
|
```
|
|
|
|
@classmethod
|
|
|
|
def get_extensions(cls) -> Set[str]:
|
|
|
|
""" Extensions for the file """
|
|
|
|
return {'.<Extension>', '.<Autre Extension possible>', ...}
|
|
|
|
```
|
|
|
|
Remplacez `<Extension>` par l’extension de fichier correspondant au fichier précédé d'un point.
|
|
|
|
Si plusieurs extensions sont possibles ajoutez les au set.
|
|
|
|
|
|
|
|
Exemple pour Python:
|
|
|
|
|
|
|
|
```
|
|
|
|
@classmethod
|
|
|
|
def get_extensions(cls) -> Set[str]:
|
|
|
|
""" Extensions for the file """
|
|
|
|
return {'.py'}
|
|
|
|
```
|
|
|
|
|
|
|
|
Autre exemple pour plusieurs extensions possibles pour Pascal:
|
|
|
|
|
|
|
|
```
|
|
|
|
@classmethod
|
|
|
|
def get_extensions(cls) -> Set[str]:
|
|
|
|
""" Extensions for the file """
|
|
|
|
return {'.pas', ‘.p’, ‘.pp’}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Nom de classe Language
|
|
|
|
|
|
|
|
```
|
|
|
|
@property
|
|
|
|
def default_language(self) -> <Nom de classe Language>:
|
|
|
|
""" Default language """
|
|
|
|
return <Nom de classe Language>()
|
|
|
|
```
|
|
|
|
|
|
|
|
Remplacez `<Nom de classe Language>` par le nom de la classe créée précédemment dans le plugin Language.
|
|
|
|
|
|
|
|
Exemple avec Python :
|
|
|
|
|
|
|
|
```
|
|
|
|
@property
|
|
|
|
def default_language(self) -> Language:
|
|
|
|
""" Default language """
|
|
|
|
return PythonLanguage()
|
|
|
|
``` |
|
|
|
\ No newline at end of file |