make_menu 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fde049dc673ab7e43c9254d5b394b9ed592a9d9799e46046c1d935a1d55e4774
4
+ data.tar.gz: 0b289aa24e021fa1ba4f2add414978de9783827fac12e028d38ebb39adcbf80f
5
+ SHA512:
6
+ metadata.gz: 443c5ad6a9eb87e424e7e693ea3e618ecafdbf1d979c03cdbe4c0c31782b6ca3905648fe01a950901b39b7706d3f7ff9870c3cd854f9d5a99218bcd1688553b8
7
+ data.tar.gz: eaf82c95dc0df11c6422c76ed49d634501bcc7ed9a0894d08ca77cb091887766c1767b6bb525a112e067925f3cb8f73647343bb6ff27858800e3a530a5c38d95
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'http://rubygems.org'
4
+
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,17 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ make_menu (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+
10
+ PLATFORMS
11
+ arm64-darwin-21
12
+
13
+ DEPENDENCIES
14
+ make_menu!
15
+
16
+ BUNDLED WITH
17
+ 2.3.26
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MakeMenu
4
+ # Monkeypatch for `String`, adds methods to change console text colo(u)r
5
+ module ColorString
6
+ COLORS = {
7
+ white: 0,
8
+ normal: 0,
9
+ bold: 1,
10
+ dark: 2,
11
+ underline: 4,
12
+ blink: 5,
13
+ invert: 7,
14
+
15
+ black: 30,
16
+ red: 31,
17
+ green: 32,
18
+ yellow: 33,
19
+ blue: 34,
20
+ magenta: 35,
21
+ cyan: 36,
22
+ grey: 37,
23
+
24
+ black_bg: 40,
25
+ red_bg: 41,
26
+ green_bg: 42,
27
+ yellow_bg: 43,
28
+ blue_bg: 44,
29
+ magenta_bg: 45,
30
+ cyan_bg: 46,
31
+ grey_bg: 47,
32
+
33
+ dark_grey: 90,
34
+ light_red: 91,
35
+ light_green: 92,
36
+ light_yellow: 93,
37
+ light_blue: 94,
38
+ light_magenta: 95,
39
+ light_cyan: 96,
40
+ light_grey: 97,
41
+
42
+ dark_grey_bg: 100,
43
+ light_red_bg: 101,
44
+ light_green_bg: 102,
45
+ light_yellow_bg: 103,
46
+ light_blue_bg: 104,
47
+ light_magenta_bg: 105,
48
+ light_cyan_bg: 106,
49
+ light_grey_bg: 107
50
+ }.freeze
51
+
52
+ COLORS.each do |name, code|
53
+ define_method name do
54
+ color(code)
55
+ end
56
+ end
57
+
58
+ # Apply specified color code to the String
59
+ # @param [Array, Symbol, Integer] color_code Can be a key in the COLORS array,
60
+ # an integer ANSI code for text color, or an array of either to be applied in order
61
+ # @return [String] String enclosed by formatting characters
62
+ def color(color_code)
63
+ case color_code
64
+ when Array
65
+ color_code.inject(self) { |string, code| string.color(code) }
66
+ when Symbol
67
+ color(COLORS[color_code])
68
+ else
69
+ "\e[#{color_code}m#{self}\e[0m"
70
+ end
71
+ end
72
+
73
+ # Changes all occurrences of a specified character to one color,
74
+ # and all other characters to another
75
+ # @param [String] char Character to highlight
76
+ # @param [Symbol] fore_color Key of color to use for highlighted character
77
+ # @param [Symbol] back_color Key of color to use for other characters
78
+ # @return [String] Highlighted text
79
+ # @example "==$$==".highlight('$', :light_yellow, :red)
80
+ # rubocop:disable Metrics/MethodLength
81
+ def highlight(char, fore_color, back_color)
82
+ inside_highlight = false
83
+ output = ''
84
+ buffer = ''
85
+ each_char do |c|
86
+ if c == char
87
+ unless inside_highlight
88
+ output += buffer.color(COLORS[back_color.to_sym])
89
+ buffer = ''
90
+ inside_highlight = true
91
+ end
92
+ elsif inside_highlight
93
+ output += buffer.color(COLORS[fore_color.to_sym]).bold
94
+ buffer = ''
95
+ inside_highlight = false
96
+ end
97
+ buffer += c
98
+ end
99
+
100
+ output += if inside_highlight
101
+ buffer.color(COLORS[fore_color.to_sym]).bold
102
+ else
103
+ buffer.color(COLORS[back_color.to_sym])
104
+ end
105
+
106
+ output
107
+ end
108
+ # rubocop:enable Metrics/MethodLength
109
+
110
+ # Remove color codes from the string
111
+ # @return [String] The modified string
112
+ def decolor
113
+ gsub(/\e\[\d+m/, '')
114
+ end
115
+
116
+ # Align the string, ignoring color code characters which would otherwise mess up String#center, etc.
117
+ # @param [Symbol] alignment :left, :center, or :right
118
+ # @param [Integer] width The number of characters to spread the string over (default to terminal width)
119
+ # @param [String] char The character to use for padding
120
+ # @param [Boolean] pad_right Set true to include trailing spaces when aligning to :center
121
+ # @return [String] The padded string
122
+ # rubocop:disable Metrics/MethodLength
123
+ def align(alignment = :left, width: nil, char: ' ', pad_right: false)
124
+ width = ::TTY::Screen.cols unless width
125
+
126
+ case alignment
127
+ when :left
128
+ right_pad = width - decolor.length
129
+ "#{self}#{char * right_pad}"
130
+ when :center
131
+ left_pad = [(width - decolor.length) / 2, 0].max
132
+ right_pad = width - left_pad - decolor.length
133
+ "#{char * left_pad}#{self}#{pad_right ? char * right_pad : ''}"
134
+ when :right
135
+ left_pad = width - decolor.length
136
+ "#{char * left_pad}#{self}"
137
+ end
138
+ end
139
+ # rubocop:enable Metrics/MethodLength
140
+ end
141
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'menu_item_group'
4
+ require_relative 'color_string'
5
+ require_relative 'text_table'
6
+
7
+ module MakeMenu
8
+ # This class builds and displays a number-selection menu from a Makefile
9
+ # then prompts for a number and executes the target.
10
+ class Menu
11
+ # @param [String] makefile Makefile name
12
+ def initialize(makefile)
13
+ @groups = []
14
+ @items = []
15
+ @status_present = false
16
+ build makefile
17
+ end
18
+
19
+ attr_reader :groups, :items
20
+ attr_accessor :status_present
21
+
22
+ # Display menu and prompt for command
23
+ # rubocop:disable Metrics/MethodLength
24
+ def run
25
+ running = true
26
+
27
+ while running
28
+ system 'clear' if clear_screen?
29
+
30
+ display_header
31
+
32
+ puts colorize(TextTable.new(groups).to_s)
33
+ puts
34
+ puts 'Press ENTER to quit'.align(:center).bold
35
+ puts
36
+ print 'Select option: '.align(:center)
37
+
38
+ running = false unless execute_option(gets.strip)
39
+ end
40
+
41
+ puts
42
+
43
+ system 'clear' if clear_screen?
44
+ end
45
+
46
+ # rubocop:enable Metrics/MethodLength
47
+
48
+ # Display the company logo and the status bar (if set)
49
+ def display_header
50
+ puts formatted_logo if logo
51
+ puts `make status` if status_present
52
+ end
53
+
54
+ private
55
+
56
+ # Build a menu from the specified Makefile
57
+ # @param [String] makefile Filename
58
+ # rubocop:disable Metrics/MethodLength
59
+ def build(makefile)
60
+ File.open(makefile, 'r') do |file|
61
+ option_number = 1
62
+ current_group = nil
63
+
64
+ file.each_line do |line|
65
+ if line.start_with? '###'
66
+ # Group header
67
+ group_title = line.gsub(/###\s+/, '').strip
68
+ current_group = MenuItemGroup.new(group_title.color(group_title_color))
69
+ groups << current_group
70
+
71
+ elsif line.match(/^[a-zA-Z_-]+:.*?## .*$$/)
72
+ # Menu item
73
+ target = line.split(':').first.strip
74
+ description = line.split('##').last.strip
75
+
76
+ # Target 'menu' should not appear
77
+ next if target == 'menu'
78
+
79
+ # Target 'status' should not appear, but is run automatically when the menu is rendered
80
+ if target == 'status'
81
+ self.status_present = true
82
+ next
83
+ end
84
+
85
+ unless current_group
86
+ current_group = MenuItemGroup.new
87
+ groups << current_group
88
+ end
89
+
90
+ items << current_group.add_item(
91
+ MenuItem.new(option_number, target, description)
92
+ )
93
+
94
+ option_number += 1
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ # rubocop:enable Metrics/MethodLength
101
+
102
+ # Execute the selected menu item
103
+ # @param [String] selected Value entered by user
104
+ # @return [Boolean] False to signify that menu should exit
105
+ def execute_option(selected)
106
+ return false if selected.empty?
107
+
108
+ selected = selected.to_i
109
+
110
+ items.each do |item|
111
+ next unless item.option_number == selected
112
+
113
+ system 'clear' if clear_screen?
114
+ item.execute
115
+ return true
116
+ end
117
+
118
+ true
119
+ end
120
+
121
+ # Apply word colorings
122
+ # @param [String] string
123
+ # @return [String]
124
+ def colorize(string)
125
+ return string unless Object.const_defined?("#{self.class.name}::HIGHLIGHTS")
126
+
127
+ Object.const_get("#{self.class.name}::HIGHLIGHTS").each do |word, color|
128
+ case color
129
+ when Array
130
+ color.each { |c| string.gsub!(word, word.send(c)) }
131
+ else
132
+ string.gsub!(word, word.send(color))
133
+ end
134
+ end
135
+ string
136
+ end
137
+
138
+ # Center each line of the logo across the screen
139
+ def formatted_logo
140
+ logo.split("\n")
141
+ .map { |line| line.align(:center) }
142
+ .join("\n")
143
+ end
144
+
145
+ # Get the menu logo from the LOGO constant
146
+ def logo
147
+ return "\n#{' make '.black_bg.light_yellow}#{' menu '.light_yellow_bg.black}\n".bold unless Object.const_defined?("#{self.class.name}::LOGO")
148
+
149
+ Object.const_get("#{self.class.name}::LOGO")
150
+ end
151
+
152
+ protected
153
+
154
+ # Override the following methods to customise the menu display
155
+
156
+ # @return [Symbol] Color for group title
157
+ def group_title_color
158
+ :light_green
159
+ end
160
+
161
+ # Clean screen before and after each command
162
+ def clear_screen?
163
+ true
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MakeMenu
4
+ # This class represents an option in the menu which runs a target from the Makefile
5
+ class MenuItem
6
+ INDENT = 6
7
+
8
+ # @param [Integer] option_number Number user enters for this command
9
+ # @param [String] target Name of target defined in Makefile
10
+ # @param [String] description Text to display for this command, taken from Makefile comment
11
+ def initialize(option_number = nil, target = nil, description = nil)
12
+ @option_number = option_number
13
+ @target = target
14
+ @description = description || target
15
+ end
16
+
17
+ attr_reader :option_number, :target, :description
18
+
19
+ # Run the make target
20
+ def execute
21
+ cmd = ['make', target]
22
+ puts "> #{cmd.join(' ').cyan}\n"
23
+ unless system(*cmd)
24
+ # Indicates the command failed, so we pause to allow user to see error message
25
+ puts "\nPress ENTER key to continue....\n"
26
+ gets
27
+ end
28
+ rescue StandardError => _e
29
+ # ignore CTRL+C from within Make target
30
+ end
31
+
32
+ # @return [Integer] Number of characters required to display the item
33
+ def width
34
+ description.size + INDENT + 1
35
+ end
36
+
37
+ # @return [String] Text to display for this item
38
+ def to_s
39
+ "#{option_number.to_s.rjust(INDENT, ' ').bold}. #{description}"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'menu_item'
4
+
5
+ module MakeMenu
6
+ # This class represents a group of menu items, with a title line
7
+ class MenuItemGroup
8
+ INDENT = 2
9
+
10
+ # @param [String] title The title text to display at the top of the group
11
+ def initialize(title = 'Commands')
12
+ @title = title
13
+ @items = []
14
+ end
15
+
16
+ attr_reader :title, :items
17
+
18
+ # Add a new item to the group
19
+ # @param [MenuItem] item The item to add
20
+ # @return [MenuItem] The added item
21
+ def add_item(item)
22
+ items << item
23
+ item
24
+ end
25
+
26
+ # @return [Integer] Number of characters needed to display the widest item
27
+ def width
28
+ [items.map(&:width).max, title.length + INDENT].max
29
+ end
30
+
31
+ # @return [Integer] Number of rows needed to display the group
32
+ def height
33
+ items.size + 2
34
+ end
35
+
36
+ # @return [String] Text representation of group
37
+ def to_s
38
+ result = "#{' ' * INDENT}#{title}\n"
39
+
40
+ items.each do |item|
41
+ result += "#{item}\n"
42
+ end
43
+
44
+ "#{result} "
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'color_string'
4
+ require 'readline'
5
+
6
+ module MakeMenu
7
+ # A panel above the menu displaying the status of Docker containers.
8
+ # The mapping of TextLabel => ContainerName must be defined in a constant called CONTAINERS
9
+ class StatusPanel
10
+ String.include(ColorString)
11
+
12
+ # Print panel
13
+ def display
14
+ return if containers.empty?
15
+
16
+ puts "\n#{panel}"
17
+ end
18
+
19
+ protected
20
+
21
+ # Return a hash mapping label to container name
22
+ # This is assumed to be provided as a constant called CONTAINERS
23
+ # @return [Hash{String=>String}]
24
+ def containers
25
+ Object.const_get "#{self.class.name}::CONTAINERS"
26
+ rescue NameError
27
+ {}
28
+ end
29
+
30
+ # Override this to change the colors for running / not running
31
+ def colors_if_running
32
+ {
33
+ true => %i[green_bg bold white],
34
+ false => %i[red_bg bold dark]
35
+ }.freeze
36
+ end
37
+
38
+ # Override this to limit each row to a maximum number of labels
39
+ def max_labels_per_line
40
+ containers.size
41
+ end
42
+
43
+ private
44
+
45
+ # @return [String] Text representation of the panel
46
+ # rubocop:disable Metrics/MethodLength
47
+ def panel
48
+ return @panel if @panel
49
+
50
+ @panel = ''
51
+ labels_on_this_line = 0
52
+ line_buffer = ''
53
+
54
+ containers.each do |label, container|
55
+ if (labels_on_this_line + 1) > labels_per_line
56
+ @panel += "#{left_indent(labels_on_this_line)}#{line_buffer}\n\n"
57
+ labels_on_this_line = 0
58
+ line_buffer = ''
59
+ end
60
+
61
+ text = label.align(:center, width: max_label_width, pad_right: true)
62
+ .color(colors_if_running[running?(container)])
63
+
64
+ line_buffer += " #{text} "
65
+
66
+ labels_on_this_line += 1
67
+ end
68
+
69
+ @panel += "#{left_indent(labels_on_this_line)}#{line_buffer}\n\n"
70
+ end
71
+ # rubocop:enable Metrics/MethodLength
72
+
73
+ # @return [String] List of Docker containers and information
74
+ def docker_ps
75
+ @docker_ps ||= `docker compose ps`
76
+ end
77
+
78
+ # @return [Boolean] whether specified container is running
79
+ def running?(container)
80
+ docker_ps.include? container
81
+ end
82
+
83
+ # Return the left indent for this line of labels
84
+ # @param [Integer] number_of_labels Number of labels on this line
85
+ # @return [String]
86
+ def left_indent(number_of_labels)
87
+ spaces = (::TTY::Screen.cols - (number_of_labels * (max_label_width + 2))) / 2
88
+ spaces = [spaces, 0].max
89
+ ' ' * spaces
90
+ end
91
+
92
+ # @return [Integer] Maximum label width, with padding
93
+ def max_label_width
94
+ @max_label_width ||= containers.map do |label, _container|
95
+ label.length
96
+ end.max + 2
97
+ end
98
+
99
+ # @return [Integer] Number of labels that can fit on one line
100
+ def labels_per_line
101
+ @labels_per_line ||= [
102
+ (::TTY::Screen.cols / max_label_width) - 1,
103
+ max_labels_per_line
104
+ ].min
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MakeMenu
4
+ # A column of text with a fixed with
5
+ class TextColumn
6
+ # @param [Integer] width Width of the column, in characters
7
+ def initialize(width)
8
+ @width = width
9
+ @rows = []
10
+ @row_index = 0
11
+ end
12
+
13
+ attr_reader :width
14
+
15
+ attr_accessor :rows, :row_index
16
+
17
+ # Add a block of text to the column. Each row will be padded to the column width
18
+ # @param [String] text The text to add, may be multi-line
19
+ def add(text)
20
+ self.rows += text.split("\n").map do |row|
21
+ row.gsub("\r", '')
22
+ end
23
+ self.row_index += text.lines.size
24
+ end
25
+
26
+ # Return the specified row of text
27
+ # @param [Integer] index The index of the row
28
+ # @return [String] The row at the specified index
29
+ def row(index)
30
+ (rows[index] || '').align(width: width)
31
+ end
32
+
33
+ # @return [Integer] The number of rows in the column
34
+ def height
35
+ row_index
36
+ end
37
+
38
+ # @return [Boolean] True if the column is empty
39
+ def empty?
40
+ row_index.zero?
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'text_column'
4
+
5
+ module MakeMenu
6
+ # This class displays the menu groups in columns across the screen.
7
+ # Each group is kept together in a column, and once a column has exceeded the
8
+ # calculated height a new column is added.
9
+ class TextTable
10
+ MAX_COLUMNS = 4
11
+
12
+ # @param [Array<MenuItemGroup>] groups
13
+ def initialize(groups)
14
+ @groups = groups
15
+ @columns = []
16
+ calculate_table_dimensions
17
+ build_table
18
+ end
19
+
20
+ # @return [String] The entire table, centered on the screen
21
+ def to_s
22
+ buffer = ''
23
+
24
+ max_height.times do |i|
25
+ row = ''
26
+ columns.each do |column|
27
+ row += column.row(i) unless column.empty?
28
+ end
29
+ buffer += "#{row.align(:center)}\n"
30
+ end
31
+
32
+ buffer
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :groups, :columns, :column_width, :column_height
38
+
39
+ attr_accessor :current_column
40
+
41
+ # Calculate width and minimum height of columns
42
+ def calculate_table_dimensions
43
+ @column_width = groups.map(&:width).max + 5
44
+ total_rows = groups.map(&:height).sum
45
+ column_count = (::TTY::Screen.cols / column_width).clamp(1, MAX_COLUMNS)
46
+ @column_height = total_rows / column_count
47
+ end
48
+
49
+ # Build columns from groups
50
+ def build_table
51
+ column_break
52
+ groups.each do |group|
53
+ add_text_block group.to_s
54
+ end
55
+ end
56
+
57
+ # Add a block of text to the current column. If the column is now larger than
58
+ # the minimum height, a new column is added
59
+ def add_text_block(text)
60
+ current_column.add(text)
61
+ column_break if current_column.height >= column_height
62
+ end
63
+
64
+ # Add a new column to the table
65
+ def column_break
66
+ self.current_column = TextColumn.new(column_width)
67
+ columns << current_column
68
+ end
69
+
70
+ # @return [Integer] Maximum column height (rows)
71
+ def max_height
72
+ columns.map(&:height).max
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,3 @@
1
+ module MakeMenu
2
+ VERSION = '0.0.1'
3
+ end
data/lib/make_menu.rb ADDED
@@ -0,0 +1,32 @@
1
+ require_relative 'make_menu/color_string'
2
+ require_relative 'make_menu/menu'
3
+ require_relative 'make_menu/status_panel'
4
+
5
+ require 'tty-screen'
6
+
7
+ module MakeMenu
8
+ String.include MakeMenu::ColorString
9
+
10
+ def self.run
11
+ # Allows CTRL+C to return to the menu instead of exiting the script
12
+ trap('SIGINT') { throw StandardError }
13
+
14
+ makefile = ENV.fetch('MAKEFILE', './Makefile')
15
+
16
+ if (menu_name = ENV.fetch('MENU', nil))
17
+ require "./#{menu_name.downcase}_menu.rb"
18
+ Object.const_get("#{menu_name.capitalize}Menu").new(makefile).run
19
+ else
20
+ MakeMenu::Menu.new(makefile).run
21
+ end
22
+ end
23
+
24
+ def self.status
25
+ if (menu_name = ENV.fetch('MENU', nil))
26
+ require "./#{menu_name.downcase}_status_panel.rb"
27
+ Object.const_get("#{menu_name.capitalize}StatusPanel").new.display
28
+ else
29
+ MakeMenu::StatusPanel.new.display
30
+ end
31
+ end
32
+ end
data/make_menu.gemspec ADDED
@@ -0,0 +1,59 @@
1
+ require File.expand_path('lib/make_menu/version', __dir__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "make_menu"
5
+ s.version = MakeMenu::VERSION
6
+ s.summary = "Generates an interactive menu from a Makefile"
7
+ s.authors = ["Barri Mason"]
8
+ s.email = "loki@amarantha.net"
9
+ s.files = Dir[
10
+ 'lib/**/*.rb',
11
+ 'make_menu.gemspec',
12
+ 'Gemfile',
13
+ 'Gemfile.lock'
14
+ ]
15
+ s.homepage =
16
+ "https://rubygems.org/gems/make_menu"
17
+ s.license = "MIT"
18
+ s.add_dependency 'tty-screen', '~> 0.8.2'
19
+ s.description = %(
20
+ Creates a number-selection menu from a Makefile. The menu will attempt to fill the width of the terminal window.
21
+
22
+ - Any targets in the Makefile with a double-hash comment will be displayed, e.g.:
23
+ serve: ## Start Rails server in background
24
+ This will display a line such as '1. Start Rails server in background' which runs the command `make serve`.
25
+
26
+ - A line that starts with a triple-hash will create a new menu group, e.g.:
27
+ ### Docker Commands
28
+ This will begin a new group with the header 'Docker Commands'
29
+
30
+ - The environment variable MENU can be used to specify a custom menu class, e.g.:
31
+ export MENU=Accounts
32
+ This assumes that a class `AccountsMenu` is defined in the file `accounts_menu.rb`
33
+
34
+ You can define two constants in your custom class:
35
+ LOGO (String) text or ASCII art to display above the menu
36
+ HIGHLIGHTS (Hash{String=>[Symbol,Array<Symbol>]}) Add coloring to specific words or phrases
37
+
38
+ - The environment variable MAKEFILE can specify a Makefile. The default is './Makefile'.
39
+
40
+ The menu will not display any targets called 'menu' or 'status'. The latter, if present, is called each
41
+ time the menu displays.
42
+
43
+ -----------------------------
44
+ Docker Container Status Panel
45
+ -----------------------------
46
+
47
+ Displays a color-coded panel indicating whether or not a Docker container is running.
48
+
49
+ You must define a custom class inheriting from `MakeMenu::StatusPanel` and indicate this using
50
+ the environment variable MENU, e.g.:
51
+ export MENU=Accounts
52
+ This assumes that a class `AccountsStatusPanel` is defined in the file `accounts_status_panel.rb`
53
+
54
+ You can define a constant CONTAINERS {String=>String} in this custom class to map the displayed
55
+ label to the container name, e.g.:
56
+ CONTAINERS = { 'Backend' => 'myapp-backend-1' }
57
+
58
+ )
59
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: make_menu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Barri Mason
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-12-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: tty-screen
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.2
27
+ description: |2+
28
+
29
+ Creates a number-selection menu from a Makefile. The menu will attempt to fill the width of the terminal window.
30
+
31
+ - Any targets in the Makefile with a double-hash comment will be displayed, e.g.:
32
+ serve: ## Start Rails server in background
33
+ This will display a line such as '1. Start Rails server in background' which runs the command `make serve`.
34
+
35
+ - A line that starts with a triple-hash will create a new menu group, e.g.:
36
+ ### Docker Commands
37
+ This will begin a new group with the header 'Docker Commands'
38
+
39
+ - The environment variable MENU can be used to specify a custom menu class, e.g.:
40
+ export MENU=Accounts
41
+ This assumes that a class `AccountsMenu` is defined in the file `accounts_menu.rb`
42
+
43
+ You can define two constants in your custom class:
44
+ LOGO (String) text or ASCII art to display above the menu
45
+ HIGHLIGHTS (Hash{String=>[Symbol,Array<Symbol>]}) Add coloring to specific words or phrases
46
+
47
+ - The environment variable MAKEFILE can specify a Makefile. The default is './Makefile'.
48
+
49
+ The menu will not display any targets called 'menu' or 'status'. The latter, if present, is called each
50
+ time the menu displays.
51
+
52
+ -----------------------------
53
+ Docker Container Status Panel
54
+ -----------------------------
55
+
56
+ Displays a color-coded panel indicating whether or not a Docker container is running.
57
+
58
+ You must define a custom class inheriting from `MakeMenu::StatusPanel` and indicate this using
59
+ the environment variable MENU, e.g.:
60
+ export MENU=Accounts
61
+ This assumes that a class `AccountsStatusPanel` is defined in the file `accounts_status_panel.rb`
62
+
63
+ You can define a constant CONTAINERS {String=>String} in this custom class to map the displayed
64
+ label to the container name, e.g.:
65
+ CONTAINERS = { 'Backend' => 'myapp-backend-1' }
66
+
67
+ email: loki@amarantha.net
68
+ executables: []
69
+ extensions: []
70
+ extra_rdoc_files: []
71
+ files:
72
+ - Gemfile
73
+ - Gemfile.lock
74
+ - lib/make_menu.rb
75
+ - lib/make_menu/color_string.rb
76
+ - lib/make_menu/menu.rb
77
+ - lib/make_menu/menu_item.rb
78
+ - lib/make_menu/menu_item_group.rb
79
+ - lib/make_menu/status_panel.rb
80
+ - lib/make_menu/text_column.rb
81
+ - lib/make_menu/text_table.rb
82
+ - lib/make_menu/version.rb
83
+ - make_menu.gemspec
84
+ homepage: https://rubygems.org/gems/make_menu
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubygems_version: 3.3.26
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Generates an interactive menu from a Makefile
107
+ test_files: []
108
+ ...