raindown 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/raindown/cli.rb +2 -2
  3. data/lib/raindown/document.rb +15 -4
  4. data/lib/raindown/endpoint/curl.rb +15 -0
  5. data/lib/raindown/projects.rb +8 -4
  6. data/lib/raindown/tui/card.rb +56 -0
  7. data/lib/raindown/tui/endpoint.rb +16 -0
  8. data/lib/raindown/tui/endpoints.rb +40 -0
  9. data/lib/raindown/tui/events.rb +35 -0
  10. data/lib/raindown/tui/file_tree.rb +53 -11
  11. data/lib/raindown/tui/layout.rb +60 -78
  12. data/lib/raindown/tui/menu_overlay.rb +59 -0
  13. data/lib/raindown/tui/navigator/commands.rb +84 -0
  14. data/lib/raindown/tui/navigator/focus.rb +25 -0
  15. data/lib/raindown/tui/navigator/navigator.rb +127 -0
  16. data/lib/raindown/tui/navigator/project_menu.rb +61 -0
  17. data/lib/raindown/tui/navigator/views.rb +49 -0
  18. data/lib/raindown/tui/renderers/dashboard_renderer.rb +102 -0
  19. data/lib/raindown/tui/renderers/endpoint_renderer.rb +77 -0
  20. data/lib/raindown/tui/renderers/list_renderer.rb +15 -0
  21. data/lib/raindown/tui/renderers/outline_renderer.rb +21 -0
  22. data/lib/raindown/tui/renderers/renderer.rb +15 -0
  23. data/lib/raindown/tui/row.rb +10 -3
  24. data/lib/raindown/tui/rows.rb +57 -0
  25. data/lib/raindown/tui/{input.rb → terminal/input.rb} +10 -11
  26. data/lib/raindown/tui/terminal/ncurses_shim.rb +46 -0
  27. data/lib/raindown/tui/terminal/quiet.rb +32 -0
  28. data/lib/raindown/tui/{screen.rb → terminal/screen.rb} +32 -17
  29. data/lib/raindown/tui/terminal/styles.rb +96 -0
  30. data/lib/raindown/tui/text.rb +83 -0
  31. data/lib/raindown/tui/title.rb +29 -0
  32. data/lib/raindown/tui/views/dashboard_view.rb +145 -0
  33. data/lib/raindown/tui/views/endpoint_view.rb +75 -0
  34. data/lib/raindown/tui/{pane.rb → views/list_view.rb} +9 -8
  35. data/lib/raindown/tui/{outline.rb → views/outline_view.rb} +39 -20
  36. data/lib/raindown/tui/workers/project.rb +122 -0
  37. data/lib/raindown/tui/workers/worker.rb +124 -0
  38. data/lib/raindown/tui/workers/workers.rb +53 -0
  39. data/lib/raindown/tui.rb +8 -5
  40. data/lib/version.rb +1 -1
  41. metadata +32 -9
  42. data/lib/raindown/tui/commands.rb +0 -70
  43. data/lib/raindown/tui/navigator.rb +0 -123
  44. data/lib/raindown/tui/styles.rb +0 -36
