-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding a new colour scheme to parse $LS_COLORS #2
Open
Nelyah
wants to merge
12
commits into
ranger:master
Choose a base branch
from
Nelyah:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
8cc5c46
Adding a new colour scheme to parse $LS_COLORS
Nelyah c0a8978
Fixing the colorscheme, which should now work.
Nelyah af9a613
Putting the code from plugin/parse_ls_colors.py in the colorscheme file.
Nelyah 7cdcbf4
Adding an exception for links not to be coloured as executable.
Nelyah e500856
Handles the case where `LS_COLORS` isn't set.
Nelyah 1975909
Removing one try/except catch inside the class
Nelyah 0480934
Added all the code to an __init__ method.
Nelyah 1ba431c
Remove print() debug
toonn a250fe8
Fixes tag and mark/cut coloring
toonn a512710
Fix many bugs and improve readability
Nelyah 3ee1526
Added comments and make bright function
Nelyah de43255
Prevent extension attributes from influencing special files
Nelyah File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
from ranger.gui.colorscheme import ColorScheme | ||
import ranger.gui.color as style | ||
import ranger.gui.context | ||
import ranger.gui.widgets.browsercolumn | ||
from os import getenv | ||
from subprocess import check_output, CalledProcessError | ||
|
||
|
||
class ls_colors(ColorScheme): | ||
def __init__(self): | ||
super(ColorScheme, self).__init__() | ||
try: | ||
self.ls_colors = getenv('LS_COLORS', | ||
self.get_default_lscolors()).split(':') | ||
except (CalledProcessError, FileNotFoundError): | ||
self.ls_colors = [] | ||
|
||
# Gets all the keys corresponding to extensions | ||
self.ls_colors_extensions = [ | ||
k.split('=')[0] for k in self.ls_colors if k != '' | ||
] | ||
self.ls_colors_extensions = [ | ||
'.' + k.split('*.')[1] for k in self.ls_colors_extensions | ||
if '*.' in k | ||
] | ||
|
||
# Add the key names to ranger context keys | ||
for key in self.ls_colors_extensions: | ||
ranger.gui.context.CONTEXT_KEYS.append(key) | ||
setattr(ranger.gui.context.Context, key, False) | ||
|
||
self.OLD_HOOK_BEFORE_DRAWING = ranger.gui.widgets.browsercolumn.hook_before_drawing | ||
|
||
ranger.gui.widgets.browsercolumn.hook_before_drawing = self.new_hook_before_drawing | ||
|
||
self.ls_colors_keys = [k.split('=') for k in self.ls_colors if k != ''] | ||
self.tup_ls_colors = [] | ||
|
||
# Not considering file extensions | ||
# The order of these two block matters, as extensions colouring should | ||
# take precedence over the 'file' type | ||
for key in [k for k in self.ls_colors_keys if '.*' not in k]: | ||
if key[0] == 'fi': | ||
self.tup_ls_colors += [('file', key[1])] | ||
|
||
# Considering files extensions | ||
self.tup_ls_colors += [('.' + k[0].split('*.')[1], k[1]) | ||
for k in self.ls_colors_keys if '*.' in k[0]] | ||
|
||
# This is added last because their color should take precedence over | ||
# what's been set before for a 'file' that would have the same | ||
# extension | ||
for key in [k for k in self.ls_colors_keys if '.*' not in k]: | ||
if key[0] == 'ex': | ||
self.tup_ls_colors += [('executable', key[1])] | ||
elif key[0] == 'pi': | ||
self.tup_ls_colors += [('fifo', key[1])] | ||
elif key[0] == 'ln': | ||
self.tup_ls_colors += [('link', key[1])] | ||
elif key[0] == 'bd' or key[0] == 'cd': | ||
self.tup_ls_colors += [('device', key[1])] | ||
elif key[0] == 'so': | ||
self.tup_ls_colors += [('socket', key[1])] | ||
elif key[0] == 'di': | ||
self.tup_ls_colors += [('directory', key[1])] | ||
|
||
# Those special context shouldn't get attributes destined to | ||
# files, based on extension | ||
self.__special_context = [ | ||
"directory", | ||
"fifo", | ||
"link", | ||
"device", | ||
"socket" | ||
] | ||
|
||
self.progress_bar_color = 1 | ||
|
||
def new_hook_before_drawing(self, fsobject, color_list): | ||
for key in self.ls_colors_extensions: | ||
if fsobject.basename.endswith(key): | ||
color_list.append(key) | ||
|
||
return self.OLD_HOOK_BEFORE_DRAWING(fsobject, color_list) | ||
|
||
def get_default_lscolors(self): | ||
"""Returns the default value for LS_COLORS | ||
as parsed from the `dircolors` command | ||
""" | ||
ls_colors = check_output('dircolors') | ||
ls_colors = ls_colors.splitlines()[0].decode('UTF-8').split("'")[1] | ||
return ls_colors | ||
|
||
def get_attr_from_lscolors(self, attribute_list): | ||
return_attr = 0 | ||
to_delete = [] | ||
|
||
for i, attr in enumerate(attribute_list): | ||
if attr == 1: | ||
return_attr |= style.bold | ||
elif attr == 4: | ||
return_attr |= style.underline | ||
elif attr == 5: | ||
return_attr |= style.blink | ||
elif attr == 7: | ||
return_attr |= style.reverse | ||
elif attr == 8: | ||
return_attr |= style.invisible | ||
to_delete.append(i) | ||
|
||
# remove style attrattributes from the array | ||
attribute_list[:] = [val for i, val in enumerate(attribute_list) if i in to_delete] | ||
|
||
return return_attr | ||
|
||
def make_colour_bright(self, colour_value): | ||
"""Only applicable to not already bright 8 bit colours. | ||
256 colour will be returned "as-is" | ||
""" | ||
|
||
if colour_value < 8 and colour_value >= 0: | ||
colour_value += style.BRIGHT | ||
return colour_value | ||
|
||
# Values from | ||
# https://en.wikipedia.org/wiki/ANSI_escape_code#Colors | ||
def get_colour_from_attributes(self, attribute_list): | ||
"""Get the colour from the different attributes passed | ||
""" | ||
fg_colour = None | ||
bg_colour = None | ||
looking_at_256_ttl = 0 | ||
for i, current_attr in enumerate(attribute_list): | ||
################# | ||
# 256 colours # | ||
################# | ||
|
||
if looking_at_256_ttl > 0: | ||
looking_at_256_ttl -= 1 | ||
continue | ||
# If colour256, we need to get to the third field (after 48 and 5) | ||
# to get the colour | ||
try: | ||
if current_attr == 48 and attribute_list[i + 1] == 5: | ||
bg_colour = attribute_list[i + 2] | ||
looking_at_256_ttl = 2 | ||
elif current_attr == 38 and attribute_list[i + 1] == 5: | ||
fg_colour = attribute_list[i + 2] | ||
looking_at_256_ttl = 2 | ||
except IndexError: | ||
print('Bad attribute value for LS_COLORS: {}'.format(attribute_list)) | ||
exit(1) | ||
|
||
###################### | ||
# Standard colours # | ||
###################### | ||
|
||
# Standard colours | ||
if (current_attr >= 30 and current_attr <= 37): | ||
fg_colour = current_attr - 30 | ||
# Bright | ||
elif (current_attr >= 90 and current_attr <= 97): | ||
fg_colour = current_attr - 82 | ||
|
||
# Standard colours | ||
elif (current_attr >= 40 and current_attr <= 47): | ||
bg_colour = current_attr - 40 | ||
# Bright | ||
elif (current_attr >= 100 and current_attr <= 107): | ||
bg_colour = current_attr - 92 | ||
|
||
return fg_colour, bg_colour | ||
|
||
def is_special_file_context(self, context): | ||
"""Return True if we are in a special file context | ||
""" | ||
|
||
for special_key in self.__special_context: | ||
if getattr(context, special_key): | ||
return True | ||
return False | ||
|
||
def use(self, context): | ||
fg, bg, attr = style.default_colors | ||
|
||
for key, t_attributes in self.tup_ls_colors: | ||
if getattr(context, key): | ||
# This means we're most likely applying extension colouring to | ||
# a special file (e.g. directory, link, etc.) | ||
if self.is_special_file_context(context) and key not in self.__special_context: | ||
continue | ||
|
||
t_attributes = t_attributes.split(';') | ||
try: | ||
t_attributes[:] = [int(attrib) for attrib in t_attributes] | ||
except ValueError: | ||
print("Bad attribute value for LS_COLORS: {}".format(attr)) | ||
exit(1) | ||
|
||
new_attr = self.get_attr_from_lscolors(t_attributes) | ||
if new_attr is not None: | ||
attr |= new_attr | ||
fg_colour, bg_colour = self.get_colour_from_attributes(t_attributes) | ||
|
||
if fg_colour is not None: | ||
fg = fg_colour | ||
if bg_colour is not None: | ||
bg = bg_colour | ||
|
||
if context.reset: | ||
return style.default_colors | ||
elif context.in_browser: | ||
if context.selected: | ||
attr |= style.reverse | ||
if context.tag_marker and not context.selected: | ||
attr |= style.bold | ||
if fg in (style.red, style.magenta): | ||
fg = style.white | ||
else: | ||
fg = style.red | ||
fg = self.make_colour_bright(fg) | ||
if not context.selected and (context.cut or context.copied): | ||
attr |= style.bold | ||
fg = style.black | ||
fg = self.make_colour_bright(fg) | ||
# If the terminal doesn't support bright colors, use | ||
# dim white instead of black. | ||
if style.BRIGHT == 0: | ||
attr |= style.dim | ||
fg = style.white | ||
if context.main_column: | ||
# Doubling up with BRIGHT here causes issues because | ||
# it's additive not idempotent. | ||
if context.selected: | ||
attr |= style.bold | ||
if context.marked: | ||
attr |= style.bold | ||
fg = style.yellow | ||
|
||
return fg, bg, attr |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that every
i
is added toto_delete
unconditionally, this is essentially clearing the entire list. Is this intended?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That does seem incorrect, yes. Though it is copying the entire list if I'm not mistaken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you're correct. It is copying. I saw
to_delete
and read that last condition asnot in
. I'm guessing that the intention was to filter out any of the style attributes that were matched in the loop above it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's not right either. Another method is making decisions based on those attributes.