rainbarf 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. #!/usr/bin/env perl
  2. # vim:fenc=utf-8:ft=perl:et:sw=4:ts=4:sts=4
  3. use 5.008;
  4. use strict;
  5. use warnings qw(all);
  6. use List::Util qw(max sum);
  7. use Storable qw(lock_retrieve lock_store);
  8. ## no critic (ProhibitBacktickOperators ProhibitComplexRegexes ProhibitInteractiveTest)
  9. our $VERSION = q(1.4);
  10. my %rgb = (
  11. black => [qw[0 0 0]],
  12. red => [qw[1 0 0]],
  13. green => [qw[0 1 0]],
  14. yellow => [qw[1 1 0]],
  15. blue => [qw[0 0 1]],
  16. magenta => [qw[1 0 1]],
  17. cyan => [qw[0 1 1]],
  18. white => [qw[1 1 1]],
  19. );
  20. my @ticks = map { chr 0x2580 + $_ } 1 .. 8;
  21. binmode \*STDOUT => q(encoding(utf8));
  22. my $order = '';
  23. my $screen = 0;
  24. my $tmux = not -t \*STDOUT;
  25. my $rgb = 0;
  26. my $skip = 0;
  27. my ($help, $show_battery, $remaining, $bolt, $chart_bg, $chart_fg,
  28. $bright, $loadavg, $swap, $threshold, $width, $history);
  29. # parse the options file
  30. parse_config();
  31. if (@ARGV) {
  32. require Getopt::Long;
  33. Getopt::Long::GetOptions(
  34. q(help) => \$help,
  35. q(battery!) => \$show_battery,
  36. q(remaining!) => \$remaining,
  37. q(bolt!) => \$bolt,
  38. q(bg=s) => \$chart_bg,
  39. q(fg=s) => \$chart_fg,
  40. q(bright!) => \$bright,
  41. q(loadavg!) => \$loadavg,
  42. q(swap!) => \$swap,
  43. q(max=i) => \$threshold,
  44. q(order=s) => \$order,
  45. q(screen) => \$screen,
  46. q(tmux!) => \$tmux,
  47. q(rgb!) => \$rgb,
  48. q(width=i) => \$width,
  49. q(datfile=s) => \$history,
  50. q(skip=i) => \$skip,
  51. ) or help(-verbose => 1);
  52. }
  53. defaults();
  54. my $chart = eval { lock_retrieve $history };
  55. $chart = [ (0) x $width ] unless defined $chart;
  56. my %top;
  57. my $cpu = $loadavg ? load() : usage();
  58. push @$chart => $cpu;
  59. splice @$chart => 0, @$chart - $width if @$chart > $width;
  60. lock_store $chart => $history
  61. if time - ((stat $history)[9] || 0) >= $skip;
  62. unshift @$chart => (0) x ($width - @$chart);
  63. # Ordering from Activity Monitor.app
  64. my %colors = (
  65. f => [ green => 1 ], # free
  66. w => [ red => 2 ], # wired
  67. a => [ yellow => 3 ], # active
  68. i => [ blue => 4 ], # inactive
  69. c => [ cyan => 5 ], # cached
  70. b => [ cyan => 5 ], # buf (FreeBSD)
  71. x => [ magenta=> 6 ], # swap
  72. );
  73. # Custom ordering
  74. my @order = split //x => lc $order;
  75. for my $i (0 .. $#order) {
  76. my $color = $order[$i];
  77. $colors{$color}->[1] = $i + 1
  78. if exists $colors{$color};
  79. }
  80. my %memory = memory();
  81. delete $memory{x} unless $swap;
  82. my $scale = @$chart / sum values %memory;
  83. my $norm = $#ticks / max @$chart => $threshold;
  84. my $c = 0;
  85. for my $type (sort { $colors{$a}->[1] <=> $colors{$b}->[1] } keys %memory) {
  86. print my_color(
  87. map { defined $_ ? $_ : $colors{$type}->[0] }
  88. $chart_fg => $chart_bg
  89. );
  90. for (1 .. max(1 => sprintf q(%.0f) => $scale * $memory{$type})) {
  91. last if $c++ >= $width;
  92. print $ticks[$norm * shift @$chart];
  93. }
  94. }
  95. print $ticks[$norm * $cpu] if $c < $width;
  96. battery() if $show_battery or $remaining;
  97. my_reset(1);
  98. # For dependencies linting
  99. #printf qq(%-20s\t%s\n), $_ => $INC{$_} for sort keys %INC;
  100. sub parse_config {
  101. my $rcname = exists($ENV{RAINBARF})
  102. ? $ENV{RAINBARF}
  103. : qq($ENV{HOME}/.rainbarf.conf);
  104. if (open(my $rcfile, q(<), $rcname)) {
  105. while (<$rcfile>) {
  106. s/\#.*$//x;
  107. s/^\s+|\s+$//gx;
  108. if (my ($k, $v) = /^(?:\-{2})?(\w+)\s*(?:=\s*(.*))?$/x) {
  109. my $p = '--' . $k;
  110. if ($v) {
  111. $v =~ s/\$(\w+)/$ENV{$1}/gx;
  112. $p .= '=' . $v;
  113. }
  114. unshift @ARGV => $p;
  115. }
  116. }
  117. close $rcfile;
  118. }
  119. return;
  120. }
  121. sub help {
  122. my (@args) = @_;
  123. require Pod::Usage;
  124. return Pod::Usage::pod2usage(-noperldoc => 1, @args);
  125. }
  126. sub defaults {
  127. help(-verbose => 99) if $help;
  128. $show_battery = 1 unless defined $show_battery;
  129. $loadavg = 0 unless defined $loadavg;
  130. $swap = 0 unless defined $swap;
  131. $threshold = 1 unless defined $threshold;
  132. $width = 38 unless defined $width;
  133. $bright = 0 unless defined $bright;
  134. $remaining = 0 unless defined $remaining;
  135. $bolt = (defined $bolt and $bolt) ? chr 0x26a1 : q(|);
  136. require Term::ANSIColor if not $tmux and not $screen;
  137. $history = qq($ENV{HOME}/.rainbarf.dat)
  138. unless defined $history;
  139. return;
  140. }
  141. sub color_idx {
  142. my ($color, $brightness) = @_;
  143. return unless defined $color;
  144. my ($r, $g, $b) = map { $_ * $brightness } @{$rgb{$color}};
  145. return q(colour) . (16 + (6 * 6 * $r) + (6 * $g) + $b);
  146. }
  147. sub color_rgb {
  148. my ($color, $brightness) = @_;
  149. return unless defined $color;
  150. return q(rgb) . join '' => map { $_ * $brightness } @{$rgb{$color}};
  151. }
  152. sub my_color {
  153. my ($fg, $bg) = @_;
  154. my $out;
  155. if ($screen) {
  156. $out = qq(\5{);
  157. $out .= defined($bg)
  158. ? chr ord $bg
  159. : q(.);
  160. $out .= $bright
  161. ? uc chr ord $fg
  162. : chr ord $fg;
  163. $out .= q(});
  164. } elsif ($tmux) {
  165. if ($rgb) {
  166. $fg = color_idx($fg => 5);
  167. $bg = color_idx($bg => 2);
  168. } else {
  169. $fg .= q(,bright) if $bright;
  170. }
  171. $out = defined($bg) ? qq(#[fg=$fg,bg=$bg]) : qq(#[fg=$fg]);
  172. } else {
  173. my ($old_fg, $old_bg) = ($fg, $bg);
  174. if ($rgb) {
  175. $fg = color_rgb($fg => 5);
  176. $bg = color_rgb($bg => 2);
  177. } else {
  178. $fg = qq(bright_$fg) if $bright;
  179. }
  180. my $color = defined($bg) ? qq($fg on_$bg) : $fg;
  181. $out = eval { Term::ANSIColor::color($color) };
  182. if (not defined $out or $@) {
  183. if ($@ =~ /bright/x) {
  184. $bright = 0;
  185. print STDERR qq(Term::ANSIColor < 3.00 does not support the "bright" attribute!\n);
  186. $color =~ s/,?bright_?//x;
  187. } elsif ($@ =~ /\brgb\d+\b/x) {
  188. $rgb = 0;
  189. print STDERR qq(Term::ANSIColor < 4.00 does not support the 256-color palette!\n);
  190. $color = qq($old_fg on_$old_bg);
  191. } else {
  192. die qq(Unknown error: $@\n);
  193. }
  194. $out = Term::ANSIColor::color($color);
  195. }
  196. }
  197. return $out;
  198. }
  199. sub my_reset {
  200. my ($eof) = @_;
  201. if ($screen) {
  202. print qq(\5{= dd});
  203. } elsif ($tmux) {
  204. print q(#[fg=default,bg=default]);
  205. } else {
  206. print Term::ANSIColor::color(q(reset));
  207. }
  208. print qq(\n) if defined $eof;
  209. return;
  210. }
  211. sub top {
  212. if (not %top and -x q{/usr/bin/top}) {
  213. my @top;
  214. if ($^O eq q(darwin)) {
  215. @top = qx{/usr/bin/top -R -F -l1 -n0 -s0 -S};
  216. } elsif ($^O eq q(freebsd)) {
  217. @top = qx{/usr/bin/top -b -d2 -I -s1 -z};
  218. }
  219. for (@top) {
  220. my ($key, $value) = /^([\w\s]+)\s*:\s*(.+)/x;
  221. next unless defined $key;
  222. $key =~ y/A-Z /a-z_/;
  223. $top{$key} = $value;
  224. }
  225. $top{cpu_usage} = delete $top{cpu} unless exists $top{cpu_usage};
  226. $top{physmem} = delete $top{mem} unless exists $top{physmem};
  227. }
  228. return scalar keys %top;
  229. }
  230. sub load {
  231. my @l = qw(0 0 0);
  232. if (open my $loadavg, q{<}, q{/proc/loadavg}) {
  233. @l = (split /\s+/x, <$loadavg>)[0 .. 2];
  234. close $loadavg;
  235. } elsif (top() and exists $top{load_avg}) {
  236. @l = split /\s*,\s*/x, $top{load_avg};
  237. } elsif (-x q{/usr/bin/uptime}) {
  238. # fallback
  239. @l = (split /\s+/x, qx{/usr/bin/uptime})[-3 .. -1];
  240. }
  241. return $l[0];
  242. }
  243. sub usage {
  244. if (-e q{/proc/stat}) {
  245. my ($diff_usage, $prev_idle, $prev_total) = qw(-1 0 0);
  246. for my $i (reverse 0 .. 1) {
  247. my $fh;
  248. unless (open $fh, q{<}, q{/proc/stat}) {
  249. close $fh;
  250. return 0;
  251. }
  252. while (<$fh>) {
  253. next unless /^cpu\s+\d+/x;
  254. my @cpu = split /\s+/x;
  255. shift @cpu;
  256. my $idle = $cpu[3];
  257. my $total = sum(@cpu);
  258. my $diff_idle = $idle - $prev_idle;
  259. my $diff_total = $total - $prev_total;
  260. $diff_usage = ($diff_total - $diff_idle) / $diff_total;
  261. $prev_idle = $idle;
  262. $prev_total = $total;
  263. last;
  264. }
  265. close $fh;
  266. ## no critic (ProhibitSleepViaSelect)
  267. select(undef, undef, undef, $i / 10);
  268. }
  269. return $diff_usage;
  270. } elsif (top()) {
  271. my %usage =
  272. map { (/([\d\.]+)%\s+(\w+)/x) [1, 0] }
  273. split /\s*,\s*/x, $top{cpu_usage};
  274. return 1 - $usage{idle} / 100;
  275. }
  276. }
  277. sub memory {
  278. my %m;
  279. my %n = (K => 1/2**10, M => 1, G => 2**10);
  280. if (exists $top{physmem} and $top{physmem} !~ /\bunused\b/ix) {
  281. %m =
  282. map { lc $_->[2] => $_->[0] * $n{$_->[1]} }
  283. map { [(/(\d+)([KMG])\s+(\w)/x)] }
  284. split /\s*,\s*/x, $top{physmem};
  285. delete $m{u};
  286. } elsif (open my $meminfo, q{<}, q{/proc/meminfo}) {
  287. %m = map {
  288. /\b(Mem|Swap)?(Free|Cached|Active|Inactive|Total):\s*(\d+)/ix
  289. ? (($1 and $1 eq q(Swap))
  290. ? (q(s) . lc chr ord $2 => $3)
  291. : ( lc chr ord $2 => $3)
  292. ) : ();
  293. } <$meminfo>;
  294. close $meminfo;
  295. $m{c} -= delete $m{sc} || 0;
  296. delete $m{c} if $m{c} < 0;
  297. my $x = delete($m{st}) - delete($m{sf});
  298. $m{w} = delete($m{t}) - sum values %m;
  299. $m{x} = $x;
  300. } elsif (-x q{/usr/bin/vm_stat}) {
  301. # fallback
  302. %m = map {
  303. /\bPages\s+(free|active|inactive|speculative|wired\s+down):\s*(\d+)/ix
  304. ? (chr ord $1 => $2 << 2)
  305. : ();
  306. } qx{/usr/bin/vm_stat};
  307. $m{f} += delete $m{s};
  308. }
  309. if ($top{swap} and $top{swap} =~ /(\d+)([KMG])\s+(?:\+|Used,?)/ix) {
  310. $m{x} = $1 * $n{$2};
  311. }
  312. return %m;
  313. }
  314. sub battery_osx {
  315. my %battery = map {
  316. /"(TimeRemaining|(?:Max|Current)Capacity|FullyCharged|ExternalConnected)"\s*=\s*(\d+|Yes|No)/ix
  317. ? (lc chr ord $1 => $2)
  318. : ()
  319. } qx{/usr/sbin/ioreg -n AppleSmartBattery -r};
  320. return () if 5 != keys %battery;
  321. my $time;
  322. if ($battery{f} eq q(No)
  323. || ($battery{f} eq q(No) && $battery{e} eq q(Yes))
  324. || ($battery{f} eq q(Yes) && $battery{e} eq q(No))) {
  325. $time = $battery{t};
  326. }
  327. my $charging = ($battery{e} =~ /^y/ix);
  328. my $battery = eval { $battery{c} / $battery{m} };
  329. return ($battery, $charging, $time);
  330. }
  331. sub battery_acpi {
  332. my ($acpi_info, $acpi_state, %battery) = ('') x 2;
  333. return () unless grep {
  334. -d $_
  335. and -e ($acpi_info ||= qq($_/info))
  336. and -e ($acpi_state ||= qq($_/state))
  337. } sort glob q(/proc/acpi/battery/{BAT,CMB}[0-9]);
  338. for my $file ($acpi_info, $acpi_state) {
  339. my $fh;
  340. if (open $fh, q(<), $file) {
  341. while (<$fh>) {
  342. my ($key, $value) = /^([\w\s]+)\s*:\s*(\w+)/x;
  343. next unless defined $key;
  344. $key =~ y/A-Z /a-z_/;
  345. $battery{$key} = $value;
  346. }
  347. }
  348. close $fh;
  349. }
  350. my $charging = $battery{charging_state} ne q(discharging);
  351. my $time;
  352. $time = eval { ($battery{remaining_capacity} / $battery{present_rate}) * 60 }
  353. if not $charging
  354. and defined $battery{present_rate}
  355. and $battery{present_rate} =~ /^\d+$/x;
  356. my $battery = eval { $battery{remaining_capacity} / $battery{last_full_capacity} };
  357. return ($battery, $charging, $time);
  358. }
  359. sub battery_sys {
  360. my ($uevent, %battery) = ('');
  361. return () unless grep {
  362. -d $_
  363. and ( ( -e qq($_/energy_full) and -e qq($_/energy_now) ) or
  364. ( -e qq($_/charge_now) and -e qq($_/current_now) ) )
  365. and -e ($uevent ||= qq($_/uevent))
  366. } sort glob q(/sys/class/power_supply/{BAT,CMB}[0-9]);
  367. my $fh;
  368. if (open $fh, q(<), $uevent) {
  369. while (<$fh>) {
  370. my ($key, $value) = /^POWER_SUPPLY_([^=]+)=(.*)$/x;
  371. next unless defined $key;
  372. $key =~ y/A-Z/a-z/;
  373. $battery{$key} = $value;
  374. }
  375. }
  376. close $fh;
  377. my $charging = $battery{status} ne q(Discharging);
  378. my $time;
  379. if (not $charging) {
  380. if (defined $battery{power_now} and $battery{power_now} =~ /^\d+$/x) {
  381. $time = eval { ($battery{energy_now} * 60 / $battery{power_now}) }
  382. } elsif (defined $battery{charge_now} and $battery{charge_now} =~ /^\d+$/x) {
  383. $time = eval { (60 * ($battery{charge_now} / 1000) / ($battery{current_now} / 1000)) }
  384. }
  385. }
  386. my $battery = $battery{capacity} / 100;
  387. return ($battery, $charging, $time);
  388. }
  389. sub battery_freebsd {
  390. my $battery = qx{/sbin/sysctl -n hw.acpi.battery.life 2>/dev/null} or return;
  391. my $charging = qx,/sbin/sysctl -n hw.acpi.battery.state,;
  392. my $time = qx,/sbin/sysctl -n hw.acpi.battery.time,;
  393. $battery /= 100;
  394. if ($charging == 2) {
  395. $charging = 1;
  396. } elsif ($charging == 7) { # Battery absent
  397. return;
  398. } else {
  399. $charging = 0;
  400. }
  401. return ($battery, $charging, $time);
  402. }
  403. sub battery {
  404. my @battery;
  405. if (-x q{/usr/sbin/ioreg}) {
  406. @battery = battery_osx();
  407. } elsif (-d q(/proc/acpi/battery)) {
  408. @battery = battery_acpi();
  409. } elsif (-d q(/sys/class/power_supply)) {
  410. @battery = battery_sys();
  411. } elsif ($^O eq q(freebsd)) {
  412. @battery = battery_freebsd();
  413. }
  414. battery_print(@battery);
  415. return;
  416. }
  417. sub battery_print {
  418. my ($battery, $charging, $time) = @_;
  419. if (defined $battery) {
  420. my_reset();
  421. print my_color(($charging ? q(green) : q(red)));
  422. if ($show_battery) {
  423. print $bolt;
  424. if ($rgb and not $screen) {
  425. my @color;
  426. if ($battery > 0.5) {
  427. # green => yellow
  428. @color = (int((1 - $battery) * 12), 5, 0);
  429. } else {
  430. # yellow => red
  431. @color = (5, int($battery * 12), 0);
  432. }
  433. if ($tmux) {
  434. print q(#[fg=colour) . (16 + (6 * 6 * $color[0]) + (6 * $color[1]) + $color[2]) . q(]);
  435. } else {
  436. print Term::ANSIColor::color(q(rgb) . join '' => @color);
  437. }
  438. } else {
  439. if ($battery < 0.333) {
  440. print my_color(q(red));
  441. } elsif ($battery < 0.666) {
  442. print my_color(q(yellow));
  443. } else {
  444. print my_color(q(green));
  445. }
  446. }
  447. print $ticks[$#ticks * $battery];
  448. }
  449. }
  450. if ($remaining and defined $time) {
  451. my $sec = $time * 60;
  452. print q( ) . (($sec / (60 * 60)) % 24) . q(h) . (($sec / 60) % 60) . q(m);
  453. }
  454. return;
  455. }
  456. __DATA__
  457. =pod
  458. =head1 NAME
  459. rainbarf - CPU/RAM/battery stats chart bar for tmux (and GNU screen)
  460. =head1 VERSION
  461. version 1.4
  462. =head1 SYNOPSIS
  463. rainbarf --tmux --width 40 --no-battery
  464. =head1 DESCRIPTION
  465. Fancy resource usage charts to put into the L<tmux|http://tmux.sourceforge.net/> status line.
  466. The CPU utilization history chart is tinted with the following colors to reflect the system memory allocation:
  467. =over 4
  468. =item * B<green>: free memory;
  469. =item * B<yellow>: active memory;
  470. =item * B<blue>: inactive memory;
  471. =item * B<red>: wired memory on I<Mac OS X> / I<FreeBSD>; "unaccounted" memory on I<Linux>;
  472. =item * B<cyan>: cached memory on I<Linux>, buf on I<FreeBSD>.
  473. =item * B<magenta>: used swap memory.
  474. =back
  475. If available, battery charge is displayed on the right.
  476. Just go to L<https://github.com/creaktive/rainbarf> to see some screenshots.
  477. =head1 USAGE
  478. =head2 Installation
  479. =over 4
  480. =item *
  481. Traditional way:
  482. perl Build.PL
  483. ./Build test
  484. ./Build install
  485. =item *
  486. L<Homebrew|http://brew.sh/> way:
  487. brew install rainbarf
  488. =item *
  489. L<MacPorts|http://www.macports.org/> way:
  490. port install rainbarf
  491. =item *
  492. CPAN way:
  493. cpan -i App::rainbarf
  494. =item *
  495. Modern Perl way:
  496. cpanm git://github.com/creaktive/rainbarf.git
  497. =back
  498. =head2 Configuration
  499. Add the following line to your F<~/.tmux.conf> file:
  500. set-option -g status-utf8 on
  501. set -g status-right '#(rainbarf)'
  502. Or, under I<GNOME Terminal>:
  503. set-option -g status-utf8 on
  504. set -g status-right '#(rainbarf --rgb)'
  505. Reload the tmux config by running C<tmux source-file ~/.tmux.conf>.
  506. =head1 CONFIGURATION FILE
  507. C<~/.rainbarf.conf> can be used to persistently store L</OPTIONS>:
  508. # example configuration file
  509. width=20 # widget width
  510. bolt # fancy charging character
  511. remaining # display remaining battery
  512. rgb # 256-colored palette
  513. L</OPTIONS> specified via command line override that values.
  514. Configuration file can be specified via C<RAINBARF> environment variable:
  515. RAINBARF=~/.rainbarf.conf rainbarf
  516. =head1 OPTIONS
  517. =over 4
  518. =item C<--help>
  519. This.
  520. =item C<--[no]battery>
  521. Display the battery charge indicator.
  522. Enabled by default.
  523. =item C<--[no]remaining>
  524. Display the time remaining until the battery is fully charged/empty. See L</CAVEAT>.
  525. Disabled by default.
  526. =item C<--[no]bolt>
  527. Display even fancier battery indicator.
  528. Disabled by default.
  529. =item C<--[no]bright>
  530. Tricky one. Disabled by default. See L</CAVEAT>.
  531. =item C<--[no]rgb>
  532. Use the B<RGB> palette instead of the system colors.
  533. Also disabled by default, for the same reasons as above.
  534. =item C<--fg COLOR_NAME>
  535. Force chart foreground color.
  536. =item C<--bg COLOR_NAME>
  537. Force chart background color.
  538. =item C<--[no]loadavg>
  539. Use L<load average|https://en.wikipedia.org/wiki/Load_(computing)> metric instead of CPU utilization.
  540. You might want to set the C<--max> threshold since this is an absolute value and has varying ranges on different systems.
  541. Disabled by default.
  542. =item C<--[no]swap>
  543. Display the swap usage.
  544. Used swap amount is added to the total amount, but the free swap amount is not!
  545. Disabled by default.
  546. =item C<--max NUMBER>
  547. Maximum C<loadavg> you expect before rescaling the chart. Default is 1.
  548. =item C<--order INDEXES>
  549. Specify the memory usage bar order.
  550. The default is C<fwaic> ( B<f>ree, B<w>ired, B<a>ctive, B<i>nactive & B<c>ached ).
  551. =item C<--[no]tmux>
  552. Force C<tmux> colors mode.
  553. By default, L<rainbarf> detects automatically if it is being called from C<tmux> or from the interactive shell.
  554. =item C<--screen>
  555. L<screen(1)|http://manpages.ubuntu.com/manpages/hardy/man1/screen.1.html> colors mode. B<Experimental>. See L</CAVEAT>.
  556. =item C<--width NUMBER>
  557. Chart width. Default is 38, so both the chart and the battery indicator fit the C<tmux> status line.
  558. Higher values may require disabling the battery indicator or raising the C<status-right-length> value in F<~/.tmux.conf>.
  559. =item C<--datfile FILENAME>
  560. Specify the file to log CPU stats to.
  561. Default: F<$HOME/.rainbarf.dat>
  562. =item C<--skip NUMBER>
  563. Do not write CPU stats if file already exists and is newer than this many seconds.
  564. Useful if you refresh C<tmux> status quite frequently.
  565. =back
  566. =head1 CAVEAT
  567. =head2 Time remaining
  568. If the C<--remaining> option is present but you do not see the time in your status bar, you may need to increase the value of C<status-right-length> to 48.
  569. =head2 Color scheme
  570. If you only see the memory usage bars but no CPU utilization chart, that's because your terminal's color scheme need an explicit distinction between foreground and background colors.
  571. For instance, "red on red background" will be displayed as a red block on such terminals.
  572. Thus, you may need the ANSI B<bright> attribute for greater contrast, or maybe consider switching to the 256-color palette.
  573. There are some issues with that, though:
  574. =over 4
  575. =item 1.
  576. Other color schemes (notably, L<solarized|http://ethanschoonover.com/solarized>) have different meaning for the ANSI B<bright> attribute.
  577. So using it will result in a quite psychedelic appearance.
  578. 256-color pallette, activated by the C<--rgb> flag, is unaffected by that.
  579. =item 2.
  580. The older versions of L<Term::ANSIColor> dependency do not recognize bright/RGB settings, falling back to the default behavior (plain 16 colors).
  581. However, the whole L<Term::ANSIColor> is optional, it is only required to preview the effects of the L</OPTIONS> via command line before actually editing the F<~/.tmux.conf>.
  582. That is, C<rainbarf --bright --tmux> B<is guaranteed to work> despite the outdated L<Term::ANSIColor>!
  583. =back
  584. Another option is skipping the system colors altogether and use the B<RGB> palette (C<rainbarf --rgb>).
  585. This fixes the I<issue 1>, but doesn't affect the I<issue 2>.
  586. It still looks better, though.
  587. =head2 Persistent storage
  588. CPU utilization stats are persistently stored in the F<~/.rainbarf.dat> file.
  589. Every L<rainbarf> execution will update and rotate that file.
  590. Since C<tmux> calls L<rainbarf> periodically (every 15 seconds, by default), the chart will display CPU utilization for the last ~9.5 minutes (15 * 38).
  591. Thus, several C<tmux> instances running simultaneously for the same user will result in a faster chart scrolling.
  592. =head2 screen
  593. Stable C<screen> version unfortunately has a broken UTF-8 handling specifically for the status bar.
  594. Thus, I have only tested the L<rainbarf> with the variant from L<git://git.savannah.gnu.org/screen.git>.
  595. My F<~/.screenrc> contents:
  596. backtick 1 15 15 rainbarf --bright --screen
  597. hardstatus string "%1`"
  598. hardstatus lastline
  599. =head1 REFERENCES
  600. =over 4
  601. =item *
  602. L<top(1)|http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/top.1.html> is used to get the CPU/RAM stats if no F</proc> filesystem is available.
  603. =item *
  604. L<ioreg(8)|http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man8/ioreg.8.html> is used to get the battery status on I<Mac OS X>.
  605. =item *
  606. L<ACPI|http://www.tldp.org/howto/acpi-howto/usingacpi.html> is used to get the battery status on I<Linux>.
  607. =item *
  608. L<Battery|https://github.com/Goles/Battery> was a source of inspiration.
  609. =item *
  610. L<Spark|http://zachholman.com/spark/> was another source of inspiration.
  611. =back
  612. =head1 AUTHOR
  613. Stanislaw Pusep <stas@sysd.org>
  614. =head1 CONTRIBUTORS
  615. =over 4
  616. =item *
  617. L<Chris Knadler|https://github.com/cknadler>
  618. =item *
  619. L<cinaeco|https://github.com/cinaeco>
  620. =item *
  621. L<Clemens Hammacher|https://github.com/hammacher>
  622. =item *
  623. L<H.Merijn Brand|https://github.com/Tux>
  624. =item *
  625. L<Henrik Hodne|https://github.com/henrikhodne>
  626. =item *
  627. L<Joe Hassick|https://github.com/jh3>
  628. =item *
  629. L<Josh Matthews|https://github.com/jmatth>
  630. =item *
  631. L<Lars Engels|https://github.com/larsengels>
  632. =item *
  633. L<Sergey Romanov|https://github.com/sergeyromanov>
  634. =item *
  635. L<Tom Cammann|https://github.com/takac>
  636. =item *
  637. L<Tuomas Jormola|https://github.com/tjormola>
  638. =back
  639. =head1 COPYRIGHT AND LICENSE
  640. This software is copyright (c) 2016 by Stanislaw Pusep <stas@sysd.org>.
  641. This is free software; you can redistribute it and/or modify it under
  642. the same terms as the Perl 5 programming language system itself.
  643. =cut