Skip to content

Commit 2c42367

Browse files
committed
Only append ConjureSchool lessons if they aren't already there
Also explain to the user that they've already run a lesson if they try again and they can undo to reset it. Fixes #355
1 parent ace0350 commit 2c42367

File tree

2 files changed

+68
-51
lines changed

2 files changed

+68
-51
lines changed

fnl/conjure/school.fnl

+36-27
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@
1212
(buffer.upsert-hidden buf-name))
1313

1414
(defn- append [lines]
15-
(let [buf (upsert-buf)]
16-
(nvim.buf_set_lines
17-
buf
18-
(if (buffer.empty? buf) 0 -1)
19-
-1 false lines)))
15+
(let [buf (upsert-buf)
16+
current-buf-str (str.join "\n" (nvim.buf_get_lines 0 0 -1 true))
17+
to-insert-str (str.join "\n" lines)]
18+
(when (not (string.find current-buf-str to-insert-str 0 true))
19+
(nvim.buf_set_lines
20+
buf
21+
(if (buffer.empty? buf) 0 -1)
22+
-1 false lines)
23+
true)))
2024

2125
(defn- map-str [m]
2226
(.. (config.get-in [:mapping :prefix])
@@ -25,6 +29,11 @@
2529
(defn- progress [n]
2630
(.. "Lesson ["n "/7] complete!"))
2731

32+
(defn- append-or-warn [current-progress lines]
33+
(if (append lines)
34+
(progress current-progress)
35+
"You've already completed this lesson! You can (u)ndo and run it again though if you'd like."))
36+
2837
(defn start []
2938
(when (not (editor.has-filetype? :fennel))
3039
(nvim.echo
@@ -68,7 +77,8 @@
6877
["(school.lesson-1)"]))))
6978

7079
(defn lesson-1 []
71-
(append
80+
(append-or-warn
81+
1
7282
[""
7383
";; Good job!"
7484
";; You'll notice the heads up display (HUD) appeared showing the result of the evaluation."
@@ -92,49 +102,49 @@
92102
";; Next, we have a form inside a comment. We want to evaluate that inner form, not the comment."
93103
(.. ";; Place your cursor on the inner form (the one inside the comment) and use " (map-str :eval_current_form) " to evaluate it.")
94104
"(comment"
95-
" (school.lesson-2))"])
96-
(progress 1))
105+
" (school.lesson-2))"]))
97106

98107
(defn lesson-2 []
99-
(append
108+
(append-or-warn
109+
2
100110
[""
101111
";; Awesome! You evaluated the inner form under your cursor."
102112
(.. ";; If we want to evaluate the outermost form under our cursor, we can use " (map-str :eval_root_form) " instead.")
103113
";; Try that below to print some output and advance to the next lesson."
104114
";; You can place your cursor anywhere inside the (do ...) form or it's children."
105115
"(do"
106-
" (print \"Hello, World!\")"
107-
" (school.lesson-3))"])
108-
(progress 2))
116+
" (print \"Hello, World!\")"
117+
" (school.lesson-3))"]))
109118

110119
(defn lesson-3 []
111-
(append
120+
(append-or-warn
121+
3
112122
[""
113123
";; You evaluated the outermost form! Nice!"
114124
";; Notice that the print output was captured and displayed in the log too."
115125
";; The result of every evaluation is stored in a Neovim register as well as the log."
116126
(.. ";; Try pressing \"" (config.get-in [:eval :result_register]) "p to paste the contents of the register into your buffer.")
117127
(.. ";; We can also evaluate a form and replace it with the result of the evaluation with " (map-str :eval_replace_form))
118128
(.. ";; We'll try that in the next lesson, place your cursor inside the form below and press " (map-str :eval_replace_form))
119-
"(school.lesson-4)"])
120-
(progress 3))
129+
"(school.lesson-4)"]))
121130

