diff --git a/demo/questions/questions-tutorial.yaml b/demo/questions/questions-tutorial.yaml
index 380cb0d..9881ebe 100644
--- a/demo/questions/questions-tutorial.yaml
+++ b/demo/questions/questions-tutorial.yaml
@@ -5,14 +5,19 @@
text: |
Texto informativo. Não conta para avaliação.
- $$ p(x) = \frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{(x-\mu)^2}{2\sigma^2}} $$
+ A Distribuição gaussiana $\mathcal{N}(x\mid\mu,\sigma^2)$ é definida por
+
+ $$
+ p(x) = \frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{(x-\mu)^2}{2\sigma^2}}.
+ $$
+
# ---------------------------------------------------------------------------
-
ref: tut-success
type: success
title: success
text: |
- Texto de positivo (sucesso). Não conta para avaliação.
+ Texto positivo (sucesso). Não conta para avaliação.
```C
int main() {
@@ -42,7 +47,10 @@
ref: tut-alert
type: alert
title: alert
- text: Texto negativo (alerta). Não conta para avaliação. 
+ text: |
+ Texto negativo (alerta). Não conta para avaliação.
+
+ 
# ----------------------------------------------------------------------------
-
diff --git a/demo/questions/questions.yaml b/demo/questions/questions.yaml
deleted file mode 100644
index 9431107..0000000
--- a/demo/questions/questions.yaml
+++ /dev/null
@@ -1,162 +0,0 @@
--
- ref: flags
- type: radio
- files:
- flag1: images/flag-pt.svg
- flag2: images/flag-es.svg
- flag3: images/flag-fr.svg
- text: Qual é a bandeira de Portugal?
- options:
- - ''
- - '
'
- - '
'
- # opcional
- title: Bandeiras nacionais
- hint: |
- > A Portuguesa, que hoje é um dos símbolos nacionais de Portugal (o seu hino nacional), nasceu como uma canção de cariz patriótico em resposta ao ultimato britânico para que as tropas portuguesas abandonassem as suas posições em África, no denominado "Mapa cor-de-rosa".
- >
- > -- da Wikipedia
-
- Mais informação
-
-
-# ---------------------------------------------------------------------------
--
- ref: solar-system
- type: radio
- files:
- solar_system_planets: images/planets.png
- text: Qual é o maior planeta do Sistema Solar?
- options:
- - Mercúrio
- - Marte
- - Júpiter
- - Têm todos o mesmo tamanho
- # opcional
- title: Sistema solar
- correct: 2
- shuffle: False
- discount: True
- hint: Se usar o markdown `!(text)[imagem]` a imagem fica com tamanho fixo. É preferível usar a tag html `
` para ter sempre a largura correcta.
-# ---------------------------------------------------------------------------
--
- ref: math-expressions
- type: checkbox
- text: Quais das seguintes expressões são verdadeiras?
- options:
- - $1 > 0$
- - $\sqrt{3} > \sqrt{2}$
- - $e^{i\pi} + 1 = 0$
- - $\frac{\partial f(x,y)}{\partial z} = 1$
- - $-1 > 1$
- correct: [1, 1, 1, -1, -1]
- # optional
- title: Expressões matemáticas
- shuffle: True
- discount: True
- hint: Duas delas são falsas.
-# ---------------------------------------------------------------------------
--
- ref: our_planet1
- type: text
- text: O nosso planeta chama-se planeta...
- correct: ['Terra', 'terra']
-# ---------------------------------------------------------------------------
--
- ref: our_planet2
- type: text-regex
- text: O nosso planeta chama-se planeta...
- correct: !regex '[Tt]erra'
- # ---------------------------------------------------------------------------
--
- ref: fractions
- type: numeric-interval
- text: Quanto é 1/4?
- correct: [0.249, 0.251]
-# ---------------------------------------------------------------------------
--
- ref: basic-colors
- type: textarea
- text: Escreva o nome das três cores básicas em inglês.
- correct: correct/correct-question.py
- # opcional
- lines: 3
- timeout: 5
- hint: Qualquer ordem serve.
-# ---------------------------------------------------------------------------
--
- ref: question-whatever
- type: generator
- script: generators/generate-question.py
- # opcional
- arg: "11,120"
- # the script should print a question in yaml format.
- # Print only the dictionary, not the list of dictionaries like here.
-# ---------------------------------------------------------------------------
--
- ref: instructions
- type: alert
- title: Atenção
- text: |
- Deverá indicar em cada pergunta se pretende ou não classificá-la. Se não quiser responder a uma questão, desactive-a para evitar penalizações na nota final.
-
-# ---------------------------------------------------------------------------
--
- ref: markdown_instructions
- type: information
- title: Que mais se pode incluir nas perguntas?
-
- # allow these files will be served:
- files:
- imagem_privada: images/flag-pt.svg
-
- text: |
- O texto das perguntas é escrito em __markdown__ e pode incluir algumas *tags* __html__. É usado __MathJax__ para gerar fórmulas matemáticas com a *syntax* do __LaTeX__.
-
- ### LaTeX
-
- As soluções da equação $ax^2+bx+c=0$ são obtidas com a fórmula resolvente:
- $$
- x = \frac{-b\pm\sqrt{b^2-4ac}}{2a}
- $$
-
- ### Código
-
- Suporta *syntax highlight* em múltiplas linguagens.
-
- C:
- ```C
- int main() {
- printf("Hello world!");
- return 0; // comentario
- }
- ```
-
- Python:
- ```python
- def myfunc(x, y):
- 'returna soma dos argumentos'
- return x + y + 1.0 # mais uma unidade
- ```
-
- Java:
- ```java
- public class HelloWorld {
- public static void main(String[] args) {
- // tanta coisa para dizer ola...
- System.out.println("Hello, World");
- }
- }
- ```
-
- ### Tabelas
-
- Left | Center | Right
- -----------------|:-------------:|----------:
- $\sin(x^2)$ | *hello* | $1600.00
- $\frac{1}{2\pi}$ | **world** | $12.50
- $\sqrt{\pi}$ | `code` | $1.99
-
- ---
-
- (c) By the author
\ No newline at end of file
diff --git a/demo/test.yaml b/demo/test.yaml
deleted file mode 100644
index 1f8f44d..0000000
--- a/demo/test.yaml
+++ /dev/null
@@ -1,74 +0,0 @@
-#=============================================================================
-# The test reference should be a unique identifier. It is saved in the database
-# so that queries for the results can be done in the terminal with
-# $ sqlite3 students.db "select * from tests where ref='demo'"
-ref: demo
-
-# (optional, default: '') You may wish to refer the course, year or kind of test
-title: Teste de Demonstração
-
-# (optional) duration in minutes FIXME
-duration: 90
-
-# Database with student credentials and grades of all questions and tests done
-# The database is an sqlite3 file generate with the script initdb.py
-database: demo/students.db
-
-# Generate a file for each test done by a student.
-# It includes the questions, answers and grades.
-answers_dir: demo/ans
-
-# (optional, default: False) Show points for each question, scale 0-20.
-show_points: True
-
-# (optional, default: False) Show hints if available
-show_hints: True
-
-# (optional, default: False) Show lots of information for debugging
-# debug: True
-
-#-----------------------------------------------------------------------------
-# Base path applied to the questions files and all the scripts
-# including question generators and correctors.
-# Either absolute path or relative to current directory can be used.
-questions_dir: demo/questions
-
-# (optional) List of files containing questions in yaml format.
-# Selected questions will be obtained from these files.
-# If undefined, all yaml files in questions_dir are loaded (not recommended).
-files:
- - questions.yaml
-
-# This is the list of questions that will make up the test.
-# The order is preserved.
-# There are several ways to define each question (explained below).
-questions:
- # show question where ref=instructions
- # - ref: instructions
-
- # show question where ref=flags and assigns 0.5 points (unnormalized)
- - ref: flags
- points: 0.5
-
- # idem
- - ref: math-expressions
- points: 2.0
-
- # # show question where ref=solar-system and assign the default of 1.0 point (unnormalized)
- - ref: solar-system
-
- # # select one questions from the list [our_planet1, our_planet2]
- # # and assign 0.75 points (unnormalized)
- - ref:
- - our_planet1
- - our_planet2
- points: 0.75
-
- # # the key 'ref:' can be omitted, a default of 1.0 points is assigned
- - basic-colors
-
- - fractions
-
- - question-whatever
-
- - markdown_instructions
diff --git a/templates/test.html b/templates/test.html
index 0ee00ee..9e3300e 100644
--- a/templates/test.html
+++ b/templates/test.html
@@ -10,7 +10,7 @@
diff --git a/tools.py b/tools.py
index 966195d..a2e7e6b 100644
--- a/tools.py
+++ b/tools.py
@@ -1,37 +1,143 @@
+# builtin
from os import path
import subprocess
import logging
+import re
+# packages
import yaml
-# import markdown
import mistune
+# from markdown import markdown
from pygments import highlight
from pygments.lexers import get_lexer_by_name
-from pygments.formatters import html
+from pygments.formatters import HtmlFormatter
# setup logger for this module
logger = logging.getLogger(__name__)
# ---------------------------------------------------------------------------
+# Markdown to HTML renderer with support for LaTeX equations
+# Inline math: $x$
+# Block math: $$x$$ or \begin{equation}x\end{equation}
+# ---------------------------------------------------------------------------
+class MathBlockGrammar(mistune.BlockGrammar):
+ block_math = re.compile(r"^\$\$(.*?)\$\$", re.DOTALL)
+ latex_environment = re.compile(r"^\\begin\{([a-z]*\*?)\}(.*?)\\end\{\1\}", re.DOTALL)
+
+
+class MathBlockLexer(mistune.BlockLexer):
+ default_rules = ['block_math', 'latex_environment'] + mistune.BlockLexer.default_rules
+
+ def __init__(self, rules=None, **kwargs):
+ if rules is None:
+ rules = MathBlockGrammar()
+ super().__init__(rules, **kwargs)
+
+ def parse_block_math(self, m):
+ """Parse a $$math$$ block"""
+ self.tokens.append({
+ 'type': 'block_math',
+ 'text': m.group(1)
+ })
+
+ def parse_latex_environment(self, m):
+ self.tokens.append({
+ 'type': 'latex_environment',
+ 'name': m.group(1),
+ 'text': m.group(2)
+ })
+
+
+class MathInlineGrammar(mistune.InlineGrammar):
+ math = re.compile(r"^\$(.+?)\$", re.DOTALL)
+ block_math = re.compile(r"^\$\$(.+?)\$\$", re.DOTALL)
+ text = re.compile(r'^[\s\S]+?(?=[\\
{mistune.escape(code)}
\n'
- else:
+ def block_code(self, code, lang='text'):
+ try:
lexer = get_lexer_by_name(lang, stripall=True)
- formatter = html.HtmlFormatter()
- return highlight(code, lexer, formatter)
+ except:
+ lexer = get_lexer_by_name('text', stripall=True)
+
+ formatter = HtmlFormatter()
+ return "{open_block}{formatted}{close_block}".format(
+ open_block="