Файловый менеджер ranger. Русификация клавиш и краткая настройка

Автор mrgoodvin, 22 октября 2019, 07:26:14

« назад - далее »

0 Пользователи и 2 гостей просматривают эту тему.

mrgoodvin

(Тема по большой части не актуальна. Поддержка горячих клавиш реализована на официальном сайте ranger)
Приветствую! Хочу осветить некие «пробелы» в сети настройки ranger и русификацию клавиш, может кому пригодиться не смотря на то что информации в сети как бы достаточно и на arch-вики, официальной странице и самом github где есть сами исходники.
Первое что нужно знать, ФМ можно настроить как под vim так и для  emacs, и для чего угодно на самом деле. Изначально он разрабатывался под vim, и пользователям vim сразу можно пользоваться им как есть, если все устраивает. Что касается emacs, для него можно скачать исходники на гитхабе, или же просто файл настроек привязок клавиш. В последнем случае, как раз в моем, будут отображаться подсказки для vim :).
Понятное дело, после установки ranger, нужно запустить команду ranger --help , ознакомиться  с ней и запустить ranger —copy-config=all
Команда создаст файлы в каталоге ~/.config/ranger. Их нужно будет подправить под себя. Так же команда попросит добавить в .profile строку вида:
export RANGER_LOAD_DEFAULT_RC=FALSE
Если есть желание что бы программа работала аналогично и с root правами, делаем ссылки в /root на настройки текущего пользователя или правим ссылки в /etc/ranger или правим конфигурация по умолчанию непосредственно по пути /usr/lib/python3/dist-packages/ranger что не желательно, и возможные и другие варианты.


Ctrl-s
Можно начать с распространенной проблемы, по крайней мере пришлось с ней столкнуться. Ctrl-s, и временное ее решение Ctrl-q.
В .bashrc строка stty -ixon прописана, терминал не "фризится", но тем не менее в ranger сочетание "замораживает" файловый менеджер....
Ctrl+s фризит ranger в терминале когда тот запускается самим терминалом или оболочкой de такими командами как exo-open --launch TerminalEmulator ranger или даже urxvt -e ranger. В самом же терминала (когда в терминале набрать ranger) клавиши отрабатывают как нужно(с stty -ixon набранном в терминале или прописном в .bashrc ), т.е сам эмулятор терминала не приостанавливает поток при нажатии клавиш. Странно конечно, но как есть, может результат замены умалчиваемого эмулятора терминала, но сомнительно, т. к. специально поставленный xterm который дал такой же результат.
Решение1: можно создать скрипт стартер, который бы запускал ranger и ссылаться на скрипт где это нужно, решение не очень, мягко говоря:

!#/bin/sh
#ranger.sh
stty -ixon
ranger


Ренение2: основано на Решение1, разница в том, что можно скрипт поместить в /usr/bin/ranger, а сам же файл запуска(это python скрипт) ranger перед этим действием переименовать на rangerorig или т.п.  и скрипт запуска или старта программы подправить:
!#/bin/sh
#usr/bin/ranger.sh
stty -ixon
/usr/bin/rangerorig


Решение3: самое удачное из приведенных выше, создать файл ниже содержания: заодно прописать по умолчанию редактор вместо опционально предлагаемых переменных окружения. У меня сделано для emacs.
/usr/lib/python3/dist-packages/ranger/core/fix.py
import os
os.system("stty -ixon")#need to work Ctrl+S
if 'VISUAL' not in os.environ:
    if 'EDITOR' not in os.environ:
        os.environ['EDITOR']="emacs -nw"#need to edit txt files
    if 'VIEW' not in os.environ:
        os.environ['VIEW']="-f view-mode"#need to view txt files

В /usr/lib/python3/dist-packages/ranger/core/main.py или /usr/lib/python3/dist-packages/ranger/core/__init__.py добавить строку после import tempfile:
...
import tempfile
from ranger.core import fix
...

