school.fnl
Branches > main > b8d45fc > files / nvim / pack / plugins / opt / conjure / fnl / conjure / school.fnl
(local {: autoload} (require :conjure.nfnl.module))
(local core (autoload :conjure.nfnl.core))
(local buffer (autoload :conjure.buffer))
(local config (autoload :conjure.config))
(local editor (autoload :conjure.editor))
(local str (autoload :conjure.nfnl.string))
(local buf-name "conjure-school.fnl")
(fn upsert-buf []
(buffer.upsert-hidden buf-name))
(fn append [lines]
(let [buf (upsert-buf)
current-buf-str (str.join "\n" (vim.api.nvim_buf_get_lines 0 0 -1 true))
to-insert-str (str.join "\n" lines)]
(when (not (string.find current-buf-str to-insert-str 0 true))
(vim.api.nvim_buf_set_lines
buf
(if (buffer.empty? buf) 0 -1)
-1 false lines)
true)))
(fn map-str [m]
(.. (config.get-in [:mapping :prefix])
(config.get-in [:mapping m])))
(fn progress [n]
(.. "Lesson [" n "/7] complete!"))
(fn append-or-warn [current-progress lines]
(if (append lines)
(progress current-progress)
"You've already completed this lesson! You can (u)ndo and run it again though if you'd like."))
(fn start []
(when (and (not= vim.g.conjure#filetype#fennel "conjure.client.fennel.aniseed")
(not= vim.g.conjure#filetype#fennel "conjure.client.fennel.nfnl"))
(vim.notify_once
(.. "Warning: g:conjure#filetype#fennel not set to a supported client.\n"
"Overriding to 'conjure.client.fennel.nfnl'"))
(set vim.g.conjure#filetype#fennel "conjure.client.fennel.nfnl"))
(when (not (editor.has-filetype? :fennel))
(vim.notify_once
(.. "Warning: No Fennel filetype found, falling back to Clojure syntax.\n"
"Install https://github.com/atweiden/vim-fennel for better Fennel support."))
(set vim.g.conjure#filetype#clojure vim.g.conjure#filetype#fennel)
(vim.api.nvim_create_autocmd
[:BufNewFile :BufRead]
{:group (vim.api.nvim_create_augroup :conjure_school_filetype {:clear true})
:pattern :*.fnl
:command "setlocal filetype=clojure"}))
(let [maplocalleader-was-unset?
(when (and (= "<localleader>" (config.get-in [:mapping :prefix]))
(core.empty? vim.g.maplocalleader))
(set vim.g.maplocalleader ",")
true)
buf (upsert-buf)]
(vim.cmd.edit buf-name)
(vim.api.nvim_buf_set_lines buf 0 -1 false [])
(append
(core.concat
[
"(local school (require :conjure.school))"
""
";; Welcome to Conjure school!"
";; Grab yourself a nice beverage and let's get evaluating. I hope you enjoy!"
""
";; This language is Fennel, it's quite similar to Clojure."
";; Conjure is written in Fennel, it's compiled to Lua and executed inside Neovim itself."
";; This means we can work with a Lisp without installing or running anything else."
""
";; Note: Some colorschemes will make the HUD unreadable, see here for more: https://git.io/JJ1Hl"
""
";; Let's learn how to evaluate it using Conjure's assortment of mappings."
";; You can learn how to change these mappings with :help conjure-mappings"
""
(.. ";; Let's begin by evaluating the whole buffer using " (map-str :eval_buf))]
(if maplocalleader-was-unset?
[";; Your <localleader> wasn't configured so I've defaulted it to comma (,) for now."
";; See :help localleader for more information. (let maplocalleader=\",\")"]
[(.. ";; Your <localleader> is currently mapped to \"" vim.g.maplocalleader "\"")])
["(school.lesson-1)"]))))
(fn lesson-1 []
(append-or-warn
1
[""
";; Good job!"
";; You'll notice the heads up display (HUD) appeared showing the result of the evaluation."
";; All results are appended to a log buffer. If that log is not open, the HUD will appear."
";; The HUD closes automatically when you move your cursor."
""
";; You can open the log buffer in a few ways:"
(.. ";; * Horizontally - " (map-str :log_split))
(.. ";; * Vertically - " (map-str :log_vsplit))
(.. ";; * New tab - " (map-str :log_tab))
""
(.. ";; All visible log windows (including the HUD) can be closed with " (map-str :log_close_visible))
";; Try opening and closing the log window to get the hang of those key mappings."
";; It's a regular window and buffer, so you can edit and close it however you want."
";; Feel free to leave the log open in a split for the next lesson to see how it behaves."
""
";; If you ever need to clear your log you can use the reset mappings:"
(.. ";; * Soft reset (leaves windows open) - " (map-str :log_reset_soft))
(.. ";; * Hard reset (closes windows, deletes the buffer) - " (map-str :log_reset_hard))
""
";; Next, we have a form inside a comment. We want to evaluate that inner form, not the comment."
(.. ";; Place your cursor on the inner form (the one inside the comment) and use " (map-str :eval_current_form) " to evaluate it.")
"(comment"
" (school.lesson-2))"]))
(fn lesson-2 []
(append-or-warn
2
[""
";; Awesome! You evaluated the inner form under your cursor."
(.. ";; If we want to evaluate the outermost form under our cursor, we can use " (map-str :eval_root_form) " instead.")
";; Try that below to print some output and advance to the next lesson."
";; You can place your cursor anywhere inside the (do ...) form or it's children."
"(do"
" (print \"Hello, World!\")"
" (school.lesson-3))"]))
(fn lesson-3 []
(append-or-warn
3
[""
";; You evaluated the outermost form! Nice!"
";; Notice that the print output was captured and displayed in the log too."
";; The result of every evaluation is stored in a Neovim register as well as the log."
(.. ";; Try pressing \"" (config.get-in [:eval :result_register]) "p to paste the contents of the register into your buffer.")
(.. ";; We can also evaluate a form and replace it with the result of the evaluation with " (map-str :eval_replace_form))
(.. ";; We'll try that in the next lesson, place your cursor inside the form below and press " (map-str :eval_replace_form))
"(school.lesson-4)"]))
(fn lesson-4 []
(append-or-warn
4
[""
";; Well done! Notice how the resulting string in the log also replaced the form in the buffer!"
";; Next let's try evaluating a form at a mark."
";; Place your cursor on the next lesson form below and use mf to set the f mark at that location."
(.. ";; Now move your cursor elsewhere in the buffer and use " (map-str :eval_marked_form) "f to evaluate it.")
";; If you use a capital letter like mF you can even open a different file and evaluate that marked form without changing buffers!"
"(school.lesson-5)"]))
(local lesson-5-message
"This is the contents of school.lesson-5-message!")
(fn lesson-5 []
(append-or-warn
5
[""
";; Excellent!"
";; This is extremely useful when you want to evaluate a specific form repeatedly as you change code elsewhere in the file or project."
(.. ";; Try inspecting the contents of the variable below by placing your cursor on it and pressing " (map-str :eval_word))
"school.lesson-5-message"
""
";; You should see the contents in the HUD or log."
""
(.. ";; You can evaluate visual selections with " (map-str :eval_visual))
";; Try evaluating the form below using a visual selection."
"(school.lesson-6)"]))
(local lesson-6-message
"This is the contents of school.lesson-6-message!")
(fn lesson-6 []
(append-or-warn
6
[""
";; Wonderful!"
";; Visual evaluation is great for specific sections of a form."
(.. ";; You can also evaluate a given motion with " (map-str :eval_motion))
(.. ";; Try " (map-str :eval_motion) "iW below to evaluate the word.")
"school.lesson-6-message"
""
(.. ";; Use " (map-str :eval_motion) "a( to evaluate the lesson form.")
"(school.lesson-7)"]))
(fn lesson-7 []
(append-or-warn
7
[""
";; Excellent job, you made it to the end!"
";; To learn more about configuring Conjure, install the plugin and check out :help conjure"
";; You can learn about specific languages with :help conjure-client- and then tab completion."
";; For example, conjure-client-fennel-nfnl or conjure-client-clojure-nrepl."
""
";; I hope you have a wonderful time in Conjure!"]))
{: start
: lesson-1
: lesson-2
: lesson-3
: lesson-4
: lesson-5
: lesson-6
: lesson-7
: lesson-5-message
: lesson-6-message}