| Server IP : 216.92.14.13 / Your IP : 216.73.216.171 Web Server : Apache System : Linux vps4089.pairvps.com 5.15.0-190-generic #200-Ubuntu SMP Fri Aug 7 15:06:04 UTC 2026 x86_64 User : rmlac2fmr ( 1040637) PHP Version : 8.2.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /usr/bin/ |
Upload File : |
#!/usr/bin/perl
# vifm
# Copyright (C) 2015 xaizek.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
use strict;
use warnings;
use File::Basename('basename');
use Getopt::Long('GetOptions');
# "{color number} -> {Vifm color name}" mapping.
my @COLORS = (
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white',
);
# "{dircolors type} -> {Vifm color group}" mapping.
my %GROUPS = (
'chr' => 'Device', 'blk' => 'Device',
'normal' => 'Win', 'file' => 'Win',
'dir' => 'Directory',
'exec' => 'Executable',
'fifo' => 'Fifo',
'link' => 'Link',
'orphan' => 'BrokenLink',
'sock' => 'Socket',
);
# "{$LS_COLORS type} -> {Vifm color group}" mapping.
my %SHORT_GROUPS = (
'cd' => 'Device', 'bd' => 'Device',
'no' => 'Win', 'fi' => 'Win',
'di' => 'Directory',
'ex' => 'Executable',
'ln' => 'Link',
'or' => 'BrokenLink',
'pi' => 'Fifo',
'so' => 'Socket',
);
my ($help, $env, $readable);
GetOptions('h|help|?' => \$help,
'e|environment' => \$env,
'r|human-readable' => \$readable) or exit 1;
if ($help) {
&abort_with_usage(1);
}
if (scalar(@ARGV) > 1) {
&abort_with_usage_error("Too many arguments.");
}
# Input source data either from file/stdin or LS_COLORS environment variable.
my ($patcol, $typecol);
if ($env) {
($patcol, $typecol) = &import_from_env('LS_COLORS');
} else {
my $dircolors = shift;
($patcol, $typecol) = &import_from_file($dircolors);
}
my %patcol = %$patcol;
my %typecol = %$typecol;
# Join extensions that have same attributes into single record.
my %colpat = &invert_attrmap(\%patcol);
# Print out Vifm commands to stdout.
if (%typecol) {
print "\" generic file types\n";
&print_typecol(\%typecol);
}
if (%colpat) {
print "\n" if %typecol;
print "\" file name specific highlight\n";
&print_attrmap(\%colpat);
}
# Aborts execution after displaying a message.
# * $msg - error message.
sub abort_with_usage_error
{
my $msg = shift;
print STDERR "@{[basename($0)]}: $msg\n";
&abort_with_usage(0);
}
# Aborts execution after displaying usage.
# * $detailed - whether short description should be displayed.
sub abort_with_usage
{
my $detailed = shift;
if ($detailed) {
print "Description:\n\n".
"Converts ls file highlighting configuration (man dircolors) ".
"into set\nof Vifm highlight commands.\n\n";
}
print "Usage: @{[basename($0)]} [-h|--help] ".
"[-e|--environment] ".
"[-r|--human-readable] ".
"[dircolors_file]
By default standard input is processed.
Options:
-h, --help brief help message
-e, --environment parse \$LS_COLORS for configuration
-r, --human-readable output patterns on separate lines\n";
exit 1;
}
# Imports initial data from file/stdin.
# * $dircolors - path to the file or undef for stdin.
# Returns (\%patcol, \%typecol), where
# * %patcol - "suffix" => "attrlist"
# * %typecol - "Vifm highlight group" => "attrlist".
sub import_from_file
{
my $dircolors = shift;
if (!defined($dircolors)) {
$dircolors = '-';
}
my %patcol = ();
my %typecol = ();
open (DIRCOLORS, $dircolors) or die("Cannot open $dircolors $!");
while (my $line = <DIRCOLORS>) {
chomp $line;
if ($line =~ /^\.(\S+)\s+(\S+)/) {
my $pat = '\.'.$1;
my $attrs = $2;
&add_to_attrmap(\%patcol, $pat, $attrs);
} elsif ($line =~ /^\*(\S+)\s+(\S+)/) {
my $pat = $1;
my $attrs = $2;
&add_to_attrmap(\%patcol, $pat, $attrs);
} elsif ($line =~ /^(\S+)\s+(\S+)/) {
my $type = lc $1;
my $attrs = $2;
if (exists($GROUPS{$type})) {
my $group = $GROUPS{$type};
$typecol{$group} = $attrs;
}
}
}
close DIRCOLORS;
return (\%patcol, \%typecol);
}
# Imports initial data from an environment variable.
# * $env - name of environment variable to use.
# Returns (\%patcol, \%typecol), where
# * %patcol - "suffix" => "attrlist"
# * %typecol - "Vifm highlight group" => "attrlist"
sub import_from_env
{
my $env = shift;
my %patcol = ();
my %typecol = ();
my @specs = split(':', $ENV{$env});
foreach my $spec (@specs) {
my ($name, $attrs) = split('=', $spec);
if (exists($SHORT_GROUPS{lc $name})) {
my $group = $SHORT_GROUPS{$name};
$typecol{$group} = $attrs;
} elsif ($name =~ /^\*\.(\S+)/) {
my $pat = '\.'.$1;
&add_to_attrmap(\%patcol, $pat, $attrs);
} elsif ($name =~ /^\*(\S+)/) {
my $pat = $1;
&add_to_attrmap(\%patcol, $pat, $attrs);
}
}
return (\%patcol, \%typecol);
}
# Adds extension pattern entry to a dictionary ("suffix" => "attrlist").
# * $extcol - the dictionary.
# * $ext - the pattern.
# * $attrs - list of attributes.
sub add_to_attrmap
{
my $extcol = shift;
my $ext = shift;
my $attrs = shift;
if (exists($extcol->{$ext}) && $extcol->{$ext} ne $attrs) {
warn 'Different attributes for extension in different cases: '.
$ext;
}
$extcol->{$ext} = $attrs;
}
# Join extensions that have same attributes into single record.
# * $attrmap - "suffix" => "attrlist".
# Returns %inverted, where
# * %inverted - "attrlist" => "suffix,...".
sub invert_attrmap
{
my $attrmap = shift;
my %attrmap = %$attrmap;
my %dotonly = ();
foreach my $ext (keys %attrmap) {
my $color = $attrmap{$ext};
if (!exists($dotonly{$color})) {
$dotonly{$color} = 1;
}
if ($ext !~ /^\\\..*$/) {
$dotonly{$color} = 0;
}
}
my %inverted = ();
foreach my $ext (sort keys %attrmap) {
my $color = $attrmap{$ext};
if (exists($inverted{$color})) {
$inverted{$color} .= $readable ? "|\n \\" : '|';
}
if ($dotonly{$color}) {
$inverted{$color} .= substr $ext, 2;
} else {
$inverted{$color} .= $ext;
}
}
foreach my $color (keys %inverted) {
if ($dotonly{$color}) {
$inverted{$color} = "^.*\\\.($inverted{$color})\$";
} else {
$inverted{$color} = "^.*($inverted{$color})\$";
}
}
return %inverted;
}
# Formats and prints to stdout generic file types highlighting commands.
# * \%typecol - "Vifm highlight group" => "attrlist".
sub print_typecol
{
my $typecol = shift;
my %typecol = %$typecol;
return unless %typecol;
foreach my $type (sort keys %typecol) {
my $color = $typecol{$type};
my $hi = &color_to_hi($color);
print 'highlight ', $type, $hi, "\n";
}
}
# Formats and prints to stdout file name specific highlighting commands.
# * \%attrmap - "attrlist" => "suffix".
sub print_attrmap
{
my $attrmap = shift;
my %attrmap = %$attrmap;
return unless %attrmap;
foreach my $color (sort keys %attrmap) {
my $pattern = "/$attrmap{$color}/I";
my $hi = &color_to_hi($color);
print 'highlight ', $pattern, $hi, "\n";
}
}
# Converts list of attributes (escape codes) into arguments for the :highlight
# command of Vifm.
# * $color - semicolon-separated list of attributes.
# Returns $hi_str, where
# * $hi_str - arguments in form of string that starts with white space.
sub color_to_hi
{
my $color = shift;
my @attrs = ();
my $fg = undef;
my $bg = undef;
my @color_components = split(';', $color);
my $long_fg = 0;
my $long_bg = 0;
foreach my $component (@color_components) {
if (&long_attr($component, \$fg, \$long_fg)) {
next;
}
if (&long_attr($component, \$bg, \$long_bg)) {
next;
}
if ($component == 0) {
@attrs = ();
$fg = undef;
$bg = undef;
} elsif ($component == 1) {
push @attrs, 'bold';
} elsif ($component == 4) {
push @attrs, 'underline';
} elsif ($component == 3 || $component == 7) {
push @attrs, 'reverse';
} elsif ($component >= 30 && $component <= 37) {
$fg = $COLORS[$component - 30];
} elsif ($component == 38) {
$long_fg = 1;
} elsif ($component == 39) {
$fg = undef;
} elsif ($component >= 40 && $component <= 47) {
$bg = $COLORS[$component - 40];
} elsif ($component == 48) {
$long_bg = 1;
} elsif ($component == 49) {
$bg = undef;
}
}
my $hi_str = '';
if (scalar(@attrs) != 0) {
$hi_str .= ' cterm='.join(',', @attrs);
} else {
$hi_str .= ' cterm=none';
}
if (defined $fg) {
$hi_str .= ' ctermfg='.$fg;
} else {
$hi_str .= ' ctermfg=default';
}
if (defined $bg) {
$hi_str .= ' ctermbg='.$bg;
} else {
$hi_str .= ' ctermbg=default';
}
return $hi_str;
}
# Parses long attribute (256-color).
# * $component - attribute.
# * \$col - final color storage.
# * \$state - long attribute parsing state (0 - not active, 1 - start, 2 - mid).
# Returns $consumed, where
# * $consumed - true when component is consumed, false otherwise.
sub long_attr
{
my $component = shift;
my $col = shift;
my $state = shift;
if (${$state} == 1) {
if ($component == 5) {
$${state} = 2;
return 1;
}
} elsif (${$state} == 2) {
${$col} = $component;
$${state} = 0;
return 1;
}
return 0;
}