122131
(defn lesson-4 []
123-
(append
132+
(append-or-warn
133+
4
124134
[""
125135
";; Well done! Notice how the resulting string in the log also replaced the form in the buffer!"
126136
";; Next let's try evaluating a form at a mark."
127137
";; Place your cursor on the next lesson form below and use mf to set the f mark at that location."
128138
(.. ";; Now move your cursor elsewhere in the buffer and use " (map-str :eval_marked_form) "f to evaluate it.")
129139
";; If you use a capital letter like mF you can even open a different file and evaluate that marked form without changing buffers!"
130-
"(school.lesson-5)"])
131-
(progress 4))
140+
"(school.lesson-5)"]))
132141

133142
(def lesson-5-message
134143
"This is the contents of school.lesson-5-message!")
135144

136145
(defn lesson-5 []
137-
(append
146+
(append-or-warn
147+
5
138148
[""
139149
";; Excellent!"
140150
";; This is extremely useful when you want to evaluate a specific form repeatedly as you change code elsewhere in the file or project."
@@ -145,14 +155,14 @@
145155
""
146156
(.. ";; You can evaluate visual selections with " (map-str :eval_visual))
147157
";; Try evaluating the form below using a visual selection."
148-
"(school.lesson-6)"])
149-
(progress 5))
158+
"(school.lesson-6)"]))
150159

151160
(def lesson-6-message
152161
"This is the contents of school.lesson-6-message!")
153162

154163
(defn lesson-6 []
155-
(append
164+
(append-or-warn
165+
6
156166
[""
157167
";; Wonderful!"
158168
";; Visual evaluation is great for specific sections of a form."
@@ -161,16 +171,15 @@
161171
"school.lesson-6-message"
162172
""
163173
(.. ";; Use " (map-str :eval_motion) "a( to evaluate the lesson form.")
164-
"(school.lesson-7)"])
165-
(progress 6))
174+
"(school.lesson-7)"]))
166175

167176
(defn lesson-7 []
168-
(append
177+
(append-or-warn
178+
7
169179
[""
170180
";; Excellent job, you made it to the end!"
171181
";; To learn more about configuring Conjure, install the plugin and check out :help conjure"
172182
";; You can learn about specific languages with :help conjure-client- and then tab completion."
173183
";; For example, conjure-client-fennel-aniseed or conjure-client-clojure-nrepl."
174184
""
175-
";; I hope you have a wonderful time in Conjure!"])
176-
(progress 7))
185+
";; I hope you have a wonderful time in Conjure!"]))

lua/conjure/school.lua

