EEditor Manual

Complete reference for the EEditor application and the EELisp language. Covers every feature, every builtin function, and every keyboard shortcut.

Contents

I. Editor Guide

  1. Getting Started
  2. The Editor
  3. Sidebar & File Tree
  4. Tabs & Pinned Files
  5. Search & Quick Open
  6. Preview & PDF Export
  7. Daily Notes & Weekly Planner
  8. Calendar View
  9. Agenda Sidebar
  10. REPL Sidebar
  11. EELisp Code Blocks
  12. Keyboard Shortcuts

II. The REPL

  1. Using the REPL
  2. REPL Commands

III. EELisp Language

  1. Arithmetic & Math
  2. Comparison & Logic
  3. Variables & Functions
  4. Control Flow
  5. Strings
  6. Lists
  7. Dictionaries
  8. Types & Conversion
  9. I/O & Dates
  10. Prelude Functions
  11. HTTP & JSON
  12. File System
  13. Editor Integration
  14. Clipboard

IV. Database

  1. Defining Tables
  2. Records & Queries
  3. Interactive Views
  4. Database Management

V. Agenda System

  1. Items
  2. Categories
  3. Auto-Categorization Rules
  4. Views
  5. Calendar Queries
  6. Smart Input
  7. Recurring Items & Templates
  8. Multiple Agendas

VI. Integration

  1. GUI & EELisp Integration
Part I — Editor Guide

1. Getting Started

When you first launch EEditor you see an empty editor with a sidebar. Three steps to begin:

  1. Open a folder — press ⌘O or tap the folder icon. EEditor scans the directory and displays all files in the sidebar tree.
  2. Select a file — click any file in the sidebar to open it in a new tab.
  3. Start writing — edits are auto-saved after 1 second of inactivity. Press ⌘S to save immediately.
Tip: EEditor remembers your last opened folder via security-scoped bookmarks. It restores automatically on relaunch.

Opening individual files

Use ⌘⇧O to open a single file from anywhere on disk. The file’s parent directory becomes the active folder.

2. The Editor

EEditor provides a distraction-free writing environment with real-time syntax highlighting for Markdown and 24+ programming languages.

3. Sidebar & File Tree

The sidebar shows a hierarchical view of your folder. Directories sort first, then files alphabetically.

The sidebar has three modes via the segmented toggle: Files, Calendar, and Agenda.

4. Tabs & Pinned Files

Each file opens as a tab at the top of the editor.

ActionShortcutNotes
Next tab⌘⌥→Wraps around
Previous tab⌘⌥←Wraps around
Close tab⌘WAuto-saves if dirty
Close all unpinned⌘⌥W
Pin / Unpin⌘⇧KPinned tabs persist across sessions

Pinned tabs show a pin icon, appear first (sorted alphabetically), and cannot be closed until unpinned. They are automatically restored on relaunch.

5. Search & Quick Open

Full-text search (⌘⇧F)

Quick Open (⌘P)

Wiki-links (⌘O)

Place your cursor on a [[filename]] link and press ⌘O to open that file directly.

6. Preview & PDF Export

Markdown preview (⌘⇧P)

PDF export (⌘⇧E)

7. Daily Notes & Weekly Planner

Daily note (⌘D)

Weekly planner (⌘⇧W)

8. Calendar View

Toggle the sidebar to Calendar mode using the segmented control.

9. Agenda Sidebar

Toggle to Agenda mode via the clipboard icon. The panel shows your upcoming schedule in three sections:

Each item shows a priority dot (red = urgent, orange = high, yellow = medium, gray = normal), text, categories, and formatted date. Tap refresh to reload after adding items in the REPL.

REPL Sidebar

Toggle to REPL mode via the terminal icon in the sidebar segmented control. This embeds a full EELisp REPL directly in the sidebar panel, so you can evaluate expressions while keeping your editor visible.

EELisp Code Blocks in Markdown

Embed executable EELisp code directly in your Markdown files using fenced code blocks:

```eelisp
(+ 1 2 3)
```

Running a code block

  1. Place your cursor anywhere inside a ```eelisp block.
  2. Press ⌘⇧Return (or use the menu: View → Run EELisp Block).
  3. The result appears as a ```result block immediately below.
