Skip to content

Commit 1fda350

Browse files
committed
Add documentation
1 parent 0f41745 commit 1fda350

File tree

5 files changed

+308
-0
lines changed

5 files changed

+308
-0
lines changed

docs/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[deps]
2+
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3+
DocumenterMarkdown = "997ab1e6-3595-5248-9280-8efb232c3433"
4+
DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8"

docs/make.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Documenter, TerminalUserInterfaces, DocumenterMarkdown
2+
3+
cp(joinpath(@__DIR__, "../README.md"), joinpath(@__DIR__, "./src/index.md"), force=true, follow_symlinks=true)
4+
5+
makedocs(
6+
sitename="TerminalUserInterfaces.jl documentation",
7+
format = Markdown()
8+
)
9+
10+
deploydocs(
11+
repo = "github.com/kdheepak/TerminalUserInterfaces.jl.git",
12+
deps = Deps.pip(
13+
"mkdocs==0.17.5",
14+
"mkdocs-material==2.9.4",
15+
"python-markdown-math",
16+
"pygments",
17+
"pymdown-extensions",
18+
),
19+
make = () -> run(`mkdocs build`),
20+
target = "site",
21+
)

docs/mkdocs.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
site_name: 'TerminalUserInterfaces.jl'
2+
site_author: 'Dheepak Krishnamurthy'
3+
4+
repo_name: 'GitHub'
5+
repo_url: 'https://github.com/kdheepak/TerminalUserInterfaces.jl'
6+
edit_uri: 'tree/master/docs/src'
7+
8+
pages:
9+
- Home: index.md
10+
- Usage: usage.md
11+
- API: api.md
12+
13+
docs_dir: 'build'
14+
15+
# theme: readthedocs
16+
theme: material
17+
18+
extra:
19+
author:
20+
github: 'kdheepak'
21+
palette:
22+
primary: 'deep orange'
23+
accent: 'indigo'
24+
# version: 0.7.4
25+
26+
markdown_extensions:
27+
- admonition
28+
- codehilite
29+
- pymdownx.arithmatex
30+
- pymdownx.details
31+
- mdx_math
32+
- codehilite
33+
- extra
34+
- tables
35+
- fenced_code
36+
- footnotes
37+
- meta
38+
- toc
39+
40+
extra_css:
41+
- assets\Documenter.css
42+
43+
extra_javascript: [
44+
'mathjax-config.js',
45+
'https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML'
46+
]

docs/src/api.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# API
2+
3+
```@autodocs
4+
Modules = [TerminalUserInterfaces]
5+
```