Ну или же поместить код в вышеприведенные файлы main.py или __init__.py, но при обновлении возможно затрется. Выбор как делать за каждым. Можно также поместить в файл /usr/bin/ranger, но не рекомендуется.
Для lxterminal нужно сделать другим способом, т.к эмулятор терминала экономит ресурсы и окно не отображается нормально, и не помогли ни флаг -f в renger, ни ключ --no-remoute в lxterminal. Если точнее то --no-remoute не хотел использовать в сочетании с флагом -f, так что этот вариант даже и не проверял. Лучше прописать отельную команду для запуска редактора в отдельном окне.
/usr/lib/python3/dist-packages/ranger/core/fix.py

import os
os.system("stty -ixon")
if 'VISUAL' not in os.environ:
    if 'EDITOR' not in os.environ:
        os.environ['EDITOR']="emacs -nw"
        os.environ['EDITOR_W']="lxterminal -e emacs -nw"
    if 'VIEW' not in os.environ:
        os.environ['VIEW']="-f view-mode"#need to view txt files



Настройка
Подправим настройки для редактора:
В ~/.config/ranger/rifle.conf находим и комментируем ниже 4-ре строки:
#mime ^text,  label editor = ${VISUAL:-$EDITOR} -- "$@"
#mime ^text,  label pager  = "$PAGER" -- "$@"
#!mime ^text, label editor, ext xml|json|csv|tex|py|pl|rb|js|sh|php = ${VISUAL:-$EDITOR} -- "$@"
#!mime ^text, label pager,  ext xml|json|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@"

Выше или ниже закомментированных строк добавляем свои:
mime ^text,  label editor, terminal          = $UserCommand $EDITOR -- "$@"
mime ^text,  label editor, terminal, flag r  = $RootCommand $EDITOR -- "$@"
mime ^text,  label pager,  terminal          = $EDITOR "$@" $VIEW
mime ^text,  label editor, terminal, flag t  = $WUserCommand $EDITOR -- "$@"
mime ^text,  label editor, terminal, flag rt = $WRootCommand $EDITOR -- "$@"
mime ^text,  label pager,  terminal, flag t  = $WEDITOR $EDITOR "$@" $VIEW
mime ^text,  label pager = "$PAGER" -- "$@"

!mime ^text, label editor, terminal, ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $UserCommand $EDITOR -- "$@"
!mime ^text, label editor, terminal, flag r, ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $RootCommand $EDITOR -- "$@"
!mime ^text, label pager,  terminal, ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $EDITOR "$@" $VIEW
!mime ^text, label editor, terminal, flag t,  ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $WUserCommand $EDITOR -- "$@"
!mime ^text, label editor, terminal, flag rt, ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $WRootCommand $EDITOR -- "$@"
!mime ^text, label pager,  terminal, flag t,  ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $WEDITOR $EDITOR  "$@" $VIEW
!mime ^text, label pager,  ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $PAGER -- "$@"

Замечание: под RootCommand имеется конечно же sudo, так что не путайте пароли.
К сожалению расширения файлов приходится прописывать вручную. Заменить переменной окружения ext $TEXTEDIT мне не удалось. Буквально воспринимается как строка.

И для lxterminal
~/.config/ranger/rifle.conf

mime ^text,  label editor, terminal          = $UserCommand $EDITOR -- "$@"
mime ^text,  label editor, terminal, flag r  = $RootCommand $EDITOR -- "$@"
mime ^text,  label pager,  terminal          = $EDITOR "$@" $VIEW
mime ^text,  label editor, terminal, flag   = $EDITOR_W -- "$@"
mime ^text,  label editor, terminal, flag r = $RootCommand $EDITOR_W -- "$@"
mime ^text,  label pager,  terminal, flag   = $EDITOR_W "$@" $VIEW
mime ^text,  label pager = "$PAGER" -- "$@"