@@ -1,123 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'file_tree'
4
- require_relative 'commands'
5
- require_relative 'outline'
6
- require_relative 'pane'
7
-
8
- module Raindown
9
- module TUI
10
- # What the terminal UI shows and does, in plain Ruby, with no terminal: a FileTree of the project's Markdown files,
11
- # beside the open file's Outline. The Screen draws it and sends it events, like :down or
12
- # [:press, :outline, 3, :execute], and handle returns what the Screen should do next:
13
- # nil draw again
14
- # :quit stop
15
- # [:run, command] leave the screen to run a command, like the editor, then call ran
16
- # [:wait, message, task] show the message while the task runs, like an endpoint's request
17
- class Navigator
18
- include Commands
19
-
20
- # Keys of the events that move the cursor or the focus, and those that act on what's selected.
21
- MOVES = { up: -1, down: 1 }.freeze
22
- PANES = { tab: nil, left: :files, right: :outline }.freeze
23
- ACTIONS = { execute: :execute, edit: :edit, write_back: :write_back, reload: :reload, tick: :refresh }.freeze
24
-
25
- attr_reader :focus, :status
26
-
27
- def initialize(root:, path: nil)
28
- @files = FileTree.new(root:)
29
- @focus = :files
30
- @panes = { files: Pane.new { @files.rows }, outline: Pane.new { @outline ? @outline.rows : [] } }
31
- @status = [:info, 'Tab switches panes, Enter opens and folds, q quits']
32
- first = @files.rows.find { it.kind == :file }&.target
33
- show(path || first) if path || first
34
- end
35
-
36
- def handle(event)
37
- name, *args = event
38
- return :quit if name == :quit
39
- return move(MOVES[name]) if MOVES.key?(name)
40
- return switch(PANES[name] || other_pane) if PANES.key?(name)
41
- return select(*args) if name == :select
42
- return press(*args) if name == :press
43
- return activate(name) if %i[enter toggle].include?(name)
44
-
45
- send(ACTIONS[name]) if ACTIONS.key?(name)
46
- end
47
-
48
- # After the editor closes, the file is written back, like a save while it's watched, and read again.
49
- def ran
50
- write_back
51
- end
52
-
53
- def root = @files.root
54
- def path = @outline&.path
55
- def relative(path) = @files.relative(path)
56
-
57
- def rows(pane) = @panes[pane].rows
58
- def cursor(pane) = @panes[pane].cursor
59
- def visible(pane, height) = @panes[pane].visible(height)
60
-
61
- private
62
-
63
- def show(path)
64
- @outline = Outline.new(File.expand_path(path))
65
- @panes[:outline].reset
66
- end
67
-
68
- def other_pane
69
- @focus == :files ? :outline : :files
70
- end
71
-
72
- def move(by)
73
- @panes[@focus].move(by)
74
- nil
75
- end
76
-
77
- def switch(pane)
78
- @focus = pane
79
- nil
80
- end
81
-
82
- def select(pane, index)
83
- @focus = pane
84
- @panes[pane].cursor = index
85
- nil
86
- end
87
-
88
- def press(pane, index, event)
89
- select(pane, index)
90
- handle(event)
91
- end
92
-
93
- def selected(pane = @focus)
94
- @panes[pane].selected
95
- end
96
-
97
- # Enter opens what's selected, or folds it, and Space only folds.
98
- # A line of output, or a directive without any, opens in the editor.
99
- def activate(name)
100
- row = selected
101
- return edit if name == :enter && editable?(row)
102
-
103
- case row&.kind
104
- when :folder then @files.toggle(row.target)
105
- when :file then open_file(row.target) if name == :enter
106
- when :heading then @outline.fold(row.target)
107
- when :directive then @outline.expand(row.target) if row.target.output
108
- end
109
- nil
110
- end
111
-
112
- def editable?(row)
113
- row&.kind == :output || (row&.kind == :directive && !row.target.output)
114
- end
115
-
116
- def open_file(path)
117
- show(path)
118
- @focus = :outline
119
- info("Opened #{relative(path)}")
120
- end
121
- end
122
- end
123
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'curses'
4
-
5
- module Raindown
6
- module TUI
7
- # The curses attributes of a Layout's styles, in colour on the terminal's own background when it has colours.
8
- module Styles
9
- COLORS = { directive: Curses::COLOR_CYAN, button: Curses::COLOR_YELLOW, error: Curses::COLOR_RED,
10
- folder: Curses::COLOR_BLUE }.freeze
11
-
12
- module_function
13
-
14
- # Sets up the colours, once the screen has started, and returns the attribute of each style.
15
- def start
16
- colors = Curses.has_colors?
17
- start_colors if colors
18
- color = ->(name) { colors ? Curses.color_pair(COLORS.keys.index(name) + 1) : Curses::A_NORMAL }
19
-
20
- {
21
- title: Curses::A_REVERSE | Curses::A_BOLD, selected: Curses::A_REVERSE, cursor: Curses::A_UNDERLINE,
22
- heading: Curses::A_BOLD, directive: color[:directive], output: Curses::A_DIM,
23
- error: color[:error] | Curses::A_BOLD, button: color[:button] | Curses::A_BOLD,
24
- selected_button: color[:button] | Curses::A_REVERSE, folder: color[:folder] | Curses::A_BOLD,
25
- key: Curses::A_REVERSE, border: Curses::A_DIM
26
- }
27
- end
28
-
29
- def start_colors
30
- Curses.start_color
31
- Curses.use_default_colors
32
- COLORS.each_value.with_index(1) { |color, pair| Curses.init_pair(pair, color, -1) }
33
- end
34
- end
35
- end
36
- end