Cómo escribo notas matemáticas en LaTeX en Vim

Hace algún tiempo, en Quora, respondí la pregunta: cómo mantenerse al día con las notas de la clase de matemáticas en LaTeX . Allí expliqué mi flujo de trabajo para tomar notas en LaTeX usando Vim e Inkscape (para dibujos). Pero desde entonces, mucho ha cambiado, por lo que quiero publicar varias publicaciones de blog que describan el nuevo proceso. Este es el primero de los artículos.

Comencé a usar LaTeX para tomar notas en el segundo semestre de un curso de matemáticas, y desde entonces he escrito más de 1700 páginas. Estos son algunos ejemplos de cómo se ve el resumen:







Estas notas, incluidos los dibujos, se realizan directamente en la conferencia y no se editan posteriormente. Para escribir resúmenes de manera eficiente en LaTeX, se deben seguir cuatro reglas:

  • Escribir texto y fórmulas en LaTeX debe ser tan rápido como un profesor escribiendo en la pizarra: el retraso es inaceptable.
  • Dibujar ilustraciones debe ser casi tan rápido como el del profesor.
  • Administrar notas, es decir, agregar notas, organizar todas las notas, las dos últimas conferencias, buscar notas, etc., debe ser rápido y fácil.
  • Debería ser posible anotar documentos pdf usando LaTeX si quiero escribir una nota con un documento pdf.

Este artículo trata sobre el primer punto: tomar notas sobre LaTeX.

Vim y LaTeX


Para escribir fórmulas matemáticas y de texto en LaTeX, uso Vim. Este es un poderoso editor de texto de propósito general, altamente extensible. Lo uso para escribir código, LaTeX, texto de Markdown ... en general, cualquier texto. Tiene una curva de aprendizaje bastante empinada, pero si ha dominado la base, ya es difícil volver al editor sin las teclas de acceso rápido habituales. Así es como se ve mi pantalla cuando edito un documento de LaTeX:



A la izquierda está Vim, y a la derecha está el visor de PDF Zathura , que también es compatible con los atajos de teclado de estilo Vim. Trabajo en Ubuntu con el administrador de ventanas bspwm . Como complemento, LaTeX instaló vimtex . Proporciona resaltado de sintaxis, tabla de contenido, synctex, etc. Usando el conector vim, lo configuré de la siguiente manera:

Plug 'lervag/vimtex'
let g:tex_flavor='latex'
let g:vimtex_view_method='zathura'
let g:vimtex_quickfix_mode=0
set conceallevel=1
let g:tex_conceal='abdmg'


Las dos últimas líneas ajustan el disfraz. Esta es una función en la que el código LaTeX se reemplaza o se vuelve invisible cuando el cursor no está en esta línea. Si oculta \ [ , \] , $ , entonces no son tan visibles, lo que proporciona una mejor visión general del documento. Esta función también reemplaza \bigcap con , \in con , etc., como se muestra en la animación:



Con esta configuración, puede lograr la tarea: escribir en LaTeX tan rápido como un profesor escribe en la pizarra. Los fragmentos entran en juego aquí.

Fragmentos


¿Qué es un fragmento?


Un fragmento es un fragmento breve de texto reutilizable que es invocado por otro texto. Por ejemplo, al escribir el signo y presionar Tab, el signo de la palabra se convierte en una firma:



Los fragmentos pueden ser dinámicos: cuando escribo today y presiono Tab , la palabra today se reemplaza por la fecha actual y el box - Tab convierte en un campo que aumenta automáticamente de tamaño.





Incluso puedes usar un fragmento dentro de otro:



Crear fragmentos con UltiSnips


Para controlar fragmentos, utilizo el complemento UltiSnips . Aquí está su configuración:

 Plug 'sirver/ultisnips' let g:UltiSnipsExpandTrigger = '<tab>' let g:UltiSnipsJumpForwardTrigger = '<tab>' let g:UltiSnipsJumpBackwardTrigger = '<s-tab>' 

Código para el sign fragmento:

 snippet sign "Signature" Yours sincerely, Gilles Castel endsnippet 

Para fragmentos dinámicos, puede poner el código entre las comillas inversas, este código se ejecutará cuando se extienda el fragmento. Aquí usé bash para formatear la fecha actual: date + %F

 snippet today "Date" `date +%F` endsnippet 

