foruiman 0.1.2

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.
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "unicode/display_width"
4
+ require_relative "../ansi"
5
+
6
+ module Foruiman::TUI
7
+ module Text
8
+ module_function
9
+
10
+ def width(text)
11
+ Unicode::DisplayWidth.of(text.gsub(Foruiman::ANSI::SGR, ""), emoji: :all)
12
+ end
13
+
14
+ def clip(text, columns, ellipsis: false)
15
+ return "" unless columns.positive?
16
+ return text if width(text) <= columns
17
+
18
+ limit = ellipsis ? columns - 1 : columns
19
+ used = 0
20
+ output = +""
21
+ text.scan(/\e\[[0-9;:]*m|\X/).each do |token|
22
+ if token.start_with?("\e[")
23
+ output << token
24
+ next
25
+ end
26
+ cells = Unicode::DisplayWidth.of(token, emoji: :all)
27
+ break if used + cells > limit
28
+
29
+ output << token
30
+ used += cells
31
+ end
32
+ output << "…" if ellipsis
33
+ output
34
+ end
35
+
36
+ def pad(text, columns)
37
+ clipped = clip(text, columns)
38
+ clipped + (" " * [columns - width(clipped), 0].max)
39
+ end
40
+
41
+ def clean(text)
42
+ Foruiman::ANSI::Decoder.new.feed(text, eof: true).gsub(Foruiman::ANSI::SGR, "").tr("\n", " ")
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../ansi"
4
+
5
+ module Foruiman::TUI
6
+ # Use the terminal's palette and default background, so its theme owns the
7
+ # actual colors (and can change them while Foruiman is running).
8
+ class Theme
9
+ COLORS = {
10
+ text: 39, muted: 90, faint: 90, border: 90, accent: 36,
11
+ green: 32, red: 31, amber: 33, cyan: 36, blue: 34, mauve: 35
12
+ }.freeze
13
+ PROCESS_COLORS = %i[cyan amber mauve green blue red].freeze
14
+ STATUS_COLORS = {
15
+ pending: :faint, running: :green, restarting: :amber, stopping: :amber,
16
+ stopped: :muted, exited: :muted, failed: :red
17
+ }.freeze
18
+ STATUS_MARKS = {
19
+ pending: "○", running: "●", restarting: "↻", stopping: "◌",
20
+ stopped: "■", exited: "✓", failed: "×"
21
+ }.freeze
22
+
23
+ attr_reader :enabled
24
+
25
+ def initialize(env: ENV)
26
+ @enabled = env.fetch("NO_COLOR", "").empty? && env["TERM"] != "dumb"
27
+ end
28
+
29
+ def base
30
+ enabled ? "\e[39m\e[49m" : ""
31
+ end
32
+
33
+ def paint(text, color = :text, selected: false, bold: false)
34
+ emphasis = "#{"\e[7m" if selected}#{"\e[1m" if bold}"
35
+ return emphasis.empty? ? text : "#{emphasis}#{text}#{reset}" unless enabled
36
+
37
+ defaults = selected ? base : "#{code(color)}\e[49m"
38
+ "#{defaults}#{emphasis}#{text}#{reset}"
39
+ end
40
+
41
+ def reset
42
+ enabled ? Foruiman::ANSI::RESET + base : Foruiman::ANSI::RESET
43
+ end
44
+
45
+ def process(index)
46
+ PROCESS_COLORS[index % PROCESS_COLORS.size]
47
+ end
48
+
49
+ # A child reset restores the UI's defaults. Explicit child colors, including
50
+ # background colors, still win; they cannot bleed into borders or later rows.
51
+ def log(text, color: :text)
52
+ return text.gsub(Foruiman::ANSI::SGR, "") unless enabled
53
+
54
+ defaults = "#{code(color)}\e[49m"
55
+ styles = Foruiman::ANSI::Styles.new
56
+ content = text.gsub(Foruiman::ANSI::SGR) do |sequence|
57
+ styles.apply(sequence)
58
+ Foruiman::ANSI::RESET + defaults + styles.prefix
59
+ end
60
+ defaults + content + reset
61
+ end
62
+
63
+ private
64
+
65
+ def code(color)
66
+ return "" unless enabled
67
+
68
+ "\e[#{COLORS.fetch(color)}m"
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Foruiman::TUI
4
+ class Viewport
5
+ attr_reader :following, :anchor
6
+
7
+ def initialize
8
+ @following = true
9
+ @anchor = nil
10
+ end
11
+
12
+ def rows(buffer, height)
13
+ height = [height, 0].max
14
+ start = top(buffer, height)
15
+ Array.new([height, buffer.size - start].min) { |offset| buffer[start + offset] }
16
+ end
17
+
18
+ def scroll(delta, buffer, height)
19
+ index = top(buffer, height)
20
+ @following = false
21
+ set_anchor(index + delta, buffer, height)
22
+ end
23
+
24
+ def home(buffer)
25
+ @following = false
26
+ @anchor = buffer[0]&.sequence
27
+ end
28
+
29
+ def follow
30
+ @following = true
31
+ @anchor = nil
32
+ end
33
+
34
+ def toggle(buffer, height)
35
+ following ? scroll(0, buffer, height) : follow
36
+ end
37
+
38
+ private
39
+
40
+ def top(buffer, height)
41
+ last = [buffer.size - height, 0].max
42
+ return last if following
43
+
44
+ index = buffer.index_of(anchor) || 0
45
+ index = [index, last].min
46
+ @anchor = buffer[index]&.sequence
47
+ index
48
+ end
49
+
50
+ def set_anchor(index, buffer, height)
51
+ last = [buffer.size - height, 0].max
52
+ index = index.clamp(0, last)
53
+ @anchor = buffer[index]&.sequence
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Foruiman
4
+ VERSION = "0.1.2"
5
+ end
data/lib/foruiman.rb ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Foruiman
4
+ class Error < StandardError
5
+ end
6
+ end
7
+
8
+ require_relative "foruiman/version"
9
+ require_relative "foruiman/procfile"
10
+ require_relative "foruiman/env"
11
+ require_relative "foruiman/engine"
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: foruiman
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Foruiman contributors
8
+ - David Dollar
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 1980-01-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: unicode-display_width
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '3.1'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '4'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '3.1'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '4'
53
+ description: Run a Procfile in a terminal interface or a plain stream. Derived from
54
+ Foreman.
55
+ executables:
56
+ - foruiman
57
+ extensions: []
58
+ extra_rdoc_files: []
59
+ files:
60
+ - CHANGELOG.md
61
+ - LICENSE
62
+ - README.md
63
+ - bin/foruiman
64
+ - docs/ARCHITECTURE.md
65
+ - docs/ASSUMPTIONS.md
66
+ - docs/COMPATIBILITY.md
67
+ - docs/RAILS.md
68
+ - docs/UPSTREAM.md
69
+ - docs/terminal-preview.png
70
+ - lib/foruiman.rb
71
+ - lib/foruiman/ansi.rb
72
+ - lib/foruiman/cli.rb
73
+ - lib/foruiman/diagnostics.rb
74
+ - lib/foruiman/engine.rb
75
+ - lib/foruiman/env.rb
76
+ - lib/foruiman/log_store.rb
77
+ - lib/foruiman/output.rb
78
+ - lib/foruiman/plain.rb
79
+ - lib/foruiman/process.rb
80
+ - lib/foruiman/procfile.rb
81
+ - lib/foruiman/ring.rb
82
+ - lib/foruiman/tui/application.rb
83
+ - lib/foruiman/tui/keyboard.rb
84
+ - lib/foruiman/tui/log_formatter.rb
85
+ - lib/foruiman/tui/renderer.rb
86
+ - lib/foruiman/tui/state.rb
87
+ - lib/foruiman/tui/terminal.rb
88
+ - lib/foruiman/tui/text.rb
89
+ - lib/foruiman/tui/theme.rb
90
+ - lib/foruiman/tui/viewport.rb
91
+ - lib/foruiman/version.rb
92
+ homepage: https://github.com/Nuzair46/foruiman
93
+ licenses:
94
+ - MIT
95
+ metadata:
96
+ rubygems_mfa_required: 'true'
97
+ source_code_uri: https://github.com/Nuzair46/foruiman
98
+ changelog_uri: https://github.com/Nuzair46/foruiman/blob/main/CHANGELOG.md
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '3.2'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubygems_version: 4.0.16
114
+ specification_version: 4
115
+ summary: A Procfile supervisor with process tabs, bounded logs, and isolated restarts
116
+ test_files: []