Referencia completa para la aplicación EEditor y el lenguaje EELisp. Cubre cada funcionalidad, cada función integrada y cada atajo de teclado.
Cuando inicias EEditor por primera vez, ves un editor vacío con una barra lateral. Tres pasos para empezar:
Usa ⌘⇧O para abrir un archivo individual desde cualquier ubicación del disco. El directorio padre del archivo se convierte en la carpeta activa.
EEditor proporciona un entorno de escritura libre de distracciones con resaltado de sintaxis en tiempo real para Markdown y más de 24 lenguajes de programación.
YYYY-MM-DD HH:mm en la posición del cursor.[[nombre_archivo]] y pulsa ⌘O para abrir ese archivo.La barra lateral muestra una vista jerárquica de tu carpeta. Los directorios se ordenan primero, luego los archivos alfabéticamente.
subcarpeta/archivo.md para crear archivos anidados..el o .lisp para ejecutarlo.La barra lateral tiene tres modos mediante el control segmentado: Archivos, Calendario y Agenda.
Cada archivo se abre como una pestaña en la parte superior del editor.
| Acción | Atajo | Notas |
|---|---|---|
| Siguiente pestaña | ⌘⌥→ | Vuelve al inicio |
| Pestaña anterior | ⌘⌥← | Vuelve al inicio |
| Cerrar pestaña | ⌘W | Guarda automáticamente si hay cambios |
| Cerrar todas las no fijadas | ⌘⌥W | |
| Fijar / Desfijar | ⌘⇧K | Las pestañas fijadas persisten entre sesiones |
Las pestañas fijadas muestran un icono de pin, aparecen primero (ordenadas alfabéticamente) y no se pueden cerrar hasta que se desfijen. Se restauran automáticamente al reiniciar.
Coloca el cursor sobre un enlace [[nombre_archivo]] y pulsa ⌘O para abrir ese archivo directamente.
YYYY-MM-DD.md en la raíz del proyecto, prerrellenado con un encabezado de fecha.Week of YYYY-MM-DD.md (lunes de la semana actual).Cambia la barra lateral al modo Calendario usando el control segmentado.
Cambia al modo Agenda mediante el icono del portapapeles. El panel muestra tu programación próxima en tres secciones:
:when anterior a hoy.Cada elemento muestra un punto de prioridad (rojo = urgente, naranja = alta, amarillo = media, gris = normal), texto, categorías y fecha formateada. Toca actualizar para recargar después de añadir elementos en el REPL.
El REPL es un panel en la barra lateral derecha que coexiste con el editor. Altérnalo con ⌘⇧L o el icono de terminal en la barra de herramientas.
Incorpora código EELisp ejecutable directamente en tus archivos Markdown usando bloques de código delimitados:
```eelisp
(+ 1 2 3)
```
```eelisp.```result inmediatamente debajo.```eelisp
(+ 1 2 3)
```
```result
6
```
Volver a ejecutar reemplaza el resultado existente. El resultado se inserta como texto plano (no en un bloque de código) y se selecciona automáticamente para que puedas usar ⌘C para copiar o ⌘X para cortar inmediatamente.
Cuando un bloque EELisp devuelve un formulario (edit, defform) o una tabla (browse), se abre como un panel lateral interactivo junto al editor en lugar de insertar texto plano. Puedes interactuar con el formulario — navegar registros, editar campos, guardar — manteniendo tu documento visible. Se inserta igualmente una línea de resumen en el documento.
Los casos de uso incluyen cálculos en línea, añadir elementos de agenda desde entradas de diario, consultar datos y operaciones con archivos:
```eelisp
(add-item (smart-parse "tomorrow review quarterly report !!"))
```
```eelisp
(write-file "todo.txt" "Buy groceries\nCall dentist")
```
Pulsa ⌘? en la aplicación para ver la hoja completa de atajos. Aquí está la referencia completa:
| Acción | Atajo |
|---|---|
| Nuevo archivo | ⌘N |
| Abrir carpeta | ⌘O |
| Abrir archivo | ⌘⇧O |
| Guardar | ⌘S |
| Actualizar árbol | ⌘⇧R |
| Nota diaria | ⌘D |
| Planificador semanal | ⌘⇧W |
| Acción | Atajo |
|---|---|
| Apertura rápida | ⌘P |
| Buscar en archivos | ⌘⇧F |
| Buscar y reemplazar | ⌘F |
| Enfocar editor | ⌘\ |
| Abrir wiki-link | ⌘O |
| Acción | Atajo |
|---|---|
| Siguiente pestaña | ⌘⌥→ |
| Pestaña anterior | ⌘⌥← |
| Cerrar pestaña | ⌘W |
| Cerrar todas las no fijadas | ⌘⌥W |
| Fijar / Desfijar pestaña | ⌘⇧K |
| Acción | Atajo |
|---|---|
| Insertar marca de tiempo | ⌘I |
| Deshacer | ⌘Z |
| Rehacer | ⌘⇧Z |
| Acción | Atajo |
|---|---|
| Vista previa | ⌘⇧P |
| Exportar PDF | ⌘⇧E |
| Alternar barra lateral del REPL | ⌘⇧L |
| Enviar al REPL | ⌘R |
| Ejecutar bloque EELisp | ⌘⇧Return |
| Insertar bloque EELisp | ⌘⇧C |
| Ejecutar (en el REPL) | ⌘Return |
| Ayuda de atajos | ⌘? |
EEditor incluye un intérprete Lisp integrado llamado EELisp — diseñado para la gestión de datos personales, cálculos y scripting.
> y pulsa ⌘Return para evaluar... y espera más entrada. Una barra de pistas muestra ⌘↩ para ejecutar · ⎋ para cancelar.Selecciona texto en el editor y pulsa ⌘R o ⌘⇧L. La barra lateral del REPL se abre con tu selección prerrellenada en el campo de entrada, lista para que pulses ⌘Return para evaluar.
EELisp incluye funciones integradas y comandos del REPL para gestionar bases de datos:
| Comando | Descripción |
|---|---|
(tables) | Listar todas las tablas de la base de datos actual |
(describe tablename) | Mostrar el esquema de una tabla |
(drop-table tablename) | Eliminar una tabla |
:db | Mostrar la ruta de la base de datos actual |
:db <path> | Cambiar a un archivo de base de datos diferente |
:db new <name> | Crear un nuevo archivo de base de datos en la carpeta actual |
:db memory | Cambiar a una base de datos en memoria |
Usa :load path/to/file.el para cargar y evaluar un script EELisp. En iOS, toca el botón Cargar en la barra de herramientas o haz clic derecho en un archivo .el en la barra lateral.
En iOS/iPadOS, aparece una barra de herramientas con: navegación del historial (↑/↓), fragmentos rápidos (query, deftable, defn), Cargar archivo y Limpiar.
Los comandos con prefijo de dos puntos controlan el propio REPL (no son expresiones EELisp):
| Comando | Alias | Descripción |
|---|---|---|
:help | :h | Mostrar referencia de comandos y ejemplos rápidos |
:load <file> | :l | Cargar y evaluar un archivo .el / .lisp |
:db | Mostrar la ruta de la base de datos actual (:memory: o ruta de archivo) | |
:db <path> | Cambiar a un archivo de base de datos diferente | |
:db new <name> | Crear una nueva base de datos en la carpeta actual | |
:db memory | Cambiar a una base de datos en memoria | |
:env | :e | Listar todos los símbolos definidos en el entorno |
:clear | :c | Limpiar el historial de salida del REPL |
:reset | :r | Reiniciar el intérprete (entorno nuevo, misma base de datos) |
eelisp.db, el REPL se conecta automáticamente para almacenamiento persistente. Los datos creados con deftable e insert se guardan en disco.
Todos los operadores aritméticos son variádicos (aceptan múltiples argumentos) y funcionan con enteros y decimales.
| Función | Firma | Descripción |
|---|---|---|
+ | (+ num ...) | Suma. (+ 1 2 3) → 6 |
- | (- num ...) | Resta o negación. (- 10 3) → 7, (- 5) → -5 |
* | (* num ...) | Multiplicación. (* 2 3 4) → 24 |
/ | (/ num num ...) | División. (/ 100 3) → 33.333... |
mod | (mod a b) | Módulo. (mod 10 3) → 1 |
abs | (abs num) | Valor absoluto. (abs -42) → 42 |
min | (min num ...) | Mínimo. (min 3 1 4) → 1 |
max | (max num ...) | Máximo. (max 3 1 4) → 4 |
floor | (floor num) | Redondear hacia abajo. (floor 3.7) → 3 |
ceil | (ceil num) | Redondear hacia arriba. (ceil 3.2) → 4 |
pow | (pow base exp) | Exponenciación. (pow 2 10) → 1024 |
round | (round num [places]) | Redondear. (round 3.14159 2) → 3.14 |
;; Ejemplos aritméticos (+ 1 2 3 4) ; → 10 (* 6 7) ; → 42 (/ 100 3) ; → 33.333... (pow 2 10) ; → 1024 (round 3.14159 2) ; → 3.14 ;; Anidamiento (+ (* 3 4) (- 10 5)) ; → 17
| Función | Firma | Descripción |
|---|---|---|
= | (= a b) | Igualdad. Funciona con números, cadenas, booleanos |
!= | (!= a b) | Desigualdad |
< | (< a b) | Menor que |
> | (> a b) | Mayor que |
<= | (<= a b) | Menor o igual que |
>= | (>= a b) | Mayor o igual que |
Estas son formas especiales (evaluación en cortocircuito):
(and true false) ; → false (or false true) ; → true (not true) ; → false ;; Cortocircuito: (or) devuelve el primer valor verdadero (or nil false 42 99) ; → 42
(def x 42) (def greeting "Hello, world!") (def pi 3.14159)
(defn square (x) (* x x)) (square 5) ; → 25 ;; Cuerpo con múltiples expresiones (se devuelve el último valor) (defn greet (name) (def msg (str "Hello, " name "!")) (println msg) msg)
(map (fn (x) (* x x)) '(1 2 3)) ; → (1 4 9)
(defn sum (first . rest) (reduce + first rest)) (sum 1 2 3 4 5) ; → 15
(let ((x 1) (y 2)) (+ x y)) ; → 3
(if (> x 0) "positive" "non-positive")
(cond (< x 0) "negative" (= x 0) "zero" else "positive")
;; Ejecutar el cuerpo solo si la condición es verdadera (when (> x 0) (println "positive!") x)
;; Sumar de 0 a 10 (loop ((i 0) (acc 0)) (> i 10) (recur (+ i 1) (+ acc i))) ; → 55
;; Evaluar múltiples expresiones, devolver la última (begin (def a 10) (def b 20) (+ a b)) ; → 30
| Función | Firma | Ejemplo → Resultado |
|---|---|---|
str | (str val ...) | (str "a" "b" "c") → "abc" |
str-len | (str-len s) | (str-len "hello") → 5 |
str-upper | (str-upper s) | (str-upper "hello") → "HELLO" |
str-lower | (str-lower s) | (str-lower "HELLO") → "hello" |
str-contains | (str-contains s sub) | (str-contains "hello" "ell") → true |
str-starts-with | (str-starts-with s prefix) | (str-starts-with "hello" "he") → true |
str-ends-with | (str-ends-with s suffix) | (str-ends-with "hello" "lo") → true |
str-split | (str-split s sep) | (str-split "a,b,c" ",") → ("a" "b" "c") |
str-join | (str-join sep list) | (str-join "-" '("a" "b")) → "a-b" |
str-trim | (str-trim s) | (str-trim " hi ") → "hi" |
str-replace | (str-replace s target repl) | (str-replace "hello" "l" "r") → "herro" |
str-matches | (str-matches s regex) | Devuelve la lista de grupos de captura o nil |
substr | (substr s start [end]) | (substr "hello" 1 3) → "el" |
| Función | Firma | Ejemplo → Resultado |
|---|---|---|
list | (list val ...) | (list 1 2 3) → (1 2 3) |
cons | (cons val list) | (cons 0 '(1 2)) → (0 1 2) |
car / head | (car list) | (car '(1 2 3)) → 1 |
cdr / tail | (cdr list) | (cdr '(1 2 3)) → (2 3) |
nth | (nth list n) | (nth '(a b c) 1) → b |
length | (length seq) | (length '(1 2 3)) → 3 |
append | (append list ...) | (append '(1) '(2 3)) → (1 2 3) |
reverse | (reverse list) | (reverse '(1 2 3)) → (3 2 1) |
map | (map fn list) | (map inc '(1 2 3)) → (2 3 4) |
filter | (filter fn list) | (filter even? '(1 2 3 4)) → (2 4) |
reduce | (reduce fn init list) | (reduce + 0 '(1 2 3)) → 6 |
range | (range [start] end [step]) | (range 1 6) → (1 2 3 4 5) |
flatten | (flatten list) | (flatten '(1 (2 3) (4))) → (1 2 3 4) |
sort-by | (sort-by fn list) | (sort-by id '(3 1 2)) → (1 2 3) |
zip | (zip list list) | (zip '(1 2) '(a b)) → ((1 a) (2 b)) |
empty? | (empty? val) | (empty? '()) → true |
;; Encadenar operaciones de listas (def nums (range 1 11)) (filter even? nums) ; → (2 4 6 8 10) (map (fn (x) (* x x)) (filter even? nums)) ; → (4 16 36 64 100) (reduce + 0 (range 1 101)) ; → 5050
Los diccionarios usan claves de tipo keyword (:name) y son inmutables — las operaciones devuelven nuevos diccionarios.
| Función | Firma | Ejemplo → Resultado |
|---|---|---|
dict | (dict :key val ...) | (dict :a 1 :b 2) → {:a 1 :b 2} |
dict-get | (dict-get d key [default]) | (dict-get d :name) → valor o nil |
dict-set | (dict-set d key val) | Devuelve un nuevo diccionario con la clave establecida |
dict-keys | (dict-keys d) | (dict-keys {:a 1 :b 2}) → (:a :b) |
dict-values | (dict-values d) | (dict-values {:a 1 :b 2}) → (1 2) |
dict-has | (dict-has d key) | (dict-has {:a 1} :a) → true |
dict-merge | (dict-merge d ...) | Fusiona diccionarios; las claves posteriores tienen prioridad |
(def person {:name "Alice" :age 30}) (dict-get person :name) ; → "Alice" (dict-set person :age 31) ; → {:name "Alice" :age 31} (dict-merge person {:city "NYC"}) ; → {:name "Alice" :age 30 :city "NYC"}
| Función | Devuelve verdadero cuando |
|---|---|
string? | El valor es una cadena de texto |
number? | El valor es un número |
bool? | El valor es un booleano |
list? | El valor es una lista |
nil? | El valor es nil/null |
symbol? | El valor es un símbolo |
keyword? | El valor es una keyword |
fn? | El valor es una función |
dict? | El valor es un diccionario |
date? | El valor es una fecha |
record? | El valor es un registro de base de datos |
item? | El valor es un elemento de agenda |
(type 42) ; → "number" (type "hello") ; → "string" (type '(1 2)) ; → "list"
| Función | Descripción |
|---|---|
->string | Convertir cualquier valor a su representación en cadena de texto |
->number | Convertir cadena a número, booleano a 0/1 |
->bool | Veracidad: nil, false, 0, "" → false; todo lo demás → true |
| Función | Descripción |
|---|---|
(print val ...) | Imprime valores sin salto de línea final |
(println val ...) | Imprime valores con salto de línea final |
| Función | Firma | Descripción |
|---|---|---|
now | (now) | Objeto de fecha/hora actual |
today | (today) | Hoy como cadena ISO "YYYY-MM-DD" |
date-format | (date-format date [fmt]) | Formatea una fecha. Por defecto: "yyyy-MM-dd HH:mm" |
date-add | (date-add date n :unit) | Añade días/semanas/meses. Unidades: :days, :weeks, :months |
date-diff | (date-diff d1 d2) | Diferencia en días entre dos cadenas de fecha ISO |
(today) ; → "2026-02-23" (date-add (today) 7 :days) ; → "2026-03-02" (date-add "2026-01-31" 1 :months) ; → "2026-02-28" (date-diff "2026-01-01" "2026-12-31") ; → 364
Estas funciones están definidas en el propio EELisp y se cargan automáticamente al inicio:
| Función | Descripción | Ejemplo |
|---|---|---|
inc | Incrementar en 1 | (inc 5) → 6 |
dec | Decrementar en 1 | (dec 5) → 4 |
even? | Verdadero si es par | (even? 4) → true |
odd? | Verdadero si es impar | (odd? 3) → true |
zero? | Verdadero si es cero | (zero? 0) → true |
pos? | Verdadero si es positivo | (pos? 5) → true |
neg? | Verdadero si es negativo | (neg? -3) → true |
first | Primer elemento | (first '(a b c)) → a |
second | Segundo elemento | (second '(a b c)) → b |
third | Tercer elemento | (third '(a b c)) → c |
last | Último elemento | (last '(a b c)) → c |
take | Tomar los primeros n | (take 2 '(a b c)) → (a b) |
drop | Descartar los primeros n | (drop 1 '(a b c)) → (b c) |
some? | ¿Alguna coincidencia? | (some? even? '(1 2 3)) → true |
every? | ¿Todas coinciden? | (every? pos? '(1 2 3)) → true |
pipe | Encadenamiento | (pipe 5 inc inc square) → 49 |
compose | Componer funciones | ((compose inc square) 5) → 26 |
partial | Aplicación parcial | ((partial + 10) 5) → 15 |
id | Función identidad | (id 42) → 42 |
| Función | Firma | Descripción |
|---|---|---|
http-get | (http-get url) | Petición GET. Devuelve {:status N :body "..."} |
http-post | (http-post url body [:content-type "..."]) | Petición POST con cuerpo |
json-parse | (json-parse string) | Analiza JSON a diccionario/lista de EELisp |
json-stringify | (json-stringify value) | Convierte un valor de EELisp a cadena JSON |
;; Obtener datos de una API (def resp (http-get "https://api.example.com/data")) (def data (json-parse (dict-get resp :body))) ;; Enviar JSON (http-post "https://api.example.com/items" (json-stringify {:name "test"}) :content-type "application/json")
| Función | Descripción |
|---|---|
(eval expr) | Evalúa una expresión no evaluada |
(parse string) | Analiza una cadena como código EELisp |
EELisp puede leer y escribir archivos en la carpeta abierta. Todas las rutas son relativas al directorio del espacio de trabajo actual.
| Función | Descripción |
|---|---|
(read-file path) | Lee el contenido de un archivo como cadena |
(write-file path content) | Escribe contenido en un archivo (crea o sobrescribe) |
(append-file path content) | Añade contenido a un archivo existente |
(file-exists? path) | Comprueba si un archivo existe |
(list-files [path]) | Lista los nombres de archivos en un directorio (por defecto: raíz del espacio de trabajo) |
(current-dir) | Obtiene la ruta raíz del espacio de trabajo |
;; Leer un archivo (def content (read-file "notes.md")) ;; Escribir resultados en un archivo (write-file "output.txt" (str "Report: " (today))) ;; Añadir a un registro (append-file "log.txt" (str (today) " - Done\n")) ;; Listar archivos del espacio de trabajo (list-files) ; → ("README.md" "notes.md" ...) (list-files "src") ; → ("main.el" "utils.el" ...)
Estas funciones nativas permiten que el código EELisp interactúe con el búfer del editor activo.
| Función | Descripción |
|---|---|
(cursor-pos) | Obtiene la posición actual del cursor (desplazamiento en caracteres) |
(set-cursor-pos pos) | Mueve el cursor a una posición |
(insert-at pos text) | Inserta texto en una posición |
(replace-range start end text) | Reemplaza texto entre inicio y fin |
(selection) | Obtiene el texto seleccionado actualmente (o nil) |
(current-file) | Obtiene la ruta del archivo activo |
(buffer-text) | Obtiene el texto completo del editor activo |
;; Insertar texto en el cursor (insert-at (cursor-pos) (str "Updated: " (today))) ;; Obtener lo seleccionado (def sel (selection)) ;; Leer el búfer completo (def text (buffer-text)) (println (str "Length: " (str-len text)))
| Función | Descripción |
|---|---|
(clipboard-get) | Lee texto del portapapeles |
(clipboard-set text) | Copia texto al portapapeles |
;; Copiar un resultado al portapapeles (clipboard-set (str "Total: $" (reduce + 0 '(10 20 30)))) ;; Pegar y procesar el contenido del portapapeles (str-upper (clipboard-get))
EELisp incluye un motor de base de datos SQLite integrado. Las tablas se definen con esquemas tipados.
(deftable contacts (name:string email:string age:number))
| Tipo | Descripción | Valores de ejemplo |
|---|---|---|
string | Datos de texto | "Alice", "hello@example.com" |
number | Entero o decimal | 42, 3.14 |
bool | Booleano | true, false |
date | Cadena de fecha ISO | "2026-02-23" |
memo | Texto largo | Contenido multilínea |
choice | Selector desplegable | Lista de opciones predefinidas |
| Función | Descripción |
|---|---|
(tables) | Lista todos los nombres de tablas |
(describe table) | Muestra el esquema de la tabla |
(drop-table table) | Elimina una tabla y todos sus datos |
(pack table) | Elimina permanentemente los registros borrados de forma lógica |
;; Ejemplo completo (deftable tasks (title:string priority:number done:bool due:date)) (tables) ; → (tasks) (describe tasks) ; → detalles del esquema
(insert tasks {:title "Write docs" :priority 1 :done false}) (insert tasks {:title "Fix bug" :priority 2 :done false :due "2026-03-01"})
;; Todos los registros (query tasks) ;; Con cláusula WHERE (query tasks :where "priority <= ?" :params (list 2)) ;; Ordenados y limitados (query tasks :order "priority" :limit 5) ;; Seleccionar columnas específicas (query tasks :select "title, done") ;; Orden descendente (query tasks :order "priority" :asc false)
;; Actualizar por ID (update tasks 1 {:done true}) ;; Borrado lógico (estilo dBASE, se puede recuperar) (delete tasks 1) ;; Eliminar permanentemente los registros borrados lógicamente (pack tasks) ;; Contar registros (count-records tasks) (count-records tasks :where "done = ?" :params (list false))
| Función | Descripción |
|---|---|
(field-get record :field) | Obtiene el valor de un campo de un registro |
(field-set record :field val) | Devuelve un nuevo registro con el campo actualizado |
(record-id record) | Obtiene el ID numérico del registro |
(records result-set) | Extrae la lista de registros de un resultado de consulta |
;; Trabajar con resultados de consulta programáticamente (def results (query tasks :where "done = ?" :params (list false))) (def recs (records results)) (map (fn (r) (field-get r :title)) recs) ; → ("Write docs" "Fix bug")
EELisp puede renderizar componentes de interfaz interactivos directamente en la salida del REPL.
;; Explorar todos los registros en una cuadrícula desplazable (browse tasks) ;; Con filtros y ordenación (browse tasks :where "done = ?" :params (list false) :order "priority")
;; Abrir un formulario interactivo para crear/leer/actualizar/eliminar (edit tasks) ;; Con filtros (edit tasks :where "priority = ?" :params (list 1))
El formulario muestra un registro a la vez con navegación Anterior/Siguiente, edición en línea, y botones Guardar, Nuevo y Eliminar.
;; Formulario calculador independiente con campos calculados (defform loan-calc (principal:number rate:number years:number) :computed ( (monthly-payment (let ((r (/ rate 1200)) (n (* years 12))) (round (/ (* principal r (pow (+ 1 r) n)) (- (pow (+ 1 r) n) 1)) 2))) (total-paid (round (* monthly-payment (* years 12)) 2))))
Los campos calculados se actualizan automáticamente cuando cambian los campos de entrada.
Usa la sintaxis (name:choice "opt1" "opt2" ...) para crear un selector desplegable:
(defform new-task (title:string (priority:choice "low" "medium" "high" "urgent") (status:choice "todo" "in-progress" "done") notes:memo))
Los campos de selección se renderizan como un menú desplegable en la interfaz del formulario.
Vincula un formulario a una tabla de base de datos existente con :source para habilitar CRUD completo:
;; Crear una tabla primero (deftable projects (name:string status:string budget:number)) (insert projects {:name "Alpha" :status "active" :budget 50000}) ;; Formulario respaldado por la tabla con desplegable para estado (defform project-editor (name:string (status:choice "planning" "active" "completed") budget:number) :source projects)
El formulario carga registros de la tabla de origen con navegación Anterior/Siguiente, y botones Guardar, Nuevo y Eliminar — como (edit table) pero con tipos de campo personalizados.
eelisp.db, el REPL se conecta automáticamente.| Comando | Descripción |
|---|---|
:db | Muestra la ruta de la base de datos actual |
:db <path> | Cambia a un archivo de base de datos diferente (relativo a la carpeta) |
:db new <name> | Crea una nueva base de datos en la carpeta actual |
:db memory | Cambia a una base de datos en memoria |
:db mydata.db en lugar de escribir la ruta completa.
El sistema de agenda es un gestor de información personal inspirado en Lotus Agenda. Los elementos son entradas de texto libre con metadatos opcionales.
(add-item "Finish quarterly report") ;; Con metadatos (add-item "Call dentist" :when "2026-03-01" :priority 2) (add-item "Buy groceries" :category "personal" :notes "milk, eggs") ;; Añadir con la fecha de hoy (add-item-today "Review pull requests" :priority 1)
(items) ; todos los elementos (vista de tabla) (items :category "work") ; filtrar por categoría (items :search "quarterly") ; búsqueda de texto (items :priority 1) ; filtrar por prioridad (items :when-before "2026-03-01") ; con fecha anterior a
| Función | Descripción |
|---|---|
(item-get id) | Obtiene un solo elemento por ID |
(item-edit id) | Abre el elemento en vista de formulario para edición |
(item-set id :field val ...) | Actualiza los campos del elemento |
(item-done id) | Marca el elemento como completado (borrado lógico) |
(item-count) | Cuenta todos los elementos |
(item-count :category "work") | Cuenta los elementos de una categoría |
Las categorías son jerárquicas (usan separadores /) y opcionalmente exclusivas (un elemento solo puede estar en una hija).
;; Categorías jerárquicas (defcategory work) (defcategory work/projects) (defcategory work/meetings) (defcategory personal) (defcategory personal/errands) ;; Exclusiva: el elemento solo puede estar en una hija (defcategory priority :exclusive true :children (high medium low)) ;; Asignar / desasignar (assign 1 "work/projects") (assign 1 "priority/high") (unassign 1 "personal") ;; Ver el árbol de categorías (categories)
:exclusive true, asignar una hija (p. ej., priority/low) elimina automáticamente las hermanas (p. ej., priority/high). Perfecto para estado, prioridad o cualquier agrupación de selección única.
Las reglas categorizan automáticamente los elementos basándose en su contenido — la función estrella de Lotus Agenda.
;; Reglas de coincidencia de texto (defrule urgent-flag :when (str-contains text "URGENT") :assign "priority/high") (defrule meeting-detect :when (or (str-contains text "meeting") (str-contains text "call with")) :assign "work/meetings") ;; Regex con extracción de fechas (defrule date-extract :when (str-matches text "\\b(\\d{4}-\\d{2}-\\d{2})\\b") :action (item-set id :when (match 1))) ;; Aplicar reglas (apply-rules) ; aplicar en lote a todos los elementos (apply-rules 42) ; aplicar al elemento #42 ;; Auto-aplicar en cada add-item (auto-categorize true)
| Función | Descripción |
|---|---|
(rules) | Lista todas las reglas definidas |
(drop-rule name) | Elimina una regla |
(auto-categorize bool) | Activa/desactiva la auto-aplicación al insertar |
text, notes, categories, todas las propiedades del elemento, además de funciones auxiliares como has-category y overdue?. Combínalas con and/or/not.
Las vistas son consultas guardadas que filtran, ordenan y agrupan elementos dinámicamente.
(defview work-board :source items :filter (has-category "work") :group-by category :sort-by when) (defview urgent :source items :filter (= priority "1") :sort-by when) (defview inbox :source items :filter (= (length categories) 0)) ;; Mostrar una vista (show work-board) (show urgent)
| Función | Descripción |
|---|---|
(views) | Lista todas las vistas definidas |
(drop-view name) | Elimina una vista |
;; Elementos para una fecha específica (items-on "2026-02-24") ;; Elementos en un rango de fechas (items-between "2026-02-24" "2026-02-28") ;; Usando funciones auxiliares de fecha (items-on (today)) (items-between (today) (date-add (today) 7 :days))
El comando add analiza lenguaje natural para extraer fechas, prioridades y personas automáticamente.
(add "Meet Alice tomorrow for coffee !!") ; → :when = tomorrow, :priority 2, :who "Alice" (add "Call Bob next Monday about the project") ; → :when = next Monday, :who "Bob" (add "URGENT fix server crash") ; → :priority 1 ;; Vista previa sin crear (smart-parse "email Sarah March 15 about renewal !!") ; → {:text "email Sarah about renewal" :when "2026-03-15" :priority 2 :who ("Sarah")}
tomorrow/today/yesterday, next Monday, this weekend, in 3 days, end of week/month, March 15URGENT/ASAP, !!!/!!/!, high/low priority@name, with/for/from Name, call/email/meet Name;; Intervalos integrados (add-item "Team standup" :when (today) :recur :daily) (add-item "Weekly review" :when (today) :recur :weekly) (add-item "Monthly report" :when (today) :recur :monthly) ;; Intervalo personalizado (add-item "Check filters" :when (today) :recur (every 3 :months)) ;; Al marcar como completado, la siguiente ocurrencia se crea automáticamente (item-done 1) ; crea la siguiente recurrencia automáticamente
;; Definir un modelo de elemento reutilizable (deftemplate weekly-review :text "Weekly review" :category "work" :priority 2 :recur :weekly) ;; Crear a partir de plantilla con modificaciones (from-template weekly-review :when "2026-03-01") ;; Gestionar plantillas (templates) ; listar todas (drop-template weekly-review) ; eliminar
Abre, cambia entre y gestiona múltiples bases de datos de agenda. Útil para separar agendas de trabajo y personales.
;; Abrir una nueva agenda (open-agenda "work.db") (open-agenda "personal.db") ;; Cambiar entre agendas (use-agenda "work") ;; Listar todas las agendas abiertas (agendas) ; muestra el marcador activo (*) ;; Cerrar una agenda (close-agenda "personal")
;; Exportar para copia de seguridad o migración (export-agenda "work" :format :json :path "work-backup.json") ;; Importar desde una exportación anterior (import-agenda "work-backup.json")
La interfaz gráfica de EEditor se integra con EELisp a través del método eval() del intérprete. Todo el flujo de datos pasa por expresiones EELisp — la interfaz gráfica nunca accede directamente a SQLite.
┌─────────────────────────┐
│ Vistas SwiftUI │
│ (Barra lateral, Calendario, │
│ Agenda, REPL) │
├─────────────────────────┤
│ ViewModels │
│ (llaman a interpreter.eval)│
├─────────────────────────┤
│ Intérprete EELisp │
│ (builtins, preludio) │
├─────────────────────────┤
│ Base de datos SQLite │
│ (eelisp.db) │
└─────────────────────────┘
(items), (items-on), (items-between) para cargar elementos y mostrarlos.(items-between start end) para contar los elementos de agenda por día.browse y edit devuelven valores .tableView / .formView que el REPL renderiza como componentes SwiftUI.;; 1. El usuario añade elementos en el REPL (add-item "Review PRs" :when (today) :priority 1) ;; 2. Cambiar a la barra lateral de Agenda → la GUI llama a: ;; interpreter.eval("(items-between startKey endKey)") ;; Analiza los resultados en estructuras AgendaDisplayItem ;; 3. Cambiar al Calendario → la GUI llama a: ;; interpreter.eval("(items-on \"2026-02-23\")") ;; Cuenta los elementos por día para los indicadores de puntos