You are not logged in.

#1276 2012-04-01 20:38:02

hut
Member
From: Hanover, Germany
Registered: 2010-03-12
Posts: 569
Website

Re: Ranger, a textbased filemanager

JoKo wrote:

Hello,

Is it possible to rename a file / directory starting from its original name? E.g. I want to rename hello1 to hello , so I select the file, press a mapping and ":rename hello1" appears, I press Backspace and Enter and it's done.


Thanks in advance!

The keys you are looking for are A and I


"hut_" or "h00th00t" in irc.freenode.net #archlinux
Ranger Mailing List: https://lists.nongnu.org/mailman/listinfo/ranger-users

Offline

#1277 2012-04-02 06:00:44

loop
Member
Registered: 2011-05-06
Posts: 58

Re: Ranger, a textbased filemanager

Hello!
Is there way to make ranger change CWD not with built in command 'cd' only, but with shell command 'cd' too?
Or can ranger check existence of current working directory (CWD) after each shell command, and run command 'cd ..' if CWD is (re)moved?


P.S. Got this bug with master-git version too:

mahatman2 wrote:

Hi, I'm using the newest ranger from git as well and I have the same problem. When I press "l" (ell) on everything with a gui (feh, file-roller, etc), the line is replaced with

/bin/sh:  1: Syntax error: Bad fd number

Last edited by loop (2012-04-02 06:01:38)

Offline

#1278 2012-04-02 11:28:03

hut
Member
From: Hanover, Germany
Registered: 2010-03-12
Posts: 569
Website

Re: Ranger, a textbased filemanager

loop wrote:

Hello!
Is there way to make ranger change CWD not with built in command 'cd' only, but with shell command 'cd' too?
Or can ranger check existence of current working directory (CWD) after each shell command, and run command 'cd ..' if CWD is (re)moved?

Since the commands run in a subshell, they can't possibly change rangers CWD

loop wrote:

P.S. Got this bug with master-git version too:

mahatman2 wrote:

Hi, I'm using the newest ranger from git as well and I have the same problem. When I press "l" (ell) on everything with a gui (feh, file-roller, etc), the line is replaced with

/bin/sh:  1: Syntax error: Bad fd number

I've tried, but failed to reproduce it. Please give me any information you got, preferably in the bug tracker.
I would be especially interested in what happens when you insert the line

raise Exception(command)

in ranger/ex/rifle.py line 264 (just before the "# Execute command" comment), then run ranger with "ranger --debug" and open an image (or something else with a gui program)


"hut_" or "h00th00t" in irc.freenode.net #archlinux
Ranger Mailing List: https://lists.nongnu.org/mailman/listinfo/ranger-users

Offline

#1279 2012-04-02 12:48:58

JoKo
Member
Registered: 2010-04-09
Posts: 37

Re: Ranger, a textbased filemanager

hut wrote:
JoKo wrote:

Hello,

Is it possible to rename a file / directory starting from its original name? E.g. I want to rename hello1 to hello , so I select the file, press a mapping and ":rename hello1" appears, I press Backspace and Enter and it's done.


Thanks in advance!

The keys you are looking for are A and I

Oops, I should have looked the list of key bindings more thoroughly. One more question, hopefully I haven't missed anything again: Is it possible to sort directories inline? E.g. we have a directory structure as <a> <b> <c> a b c, where <> denote directories, and we want to have it sorted as <a> a <b> b <c> c.

In the sorting bindings I've only seen sorting by name, size, times, type, natural (I don't know what this is exactly) and reverse the sortings.

Offline

#1280 2012-04-02 12:52:58

hut
Member
From: Hanover, Germany
Registered: 2010-03-12
Posts: 569
Website

Re: Ranger, a textbased filemanager

Sort by name sorts "9.txt" after "10.txt" while natural takes numbers into consideration and sorts "10.txt" after "9.txt".
And the option you're looking for is sort_directories_first, toggleable with "zd"


"hut_" or "h00th00t" in irc.freenode.net #archlinux
Ranger Mailing List: https://lists.nongnu.org/mailman/listinfo/ranger-users

Offline

#1281 2012-04-02 15:06:34

loop
Member
Registered: 2011-05-06
Posts: 58

Re: Ranger, a textbased filemanager

hut wrote:

Since the commands run in a subshell, they can't possibly change rangers CWD

I see. Maybe you plan to implement mixed sequences of shell and ranger commands?

hut wrote:

Please give me any information you got, preferably in the bug tracker.
I would be especially interested in what happens when you insert the line

raise Exception(command)

in ranger/ex/rifle.py line 264 (just before the "# Execute command" comment), then run ranger with "ranger --debug" and open an image (or something else with a gui program)

I`ve failed to login to bugtracker, so here is the traceback:

ranger version: 1.5.3, executed with python 2.7.2+
Locale: en_US.UTF-8
Current file: /tmp/tmp.7E7ABvYw4K/test.jpg
Traceback (most recent call last):
  File "/tmp/tmp.7E7ABvYw4K/ranger-master/ranger/core/main.py", line 135, in main
    fm.loop()
  File "/tmp/tmp.7E7ABvYw4K/ranger-master/ranger/core/fm.py", line 194, in loop
    ui.handle_input()
  File "/tmp/tmp.7E7ABvYw4K/ranger-master/ranger/gui/ui.py", line 206, in handle_input
    self.handle_key(key)
  File "/tmp/tmp.7E7ABvYw4K/ranger-master/ranger/gui/ui.py", line 142, in handle_key
    self.press(key)
  File "/tmp/tmp.7E7ABvYw4K/ranger-master/ranger/gui/ui.py", line 157, in press
    quantifier=keybuffer.quantifier)
  File "/tmp/tmp.7E7ABvYw4K/ranger-master/ranger/core/actions.py", line 148, in execute_console
    cmd_class(string, quantifier=quantifier).execute()
  File "/tmp/tmp.7E7ABvYw4K/ranger-master/ranger/api/commands.py", line 306, in execute
    return self._based_function(*args, **keywords)
  File "/tmp/tmp.7E7ABvYw4K/ranger-master/ranger/core/actions.py", line 349, in move
    if self.execute_file(selection, mode=mode) is False:
  File "/tmp/tmp.7E7ABvYw4K/ranger-master/ranger/core/actions.py", line 305, in execute_file
    return self.rifle.execute(filenames, mode, label, flags, mimetype)
  File "/tmp/tmp.7E7ABvYw4K/ranger-master/ranger/ext/rifle.py", line 264, in execute
    raise Exception(command)
Exception: set -- '/tmp/tmp.7E7ABvYw4K/test.jpg'
setsid sxiv -- "$@" >& /dev/null &

Offline

#1282 2012-04-02 15:12:57

hut
Member
From: Hanover, Germany
Registered: 2010-03-12
Posts: 569
Website

Re: Ranger, a textbased filemanager

loop wrote:
hut wrote:

Since the commands run in a subshell, they can't possibly change rangers CWD

I see. Maybe you plan to implement mixed sequences of shell and ranger commands?

Try the :chain command.

chain shell mv Makefile ..; cd ..; shell make

About the bug: What is your shell?
EDIT: I mean, what is your /bin/sh?

Last edited by hut (2012-04-02 15:17:10)


"hut_" or "h00th00t" in irc.freenode.net #archlinux
Ranger Mailing List: https://lists.nongnu.org/mailman/listinfo/ranger-users

Offline

#1283 2012-04-02 15:32:43

loop
Member
Registered: 2011-05-06
Posts: 58

Re: Ranger, a textbased filemanager

hut wrote:

Try the :chain command.

chain shell mv Makefile ..; cd ..; shell make

Great! Thank you.

hut wrote:

About the bug: What is your shell?
EDIT: I mean, what is your /bin/sh?

There is some ambiguity:

readlink /bin/sh
dash

chsh
        Login Shell [/usr/bin/zsh]:

Offline

#1284 2012-04-02 15:48:03

hut
Member
From: Hanover, Germany
Registered: 2010-03-12
Posts: 569
Website

Re: Ranger, a textbased filemanager

Okay, I didn't test with dash. Apparently dash doesn't support redirection in the form of ">& /dev/null". I replaced it with ">/dev/null 2>/dev/null" and it should work now.


"hut_" or "h00th00t" in irc.freenode.net #archlinux
Ranger Mailing List: https://lists.nongnu.org/mailman/listinfo/ranger-users

Offline

#1285 2012-04-02 15:55:31

loop
Member
Registered: 2011-05-06
Posts: 58

Re: Ranger, a textbased filemanager

hut wrote:

Okay, I didn't test with dash. Apparently dash doesn't support redirection in the form of ">& /dev/null". I replaced it with ">/dev/null 2>/dev/null" and it should work now.

Confirm, the bug is disappeared.

Offline

#1286 2012-04-02 18:08:23

loop
Member
Registered: 2011-05-06
Posts: 58

Re: Ranger, a textbased filemanager

Trying git version, have a question.
If i have a directory with mixed content (e.g. subdirectories, *jpg, *png, *txt files, so on) and want to look through only image files, i have to mark these files first, or use shell command. In ranger 1.5.3 it was enough to run any image file, and all image files in directory were queued to viewer.
Can i change current behaviour to oldstyle one? As i can see, rifle.conf supports selected files only and can`t run command with directory as parameter.