```eelisp
(+ 1 2 3)
```
```result
6
```

Re-running replaces the existing result. Use cases include inline calculations, adding agenda items from journal entries, querying data, and file operations:

```eelisp
(add-item (smart-parse "tomorrow review quarterly report !!"))
```

```eelisp
(write-file "todo.txt" "Buy groceries\nCall dentist")
```

10. Keyboard Shortcuts

Press ⌘? in the app to see the full shortcut sheet. Here is the complete reference:

Files

ActionShortcut
New file⌘N
Open folder⌘O
Open file⌘⇧O
Save⌘S
Refresh tree⌘⇧R
Daily note⌘D
Weekly planner⌘⇧W

Navigation

ActionShortcut
Quick Open⌘P
Search in files⌘⇧F
Find & Replace⌘F
Focus editor⌘\
Open wiki-link⌘O

Tabs

ActionShortcut
Next tab⌘⌥→
Previous tab⌘⌥←
Close tab⌘W
Close all unpinned⌘⌥W
Pin / Unpin tab⌘⇧K

Editing

ActionShortcut
Insert timestamp⌘I
Undo⌘Z
Redo⌘⇧Z

View & Export

ActionShortcut
Preview⌘⇧P
Export PDF⌘⇧E
Open REPL⌘⇧L
Send to REPL⌘R
Run EELisp Block⌘⇧Return
Shortcuts help⌘?
Part II — The REPL

11. Using the REPL

EEditor includes a built-in Lisp interpreter called EELisp — designed for personal data management, calculations, and scripting.

Opening the REPL

Evaluating expressions

Send to REPL (⌘R)

Select text in the editor and press ⌘R. The REPL opens with your selection pre-filled in the input field, ready for you to press Enter to evaluate.

Loading files

Use :load path/to/file.el to load and evaluate an EELisp script. On iOS, tap the Load button in the toolbar or right-click a .el file in the sidebar.

iOS toolbar

On iOS/iPadOS, a toolbar appears with: history navigation (↑/↓), quick snippets (query, deftable, defn), Load File, and Clear.

12. REPL Commands

Colon-prefixed commands control the REPL itself (not EELisp expressions):

CommandAliasDescription
:help:hShow command reference and quick examples
:load <file>:lLoad and evaluate a .el / .lisp file
:dbShow current database path (:memory: or file path)
:db <path>Switch to a different database file
:db new <name>Create a new database in the current folder
:db memorySwitch to an in-memory database
:env:eList all defined symbols in the environment
:clear:cClear REPL output history
:reset:rReset interpreter (fresh environment, same database)
Database auto-connect: When you open a folder containing an eelisp.db file, the REPL automatically connects to it for persistent storage. Data created with deftable and insert is saved to disk.
Part III — EELisp Language Reference

13. Arithmetic & Math

All arithmetic operators are variadic (accept multiple arguments) and work with integers and floats.

FunctionSignatureDescription
+(+ num ...)Addition. (+ 1 2 3)6
-(- num ...)Subtraction or negation. (- 10 3)7, (- 5)-5
*(* num ...)Multiplication. (* 2 3 4)24
/(/ num num ...)Division. (/ 100 3)33.333...
mod(mod a b)Modulo. (mod 10 3)1
abs(abs num)Absolute value. (abs -42)42
min(min num ...)Minimum. (min 3 1 4)1
max(max num ...)Maximum. (max 3 1 4)4
floor(floor num)Round down. (floor 3.7)3
ceil(ceil num)Round up. (ceil 3.2)4
pow(pow base exp)Exponentiation. (pow 2 10)1024
round(round num [places])Round. (round 3.14159 2)3.14
;; Arithmetic examples
(+ 1 2 3 4)            ; → 10
(* 6 7)                ; → 42
(/ 100 3)              ; → 33.333...
(pow 2 10)             ; → 1024
(round 3.14159 2)     ; → 3.14

;; Nesting
(+ (* 3 4) (- 10 5))    ; → 17

14. Comparison & Logic