!mime ^text, label editor, terminal, ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $UserCommand $EDITOR -- "$@"
!mime ^text, label editor, terminal, flag r, ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $RootCommand $EDITOR -- "$@"
!mime ^text, label pager,  terminal, ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $EDITOR "$@" $VIEW
!mime ^text, label editor, terminal, flag t,  ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $WUserCommand $EDITOR -- "$@"
!mime ^text, label editor, terminal, flag rt, ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $WRootCommand $EDITOR -- "$@"
!mime ^text, label pager,  terminal, flag t,  ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $WEDITOR $EDITOR "$@" $VIEW
!mime ^text, label pager,  ext xml|json|csv|tex|pyw|py|c|cpp|pl|rb|js|sh|php|conf = $PAGER -- "$@"


Предпросмотр файлов (устаревшая информация, см. далее):
В ~/.config/ranger/scope.sh добавляем строку для просмотра количества строк deb-info:
minln=10    # Stop after $minln lines.  Can be used like ls | tail -n $minln
Для просмотра инфо архивов добавляем try 7z (должен быть установлен).
case "$extension" in
try 7z l "$path" && { dump | trim; exit 0; }
try als "$path" && { dump | trim; exit 0; }
try acat "$path" && { dump | trim; exit 3; }
try bsdtar -lf "$path" && { dump | trim; exit 0; }
exit 1;;

Просмотр инфо deb, собственно minln для этого был и нужен, хотя можно заменить и просто числом. Отображает первые и последние 10 строк.
#deb info
deb)
try dpkg --info "$path" && { dump | trim | head -n $minln; dump | echo "..."; dump | trim | tail -n $minln; exit 5;} || exit 1;;

На самом деле этот файл часто обновляется. К примеру если у вас перестали отображаться изображения в предпросмотре, то это повод сделать резервную копию данного файла и обновить существующий командой ranger --copy-config=scope, сравнить с резервной копией, и при необходимости внести изменения в новый файл.


Украинизация/Русификация клавиш
Далее украинизация/русификация клавиш/key-bindings, пока не красиво сделано, но как есть. ranger отличный ФМ, так что со временем сделается красиво :).
Суть русификации сводится к редактированию /usr/lib/python3/dist-packages/ranger/gui/ui.py. Наиболее - замены метода def handle_input(self):

class UI(..):
....
    ru ="фисвуапршолдьтщзйкыіегмцчнябю.хъїжэєё'" +'ФИСВУАПРШОЛДЬТЩЗЙКЫІЕГМЦЧНЯБЮ,ХЪЇЖЭЄЁʼ'
    en ="abcdefghijklmnopqrsstuvwxyz,./[]];''``" +'ABCDEFGHIJKLMNOPQRSSTUVWXYZ<>?{}}:""~~'
    def handle_input(self):
        def key_translate(keys):# translate key from en into ua or ru
            if not self.console.visible or self.console.question_queue:
                ch =b''.join([bytes.fromhex('{0:X}'.format(i)) for i in keys]).decode('utf-8')
                if not ch: return []
                if ch in self.ru:
                    i =self.ru.index(ch)
                    ch =self.en[i]
                    return [ord(ch)]
        def simple_key(key):# Handle simple key presses, CTRL+X, etc here:
            if key<0:return
            if self.settings.flushinput and not self.console.visible:
                curses.flushinp()
            if key==curses.KEY_MOUSE:
                self.handle_mouse()
            elif key==curses.KEY_RESIZE:
                self.update_size()
            else:
                if not self.fm.input_is_blocked():
                    self.handle_key(key)
                   
        keys = self.win.getch()           
        if keys==27 or (keys>=128 and keys<256):# Handle special keys like ALT+X or unicode here
            keys =[keys]
            previous_load_mode =self.load_mode
            self.set_load_mode(True) 
            for _ in range(4):
                getkey =self.win.getch()
                if getkey==-1:continue
                keys.append(getkey)
            tkeys =key_translate(keys)
            if tkeys:return simple_key(tkeys[0])
            if len(keys)==1:
                keys.append(-1)
            elif keys[0]==27:
                keys[0] =ALT_KEY
                tkeys =key_translate(keys[1:])
                if tkeys:keys =keys[0:1] +tkeys +keys[2:]
            if self.settings.xterm_alt_key:
                if len(keys)==2 and keys[1] in range(127, 256):
                    if keys[0]==195:
                        keys =[ALT_KEY, keys[1] -64]
                    elif keys[0] == 194:
                        keys =[ALT_KEY, keys[1] -128]
            self.handle_keys(*keys)
            self.set_load_mode(previous_load_mode)
            if self.settings.flushinput and not self.console.visible:
                curses.flushinp()
        else:simple_key(keys)