'1?', '2?' '3?' hotkeys not work, only '?' (please, ignore if this feature just wasn`t covered yet).

Offline

#1287 2012-04-02 20:01:16

hut
Member
From: Hanover, Germany
Registered: 2010-03-12
Posts: 569
Website

Re: Ranger, a textbased filemanager

loop wrote:

Trying git version, have a question.
If i have a directory with mixed content (e.g. subdirectories, *jpg, *png, *txt files, so on) and want to look through only image files, i have to mark these files first, or use shell command. In ranger 1.5.3 it was enough to run any image file, and all image files in directory were queued to viewer.
Can i change current behaviour to oldstyle one? As i can see, rifle.conf supports selected files only and can`t run command with directory as parameter.

I still ponder on what would be the best way to re-implement this feature.
Here is one solution that I posted a few days ago in this thread:

hut wrote:

I guess some people miss the apps.py entry which opens all image files in sxiv and starts at the current file. Here's a script for that:

#!/bin/sh
target="$(realpath -s "$1")"
[ "$1" == '--' ] && shift
function listfiles {
  find "$(dirname "$target")" -maxdepth 1 -type f -regex '.*\(jpe?g\|png\|gif\)$' -print0 | sort -z
}
count="$(listfiles | grep -m 1 -Zznx "$target" | cut -d: -f1)"

if [ -n "$count" ]; then
  listfiles | xargs -0 sxiv -n "$count" --
else
  sxiv -- "$@" # fallback
fi

rifle.conf entry:

ext jpe?g|png|gif, flag f, X = <scriptname> "$@"

It would be good to have in ranger by default but such a large script doesn't fit in rifle.conf. I guess i'll put it in the doc/ directory or something.

By the way, You can always get the name of the directory with "$(dirname "$1")" or something.

loop wrote:

'1?', '2?' '3?' hotkeys not work, only '?' (please, ignore if this feature just wasn`t covered yet).

Fixed, thanks for pointing it out.

Last edited by hut (2012-04-02 20:03:47)


"hut_" or "h00th00t" in irc.freenode.net #archlinux
Ranger Mailing List: https://lists.nongnu.org/mailman/listinfo/ranger-users

Offline

#1288 2012-04-03 05:34:48

loop
Member
Registered: 2011-05-06
Posts: 58

Re: Ranger, a textbased filemanager

hut, thank you for help!

Offline

#1289 2012-04-03 18:48:25

loop
Member
Registered: 2011-05-06
Posts: 58

Re: Ranger, a textbased filemanager

Have a new question, sorry, if it`s dumb.
What should i place instead of MAGIC in followed line from rc.conf to force ranger run command immediately and not wait for Enter pressed? Example line:

map <somekey> console shell command <MAGIC>

Offline

#1290 2012-04-03 22:05:31

hut
Member
From: Hanover, Germany
Registered: 2010-03-12
Posts: 569
Website

Re: Ranger, a textbased filemanager

map <somekey> shell command

"hut_" or "h00th00t" in irc.freenode.net #archlinux
Ranger Mailing List: https://lists.nongnu.org/mailman/listinfo/ranger-users

Offline

#1291 2012-04-05 15:33:59

loop
Member
Registered: 2011-05-06
Posts: 58

Re: Ranger, a textbased filemanager

Hello!
hut, thanks for your answer.

I`ve been tested ranger from git for last days as default filemanager (instead of mc), and it looks stable and fast.

Is it possible to press single key 'y' (without 'Enter') when ranger warns to delete files seriously?
I know about

map('<DELETE>', fm.open_console('delete seriously? '))

but it`s not the same thing.

And another question: how specified filenames could be copied to console in arbitrary order (like <Alt-Enter> in mc)?
Thank you in advance.

Last edited by loop (2012-04-05 17:18:11)

Offline

#1292 2012-04-06 11:49:07

Veedrac
Member
Registered: 2011-07-19
Posts: 81

Re: Ranger, a textbased filemanager

Hut, I am loving the new ranger/rifle, but may I request a change?

The syntax for "open_with" commands seem like they should be unified with "shell". In other words, "open_with" should just be a quick way of running "shell" commands. I'm asking because it would unify the suggestions with the shell commands, and probably even make "open_with" slightly more powerful. Mostly this is just to make it easier to parse mentally - plus the "shell"-syntax is nicer.

It's weird to have new '"$@" ' place-holders instead of '%s', and '%[123456789]' can be added any-time. Is there a reason for the new syntax? I understand you probably want rifle to be separate from ranger, so you may not want to hook "open_with" directly to "shell", but that doesn't necessitate a new syntax.

Finally, am I right in guessing from the code that you set $@ and $1 to $9 as environment variables, but then do substitution in the code anyway? If I am, why is that? If not, what do you do?

Thanks for the time.

Offline

#1293 2012-04-06 18:30:04

hut
Member
From: Hanover, Germany
Registered: 2010-03-12
Posts: 569
Website

Re: Ranger, a textbased filemanager

@loop question 1:
You'd have to change the :delete command to use the quick() function. That is documented in commands.py

@loop question 2:
Try <tab> or writing %s.

Veedrac wrote:

Finally, am I right in guessing from the code that you set $@ and $1 to $9 as environment variables, but then do substitution in the code anyway? If I am, why is that? If not, what do you do?

No substitution involved. I just set the arguments with "set -- argument1 argument2 [...]" I run the command (which can be combined with setsid/nohup/sudo/terminal depending on the flags you use.

About your other question: Do you mean the syntax of the ":open_with" command or of the rifle.conf file?


"hut_" or "h00th00t" in irc.freenode.net #archlinux
Ranger Mailing List: https://lists.nongnu.org/mailman/listinfo/ranger-users

Offline

#1294 2012-04-06 19:39:12

Veedrac
Member
Registered: 2011-07-19
Posts: 81

Re: Ranger, a textbased filemanager

hut wrote:
Veedrac wrote:

Finally, am I right in guessing from the code that you set $@ and $1 to $9 as environment variables, but then do substitution in the code anyway? If I am, why is that? If not, what do you do?

No substitution involved. I just set the arguments with "set -- argument1 argument2 [...]" I run the command (which can be combined with setsid/nohup/sudo/terminal depending on the flags you use.

I see, I was just misunderstanding how bash works.

hut wrote:

About your other question: Do you mean the syntax of the ":open_with" command or of the rifle.conf file?

Basically, I think rifle.conf should look like:

ext py  = python -- %s
ext pl  = perl -- %s

which would make the suggestion-thing look more like:

0 | python -- %s
1 | "$PAGER" -- %s

where %s, %f, %t etc. should be active as well for consistency.

So that ":shell python -- %s" means the same as option 0.

Offline

#1295 2012-04-10 21:04:15

Veedrac
Member
Registered: 2011-07-19
Posts: 81

Re: Ranger, a textbased filemanager

Bwahaha!

Being the fool that I am, may I propose another way entirely, an extension of my last‽
One such as myself might completely appreciate a merging of rc.conf and rifle.conf, although the files could still be kept separate. Of course, if rifle is used standalone this may not be ideal, but if not I believe you may come to like this idea.

Subtitute:

ext py  = python -- "$@"
ext pl  = perl -- "$@"

for:

context [ext py] r shell python -- %s
context [ext pl] r shell perl -- %s

Which then allows things like:

context [ext rar] r markFiles %s
context [ext rar] R <secondary shortcut key options>

or summin'. I haven't really thought about the uses, but it unifies things. One less config file, the ability to change "context" stuff on-the-fly, the ability to have different shortcuts, the ability to use not just shell, the sensible merging of syntax.

Heck, I'm sorry I'm not confident enough to implement this myself as a field test, though I may try. And sorry for bugging you, I know I must be by now.

ALTERNATE SUGGESTIONS

You may not like the increased verbosity, but it can be compressed*, with no loss of features, to

context [ext py] python -- %s
context [ext pl] perl -- %s
context [ext rar, noshell] markFiles %s
context [ext rar, key R, noshell] <secondary shortcut key options>

or, if you hate the square brackets:

context ext py = python -- %s
context ext pl = perl -- %s
context ext rar, noshell = markFiles %s
context ext rar, key R, noshell= <secondary shortcut key options>

The problem is that the keys should not be implicit because that would imply that we have another setup command. I wouldn't mind implicit "shell", as it's wanted most of the time and doesn't have the same problem, but it's less obvious what "[noshell]" does than what "[] shell" does, if you see what I mean wink.

*In the general case (first two), it's only a few characters more than the current rifle.conf because "context" is a long word. In the non-general case, more characters are used than even the first suggestion because "noshell" is needed, but they should be exceedingly rare anyway.

Offline

#1296 2012-04-10 21:46:23

hut
Member
From: Hanover, Germany
Registered: 2010-03-12
Posts: 569
Website

Re: Ranger, a textbased filemanager

I appreciate your suggestions Vedrac.

But one of the goals of ranger is to "do one thing and do it well". This is why I separated file opening to an external program. I admit, it is not *really* an external program since it is included as a module, but this is only for performance reasons. rifle can be used as a standalone program and can also be replaced by any other file opener. The config is easily parseable and doesn't depend on ranger specifics at all. I can see that this way of doing things has some drawbacks but this is the way to go IMO. There are good sides too:

  • to understand rifle, you don't need to understand ranger

  • rifle can be used outside of ranger

  • rifle starts much faster than ranger

  • rifle can be rewritten in any language (i plan to rewrite it in C while using the same config, once it's done)

  • rifle can be packaged as a separate program

Implementing your suggestions would interweave rifle back into ranger and destroy the separation.

Last edited by hut (2012-04-10 21:58:14)


"hut_" or "h00th00t" in irc.freenode.net #archlinux
Ranger Mailing List: https://lists.nongnu.org/mailman/listinfo/ranger-users

Offline

#1297 2012-04-11 10:51:42

Veedrac
Member
Registered: 2011-07-19
Posts: 81

Re: Ranger, a textbased filemanager

This was one thing I considered, but it's easily* separable even this way.

Ranger just uses "context" to configure a Rifle instance instead** of that Rifle instance using a config file and then calls a new "get_command" function of the instance which does everything "execute" currently does - bar running the command. Ranger then runs the command.

I see one drawback of this method, minus it taking effort to implement - to implement different keys ("context [] r <command>; context [] R <command>") we would need separate Rifle instances*** or a modal Rifle class of some sort.

*In concept, not implementation
**Or, on top of
***Less preferably, a "key" could be passed to rifle.py - but that would hurt usage outside of Ranger.

-----------------------------

"rifle can be rewritten in any language (i plan to rewrite it in C while using the same config, once it's done)"
Have you considered Cython for this? I'm not sure, but if you avoid your python libraries and stick to C ones, it might make it easier to transfer. Additionally, I see a few obvious micro-optimizations you can make to rifle now, I'll send you a new file after I implement them I guess.
Actually, it's fast enough already. I've changed a touch of the code to no real change in speed but with profiling it's taking <0.07 seconds, which is faster than human reaction times. I have no reason to speed it up, so why are you rewriting it? If anything I'd just change your ranger.ext.spawn.spawn dependency for the built-in mimetypes module. It takes longer, but it's still far less than 0.1 seconds.

My last comment: why does "get_executables" sort? It has a set before then, which seems far more appropriate.

Last edited by Veedrac (2012-04-11 11:27:38)

Offline

#1298 2012-04-11 11:58:42

hut
Member
From: Hanover, Germany
Registered: 2010-03-12
Posts: 569
Website

Re: Ranger, a textbased filemanager

Veedrac wrote:

Actually, it's fast enough already. I've changed a touch of the code to no real change in speed but with profiling it's taking <0.07 seconds, which is faster than human reaction times. I have no reason to speed it up, so why are you rewriting it? If anything I'd just change your ranger.ext.spawn.spawn dependency for the built-in mimetypes module. It takes longer, but it's still far less than 0.1 seconds.

How do you do that? For me, it's

$ time python3 ranger/ext/rifle.py &> /dev/null

real	0m0.492s
user	0m0.393s
sys	0m0.010s

If it were 0.07s I wouldn't care either smile.

Veedrac wrote:

My last comment: why does "get_executables" sort? It has a set before then, which seems far more appropriate.

I wish I knew. It's only used like "if foo in get_executables()" so it doesn't have to be sorted. I guess I'll take out the sorting, thanks.


"hut_" or "h00th00t" in irc.freenode.net #archlinux
Ranger Mailing List: https://lists.nongnu.org/mailman/listinfo/ranger-users

Offline

#1299 2012-04-11 15:44:33

Veedrac
Member
Registered: 2011-07-19
Posts: 81

Re: Ranger, a textbased filemanager

hut wrote:
Veedrac wrote:

Actually, it's fast enough already. I've changed a touch of the code to no real change in speed but with profiling it's taking <0.07 seconds, which is faster than human reaction times. I have no reason to speed it up, so why are you rewriting it? If anything I'd just change your ranger.ext.spawn.spawn dependency for the built-in mimetypes module. It takes longer, but it's still far less than 0.1 seconds.

How do you do that? For me, it's

$ time python3 ranger/ext/rifle.py &> /dev/null

real	0m0.492s
user	0m0.393s
sys	0m0.010s

If it were 0.07s I wouldn't care either smile.

Pah, cProfile doesn't include python's start-up time tongue
You can speed that, if you change the file to not require any non-standard libs:

python    'rifle.py' -l 'rifle.py'  0.16s user 0.01s system 98% cpu 0.170 total
python -S 'rifle.py' -l 'rifle.py'  0.09s user 0.02s system 72% cpu 0.153 total

Pythons slows a lot if you have a lot of extraneous libraries. "-S" ignores those. You can probably save much more than me by running it like that, as I bet it's the cause of your slowness.
EDIT: When running without arguments ("time python 'rifle.py'") it takes a touch longer, but not significantly.

Here's my revised code, which can run with "-S":

#!/usr/bin/python
# Copyright (C) 2012  Roman Zimbelmann <romanz@lavabit.com>
# This software is distributed under the terms of the GNU GPL version 3.

"""
rifle, the file executor/opener of ranger

This can be used as a standalone program or can be embedded in python code.
When used together with ranger, it doesn't have to be installed to $PATH.

You can use this program without installing ranger by inlining the imported
ranger functions. (shell_quote, spawn, ...)

Example usage:

	rifle = Rifle("rifle.conf")
	rifle.reload_config()
	rifle.execute(["file1", "file2"])
"""

import os, re, sys
from subprocess import Popen
from mimetypes import guess_type

_cached_executables = None

def get_executables():
	"""
	Return all executable files in each of the given directories.

	Looks in $PATH by default.
	"""
	global _cached_executables
	if _cached_executables is None:
		_cached_executables = get_executables_uncached()
	return _cached_executables


def get_executables_uncached(*paths):
	"""
	Return all executable files in each of the given directories.

	Looks in $PATH by default.
	"""
	if not paths:
		try:
			pathstring = os.environ['PATH']
		except KeyError:
			return ()
		paths = set(pathstring.split(':'))

	executables = set()
	for path in paths:
		try:
			content = os.listdir(path)
		except:
			continue
		for item in content:
			abspath = path + '/' + item
			try:
				filestat = os.stat(abspath)
			except:
				continue
			if filestat.st_mode & (os.stat.S_IXOTH | os.stat.S_IFREG):
				executables.add(item)
	return executables



DEFAULT_PAGER = 'less'
DEFAULT_EDITOR = 'nano'

def _is_terminal():
	# Check if stdin (file descriptor 0), stdout (fd 1) and
	# stderr (fd 2) are connected to a terminal
	try:
		os.ttyname(0)
		os.ttyname(1)
		os.ttyname(2)
	except:
		return False
	return True


def squash_flags(flags):
	"""
	Remove lowercase flags if the respective uppercase flag exists

	>>> squash_flags('abc')
	'abc'
	>>> squash_flags('abcC')
	'ab'
	>>> squash_flags('CabcAd')
	'bd'
	"""
	exclude = ''.join(f.upper() + f.lower() for f in flags if f == f.upper())
	return ''.join(f for f in flags if f not in exclude)


class Rifle(object):
	delimiter1 = '='
	delimiter2 = ','

	def hook_before_executing(self, command, mimetype, flags):
		pass

	def hook_after_executing(self, command, mimetype, flags):
		pass

	def hook_command_preprocessing(self, command):
		return command

	def hook_command_postprocessing(self, command):
		return command

	def hook_environment(self, env):
		return env

	def hook_logger(self, string):
		sys.stderr.write(string + "\n")

	def __init__(self, config_file):
		self.config_file = config_file
		self._app_flags = ''
		self._app_label = None

	def reload_config(self, config_file=None):
		"""Replace the current configuration with the one in config_file"""
		if config_file is None:
			config_file = self.config_file
		f = open(config_file, 'r')
		self.rules = []
		lineno = 1
		for line in f:
			if line.startswith('#') or line == '\n':
				continue
			line = line.strip()
			try:
				if self.delimiter1 not in line:
					raise Exception("Line without delimiter")
				tests, command = line.split(self.delimiter1, 1)
				tests = tests.split(self.delimiter2)
				tests = tuple(tuple(f.strip().split(None, 1)) for f in tests)
				tests = tuple(tests)
				command = command.strip()
				self.rules.append((command, tests))
			except Exception as e:
				self.hook_logger("Syntax error in %s line %d (%s)" % \
					(config_file, lineno, str(e)))
			lineno += 1
		f.close()

	def _eval_condition(self, condition, files, label):
		# Handle the negation of conditions starting with an exclamation mark,
		# then pass on the arguments to _eval_condition2().

		if not condition:
			return True
		if condition[0].startswith('!'):
			new_condition = tuple([condition[0][1:]]) + tuple(condition[1:])
			return not self._eval_condition2(new_condition, files, label)
		return self._eval_condition2(condition, files, label)

	def _eval_condition2(self, rule, files, label):
		# This function evaluates the condition, after _eval_condition() handled
		# negation of conditions starting with a "!".

		if not files: return False

		function = rule[0]
		argument = rule[1] if len(rule) > 1 else ''

		if   function == 'ext':
			extension = os.path.basename(files[0]).rsplit('.', 1)[-1]
			return bool(re.search('^' + argument + '$', extension))
		elif function == 'name':
			return bool(re.search(argument, os.path.basename(files[0])))
		elif function == 'path':
			return bool(re.search(argument, os.path.abspath(files[0])))
		elif function == 'mime':
			return bool(re.search(argument, self._get_mimetype(files[0])))
		elif function == 'has':
			return argument in get_executables()
		elif function == 'terminal':
			return _is_terminal()
		elif function == 'number':
			if argument.isdigit():
				self._skip = int(argument)
			return True
		elif function == 'label':
			self._app_label = argument
			if label:
				return argument == label
			return True
		elif function == 'flag':
			self._app_flags = argument
			return True
		elif function == 'X':
			return 'DISPLAY' in os.environ
		elif function == 'else':
			return True

	def _get_mimetype(self, fname):
		# Spawn "file" to determine the mime-type of the given file.
		if self._mimetype:
			return self._mimetype
		mimetype = guess_type(fname)[0]
		self._mimetype = mimetype
		return mimetype

	def _build_command(self, files, action, flags):
		# Get the flags
		if isinstance(flags, str):
			self._app_flags += flags
		self._app_flags = squash_flags(self._app_flags)
		flags = self._app_flags

		_filenames = "' '".join(f.replace("'", "'\\\''") for f in files
				if "\x00" not in f)
		command = "set -- '%s'" % _filenames + '\n'

		# Apply flags
		command += self._apply_flags(action, flags)
		return command

	def _apply_flags(self, action, flags):
		# FIXME: Flags do not work properly when pipes are in the command.
		if 'r' in flags:
			action = 'sudo ' + action
		if 't' in flags:
			if 'TERMCMD' not in os.environ:
				term = os.environ['TERM']
				if term.startswith('rxvt-unicode'):
					term = 'urxvt'
				if term not in get_executables():
					self.hook_logger("Can not determine terminal command.  "
						"Please set $TERMCMD manually.")
				os.environ['TERMCMD'] = term
			action = "$TERMCMD -e %s" % action
		if 'f' in flags:
			if 'setsid' in get_executables():
				action = "setsid %s > /dev/null 2> /dev/null &" % action
			else:
				action = "nohup %s > /dev/null 2> /dev/null &" % action
		return action

	def list_commands(self, files, mimetype=None):
		"""
		Returns one 4-tuple for all currently applicable commands
		The 4-tuple contains (count, command, label, flags).
		count is the index, counted from 0 upwards,
		command is the command that will be executed.
		label and flags are the label and flags specified in the rule.
		"""
		self._mimetype = mimetype
		count = -1
		for cmd, tests in self.rules:
			self._skip = None
			self._app_flags = ''
			self._app_label = None
			for test in tests:
				if not self._eval_condition(test, files, None):
					break
			else:
				if self._skip is None:
					count += 1
				else:
					count = self._skip
				yield (count, cmd, self._app_label, self._app_flags)

	def execute(self, files, number=0, label=None, flags=None, mimetype=None):
		"""
		Executes the given list of files.

		By default, this executes the first command where all conditions apply,
		but by specifying number=N you can run the 1+Nth command.

		If a label is specified, only rules with this label will be considered.

		If you specify the mimetype, rifle will not try to determine it itself.

		By specifying a flag, you extend the flag that is defined in the rule.
		Uppercase flags negate the respective lowercase flags.
		For example: if the flag in the rule is "pw" and you specify "Pf", then
		the "p" flag is negated and the "f" flag is added, resulting in "wf".
		"""
		command = None
		found_at_least_one = None

		# Determine command
		for count, cmd, lbl, flags in self.list_commands(files, mimetype):
			if label and label == lbl or not label and count == number:
				cmd = self.hook_command_preprocessing(cmd)
				command = self._build_command(files, cmd, flags)
				break
			else:
				found_at_least_one = True
		else:
			if label and label in get_executables():
				cmd = '%s -- "$@"' % label
				command = self._build_command(files, cmd, flags)

		# Execute command
		if command is None:
			if found_at_least_one:
				if label:
					self.hook_logger("Label '%s' is undefined" % label)
				else:
					self.hook_logger("Method number %d is undefined." % number)
			else:
				self.hook_logger("No action found.")
		else:
			if 'PAGER' not in os.environ:
				os.environ['PAGER'] = DEFAULT_PAGER
			if 'EDITOR' not in os.environ:
				os.environ['EDITOR'] = DEFAULT_EDITOR
			command = self.hook_command_postprocessing(command)
			self.hook_before_executing(command, self._mimetype, self._app_flags)
			try:
				p = Popen(command, env=self.hook_environment(os.environ), shell=True)
				p.wait()
			finally:
				self.hook_after_executing(command, self._mimetype, self._app_flags)


def main():
	"""The main function which is run when you start this program direectly."""
	import sys

	# Find configuration file path
	if 'XDG_CONFIG_HOME' in os.environ and os.environ['XDG_CONFIG_HOME']:
		conf_path = os.environ['XDG_CONFIG_HOME'] + '/ranger/rifle.conf'
	else:
		conf_path = os.path.expanduser('~/.config/ranger/rifle.conf')
	if not os.path.isfile(conf_path):
		conf_path = os.path.normpath(os.path.join(os.path.dirname(__file__),
			'../defaults/rifle.conf'))

	# Evaluate arguments
	from optparse import OptionParser
	parser = OptionParser(usage="%prog [-fhlpw] [files]")
	parser.add_option('-f', type="string", default=None, metavar="FLAGS",
			help="use additional flags: f=fork, r=root, t=terminal. "
			"Uppercase flag negates respective lowercase flags.")
	parser.add_option('-l', action="store_true",
			help="list possible ways to open the files (id:label:flags:command)")
	parser.add_option('-p', type='string', default='0', metavar="KEYWORD",
			help="pick a method to open the files.  KEYWORD is either the "
			"number listed by 'rifle -l' or a string that matches a label in "
			"the configuration file")
	parser.add_option('-w', type='string', default=None, metavar="PROGRAM",
			help="open the files with PROGRAM")
	options, positional = parser.parse_args()
	if not positional:
		parser.print_help()
		raise SystemExit(1)

	if options.p.isdigit():
		number = int(options.p)
		label = None
	else:
		number = 0
		label = options.p

	if options.w is not None and not options.l:
		p = Popen([options.w] + list(positional))
		p.wait()
	else:
		# Start up rifle
		rifle = Rifle(conf_path)
		rifle.reload_config()
		#print(rifle.list_commands(sys.argv[1:]))
		if options.l:
			for count, cmd, label, flags in rifle.list_commands(positional):
				print("%d:%s:%s:%s" % (count, label or '', flags, cmd))
		else:
			rifle.execute(positional, number=number, label=label, flags=options.f)


if __name__ == '__main__':
	main()

EDIT: Minor code update
EDIT: Minor code update, again
EDIT: And again, aargh
EDIT: Woa, you like tuples:

tests = tuple(tuple(f.strip().split(None, 1)) for f in tests)
tests = tuple(tests)

Last edited by Veedrac (2012-04-11 17:54:09)

Offline

#1300 2012-04-12 17:21:58

TheImmortalPhoenix
Member
From: 127.0.0.1
Registered: 2011-08-13
Posts: 436

Re: Ranger, a textbased filemanager

Hi, i have a problem: when i type a command in ranger (for example :delete) nothing appens and ranger is locked and i can't do anything, just exit ... This appens with all commands i type after " : "

Offline

Board footer

Powered by FluxBB