FunctionSignatureDescription
=(= a b)Equality. Works with numbers, strings, bools
!=(!= a b)Inequality
<(< a b)Less than
>(> a b)Greater than
<=(<= a b)Less than or equal
>=(>= a b)Greater than or equal

Logical operators

These are special forms (short-circuit evaluation):

(and true false)        ; → false
(or  false true)        ; → true
(not true)              ; → false

;; Short-circuit: (or) returns first truthy value
(or nil false 42 99)    ; → 42

15. Variables & Functions

Defining variables

(def x 42)
(def greeting "Hello, world!")
(def pi 3.14159)

Defining functions

(defn square (x)
  (* x x))

(square 5)  ; → 25

;; Multi-expression body (last value returned)
(defn greet (name)
  (def msg (str "Hello, " name "!"))
  (println msg)
  msg)

Anonymous functions

(map (fn (x) (* x x)) '(1 2 3))  ; → (1 4 9)

Rest parameters

(defn sum (first . rest)
  (reduce + first rest))

(sum 1 2 3 4 5)  ; → 15

Local bindings

(let ((x 1) (y 2))
  (+ x y))  ; → 3

16. Control Flow

if

(if (> x 0) "positive" "non-positive")

cond

(cond
  (< x 0)  "negative"
  (= x 0)  "zero"
  else     "positive")

when

;; Execute body only if condition is true
(when (> x 0)
  (println "positive!")
  x)

loop / recur

;; Sum from 0 to 10
(loop ((i 0) (acc 0))
  (> i 10)
  (recur (+ i 1) (+ acc i)))  ; → 55

begin

;; Evaluate multiple expressions, return last
(begin
  (def a 10)
  (def b 20)
  (+ a b))  ; → 30

17. Strings

FunctionSignatureExample → Result
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)Returns list of capture groups or nil
substr(substr s start [end])(substr "hello" 1 3)"el"

18. Lists