Сами настройки тоже прилагаются: ~/.config/ranger/rc.conf и ~/.config/ranger/emacs-keys.conf


Отображение команд и группы команд
По умолчанию команды горячих клавиш отображаются точно также как прописано в настройках, что не удобно. Более того, также отображается '...' там где команды собираются в группу к примеру:

map xlf linemode filename
map xli linemode fileinfo
map xlm linemode mtime
map xlp linemode permissions
map xls linemode sizemtime
map xlt linemode metatitle

Это можно легко улучшить, и ниже показана реализация...



Редактируем /usr/lib/python3/dist-packages/ranger/gui/widgets/view_base.py
Находим и заменяем две строчки кода в блоке (add, change)

if len(hints) > self.fm.settings.hint_collapse_threshold:
                def first_key_in_group(group):
                    return group[0][0][0]
                get_descr_hint = lambda a: "..." + ", ".join({s[1].replace("chain echo ","").split("::")[0] for s in a})#add
                grouped_hints = (
                    [(first_key_in_group(hint_group), get_descr_hint(hint_group))]#change
                    if len(hint_group) > 1
                    else hint_group
                    for hint_group in grouped_hints
                )

И еще в одном месте, уже три строки:

        for key, cmd in hints:
            str_command = cmd.replace("chain echo ","").split("::")[-1].split(";")#add
            str_command = str_command[0] if str_command[0] != "" else str_command[-1]#add
            string = " " + key.ljust(11) + " " +  str_command.strip()#change
            self.addstr(i, 0, whitespace)
            self.addnstr(i, 0, string, self.wid)
            i += 1

Если посмотреть сейчас команды менеджера, то отображаются так же, а вот вместе с троеточием должен быть перечень команд там где есть группы, что уже лучше. Что бы задать отображаемое имя команде или группе, нужно подправить файл настроек горячих клавиш, которые лучше вынести в отдельный файл.
source ~/.config/ranger/emacs-keys.conf
Команда преображается в следующий вид:
map KEY [chain echo MY_NAME_OF_GROUPE::[MY_NAME_OF_COMMAND];] command1 [; command2] [; ...]
Если опустить MY_NAME_OF_COMMAND, то будет отображаться для сочетания клавиши последняя команда из файла настроек. Можно за основу взять прикрепленный файл emacs-keys.conf (* c одной оговоркой — нужно выполнить "fix %s %p %S %P" дальше по тексту).
Если не работает клавиша Enter, можно: закоментировать строчку cunmap <C-j>; или добавить сочетание на Enter; или <C-f>


