Class: Everywhere::Dock
- Inherits:
-
Object
- Object
- Everywhere::Dock
- Defined in:
- lib/everywhere/dock.rb,
lib/everywhere/dock/state.rb,
lib/everywhere/dock/footer.rb,
lib/everywhere/dock/screen.rb
Overview
The pinned status bar at the bottom of every dev.
The old key menu was printed once, before the loop, and was gone from the screen within seconds of the Rails server starting to log. The dock keeps the keymap — and what each target is actually doing — permanently visible, while the logs scroll normally above it.
It installs itself as Console's sink, so every write in the process (CLI chrome, relayed server output, filtered build output) is framed by an erase and a repaint. See Dock::Screen for why it repaints rather than reserving rows with a scroll region.
Defined Under Namespace
Modules: Footer Classes: Null, Screen, State
Constant Summary collapse
- TICK =
0.2- KEYS =
[ ["d", "desktop"], ["i", "iOS"], ["a", "Android"], ["b", "browser"], ["l", "logs"], ["r", "restart"], ["?", "help"], ["q", "quit"] ].freeze
- HELP =
[ ["d", "relaunch the desktop shell (opens it if it isn't running)"], ["i", "rebuild, reinstall and relaunch on the iOS Simulator"], ["a", "rebuild, reinstall and relaunch on the Android emulator"], ["b", "open the app in your default browser"], ["l", "start/stop streaming iOS Simulator logs"], ["r", "restart the dev server only"], ["?", "hide this help"], ["q", "quit (Ctrl-C works too)"] ].freeze
- MIN_ROWS =
A dock needs room to be worth having, and a terminal that understands cursor movement. NO_COLOR is deliberately NOT a disqualifier: it governs SGR, not cursor control, and the footer's glyphs carry the meaning on their own.
12- MIN_COLS =
40
Instance Attribute Summary collapse
-
#state ⇒ Object
readonly
Returns the value of attribute state.
Class Method Summary collapse
Instance Method Summary collapse
-
#announce_keys ⇒ Object
The dock draws the keymap permanently, so there is nothing to announce.
-
#clear ⇒ Object
Wipe the footer and leave it wiped — for stderr, or an interactive child that needs the screen to itself.
- #close ⇒ Object
- #detail(key, text) ⇒ Object
-
#emit(text) ⇒ Object
Called by Console, which already holds the lock.
-
#initialize(targets, io: $stdout, keys: true, size: nil) ⇒ Dock
constructor
A new instance of Dock.
- #install ⇒ Object
- #refresh ⇒ Object
-
#set(key, state, detail: nil) ⇒ Object
--- state --------------------------------------------------------------.
- #toggle_help ⇒ Object
Constructor Details
#initialize(targets, io: $stdout, keys: true, size: nil) ⇒ Dock
Returns a new instance of Dock.
68 69 70 71 72 73 74 75 76 |
# File 'lib/everywhere/dock.rb', line 68 def initialize(targets, io: $stdout, keys: true, size: nil) @state = State.new(targets) @screen = Screen.new(io: io, size: size) @keys = keys @help = false @frame = 0 @dirty = true @open = false end |
Instance Attribute Details
#state ⇒ Object (readonly)
Returns the value of attribute state.
78 79 80 |
# File 'lib/everywhere/dock.rb', line 78 def state @state end |
Class Method Details
.drawable?(io, size) ⇒ Boolean
59 60 61 62 63 64 65 66 |
# File 'lib/everywhere/dock.rb', line 59 def self.drawable?(io, size) return false if ENV["EVERY_NO_DOCK"] return false unless io.respond_to?(:tty?) && io.tty? return false if ENV["TERM"].to_s.empty? || ENV["TERM"] == "dumb" rows, cols = size || Screen.new(io: io).size rows >= MIN_ROWS && cols >= MIN_COLS end |
.open(targets, io: $stdout, keys: true, size: nil) ⇒ Object
53 54 55 56 57 |
# File 'lib/everywhere/dock.rb', line 53 def self.open(targets, io: $stdout, keys: true, size: nil) return Null.new(targets, keys: keys) unless drawable?(io, size) new(targets, io: io, keys: keys, size: size).tap(&:install) end |
Instance Method Details
#announce_keys ⇒ Object
The dock draws the keymap permanently, so there is nothing to announce. Null overrides this to print the one-shot hint the old command used.
110 |
# File 'lib/everywhere/dock.rb', line 110 def announce_keys = nil |
#clear ⇒ Object
Wipe the footer and leave it wiped — for stderr, or an interactive child that needs the screen to itself.
133 |
# File 'lib/everywhere/dock.rb', line 133 def clear = @screen.clear |
#close ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/everywhere/dock.rb', line 135 def close return unless @open # Order matters: drop the flag so the ticker stops drawing, let it finish # the frame it may be mid-way through, and only then unhook and restore. @open = false @ticker&.join(TICK * 2) @ticker&.kill Console.dock = nil Console.synchronize { @screen.close } end |
#detail(key, text) ⇒ Object
97 98 99 100 |
# File 'lib/everywhere/dock.rb', line 97 def detail(key, text) @state.detail(key, text) @dirty = true end |
#emit(text) ⇒ Object
Called by Console, which already holds the lock. Content must end at column 1, or the erase math for the next frame is off by a row.
116 117 118 119 120 |
# File 'lib/everywhere/dock.rb', line 116 def emit(text) body = text.end_with?("\n") ? text : "#{text}\n" @screen.frame(body, ) @dirty = false end |
#install ⇒ Object
80 81 82 83 84 85 86 87 |
# File 'lib/everywhere/dock.rb', line 80 def install @open = true @screen.open Console.dock = self trap_resize start_ticker self end |
#refresh ⇒ Object
122 123 124 125 126 127 128 129 |
# File 'lib/everywhere/dock.rb', line 122 def refresh Console.synchronize do next unless @open @screen.frame("", ) @dirty = false end end |
#set(key, state, detail: nil) ⇒ Object
--- state --------------------------------------------------------------
91 92 93 94 95 |
# File 'lib/everywhere/dock.rb', line 91 def set(key, state, detail: nil) @state.set(key, state, detail: detail) @dirty = true refresh end |
#toggle_help ⇒ Object
102 103 104 105 106 |
# File 'lib/everywhere/dock.rb', line 102 def toggle_help @help = !@help @dirty = true refresh end |