FunctionSignatureExample → Result
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
;; Chaining list operations
(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

19. Dictionaries

Dictionaries use keyword keys (:name) and are immutable — operations return new dicts.

FunctionSignatureExample → Result
dict(dict :key val ...)(dict :a 1 :b 2){:a 1 :b 2}
dict-get(dict-get d key [default])(dict-get d :name) → value or nil
dict-set(dict-set d key val)Returns new dict with key set
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 ...)Merges dicts; later keys override
(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"}

20. Types & Conversion

Type predicates

FunctionReturns true when
string?Value is a string
number?Value is a number
bool?Value is a boolean
list?Value is a list
nil?Value is nil/null
symbol?Value is a symbol
keyword?Value is a keyword
fn?Value is a function
dict?Value is a dictionary
date?Value is a date
record?Value is a database record
item?Value is an agenda item

Type inspection

(type 42)          ; → "number"
(type "hello")     ; → "string"
(type '(1 2))      ; → "list"

Conversion functions

FunctionDescription
->stringConvert any value to its string representation
->numberParse string to number, bool to 0/1
->boolTruthiness: nil, false, 0, "" → false; everything else → true

21. I/O & Dates

Output

FunctionDescription
(print val ...)Print values without trailing newline
(println val ...)Print values with trailing newline

Date functions

FunctionSignatureDescription
now(now)Current date/time object
today(today)Today as ISO string "YYYY-MM-DD"
date-format(date-format date [fmt])Format a date. Default: "yyyy-MM-dd HH:mm"
date-add(date-add date n :unit)Add days/weeks/months. Units: :days, :weeks, :months
date-diff(date-diff d1 d2)Difference in days between two ISO date strings
(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

22. Prelude Functions

These functions are defined in EELisp itself and loaded automatically at startup:

FunctionDescriptionExample
incIncrement by 1(inc 5)6
decDecrement by 1(dec 5)4
even?True if even(even? 4)true
odd?True if odd(odd? 3)true
zero?True if zero(zero? 0)true
pos?True if positive(pos? 5)true
neg?True if negative(neg? -3)true
firstFirst element(first '(a b c))a
secondSecond element(second '(a b c))b
thirdThird element(third '(a b c))c
lastLast element(last '(a b c))c
takeTake first n(take 2 '(a b c))(a b)
dropDrop first n(drop 1 '(a b c))(b c)
some?Any match?(some? even? '(1 2 3))true
every?All match?(every? pos? '(1 2 3))true
pipeThreading(pipe 5 inc inc square)49
composeCompose functions((compose inc square) 5)26
partialPartial application((partial + 10) 5)15
idIdentity function(id 42)42

23. HTTP & JSON

FunctionSignatureDescription
http-get(http-get url)GET request. Returns {:status N :body "..."}
http-post(http-post url body [:content-type "..."])POST request with body
json-parse(json-parse string)Parse JSON to EELisp dict/list
json-stringify(json-stringify value)Convert EELisp value to JSON string
;; Fetch data from an API
(def resp (http-get "https://api.example.com/data"))
(def data (json-parse (dict-get resp :body)))

;; Post JSON
(http-post "https://api.example.com/items"
  (json-stringify {:name "test"})
  :content-type "application/json")

Evaluation

FunctionDescription
(eval expr)Evaluate an unevaluated expression
(parse string)Parse a string as EELisp code

File System

EELisp can read and write files in your open folder. All paths are relative to the current workspace directory.

FunctionDescription
(read-file path)Read file contents as a string
(write-file path content)Write content to a file (creates or overwrites)
(append-file path content)Append content to an existing file
(file-exists? path)Check if a file exists
(list-files [path])List filenames in a directory (default: workspace root)
(current-dir)Get the workspace root path
;; Read a file
(def content (read-file "notes.md"))

;; Write results to a file
(write-file "output.txt" (str "Report: " (today)))

;; Append to a log
(append-file "log.txt" (str (today) " - Done\n"))

;; List workspace files
(list-files)       ; → ("README.md" "notes.md" ...)
(list-files "src") ; → ("main.el" "utils.el" ...)

Editor Integration

These builtins let EELisp code interact with the active editor buffer.

FunctionDescription
(cursor-pos)Get current cursor position (character offset)
(set-cursor-pos pos)Move cursor to a position
(insert-at pos text)Insert text at a position
(replace-range start end text)Replace text between start and end
(selection)Get the currently selected text (or nil)
(current-file)Get the path of the active file
(buffer-text)Get the full text of the active editor
;; Insert text at the cursor
(insert-at (cursor-pos) (str "Updated: " (today)))

;; Get what's selected
(def sel (selection))

;; Read the entire buffer
(def text (buffer-text))
(println (str "Length: " (str-len text)))

Clipboard

FunctionDescription
(clipboard-get)Read text from the clipboard
(clipboard-set text)Copy text to the clipboard
;; Copy a result to clipboard
(clipboard-set (str "Total: $" (reduce + 0 '(10 20 30))))

;; Paste and process clipboard contents
(str-upper (clipboard-get))
Part IV — Database Reference

24. Defining Tables

EELisp includes a built-in SQLite database engine. Tables are defined with typed schemas.

Basic syntax

(deftable contacts (name:string email:string age:number))

Field types

TypeDescriptionExample values
stringText data"Alice", "hello@example.com"
numberInteger or float42, 3.14
boolBooleantrue, false
dateISO date string"2026-02-23"
memoLong textMulti-line content
choiceDropdown pickerPredefined options list

Table management

FunctionDescription
(tables)List all table names
(describe table)Show table schema
(drop-table table)Delete a table and all its data
(pack table)Permanently remove soft-deleted records
;; Full example
(deftable tasks (title:string priority:number done:bool due:date))
(tables)       ; → (tasks)
(describe tasks) ; → schema details

25. Records & Queries

Inserting records

(insert tasks {:title "Write docs" :priority 1 :done false})
(insert tasks {:title "Fix bug" :priority 2 :done false :due "2026-03-01"})

Querying

;; All records
(query tasks)

;; With WHERE clause
(query tasks :where "priority <= ?" :params (list 2))

;; Sorted and limited
(query tasks :order "priority" :limit 5)

;; Select specific columns
(query tasks :select "title, done")

;; Descending order
(query tasks :order "priority" :asc false)

Updating & deleting

;; Update by ID
(update tasks 1 {:done true})

;; Soft-delete (dBASE-style, can be recovered)
(delete tasks 1)

;; Permanently remove soft-deleted records
(pack tasks)

;; Count records
(count-records tasks)
(count-records tasks :where "done = ?" :params (list false))

Record access

FunctionDescription
(field-get record :field)Get a field value from a record
(field-set record :field val)Return new record with field updated
(record-id record)Get the record’s numeric ID
(records result-set)Extract list of records from a query result
;; Working with query results programmatically
(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")

26. Interactive Views

EELisp can render interactive UI components directly in the REPL output.

Browse (table view)

;; Browse all records in a scrollable grid
(browse tasks)

;; With filters and sorting
(browse tasks :where "done = ?" :params (list false) :order "priority")

Edit (CRUD form)

;; Open an interactive form for create/read/update/delete
(edit tasks)

;; With filters
(edit tasks :where "priority = ?" :params (list 1))

The form shows one record at a time with Prev/Next navigation, inline editing, Save, New, and Delete buttons.

Computed forms (defform)

;; Standalone calculator form with computed fields
(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))))

Computed fields update automatically when input fields change.

Choice fields (dropdown)

Use the (name:choice "opt1" "opt2" ...) syntax to create a dropdown picker:

(defform new-task
  (title:string
   (priority:choice "low" "medium" "high" "urgent")
   (status:choice "todo" "in-progress" "done")
   notes:memo))

Choice fields render as a dropdown menu in the form UI.

Table-backed forms (:source)

Link a form to an existing database table with :source to enable full CRUD:

;; Create a table first
(deftable projects (name:string status:string budget:number))
(insert projects {:name "Alpha" :status "active" :budget 50000})

;; Form backed by the table with dropdown for status
(defform project-editor
  (name:string
   (status:choice "planning" "active" "completed")
   budget:number)
  :source projects)

The form loads records from the source table with Prev/Next navigation, Save, New, and Delete buttons — like (edit table) but with custom field types.

27. Database Management

Automatic connection

REPL database commands

CommandDescription
:dbShow current database path
:db <path>Switch to a different database file (relative to folder)
:db new <name>Create a new database in the current folder
:db memorySwitch to an in-memory database
Tip: Database paths are relative to the currently open folder. Use :db mydata.db rather than typing the full path.
Part V — Agenda System

28. Items

The agenda system is a Lotus Agenda-inspired personal information manager. Items are free-form text entries with optional metadata.

Adding items

(add-item "Finish quarterly report")

;; With metadata
(add-item "Call dentist" :when "2026-03-01" :priority 2)
(add-item "Buy groceries" :category "personal" :notes "milk, eggs")

;; Add with today's date
(add-item-today "Review pull requests" :priority 1)

Querying items

(items)                          ; all items (table view)
(items :category "work")        ; filter by category
(items :search "quarterly")     ; text search
(items :priority 1)             ; filter by priority
(items :when-before "2026-03-01") ; due before date

Managing items

FunctionDescription
(item-get id)Fetch a single item by ID
(item-edit id)Open item in form view for editing
(item-set id :field val ...)Update item fields
(item-done id)Mark item as done (soft-delete)
(item-count)Count all items
(item-count :category "work")Count items in a category

29. Categories

Categories are hierarchical (use / separators) and optionally exclusive (item can be in only one child).

;; Hierarchical categories
(defcategory work)
(defcategory work/projects)
(defcategory work/meetings)
(defcategory personal)
(defcategory personal/errands)

;; Exclusive: item can only be in one child
(defcategory priority :exclusive true
  :children (high medium low))

;; Assign / unassign
(assign 1 "work/projects")
(assign 1 "priority/high")
(unassign 1 "personal")

;; View category tree
(categories)
Tip: When a parent is :exclusive true, assigning one child (e.g., priority/low) automatically removes siblings (e.g., priority/high). Perfect for status, priority, or any single-choice grouping.

30. Auto-Categorization Rules

Rules automatically categorize items based on their content — the signature feature of Lotus Agenda.

;; Text-matching rules
(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 with date extraction
(defrule date-extract
  :when (str-matches text "\\b(\\d{4}-\\d{2}-\\d{2})\\b")
  :action (item-set id :when (match 1)))

;; Apply rules
(apply-rules)      ; batch-apply to all items
(apply-rules 42)   ; apply to item #42

;; Auto-apply on every add-item
(auto-categorize true)

Rule management

FunctionDescription
(rules)List all defined rules
(drop-rule name)Delete a rule
(auto-categorize bool)Toggle auto-apply on insert
Rule context: Conditions have access to text, notes, categories, all item properties, plus helpers like has-category and overdue?. Combine with and/or/not.

31. Views

Views are saved queries that filter, sort, and group items dynamically.

(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))

;; Show a view
(show work-board)
(show urgent)
FunctionDescription
(views)List all defined views
(drop-view name)Delete a view

32. Calendar Queries

;; Items for a specific date
(items-on "2026-02-24")

;; Items in a date range
(items-between "2026-02-24" "2026-02-28")

;; Using date helpers
(items-on (today))
(items-between (today) (date-add (today) 7 :days))
Tip: The Calendar sidebar and Agenda sidebar in the GUI use these same functions behind the scenes. Add items in the REPL, then switch to Calendar or Agenda mode to see them visually.

33. Smart Input

The add command parses natural language to extract dates, priorities, and people automatically.

(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

;; Preview without creating
(smart-parse "email Sarah March 15 about renewal !!")
; → {:text "email Sarah about renewal" :when "2026-03-15" :priority 2 :who ("Sarah")}

Recognized patterns

34. Recurring Items & Templates

Recurrence

;; Built-in intervals
(add-item "Team standup" :when (today) :recur :daily)
(add-item "Weekly review" :when (today) :recur :weekly)
(add-item "Monthly report" :when (today) :recur :monthly)

;; Custom interval
(add-item "Check filters" :when (today) :recur (every 3 :months))

;; When you mark done, the next occurrence is auto-created
(item-done 1)  ; creates next recurrence automatically

Templates

;; Define a reusable item blueprint
(deftemplate weekly-review
  :text "Weekly review"
  :category "work"
  :priority 2
  :recur :weekly)

;; Create from template with overrides
(from-template weekly-review :when "2026-03-01")

;; Manage templates
(templates)           ; list all
(drop-template weekly-review)  ; delete

35. Multiple Agendas

Open, switch between, and manage multiple agenda databases. Useful for separating work and personal agendas.

;; Open a new agenda
(open-agenda "work.db")
(open-agenda "personal.db")

;; Switch between agendas
(use-agenda "work")

;; List all open agendas
(agendas)  ; shows active marker (*)

;; Close an agenda
(close-agenda "personal")

Export & Import

;; Export for backup or migration
(export-agenda "work" :format :json :path "work-backup.json")

;; Import from a previous export
(import-agenda "work-backup.json")
Part VI — Integration

36. GUI & EELisp Integration

The EEditor GUI integrates with EELisp through the interpreter’s eval() method. All data flows through EELisp expressions — the GUI never accesses SQLite directly.

Architecture

┌─────────────────────────┐
│  SwiftUI Views          │
│  (Sidebar, Calendar,    │
│   Agenda, REPL)         │
├─────────────────────────┤
│  ViewModels             │
│  (call interpreter.eval)│
├─────────────────────────┤
│  EELisp Interpreter     │
│  (builtins, prelude)    │
├─────────────────────────┤
│  SQLite Database        │
│  (eelisp.db)            │
└─────────────────────────┘

How it works

Data flow example

;; 1. User adds items in the REPL
(add-item "Review PRs" :when (today) :priority 1)

;; 2. Switch to Agenda sidebar → GUI calls:
;;    interpreter.eval("(items-between startKey endKey)")
;;    Parses results into AgendaDisplayItem structs

;; 3. Switch to Calendar → GUI calls:
;;    interpreter.eval("(items-on \"2026-02-23\")")
;;    Counts items per day for dot indicators
Key principle: The GUI is a thin presentation layer. All business logic — table schemas, queries, agenda rules, views — lives in EELisp. This means you can script and automate everything from the REPL.

iOS & iPadOS tips