module Termclock
Constants
- ANTIFLICKER
- CLEAR
- EMPTY
- EPSILON
- FILESYSTEM_LABEL
- GC_COMPACT_TIME
- LANG
- LANGS
All languages
- NEWLINE
- SPACE
- TAB
- TRANSLATIONS
- TRANSLATION_FILES
Load translations
- VERSION
Public Class Methods
center_puts(message)
click to toggle source
# File lib/termclock/center_puts.rb, line 2 def self.center_puts(message) winsize = STDOUT.winsize puts "\e[2J\e[H\e[3J\e[#{winsize[0] / 2}H"\ "#{?\s.*(winsize[1] / 2 - message.bytesize / 2)}#{message}" end
hex2rgb(hex)
click to toggle source
# File lib/termclock/hex2rgb.rb, line 2 def self.hex2rgb(hex) colour = hex.dup.to_s colour.strip! colour.downcase! colour[0] = EMPTY if colour[0] == ?#.freeze # out of range oor = colour.scan(/[^a-f0-9]/) unless oor.empty? invalids = colour.chars.map { |x| oor.include?(x) ? "\e[1;31m#{x}\e[0m" : x }.join puts "Hex Colour ##{invalids} is Out of Range" raise ArgumentError end clen = colour.length if clen == 3 colour.chars.map { |x| x.<<(x).to_i(16) } elsif clen == 6 colour.chars.each_slice(2).map { |x| x.join.to_i(16) } else sli = clen > 6 ? 'too long'.freeze : clen < 3 ? 'too short'.freeze : 'invalid'.freeze raise ArgumentError, "Invalid Hex Colour ##{colour} (length #{sli})" end end
start(colour1, colour2, colour3, colour4, textcolour1 = nil, textcolour2 = nil, refresh: 0.1, bold: false, italic: false, print_info: true, print_message: true, print_date: true, time_format: "%H %M %S %2N", date_format: '%a, %d %B %Y', no_logo: false, anti_flicker: false, logo_colour: [Termclock.hex2rgb('ff0'), Termclock.hex2rgb('f55'), Termclock.hex2rgb('55f')] )
click to toggle source
# File lib/termclock/start.rb, line 2 def self.start(colour1, colour2, colour3, colour4, textcolour1 = nil, textcolour2 = nil, refresh: 0.1, bold: false, italic: false, print_info: true, print_message: true, print_date: true, time_format: "%H %M %S %2N", date_format: '%a, %d %B %Y', no_logo: false, anti_flicker: false, logo_colour: [Termclock.hex2rgb('ff0'), Termclock.hex2rgb('f55'), Termclock.hex2rgb('55f')] ) clear_character = anti_flicker ? ANTIFLICKER : CLEAR generate = proc do |start, stop, n = 5| r_op = r_val = nil ary = [] if start > stop r_op, r_val = :-, start.-(stop).fdiv(n - 1) elsif start < stop r_op, r_val = :+, stop.-(start).fdiv(n - 1) end _r = r_op ? start.send(r_op, r_val * -1) : start n.times { _r = _r.send(r_op, r_val) if r_op ary << _r.clamp(0, 255).to_i } ary end gc_compact, gc_compacted = GC.respond_to?(:compact), Time.now.to_i + GC_COMPACT_TIME r1, g1, b1 = *colour1 r2, g2, b2 = *colour2 r3, g3, b3 = *colour3 r4, g4, b4 = *colour4 # colour1 -> colour3 rs1 = generate.(r1, r3) gs1 = generate.(g1, g3) bs1 = generate.(b1, b3) # colour2 -> colour4 rs2 = generate.(r2, r4) gs2 = generate.(g2, g4) bs2 = generate.(b2, b4) # All Gradient Colours colours = [rs1, gs1, bs1].transpose.zip([rs2, gs2, bs2].transpose) colours.unshift(colours[0]) colours.push(colours[-1]) # Text colours tc1 = textcolour1 ? hex2rgb(textcolour1) : hex2rgb('5555ff') tc2 = textcolour2 ? hex2rgb(textcolour2) : hex2rgb('3ce3b5') message_counter = -1 message = '' message_final = '' message_align = 0 message_temp = '' date, info = '', '' clock_emoji = ?\u{1F550}.ord.-(1).chr('utf-8') clock_emoji = 12.times.map { clock_emoji.next!.dup } braille = %W(\u2821 \u2811 \u2812 \u280A \u280C) get_message = proc { braille.rotate! braille_0 = braille[0] case Time.now.hour when 5...12 _m = translate('Good Morning') "\u{1F304} #{braille_0} #{_m} #{braille_0} \u{1F304}" when 12...16 _m = translate('Good Afternoon') "\u26C5 #{braille_0} #{_m} #{braille_0} \u26C5" when 16...18 _m = translate('Good Evening') "\u{1F307} #{braille_0} #{_m} #{braille_0} \u{1F307}" when 18...20 _m = translate('Good Evening') "\u{1F31F} #{braille_0} #{_m} #{braille_0} \u{1F31F}" when 20...24 _m = translate('Good Night') "\u{1F303} #{braille_0} #{_m} #{braille_0} \u{1F303}" else _m = translate('Good Night') "\u{2728} #{braille_0} #{_m} #{braille_0} \u{2728}" end } version = "Termclock v#{Termclock::VERSION}" v_col1 = logo_colour[0] v_col2 = logo_colour[1] v_col3 = logo_colour[2] vl_2 = version.length / 2 _term_clock_v = version[0...vl_2].gradient(v_col1, v_col2, underline: true, bold: bold, italic: italic) << version[vl_2..-1].gradient(v_col2, v_col3, underline: true, bold: bold, italic: italic) term_clock_v = '' chop_message = 0 deviation = 0 time_seperators = [?:, ?$] time_seperator = time_seperators[0] point_five_tick = -0.5 height, width = *STDOUT.winsize height2, width2 = *STDOUT.winsize print CLEAR while true monotonic_time_1 = Process.clock_gettime(Process::CLOCK_MONOTONIC) time_now = Time.now height, width = *STDOUT.winsize if time_now.to_f > point_five_tick point_five_tick = time_now.to_f + 0.5 time_seperators.rotate! clock_emoji.rotate! time_seperator = time_seperators[0] end unless no_logo term_clock_v = "\e[#{height}H #{clock_emoji[0]} #{_term_clock_v} \e[0m" end if print_message message_temp = get_message.call message_counter += 1 message_length = message.length if (width - message_counter % width < 8) unless chop_message == message_temp.length chop_message += 1 message_counter -= 1 message_align -= 1 _chopped = message_temp[chop_message..-1] message.replace(_chopped) if _chopped end else chop_message = 0 unless chop_message == 0 message.clear if width - message_counter % width == width message_align = width - message_counter % width + message_length - 4 if message_temp != message if message_length < message_temp.length message.replace(message_temp[0..message_length]) else message.replace(message_temp) end end end message_final = message.rjust(message_align).gradient( tc1, tc2, exclude_spaces: true, bold: bold, italic: italic ) end info = system_info(width, tc1, tc2, bold, italic) if print_info if print_date _date = time_now.strftime(date_format) unless LANG == :en _date = _date.split(/(\W)/).map { |x| translate( x, breakword: !x[/[^0-9]/] ) }.join end date = _date.center(width) .gradient(tc1, tc2, bold: bold, italic: italic, exclude_spaces: true) end time = time_now.strftime(time_format).split.join(time_seperator) art = Termclock::ParseCharacters.display(time).lines art_aligned = art.each_with_index do |x, i| chomped = x.chomp(EMPTY).+(NEWLINE) gr = chomped.gradient(*colours[i], bold: bold, italic: italic) w = width./(2.0).-(chomped.length / 2.0) + 2 w = 0 if w < 0 x.replace(SPACE.*(w) + gr) end.join vertical_gap = "\e[#{height./(2.0).-(art.length / 2.0).to_i + 1}H" final_output = "#{info}#{vertical_gap}#{art_aligned}\n#{date}\n\n\e[K#{message_final}#{term_clock_v}" if anti_flicker && (height != height2 || width != width2) height2, width2 = *STDOUT.winsize print CLEAR end print "#{clear_character}#{final_output}" if gc_compact && time_now.to_i > gc_compacted GC.compact gc_compacted = time_now.to_i + GC_COMPACT_TIME end monotonic_time_2 = Process.clock_gettime(Process::CLOCK_MONOTONIC) time_diff = monotonic_time_2 - monotonic_time_1 sleep_time = refresh.-(time_diff + deviation) sleep_time = 0 if sleep_time < 0 sleep(sleep_time) deviation = Process.clock_gettime(Process::CLOCK_MONOTONIC).-(monotonic_time_2 + sleep_time + EPSILON) end end
system_info(width, tc1, tc2, bold, italic)
click to toggle source
# File lib/termclock/system_info.rb, line 18 def system_info(width, tc1, tc2, bold, italic) unless @@cpu_usage_t.alive? @@cpu_usage_t = Thread.new { _cpu_usage = LS::CPU.usage(0.25) @@cpu_usage = _cpu_usage ? "%0.2f".freeze % _cpu_usage : nil } end unless @@current_net_usage_t.alive? @@current_net_usage_t = Thread.new do _m = LS::Net.current_usage(0.25) _dl = _m[:received] _ul = _m[:transmitted] @@current_net_usage = if _dl && _ul _tr = translate('Curr. DL/UL') dl = LS::PrettifyBytes.convert_short_decimal(_dl) ul = LS::PrettifyBytes.convert_short_decimal(_ul) "\u{1F4CA} #{_tr}: #{t!("%-9s" % dl)} | #{t!("%9s" % ul)}" else EMPTY end end end cpu = if @@cpu_usage _tr = translate('CPU') "\u{1F9E0} #{_tr}: #{t!("%6s" % @@cpu_usage)}% (#{t!(LS::CPU.count_online)}/#{t!(LS::CPU.count)})" else EMPTY end battery = if LS::Battery.present? stat = LS::Battery.stat charge = stat[:charge].to_i emoji, plug = "\u{1F50B}".freeze, EMPTY if LS::Battery.charging? emoji, plug = "\u{1F4A1}".freeze, "\u{1F50C} ".freeze end lives = "\u2665 ".freeze.*(charge.fdiv(20).ceil).chop _tr = translate('Battery') "#{emoji} #{_tr}: #{t!(charge)}% #{lives} (#{plug}#{translate(stat[:status])})" else EMPTY end _tr = translate('User') user = "\u{1F481} #{_tr}: #{LS::User.get_current_user.capitalize}" _tr = translate('Hostname') hostname = "\u{1F4BB} #{_tr}: #{LS::OS.hostname}" _tr = translate('IP Addr') _m = LS::Net.total_bytes ip = "\u{1F30F} #{_tr}: #{translate(LS::Net.ipv4_private, b: true)}" _received = _m[:received] _transmitted = _m[:transmitted] _tr = translate('Totl. DL/UL') tot_received = _received ? "\u{1F4C8} #{_tr}: #{t!('%-9s'.freeze % LS::PrettifyBytes.convert_short_decimal(_m[:received]))}" : nil tot_transmitted = _transmitted ? " | #{t!('%9s'.freeze % LS::PrettifyBytes.convert_short_decimal(_transmitted))}" : nil net_usage = if tot_received && tot_transmitted tot_received + tot_transmitted else EMPTY end _m = LS::Memory.stat _m.default = 0 _tr = translate('Mem') memory = "\u{1F3B0} #{_tr}: #{t!(LS::PrettifyBytes.convert_short_decimal(_m[:used] * 1000))}"\ " / #{t!(LS::PrettifyBytes.convert_short_decimal(_m[:total] * 1000))}"\ " (#{t!("%.2f" % _m[:percent_used])}%)" _m = LS::Swap.stat _m.default = 0 _tr = translate('Swap') swap = "\u{1F300} #{_tr}: #{t!(LS::PrettifyBytes.convert_short_decimal(_m[:used] * 1000))}"\ " / #{t!(LS::PrettifyBytes.convert_short_decimal(_m[:total] * 1000))}"\ " (#{t!("%.2f" % _m[:percent_used])}%)" _m = LS::Filesystem.stat(FILESYSTEM) _m.default = 0 _tr = translate('FS') fs = "\u{1F4BD} #{_tr} (#{FILESYSTEM_LABEL}): #{t!(LS::PrettifyBytes.convert_short_decimal(_m[:used]))}"\ " / #{t!(LS::PrettifyBytes.convert_short_decimal(_m[:total]))}"\ " (#{t!("%.2f" % _m[:used].*(100).fdiv(_m[:total]).round(2))}%)" pt = LS::Process.types.values process = if pt.length > 0 _tr = translate('Process') "\u{1F3ED} #{_tr}: T:#{t!("%4s" % pt.length)}|"\ "R:#{"%3s" % t!(pt.count(:running))}|"\ "S:#{"%3s" % t!(pt.count(:sleeping))}|"\ "I:#{"%3s" % t!(pt.count(:idle))}" else EMPTY end @@os_v ||= unless LS::OS.version.empty? " (#{LS::OS.version})" else EMPTY end _tr = translate('Distrib') @@os ||= "\u{1F427} #{_tr}: #{LS::OS.distribution} #{LS::OS.machine}#{@@os_v}" _temp_uptime = LS::OS.uptime _uptime = unless _temp_uptime.empty? _temp_uptime else _u = LS::OS.uptime_i { hour: _u / 3600, minute: _u % 3600 / 60, second: _u % 3600 % 60, jiffy: 0 } end _second = _uptime[:second] _second_i = _second.to_i hour = "%02d" % _uptime[:hour] minute = "%02d" % _uptime[:minute] second = "%02d" % _uptime[:second] jiffy = "%02d" % _uptime[:jiffy] _tr = translate('Uptime') uptime = "\u{1F3A1} #{_tr}: #{t! hour}:#{t! minute}:#{t! second}:#{t! jiffy} (#{t! LS::OS.uptime_i}s)" _tr = translate('LoadAvg') _loadavg = LS::Sysinfo.loads.map! { |x| "%.2f" % x } loadavg = "\u{1F525} #{_tr}: 1m #{translate(_loadavg[0], b: true)}|5m #{translate(_loadavg[1], b: true)}|15m #{translate(_loadavg[2], b: true)}" all_info = [] max_l = 0 i = -1 [ user, hostname, @@os, battery, cpu, ip, memory, @@current_net_usage, swap, net_usage, fs, process, uptime, loadavg ].each { |x| unless x.empty? all_info << x i += 1 if i.odd? _x_len = x.length max_l = _x_len if max_l < _x_len end end } max_l += 4 all_info.each_slice(2).map { |x, y| _diff = width.-(x.length + max_l) _diff = 0 if _diff < 1 y_to_s = y.to_s padding = "#{SPACE * _diff}" str = SPACE + x + padding + y_to_s grads = SPACE + x.gradient(tc1, tc2, bold: bold, italic: italic) + padding + y_to_s.gradient(tc1, tc2, bold: bold, italic: italic) len = str.grapheme_clusters.map { |x| _x = x.bytesize./(2) _x == 0 ? 1 : _x }.sum w = width - 2 len < w ? grads.+(SPACE.*(w - len)) : grads }.join(NEWLINE) end
t!(keyword, breakword: true, b: true)
click to toggle source
# File lib/termclock/translate.rb, line 57 def self.t!(keyword, breakword: true, b: true) return keyword if LANG == :en translate(keyword.to_s, breakword: true) end
translate(keyword, breakword: nil, b: nil)
click to toggle source
# File lib/termclock/translate.rb, line 2 def self.translate(keyword, breakword: nil, b: nil) return keyword if LANG == :en characters = keyword.grapheme_clusters b = breakword if breakword && !b breakword = b if b && !breakword upcased = characters.all? { |x| x.ord.between?(65, 90) } downcased = upcased ? false : characters.all? { |x| x.ord.between?(97, 122) } capitalized = if (upcased || downcased) false else characters[0].ord.between?(65, 90) && characters.drop(1).all? { |x| x.ord.between?(97, 122) } end camelized = if (upcased || downcased || capitalized) false else keyword.split(?\s.freeze).all? { |x| x[0].ord.between?(65, 90) && x.chars.drop(1).all? { |y| y.ord.between?(97, 122) } } end if breakword return characters.map { |x| tr = TRANSLATIONS[x] if !tr tr = TRANSLATIONS[x.downcase] end tr.upcase! if tr && upcased tr.downcase! if tr && downcased tr.capitalize! if tr && capitalized tr.camelize! if tr && camelized tr ? tr : x }.join end tr = TRANSLATIONS[keyword] if !tr tr = TRANSLATIONS[keyword.downcase] tr.upcase! if tr && upcased tr.downcase! if tr && downcased tr.capitalize! if tr && capitalized tr.camelize! if tr && camelized end tr ? tr : keyword end