Dentro del bloque `!p ... ` , puedes escribir en Python. Mire el código para el fragmento de box :

 snippet box "Box" `!p snip.rv = '┌' + '─' * (len(t[1]) + 2) + '┐'` │ $1 │ `!p snip.rv = '└' + '─' * (len(t[1]) + 2) + '┘'` $0 endsnippet 

En lugar de este código, el valor de la variable snip.rv se insertará en el documento. Dentro de los bloques, tiene acceso al estado actual del fragmento, por ejemplo, t[1] corresponde al lugar de la primera pestaña, fn nombre del archivo actual, etc.

Fragmentos de LaTeX


Los fragmentos aceleran significativamente el trabajo, especialmente algunos de los fragmentos más complejos. Comencemos con lo más simple.

El medio ambiente


Para insertar un entorno, simplemente ingrese beg al comienzo de la línea. Luego, el nombre del entorno, que se refleja en el comando \end{} . Al presionar Tab coloca el cursor dentro.



El código es el siguiente:

 snippet beg "begin{} / end{}" bA \begin{$1} $0 \end{$1} endsnippet 

El símbolo b significa que dicho fragmento funciona solo al comienzo de una línea, A significa expansión automática, es decir, no es necesario presionar Tab . Las pestañas donde vayas presionando Tab y Shift + Tab se denotan como $1 , $2 , ... y este último se denota como $0 .

Fórmulas en línea y de visualización


Los dos fragmentos más utilizados son mk y dm , que activan el modo matemático. El primero para las fórmulas en línea, el segundo para las que se muestran.



Fragmento de fórmula inteligente: sabe cuándo insertar un espacio después del signo de dólar. Cuando empiezo a escribir una palabra inmediatamente después del cierre $, agrega un espacio. Pero si escribo otro carácter, entonces no agrega un espacio, como en el caso de '$ p $ -value'.



El código para este fragmento es:

 snippet mk "Math" wA $${1}$`!p if t[2] and t[2][0] not in [',', '.', '?', '-', ' ']: snip.rv = ' ' else: snip.rv = '' `$2 endsnippet 

W al final de la primera línea significa que el fragmento se expande solo en los límites de las palabras. Por lo tanto, por ejemplo, hellomk no funcionará y hello mk funcionará.

El fragmento de las fórmulas mostradas es más simple, pero también bastante conveniente. Siempre hace que las ecuaciones terminen con un punto.



 <snippet dm "Math" wA \[ $1 .\] $0 endsnippet 

Subíndice y caracteres superíndice


Otro fragmento útil es para los índices. Cambia a1 a a_1 y a_12 a a_{12} .



El código para este fragmento utiliza una expresión regular como desencadenante. Expande el fragmento cuando ingresa un carácter seguido de un dígito codificado como [A-Za-z]\d , o un carácter seguido de _ y dos dígitos: [A-Za-z]_\d\d .

 snippet '([A-Za-z])(\d)' "auto subscript" wrA `!p snip.rv = match.group(1)`_`!p snip.rv = match.group(2)` endsnippet snippet '([A-Za-z])_(\d\d)' "auto subscript2" wrA `!p snip.rv = match.group(1)`_{`!p snip.rv = match.group(2)`} endsnippet 

Cuando combina partes de una expresión regular en un grupo usando paréntesis, por ejemplo, (\d\d) , puede usarlos en la extensión de fragmento a través de match.group(i) en Python.

Para los caracteres en superíndice, uso td , que se convierte en ^{} . Aunque para los más comunes (cuadrado, cubo y varios otros), se pretenden fragmentos separados, como sr , cb y comp .



 snippet sr "^2" iA ^2 endsnippet snippet cb "^3" iA ^3 endsnippet snippet compl "complement" iA ^{c} endsnippet snippet td "superscript" iA ^{$1}$0 endsnippet 

Fracción


Uno de los fragmentos más convenientes funciona con fracciones. Realiza los siguientes reemplazos:

//\frac{}{}
3/\frac{3}{}
4\pi^2/\frac{4\pi^2}{}
(1 + 2 + 3)/\frac{1 + 2 + 3}{}
(1+(2+3)/)(1 + \frac{2+3}{})
(1 + (2+3))/\frac{1 + (2+3)}{}



Para el primero, un código simple:

 snippet // "Fraction" iA \\frac{$1}{$2}$0 endsnippet 

Las sustituciones segunda y tercera se producen con la ayuda de expresiones regulares correspondientes a las expresiones 3/ , 4ac/ , 6\pi^2/ , a_2/ , etc.

 snippet '((\d+)|(\d*)(\\)?([A-Za-z]+)((\^|_)(\{\d+\}|\d))*)/' "Fraction" wrA \\frac{`!p snip.rv = match.group(1)`}{$1}$0 endsnippet 

