-
Notifications
You must be signed in to change notification settings - Fork 15
/
dirhist
executable file
·135 lines (107 loc) · 4.31 KB
/
dirhist
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env python2
import sys
import os
import re
from collections import OrderedDict
from os.path import expanduser
# Size of the history
HISTSIZE = 10000
# History file
HISTFILE = ".directory_history"
# Home directory of user
home = expanduser("~")
def get_dir_and_command(line):
parts = line.split(";")
return (parts[1], ";".join(parts[2:]))
def remove_duplicates_front(commands):
"""Remove duplicate entries from the front in commands.
Remove from the front since entries in the front are older
than the ones at the end of commands.
"""
# [ls,vim,su,cat,ls] -> [vim,su,cat,ls]
commands.reverse()
commands_unique = list(OrderedDict.fromkeys(commands))
commands_unique.reverse()
return commands_unique
def read_backwards(f, num_lines, delimiter, blocksize=1024):
"""Read num_lines seperated by delimiter from end of file without
loading whole file."""
f.seek(0, 2)
end = f.tell()
block_number = -1
blocks = []
while num_lines > 0 and end > 0:
if (end - blocksize > 0):
f.seek(block_number*blocksize, 2)
blocks.append(f.read(blocksize))
else:
# Read remaining data
f.seek(0,0)
blocks.append(f.read(end))
num_lines -= blocks[-1].count(delimiter)
end -= blocksize
block_number -= 1
return ''.join(reversed(blocks))
def get_commands_in_directory(directory):
"""Returns all commands executed in directory.
Duplicates will be removed and more important commands will be at
the end of the returned list.
The most recent command in directory is considered the most
important command.
The oldest command from all other directories is considered the
least important command.
"""
commands_dir = []
commands_not_dir = []
try:
with open(home + "/" + HISTFILE, "r") as f:
# Get commands from this directory
for line in reversed(read_backwards(f, HISTSIZE, '\0').strip().strip('\0').split('\0')):
try:
directory_in_history, command = get_dir_and_command(line.strip())
except (ValueError, IndexError):
continue
if directory_in_history == directory:
commands_dir.append(command)
# Get commands not in this directory
for line in reversed(read_backwards(f, HISTSIZE, '\0').strip().strip('\0').split('\0')):
try:
directory_in_history, command = get_dir_and_command(line.strip())
except (ValueError, IndexError):
continue
if len(commands_not_dir) + len(commands_dir) >= HISTSIZE:
break
if directory_in_history != directory:
commands_not_dir.append(command)
except IOError:
open(home + "/" + HISTFILE, 'a').close()
# Least important command needs to be at the start
commands = list(reversed(commands_not_dir)) + list(reversed(commands_dir))
# Remove duplicates from the front
commands = remove_duplicates_front(commands)
return commands
def get_indices_by_substring_and_directory(directory, substring):
"""Return indices of substrings from a certain directory."""
commands = get_commands_in_directory(directory)
# Remove backslashes in front of ][()|\*?#<>~^
substring_no_escape = re.sub(r'\\([\][()|\\*?#<>~^])', r'\1', substring)
indices = []
for cmd in commands:
if substring_no_escape.lower() in cmd.lower():
index = commands.index(cmd)+1
indices.append(index)
return indices
# Return complete history for a directory if -a/-all -d DIRECTORY are arguments
if len(sys.argv) == 4 and (sys.argv[1] == "-a" or sys.argv[1] == "--all") and (sys.argv[2] == "-d"):
directory = sys.argv[3]
print "\0\n".join(get_commands_in_directory(directory))
# Return list of indizes which match a given substring
# dirhist -s/--substring SUBSTRING -d DIRECTORY
if len(sys.argv) == 5 and (sys.argv[1] == "-s" or sys.argv[1] == "--substring") and sys.argv[3] == "-d":
directory = sys.argv[4]
substring = sys.argv[2]
indices = [str(i) for i in get_indices_by_substring_and_directory(directory, substring)]
if indices:
print "\n".join(indices)
else:
print "NONE"