diff options
author | Abdo Roig-Maranges <abdo.roig@gmail.com> | 2013-02-10 12:19:22 +0100 |
---|---|---|
committer | Abdo Roig-Maranges <abdo.roig@gmail.com> | 2013-02-12 12:08:44 +0100 |
commit | aa4d6a7073165294f1e251df7d6310d20d449e81 (patch) | |
tree | 36d726ad31e0681b9fb0672e63a0333ff8417f93 | |
parent | 94bf56dd024b4fa33b5ae4c80f5091fec0995d1c (diff) | |
download | ranger-aa4d6a7073165294f1e251df7d6310d20d449e81.tar.gz |
Displays version control data on browser column
* I have restructured BrowserColumn._draw_directory. Hopefully it is easier mantain now. Simplified horizontal space computations, etc. * Displays two symbols on the right of every entry, showing local status, and status regarding the remote vcs repo. * Added the necessary context to be able to change colors for individual symbols from the colorscheme.
-rw-r--r-- | ranger/colorschemes/default.py | 35 | ||||
-rw-r--r-- | ranger/gui/context.py | 6 | ||||
-rw-r--r-- | ranger/gui/widgets/__init__.py | 17 | ||||
-rw-r--r-- | ranger/gui/widgets/browsercolumn.py | 202 |
4 files changed, 180 insertions, 80 deletions
diff --git a/ranger/colorschemes/default.py b/ranger/colorschemes/default.py index 58c79962..6f6040ba 100644 --- a/ranger/colorschemes/default.py +++ b/ranger/colorschemes/default.py @@ -94,6 +94,13 @@ class Default(ColorScheme): fg = red if context.loaded: bg = self.progress_bar_color + if context.vcsinfo: + fg = blue + attr &= ~bold + if context.vcscommit: + fg = yellow + attr &= ~bold + if context.text: if context.highlight: @@ -112,4 +119,32 @@ class Default(ColorScheme): else: bg = self.progress_bar_color + + if context.vcsfile and not context.selected: + attr &= ~bold + if context.vcsconflict: + fg = magenta + elif context.vcschanged: + fg = red + elif context.vcsunknown: + fg = red + elif context.vcsstaged: + fg = green + elif context.vcssync: + fg = green + elif context.vcsignored: + fg = default + + elif context.vcsremote and not context.selected: + attr &= ~bold + if context.vcssync: + fg = green + elif context.vcsbehind: + fg = red + elif context.vcsahead: + fg = blue + elif context.vcsdiverged: + fg = magenta + + return fg, bg, attr diff --git a/ranger/gui/context.py b/ranger/gui/context.py index c9e8104e..2ea23571 100644 --- a/ranger/gui/context.py +++ b/ranger/gui/context.py @@ -15,7 +15,11 @@ CONTEXT_KEYS = ['reset', 'error', 'badinfo', 'help_markup', # COMPAT 'seperator', 'key', 'special', 'border', # COMPAT 'title', 'text', 'highlight', 'bars', 'quotes', 'tab', 'loaded', - 'keybuffer'] + 'keybuffer', + 'infostring', + 'vcsfile', 'vcsremote', 'vcsinfo', 'vcscommit', + 'vcsconflict', 'vcschanged', 'vcsunknown', 'vcsignored', + 'vcsstaged', 'vcssync', 'vcsbehind', 'vcsahead', 'vcsdiverged'] class Context(object): def __init__(self, keys): diff --git a/ranger/gui/widgets/__init__.py b/ranger/gui/widgets/__init__.py index 2a930b6c..3d0899bb 100644 --- a/ranger/gui/widgets/__init__.py +++ b/ranger/gui/widgets/__init__.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + from ranger.gui.displayable import Displayable class Widget(Displayable): @@ -5,3 +7,18 @@ class Widget(Displayable): The Widget class defines no methods and only exists for classification of widgets. """ + vcsfilestatus_symb = {'conflict': ('X', ["vcsconflict"]), + 'untracked': ('+', ["vcschanged"]), + 'deleted': ('-', ["vcschanged"]), + 'changed': ('*', ["vcschanged"]), + 'staged': ('*', ["vcsstaged"]), + 'ignored': ('·', ["vcsignored"]), + 'sync': ('√', ["vcssync"]), + 'none': (' ', []), + 'unknown': ('?', ["vcsunknown"])} + + vcsremotestatus_symb = {'none': (' ', []), + 'sync': ('=', ["vcssync"]), + 'behind': ('<', ["vcsbehind"]), + 'ahead': ('>', ["vcsahead"]), + 'diverged': ('Y', ["vcsdiverged"])} diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py index a6653070..38a7fdcb 100644 --- a/ranger/gui/widgets/browsercolumn.py +++ b/ranger/gui/widgets/browsercolumn.py @@ -1,4 +1,4 @@ -# -*- encoding: utf8 -*- +# -*- coding: utf-8 -*- # Copyright (C) 2009, 2010, 2011 Roman Zimbelmann <romanz@lavabit.com> # This software is distributed under the terms of the GNU GPL version 3. @@ -12,9 +12,12 @@ from .pager import Pager from ranger.fsobject import BAD_INFO from ranger.ext.widestring import WideString +from ranger.gui.color import * + class BrowserColumn(Pager): main_column = False display_infostring = False + display_vcsstate = True scroll_begin = 0 target = None last_redraw_time = -1 @@ -91,7 +94,7 @@ class BrowserColumn(Pager): """ Executes a list of "commands" which can be easily cached. - "commands" is a list of lists. Each element contains + "commands" is a list of lists. Each element contains a text and an attribute. First, the attribute will be set with attrset, then the text is printed. @@ -136,7 +139,7 @@ class BrowserColumn(Pager): self.need_redraw = True self.old_dir = self.target - if self.target: # don't garbage collect this directory please + if self.target: # don't garbage collect this directory please self.target.use() if self.target and self.target.is_directory \ @@ -224,7 +227,6 @@ class BrowserColumn(Pager): self._set_scroll_begin() copied = [f.path for f in self.fm.copy_buffer] - ellipsis = self.ellipsis[self.settings.unicode_ellipsis] selected_i = self.target.pointer for line in range(self.hei): @@ -245,100 +247,142 @@ class BrowserColumn(Pager): key = (self.wid, selected_i == i, drawn.marked, self.main_column, drawn.path in copied, tagged_marker, drawn.infostring, - self.fm.do_cut) + drawn.vcsfilestatus, drawn.vcsremotestatus, self.fm.do_cut) if key in drawn.display_data: self.execute_curses_batch(line, drawn.display_data[key]) self.color_reset() continue + text = drawn.basename + if drawn.marked and (self.main_column or self.settings.display_tags_in_all_columns): + text = " " + text + + # Computing predisplay data. predisplay contains a list of lists [string, colorlst] + # where string is a piece of string to display, and colorlst a list of contexts + # that we later pass to the colorscheme, to compute the curses attribute. + predisplay_left = [] + predisplay_right = [] + + predisplay_left = predisplay_left + self._draw_tagged_display(tagged, tagged_marker) + predisplay_right = predisplay_right + self._draw_vcsstring_display(drawn) + space = self.wid - self._total_len(predisplay_left) - self._total_len(predisplay_right) + + # If not enough space + if space <= 2: + predisplay_right = [] + predisplay_left = [] + + predisplay_left = predisplay_left + self._draw_text_display(text, space) + space = self.wid - self._total_len(predisplay_left) - self._total_len(predisplay_right) + + predisplay_right = self._draw_infostring_display(drawn, space) + predisplay_right + space = self.wid - self._total_len(predisplay_left) - self._total_len(predisplay_right) + + if space > 0: + predisplay_left.append([' ' * space, []]) + elif space < 0: + raise Exception("Error: there is not enough space to write the text. I have computed spaces wrong.") + + # Computing display data. Now we compute the display_data list ready to display in + # curses. It is a list of lists [string, attr] + + this_color = base_color + list(drawn.mimetype_tuple) + self._draw_directory_color(i, drawn, copied) display_data = [] drawn.display_data[key] = display_data - if self.display_infostring and drawn.infostring \ - and self.settings.display_size_in_main_column: - infostring = str(drawn.infostring) + " " - else: - infostring = "" + predisplay = predisplay_left + predisplay_right + for txt, color in predisplay: + attr = self.settings.colorscheme.get_attr(*(this_color + color)) + display_data.append([txt, attr]) - this_color = base_color + list(drawn.mimetype_tuple) - text = drawn.basename + self.execute_curses_batch(line, display_data) + self.color_reset() - space = self.wid - len(infostring) - if self.main_column: - space -= 2 - elif self.settings.display_tags_in_all_columns: - space -= 1 + def _total_len(self, predisplay): + return sum([len(WideString(s)) for s, L in predisplay]) - if i == selected_i: - this_color.append('selected') + def _draw_text_display(self, text, space): + wtext = WideString(text) + if len(wtext) > space: + wtext = wtext[:max(0, space - 1)] + self.ellipsis[self.settings.unicode_ellipsis] - if drawn.marked: - this_color.append('marked') - if self.main_column or self.settings.display_tags_in_all_columns: - text = " " + text + return [[str(wtext), []]] + def _draw_tagged_display(self, tagged, tagged_marker): + tagged_display = [] + if (self.main_column or self.settings.display_tags_in_all_columns) and self.wid > 2: if tagged: - this_color.append('tagged') - - if drawn.is_directory: - this_color.append('directory') + tagged_display.append([tagged_marker, ['tag_marker']]) else: - this_color.append('file') - - if drawn.stat: - mode = drawn.stat.st_mode - if mode & stat.S_IXUSR: - this_color.append('executable') - if stat.S_ISFIFO(mode): - this_color.append('fifo') - if stat.S_ISSOCK(mode): - this_color.append('socket') - if drawn.is_device: - this_color.append('device') - - if drawn.path in copied: - this_color.append('cut' if self.fm.do_cut else 'copied') - - if drawn.is_link: - this_color.append('link') - this_color.append(drawn.exists and 'good' or 'bad') - - attr = self.settings.colorscheme.get_attr(*this_color) - - if (self.main_column or self.settings.display_tags_in_all_columns) \ - and tagged and self.wid > 2: - this_color.append('tag_marker') - tag_attr = self.settings.colorscheme.get_attr(*this_color) - display_data.append([tagged_marker, tag_attr]) + tagged_display.append([" ", ['tag_marker']]) + return tagged_display + + def _draw_infostring_display(self, drawn, space): + infostring_display = [] + if self.display_infostring and drawn.infostring \ + and self.settings.display_size_in_main_column: + infostring = str(drawn.infostring) + " " + if len(infostring) <= space: + infostring_display.append([infostring, ['infostring']]) + return infostring_display + + def _draw_vcsstring_display(self, drawn): + vcsstring_display = [] + if self.settings.vcs_aware and (drawn.vcsfilestatus or drawn.vcsremotestatus): + if drawn.vcsfilestatus: + vcsstr, vcscol = self.vcsfilestatus_symb[drawn.vcsfilestatus] else: - text = " " + text - space += 1 - - wtext = WideString(text) - if len(wtext) > space: - wtext = wtext[:max(0, space - 1)] + ellipsis - text = str(wtext) - - display_data.append([text, attr]) - - padding = self.wid - len(wtext) - if tagged and (self.main_column or \ - self.settings.display_tags_in_all_columns): - padding -= 1 - if infostring: - if len(wtext) + 1 + len(infostring) > self.wid: - pass - else: - padding -= len(infostring) - padding = max(0, padding) - infostring = (" " * padding) + infostring - display_data.append([infostring, attr]) + vcsstr = " " + vcscol = [] + vcsstring_display.append([vcsstr, ['vcsfile'] + vcscol]) + + if drawn.vcsremotestatus: + vcsstr, vcscol = self.vcsremotestatus_symb[drawn.vcsremotestatus] else: - display_data.append([" " * max(0, padding), attr]) - self.execute_curses_batch(line, display_data) - self.color_reset() + vcsstr = " " + vcscol = [] + vcsstring_display.append([vcsstr, ['vcsremote'] + vcscol]) + elif self.target.has_vcschild: + vcsstring_display.append([" ", []]) + return vcsstring_display + + def _draw_directory_color(self, i, drawn, copied): + this_color = [] + if i == self.target.pointer: + this_color.append('selected') + + if drawn.marked: + this_color.append('marked') + + if self.fm.tags and drawn.realpath in self.fm.tags: + this_color.append('tagged') + + if drawn.is_directory: + this_color.append('directory') + else: + this_color.append('file') + + if drawn.stat: + mode = drawn.stat.st_mode + if mode & stat.S_IXUSR: + this_color.append('executable') + if stat.S_ISFIFO(mode): + this_color.append('fifo') + if stat.S_ISSOCK(mode): + this_color.append('socket') + if drawn.is_device: + this_color.append('device') + + if drawn.path in copied: + this_color.append('cut' if self.fm.do_cut else 'copied') + + if drawn.is_link: + this_color.append('link') + this_color.append(drawn.exists and 'good' or 'bad') + + return this_color def _get_scroll_begin(self): """Determines scroll_begin (the position of the first displayed file)""" |