+32-24
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,20 @@ end
2626
_2amodule_locals_2a["upsert-buf"] = upsert_buf
2727
local function append(lines)
2828
local buf = upsert_buf()
29-
local _1_
30-
if buffer["empty?"](buf) then
31-
_1_ = 0
29+
local current_buf_str = str.join("\n", nvim.buf_get_lines(0, 0, -1, true))
30+
local to_insert_str = str.join("\n", lines)
31+
if not string.find(current_buf_str, to_insert_str, 0, true) then
32+
local _1_
33+
if buffer["empty?"](buf) then
34+
_1_ = 0
35+
else
36+
_1_ = -1
37+
end
38+
nvim.buf_set_lines(buf, _1_, -1, false, lines)
39+
return true
3240
else
33-
_1_ = -1
41+
return nil
3442
end
35-
return nvim.buf_set_lines(buf, _1_, -1, false, lines)
3643
end
3744
_2amodule_locals_2a["append"] = append
3845
local function map_str(m)
@@ -43,6 +50,14 @@ local function progress(n)
4350
return ("Lesson [" .. n .. "/7] complete!")
4451
end
4552
_2amodule_locals_2a["progress"] = progress
53+
local function append_or_warn(current_progress, lines)
54+
if append(lines) then
55+
return progress(current_progress)
56+
else
57+
return "You've already completed this lesson! You can (u)ndo and run it again though if you'd like."
58+
end
59+
end
60+
_2amodule_locals_2a["append-or-warn"] = append_or_warn
4661
local function start()
4762
if not editor["has-filetype?"]("fennel") then
4863
nvim.echo("Warning: No Fennel filetype found, falling back to Clojure syntax.", "Install https://github.com/Olical/aniseed for better Fennel support.")
@@ -56,58 +71,51 @@ local function start()
5671
local buf = upsert_buf()
5772
nvim.ex.edit(buf_name)
5873
nvim.buf_set_lines(buf, 0, -1, false, {})
59-
local _4_
74+
local _6_
6075
if ("<localleader>" == config["get-in"]({"mapping", "prefix"})) then
6176
if a["empty?"](nvim.g.maplocalleader) then
6277
nvim.g.maplocalleader = ","
6378
nvim.ex.edit()
64-
_4_ = {";; Your <localleader> wasn't configured so I've defaulted it to comma (,) for now.", ";; See :help localleader for more information. (let maplocalleader=\",\")"}
79+
_6_ = {";; Your <localleader> wasn't configured so I've defaulted it to comma (,) for now.", ";; See :help localleader for more information. (let maplocalleader=\",\")"}
6580
else
66-
_4_ = {(";; Your <localleader> is currently mapped to \"" .. nvim.g.maplocalleader .. "\"")}
81+
_6_ = {(";; Your <localleader> is currently mapped to \"" .. nvim.g.maplocalleader .. "\"")}
6782
end
6883
else
69-
_4_ = nil
84+
_6_ = nil
7085
end
71-
return append(a.concat({"(module user.conjure-school", " {require {school 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"))}, _4_, {"(school.lesson-1)"}))
86+
return append(a.concat({"(module user.conjure-school", " {require {school 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"))}, _6_, {"(school.lesson-1)"}))
7287
end
7388
_2amodule_2a["start"] = start
7489
local function lesson_1()
75-
append({"", ";; 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))"})
76-
return progress(1)
90+
return 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))"})
7791
end
7892
_2amodule_2a["lesson-1"] = lesson_1
7993
local function lesson_2()
80-
append({"", ";; 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))"})
81-
return progress(2)
94+
return 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))"})
8295
end
8396
_2amodule_2a["lesson-2"] = lesson_2
8497
local function lesson_3()
85-
append({"", ";; 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)"})
86-
return progress(3)
98+
return 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)"})
8799
end
88100
_2amodule_2a["lesson-3"] = lesson_3
89101
local function lesson_4()
90-
append({"", ";; 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)"})
91-
return progress(4)
102+
return 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)"})
92103
end
93104
_2amodule_2a["lesson-4"] = lesson_4
94105
local lesson_5_message = "This is the contents of school.lesson-5-message!"
95106
_2amodule_2a["lesson-5-message"] = lesson_5_message
96107
local function lesson_5()
97-
append({"", ";; 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)"})
98-
return progress(5)
108+
return 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)"})
99109
end
100110
_2amodule_2a["lesson-5"] = lesson_5
101111
local lesson_6_message = "This is the contents of school.lesson-6-message!"
102112
_2amodule_2a["lesson-6-message"] = lesson_6_message
103113
local function lesson_6()
104-
append({"", ";; 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)"})
105-
return progress(6)
114+
return 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)"})
106115
end
107116
_2amodule_2a["lesson-6"] = lesson_6
108117
local function lesson_7()
109-
append({"", ";; 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-aniseed or conjure-client-clojure-nrepl.", "", ";; I hope you have a wonderful time in Conjure!"})
110-
return progress(7)
118+
return 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-aniseed or conjure-client-clojure-nrepl.", "", ";; I hope you have a wonderful time in Conjure!"})
111119
end
112120
_2amodule_2a["lesson-7"] = lesson_7
113121
return _2amodule_2a

0 commit comments

Comments
 (0)