docs/src/usage.md

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
# Usage
2+
3+
To use it in Julia, first add it:
4+
5+
```
6+
(v1.1)> add TerminalUserInterfaces
7+
```
8+
9+
To build a Terminal User Interface (TUI), you'll need a main loop.
10+
`TerminalUserInterfaces.jl` is a library based on the immediate mode rendering concept.
11+
Every iteration of the main loop, the User Interface is "drawn" from scratch.
12+
This means writing out text to the screen every frame.
13+
14+
While this may appear to be a limitation from a performance perspective, in practice it works well with stateful UI.
15+
Also to increase performance, `TerminalUserInterfaces.jl` maintains two buffers and draws only the difference between frames.
16+
17+
18+
```
19+
START TUI.draw.(t, w) END
20+
*-------*-----*---*----*-----*
21+
^ /
22+
\ v
23+
* <------*
24+
TUI.get_event(t) TUI.flush(t)
25+
```
26+
27+
## Example
28+
29+
```julia
30+
using TerminalUserInterfaces
31+
const TUI = TerminalUserInterfaces
32+
```
33+
34+
### Initialize
35+
36+
To create a TUI, the first thing you need to do is call `initialize`
37+
38+
39+
```julia
40+
TUI.initialize()
41+
```
42+
43+
This function does a few things:
44+
45+
```julia
46+
tui_mode()
47+
hide_cursor()
48+
enable_raw_mode()
49+
clear_screen()
50+
move_cursor_home()
51+
```
52+
53+
- `tui_mode()`: starts an alternate buffer
54+
- `hide_cursor()`: makes cursor not visible
55+
- `enable_raw_mode()`: capture key presses as they happen without waiting for the enter key
56+
- `clear_screen()`: clear the screen of all text
57+
- `move_cursor_home()`: moves the cursor to the top left of the terminal window
58+
59+
Every `TUI.initialize()` at beginning of a program must be paired with `TUI.cleanup()` at the end of a program.
60+
61+
```julia
62+
move_cursor_home()
63+
clear_screen()
64+
disable_raw_mode()
65+
show_cursor()
66+
default_mode()
67+
```
68+
69+
After calling `initialize`, we can create the application.
70+
To start, let's create an instance of `Terminal`.
71+
72+
```julia
73+
t = TUI.Terminal()
74+
```
75+
76+
This holds references to the frame buffers and allows us to call helper functions to create a TUI.
77+
78+
### Draw Widgets
79+
80+
Let's look at an example of a `SelectableList` widget.
81+
82+
![](https://user-images.githubusercontent.com/1813121/74565866-15daa600-4f6a-11ea-8d4a-58ec8e7679a1.gif)
83+
84+
```julia
85+
w, _ = TUI.terminal_size()
86+
rect = TUI.Rect(1, 1, w ÷ 4, 20)
87+
widget = TUI.SelectableList(
88+
TUI.Block(title = "Option Picker"),
89+
words,
90+
scroll,
91+
selection,
92+
)
93+
TUI.draw(t, widget, rect)
94+
```
95+
96+
`TUI.draw(t, widget, rect)` calls `draw(list::SelectableList, area::Rect, buf::Buffer)` which implements how to draw the widget.
97+
The `Buffer` is a `Matrix{Cell}` where `Cell` contains a julia `Char` and information on how to style it.
98+
99+
```julia
100+
struct Cell
101+
char::Char
102+
style::Crayons.Crayon
103+
end
104+
```
105+
106+
This is useful to know when implementing your own widgets.
107+
108+
You can draw as many widgets as you want. If widgets are drawn at the same location, they will overwrite the `Cell` characters in the `Buffer`.
109+
110+
Finally, calling `TUI.flush(t)` draws the current frame to the terminal.
111+
112+
```julia
113+
TUI.flush(t)
114+
```
115+
116+
### Getting user input
117+
118+
`TerminalUserInterfaces.jl` sets up `stdout` and `stdin` `Channel`s
119+
120+
Calling `TUI.get_event(t)` reads from the `stdin` `Channel`.
121+
122+
```julia
123+
function get_event(t)
124+
if isready(t.stdin_channel)
125+
return take!(t.stdin_channel)
126+
end
127+
end
128+
```
129+
130+
This function is non-blocking. You can also call `take!(t.stdin_channel)` to block till the user presses a key.
131+
132+
Drawing, taking user input and acting on it and redrawing is what your main loop of the terminal user interface will look like.
133+
134+
### Minimum Working Example
135+
136+
```julia
137+
using TerminalUserInterfaces
138+
const TUI = TerminalUserInterfaces
139+
using Random
140+
141+
function main()
142+
TUI.initialize()
143+
y, x = 1, 1
144+
145+
count = 1
146+
t = TUI.Terminal()
147+
148+
# TUI.enableRawMode()
149+
TUI.clear_screen()
150+
TUI.hide_cursor()
151+
152+
words = [
153+
"Option A"
154+
"Option B"
155+
"Option C"
156+
"Option D"
157+
"Option E"
158+
"Option F"
159+
"Option G"
160+
"Option H"
161+
"Option I"
162+
]
163+
164+
rng = MersenneTwister()
165+
styles = [
166+
# TUI.Crayon(bold = true)
167+
# TUI.Crayon(italics = true)
168+
# TUI.Crayon(foreground = :red)
169+
# TUI.Crayon(foreground = :blue)
170+
# TUI.Crayon(foreground = :green)
171+
# TUI.Crayon(bold = true, foreground = :red)
172+
# TUI.Crayon(bold = true, foreground = :blue)
173+
# TUI.Crayon(bold = true, foreground = :green)
174+
# TUI.Crayon(italics = true, foreground = :red)
175+
# TUI.Crayon(italics = true, foreground = :blue)
176+
# TUI.Crayon(italics = true, foreground = :green)
177+
TUI.Crayon()
178+
]
179+
180+
words = [TUI.Word(word, styles[rand(rng, 1:length(styles))]) for word in words]
181+
182+
scroll = 1
183+
selection = 1
184+
final = ""
185+
186+
while true
187+
188+
w, _ = TUI.terminal_size()
189+
190+
r = TUI.Rect(x, y, w ÷ 4, 20)
191+
192+
b = TUI.Block(title = "Option Picker")
193+
p = TUI.SelectableList(
194+
b,
195+
words,
196+
scroll,
197+
selection,
198+
)
199+
200+
TUI.draw(t, p, r)
201+
202+
TUI.flush(t)
203+
204+
count += 1
205+
206+
c = TUI.get_event(t)
207+
208+
if c == 'j'
209+
selection += 1
210+
elseif c == 'k'
211+
selection -= 1
212+
elseif c == '\r'
213+
final = words[selection].text
214+
break
215+
end
216+
if selection < 1
217+
selection = 1
218+
end
219+
if selection > length(words)
220+
selection = length(words)
221+
end
222+
223+
end
224+
225+
TUI.cleanup()
226+
227+
println(final)
228+
229+
end
230+
231+
main()
232+
```

0 commit comments

Comments
 (0)