fix %s %p %S %P
Есть одна неприятность в ranger с работой командной оболочки, а именно множественная выборка файлов/каталогов, которые представленные ключом %s в файле настроек (команда shell). Выбранные файлы в менеджере появляются при выполнение в оболочке без разделителей и если у вас файлы или каталоги при выборке с пробелами, то результат выполнения команды в оболочке будет неудачный. И если с одним файлом/каталогом (а это ключ %f к примеру) можно справиться, обернув его в ' — '%f', то с ключом %s так не получиться сделать. Для исправления ситуации нужно отредактировать файл ниже. Изменений не много — оборачивание некого кода в ' там где это нужно. (change). В самом файле настроек нужно использовать ключ %s без заключения его в '.
/usr/lib/python3/dist-packages/ranger/core/actions.py

    def get_macros(self):  # pylint: disable=too-many-branches,too-many-statements
        macros = {}

        macros['rangerdir'] = ranger.RANGERDIR
        if not ranger.args.clean:
            macros['confdir'] = self.fm.confpath()
            macros['datadir'] = self.fm.datapath()
        macros['space'] = ' '

        if self.fm.thisfile:
            macros['f'] = self.fm.thisfile.relative_path
        else:
            macros['f'] = MACRO_FAIL

        if self.fm.thistab.get_selection:
            macros['p'] = ["'" +  os.path.join(self.fm.thisdir.path, fl.relative_path) + "'"
                           for fl in self.fm.thistab.get_selection()]#change
            macros['s'] = ["'" + fl.relative_path + "'" for fl in self.fm.thistab.get_selection()]#change
        else:
            macros['p'] = MACRO_FAIL
            macros['s'] = MACRO_FAIL

        if self.fm.copy_buffer:
            macros['c'] = [fl.path for fl in self.fm.copy_buffer]
        else:
            macros['c'] = MACRO_FAIL

        if self.fm.thisdir.files:
            macros['t'] = [fl.relative_path for fl in self.fm.thisdir.files
                           if fl.realpath in self.fm.tags or []]
        else:
            macros['t'] = MACRO_FAIL

        if self.fm.thisdir:
            macros['d'] = self.fm.thisdir.path
        else:
            macros['d'] = '.'

        # define d/f/p/s macros for each tab
        for i in range(1, 10):
            try:
                tab = self.fm.tabs[i]
            except KeyError:
                continue
            tabdir = tab.thisdir
            if not tabdir:
                continue
            i = str(i)
            macros[i + 'd'] = tabdir.path
            if tabdir.get_selection():
                macros[i + 'p'] = ["'" + os.path.join(tabdir.path, fl.relative_path) + "'"
                                   for fl in tabdir.get_selection()]#change
                macros[i + 's'] = ["'" + fl.path  + "'" for fl in tabdir.get_selection()]#change
            else:
                macros[i + 'p'] = MACRO_FAIL
                macros[i + 's'] = MACRO_FAIL
            if tabdir.pointed_obj:
                macros[i + 'f'] = tabdir.pointed_obj.path
            else:
                macros[i + 'f'] = MACRO_FAIL

        # define D/F/P/S for the next tab
        found_current_tab = False
        next_tab = None
        first_tab = None
        for tabname in self.fm.tabs:
            if not first_tab:
                first_tab = tabname
            if found_current_tab:
                next_tab = self.fm.tabs[tabname]
                break
            if self.fm.current_tab == tabname:
                found_current_tab = True
        if found_current_tab and next_tab is None:
            next_tab = self.fm.tabs[first_tab]
        next_tab_dir = next_tab.thisdir

        if next_tab_dir:
            macros['D'] = str(next_tab_dir.path)
            if next_tab.thisfile:
                macros['F'] = next_tab.thisfile.path
            else:
                macros['F'] = MACRO_FAIL
            if next_tab_dir.get_selection():
                macros['P'] = ["'" + os.path.join(next_tab.path, fl.path) + "'"
                               for fl in next_tab.get_selection()]#change
                macros['S'] = ["'" + fl.path + "'" for fl in next_tab.get_selection()]#change
            else:
                macros['P'] = MACRO_FAIL
                macros['S'] = MACRO_FAIL
        else:
            macros['D'] = MACRO_FAIL
            macros['F'] = MACRO_FAIL
            macros['S'] = MACRO_FAIL

        return macros



Предпросмотр изображений с помощью mpv
Собственно способ описан на официальной вики: https://github.com/ranger/ranger/wiki/Image-Previews
Но пока к сожалению изображения полноразмерные что не удобно, думаю со временем будет более доработано.

zse

Приветствую всех интересующихся ranger'ом!
Уже больше года для просмотра изображений использую:
https://github.com/seebye/ueberzug
Работает корректно. Остальное настраивается в самом ranger'е , включая просмотр pdf видеофайлов и даже файлов djvu!
2020 Aug 24; 07:27 AM