Como puede ver, las expresiones regulares pueden llegar a ser bastante largas, pero aquí hay un diagrama que debería explicar todo:



En el cuarto y quinto casos, el fragmento intenta encontrar el soporte correspondiente. Como el motor de expresiones regulares UltiSnips no sabe cómo hacer esto, tuve que usar Python:

 priority 1000 snippet '^.*\)/' "() Fraction" wrA `!p stripped = match.string[:-1] depth = 0 i = len(stripped) - 1 while True: if stripped[i] == ')': depth += 1 if stripped[i] == '(': depth -= 1 if depth == 0: break; i -= 1 snip.rv = stripped[0:i] + "\\frac{" + stripped[i+1:-1] + "}" `{$1}$0 endsnippet 

Finalmente, quiero compartir un fragmento que convierte la selección actual en una fracción. Seleccione el texto, presione Tab , escriba / y nuevamente Tab .



El código usa la variable ${VISUAL} , que refleja su elección.

 snippet / "Fraction" iA \\frac{${VISUAL}}{$1}$0 endsnippet 

Sympy y Mathematica


Otro fragmento interesante pero menos usado se ejecuta simétricamente para evaluar las expresiones matemáticas. Por ejemplo: sympy Tab expande a sympy | sympy sympy | sympy , y sympy 1 + 1 sympy Tab convierte en 2 .



 snippet sympy "sympy block " w sympy $1 sympy$0 endsnippet priority 10000 snippet 'sympy(.*)sympy' "evaluate sympy" wr `!p from sympy import * x, y, z, t = symbols('xyz t') k, m, n = symbols('km n', integer=True) f, g, h = symbols('fg h', cls=Function) init_printing() snip.rv = eval('latex(' + match.group(1).replace('\\', '') \ .replace('^', '**') \ .replace('{', '(') \ .replace('}', ')') + ')') ` endsnippet 

Para Mathematica, algo similar también es posible:



 priority 1000 snippet math "mathematica block" w math $1 math$0 endsnippet priority 10000 snippet 'math(.*)math' "evaluate mathematica" wr `!p import subprocess code = 'ToString[' + match.group(1) + ', TeXForm]' snip.rv = subprocess.check_output(['wolframscript', '-code', code]) ` endsnippet 

Fragmentos de Postfix


Me parece que vale la pena mencionar también fragmentos de postfix que insertan el texto apropiado después de ingresar ciertos caracteres. Por ejemplo, phat\hat{p} y zbar\overline{z} . Un fragmento similar inserta un vector, por ejemplo, v,.\vec{v} y v.,\vec{v} . El orden del punto y el punto y coma no importa, por lo que puedo hacer clic en ellos al mismo tiempo. Estos fragmentos realmente ahorran tiempo, porque los ingresa a la misma velocidad que un profesor escribe en la pizarra.



Tenga en cuenta que los prefijos de bar y hat siguen funcionando, solo que con una prioridad más baja. El código para estos fragmentos es:

 priority 10 snippet "bar" "bar" riA \overline{$1}$0 endsnippet priority 100 snippet "([a-zA-Z])bar" "bar" riA \overline{`!p snip.rv=match.group(1)`} endsnippet 

 priority 10 snippet "hat" "hat" riA \hat{$1}$0 endsnippet priority 100 snippet "([a-zA-Z])hat" "hat" riA \hat{`!p snip.rv=match.group(1)`} endsnippet 

 snippet "(\\?\w+)(,\.|\.,)" "Vector postfix" riA \vec{`!p snip.rv=match.group(1)`} endsnippet 

Otros fragmentos


Todavía tengo alrededor de un centenar de fragmentos de uso común. Todos ellos están disponibles aquí . La mayoría de ellos son bastante simples. Por ejemplo, !> convierte en \mapsto , -> convierte en \to , etc.



fun transforma en f: \R \to \R : , !>\mapsto , cc\subset .



lim convierte en \lim_{n \to \infty} , sum\sum_{n = 1}^{\infty} , ooo\infty .





Fragmentos específicos del curso


Además de los de uso frecuente, también tengo fragmentos específicos. Se cargan como una sola línea en .vimrc :

 set rtp+=~/current_course 

Aquí current_course es un enlace simbólico al curso actual (más sobre esto en otro artículo). En esta carpeta está el archivo ~/current_course/UltiSnips/tex.snippets , donde agrego fragmentos de curso. Por ejemplo, para la mecánica cuántica, hay fragmentos para registrar los estados cuánticos de apliques y cetos.

<a|\bra{a}
<q|\bra{\psi}
|a>\ket{a}
|q>\ket{\psi}
\braket{a}{b}\braket{a}{b}

Como la mecánica cuántica a menudo usa \psi , reemplacé automáticamente todos los q en braket con \psi .



 snippet "\<(.*?)\|" "bra" riA \bra{`!p snip.rv = match.group(1).replace('q', f'\psi').replace('f', f'\phi')`} endsnippet snippet "\|(.*?)\>" "ket" riA \ket{`!p snip.rv = match.group(1).replace('q', f'\psi').replace('f', f'\phi')`} endsnippet snippet "(.*)\\bra{(.*?)}([^\|]*?)\>" "braket" riA `!p snip.rv = match.group(1)`\braket{`!p snip.rv = match.group(2)`}{`!p snip.rv = match.group(3).replace('q', f'\psi').replace('f', f'\phi')`} endsnippet 

Contexto


Al escribir estos fragmentos, debe considerar si se pueden encontrar en texto sin formato. Por ejemplo, según mi diccionario, hay alrededor de 72 palabras en inglés y 2,000 palabras en holandés con sr. Por lo tanto, cuando di^2egard disregard , sr cambia a ^2 , y obtenemos di^2egard .

La solución a este problema es agregar contexto a los fragmentos. El resaltado de sintaxis de Vim determina si UltiSnips debe usar un fragmento, dependiendo de si está en modo fórmula o texto. Se me ocurrió esta opción:

 global !p texMathZones = ['texMathZone'+x for x in ['A', 'AS', 'B', 'BS', 'C', 'CS', 'D', 'DS', 'E', 'ES', 'F', 'FS', 'G', 'GS', 'H', 'HS', 'I', 'IS', 'J', 'JS', 'K', 'KS', 'L', 'LS', 'DS', 'V', 'W', 'X', 'Y', 'Z']] texIgnoreMathZones = ['texMathText'] texMathZoneIds = vim.eval('map('+str(texMathZones)+", 'hlID(v:val)')") texIgnoreMathZoneIds = vim.eval('map('+str(texIgnoreMathZones)+", 'hlID(v:val)')") ignore = texIgnoreMathZoneIds[0] def math(): synstackids = vim.eval("synstack(line('.'), col('.') - (col('.')>=2 ? 1 : 0))") try: first = next( i for i in reversed(synstackids) if i in texIgnoreMathZoneIds or i in texMathZoneIds ) return first != ignore except StopIteration: return False endglobal 

Ahora puede agregar el context "math()" a esos fragmentos que desea aplicar solo en un contexto matemático.

 context "math()" snippet sr "^2" iA ^2 endsnippet 

Tenga en cuenta que el contexto matemático es algo sutil. Algunas veces en el modo fórmula también escribimos texto usando \text{...} . En este caso, no queremos usar fragmentos. Sin embargo, en el siguiente caso: \[ \text{$...$} \] , deben aplicarse. Es por eso que el código para el contexto math no es tan simple. La siguiente animación ilustra estas sutilezas.



Corrección ortográfica sobre la marcha


Aunque las fórmulas son una parte importante del resumen, imprimo la mayor parte del tiempo en inglés. Alrededor de 80 palabras por minuto, mis habilidades de escritura son bastante buenas, pero hago muchos errores tipográficos. Es por eso que agregué un enlace a Vim que corrige los errores ortográficos sin interferir con el trabajo. Cuando Ctrl+L durante la entrada, se corrige el error de ortografía anterior. Se ve así:



Mi configuración para la corrección ortográfica:

 setlocal spell set spelllang=nl,en_gb inoremap <Cl> <cg>u<Esc>[s1z=`]a<cg>u 

Aquí, vaya al error de ortografía anterior [s , luego seleccione la primera opción 1z= y devuelva `]a . Los comandos <cg>u en el medio le permiten deshacer rápidamente la corrección.

En conclusión


Gracias a los fragmentos de Vim, escribir código LaTeX ya no es molesto, sino más bien un placer. En combinación con la ortografía sobre la marcha, esto le permite esbozar conveniente y rápidamente conferencias sobre matemáticas. En el próximo artículo, hablaré sobre otros temas, como dibujar ilustraciones digitalmente e insertarlas en un documento de LaTeX.

Source: https://habr.com/ru/post/445066/


All Articles