You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
11 KiB

import sys
import os
import subprocess
5 years ago
import configparser
import magic
import json
import datetime
mime = magic.Magic(mime=True)
5 years ago
# supported values: fish, bash, zsh
if ( 'DO_WHAT_SHELL' in os.environ ):
shell=os.environ['DO_WHAT_SHELL']
else:
print("echo Shell type not set. To set up the environment, add the following line to your shell\\\'s init file:")
print("echo dowhat {shell} \| .")
exit()
5 years ago
# Defaults
print_file="cat"
pretty_print_file="less -R"
edit_file="vim"
list_directory="ls --color=auto"
list_git_directory="ls --color=auto"
5 years ago
change_dir="cd"
print_dir="pwd"
help_command="man"
path_locator="which"
open_file="xdg-open"
5 years ago
# general function for setting a shell's environment variable
def set_runtime_var(name, value, options=""):
5 years ago
if ( shell == "fish" ):
print("set "+name+" "+options+" \""+value+"\"")
5 years ago
elif ( shell == "bash" or shell == "zsh" ):
5 years ago
print("export "+name+"="+"\""+value+"\"")
5 years ago
# checks if a file is a binary file or a plaintext file
def is_binary_file(filepathname):
textchars = bytearray([7,8,9,10,12,13,27]) + bytearray(range(0x20, 0x7f)) + bytearray(range(0x80, 0x100))
is_binary_string = lambda bytes: bool(bytes.translate(None, textchars))
if is_binary_string(open(filepathname, 'rb').read(1024)):
return True
else:
return False
5 years ago
# check if a given program is in the path environment using which
5 years ago
def env_has(program):
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
fpath, fname = os.path.split(program)
if fpath:
if is_exe(program):
return True
else:
for path in os.environ["PATH"].split(os.pathsep):
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return True
return None
5 years ago
5 years ago
# get the number of lines in a file
def file_len(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
try:
i
except NameError:
return 0
else:
return i + 1
5 years ago
# bootstrap the config
ENV_HOME=os.environ['HOME']
5 years ago
subprocess.call(['mkdir', '-p', ENV_HOME+'/.config/do_what'])
if ( os.path.isfile(ENV_HOME+'/.config/do_what/what.config') ):
5 years ago
config = configparser.ConfigParser()
5 years ago
config.read(ENV_HOME+'/.config/do_what/what.config')
# TODO add else default configs
5 years ago
if ( 'DEFAULT' in config ):
if ( 'print_file' in config['DEFAULT'] ):
print_file = config['DEFAULT']['print_file']
if ( 'pretty_print_file' in config['DEFAULT'] ):
pretty_print_file = config['DEFAULT']['pretty_print_file']
if ( 'edit_file' in config['DEFAULT'] ):
5 years ago
edit_file = config['DEFAULT']['edit_file']
5 years ago
if ( 'list_directory' in config['DEFAULT'] ):
list_directory = config['DEFAULT']['list_directory']
5 years ago
if ( 'help_command' in config['DEFAULT'] ):
help_command = config['DEFAULT']['help_command']
if ( 'path_locator' in config['DEFAULT'] ):
path_locator = config['DEFAULT']['path_locator']
if ( 'list_git_directory' in config['DEFAULT'] ):
list_git_directory = config['DEFAULT']['list_git_directory']
if ( 'open_file' in config['DEFAULT'] ):
open_file = config['DEFAULT']['open_file']
5 years ago
else:
config = configparser.ConfigParser()
config['DEFAULT'] = {
'list_directory': list_directory,
'edit_file': edit_file,
'pretty_print_file': pretty_print_file,
5 years ago
'print_file': print_file,
'help_command': help_command,
'path_locator': path_locator,
'list_git_directory': list_git_directory,
'open_file': open_file
5 years ago
}
print("echo Default config loaded.")
5 years ago
with open(ENV_HOME+'/.config/do_what/what.config', 'w') as configfile:
5 years ago
config.write(configfile)
configfile.close()
5 years ago
# check if active mode is enabled
argiter = 0
active = False
for arg in sys.argv:
if ( str(arg) == '-' ):
active = True
break
argiter += 1
5 years ago
# absolutize the path for python
if ( (active and len(sys.argv) >= 3) or (not active and len(sys.argv) >= 2) ):
filearg = sys.argv[1]
path = sys.argv[1]
if ( path[0] != "/" and path[0] != "~" and path[0] != "." ):
path = os.getcwd()+"/"+path
elif ( path[0] == "." and len(path) > 1 and ( path[:2] == "./" ) ):
path = os.getcwd()+path[1:]
elif ( path[0] == "." and len(path) > 1 and ( path[:2] == ".." ) ):
path = os.getcwd()+"/"+path
elif ( path[0] == "." and len(path) == 1 ):
path = os.getcwd()
# CLIpboard (ha.)
if ( active and len(sys.argv) > argiter+1 and sys.argv[argiter+1] == 'c' ):
subprocess.call(['rm', '-rf', ENV_HOME+'/.config/do_what/clipboard'])
subprocess.call(['touch', ENV_HOME+'/.config/do_what/clipboard'])
if ( filearg == '-' ):
path = os.getcwd()
if ( os.path.isdir(path) or os.path.isfile(path) ):
with open(ENV_HOME+"/.config/do_what/clipboard", "w") as cb:
cbdata = { 'action': 'copy', 'path': path }
json.dump(cbdata, cb)
print("echo Copied: "+path)
exit()
else:
print("echo Unknown file/directory.")
exit()
elif ( active and len(sys.argv) > argiter+1 and sys.argv[argiter+1] == 'x' ):
subprocess.call(['rm', '-rf', ENV_HOME+'/.config/do_what/clipboard'])
subprocess.call(['touch', ENV_HOME+'/.config/do_what/clipboard'])
if ( filearg == '-' ):
path = os.getcwd()
if ( os.path.isdir(path) or os.path.isfile(path) ):
with open(ENV_HOME+"/.config/do_what/clipboard", "w") as cb:
cbdata = { 'action': 'cut', 'path': path }
json.dump(cbdata, cb)
print("echo Cut: "+path)
exit()
else:
print("echo Unknown file/directory.")
exit()
elif ( active and len(sys.argv) > argiter+1 and sys.argv[argiter+1] == 'p' ):
if ( os.path.isfile(ENV_HOME+"/.config/do_what/clipboard") ):
with open(ENV_HOME+"/.config/do_what/clipboard", "r") as cb:
try:
cbdata = json.load(cb)
except json.decoder.JSONDecodeError:
print("echo Invalid clipboard file.")
exit()
print("echo \""+str(cbdata)+"\"")
if ( cbdata['action'] == 'copy' ):
file_op = 'cp'
elif ( cbdata['action'] == 'cut' ):
file_op = 'mv'
if ( os.path.isdir( cbdata['path'] ) and filearg == '-' ):
print("echo Pasted directory: "+cbdata['path'])
print(file_op+" -r "+cbdata['path']+" .")
elif ( os.path.isdir( cbdata['path'] ) and os.path.isdir( path ) ):
print("echo Pasted directory "+cbdata['path']+" in "+path)
print(file_op+" -r "+cbdata['path']+" "+path)
elif ( os.path.isdir( cbdata['path'] ) and os.path.isfile( path ) ):
print("echo Cannot paste directory into regular file.")
print("echo \"("+cbdata['path']+" -> "+path+")\"")
elif ( os.path.isfile( cbdata['path'] ) and filearg == '-' ):
print("echo Pasted file: "+cbdata['path'])
print(file_op+" "+cbdata['path']+" .")
elif ( os.path.isfile( cbdata['path'] ) and os.path.isdir( path ) ):
print("echo Pasted file "+cbdata['path']+" in directory "+path)
print(file_op+" "+cbdata['path']+" "+path)
elif ( os.path.isfile( cbdata['path'] ) and os.path.isfile( path ) ):
print("echo Pasted file "+cbdata['path']+" over existing file "+path)
print(file_op+" "+cbdata['path']+" "+path)
elif ( os.path.isfile( cbdata['path'] ) and filearg != '-' ):
print("echo Pasted file "+cbdata['path']+" as new file "+path)
print(file_op+" "+cbdata['path']+" "+path)
elif ( os.path.isdir( cbdata['path'] ) and filearg != '-' ):
print("echo Pasted directory "+cbdata['path']+" as new directory "+path)
print(file_op+" "+cbdata['path']+" "+path)
else:
print("echo Invalid clipboard. Use \\\'c\\\' directive to copy a file or directory.")
else:
print("echo Empty clipboard. Use \\\'c\\\' directive to copy a file or directory.")
exit()
# File/Directory backup creator
# Capital B = Time versioned backup
elif ( active and len(sys.argv) > argiter+1 and sys.argv[argiter+1] == 'B' ):
if ( filearg == '-' ):
print("No file/directory specified to backup.")
elif ( os.path.isfile( path ) ):
bakname = ".bak-"+datetime.datetime.now().strftime("%Y-%B-%d_%I:%M%p")
print("cp "+path+" "+path+bakname)
print("echo Created file backup: "+path+bakname)
elif( os.path.isdir( path ) ):
bakname = ".bak-"+datetime.datetime.now().strftime("%Y-%B-%d_%I:%M%p")
print("cp -r "+path+" "+path+bakname)
print("echo Created directory backup: "+path+bakname)
exit()
# Lowercase b = un-versioned backup
elif ( active and len(sys.argv) > argiter+1 and sys.argv[argiter+1] == 'b' ):
if ( filearg == '-' ):
print("No file/directory specified to backup.")
elif ( os.path.isfile( path ) ):
bakname = ".bak"
print("cp "+path+" "+path+bakname)
print("echo Created file backup: "+path+bakname)
elif( os.path.isdir( path ) ):
bakname = ".bak"
print("cp -r "+path+" "+path+bakname)
print("echo Created directory backup: "+path+bakname)
exit()
# Lowercase r = restore the specified backup
elif ( active and len(sys.argv) > argiter+1 and sys.argv[argiter+1] == 'r' ):
if ( filearg == '-' ):
print("No file/directory specified to restore.")
elif ( os.path.isfile( path ) ):
if ( ".bak" not in path ):
print("echo "+path+" is not a valid backup file.")
else:
restorepath = path.split(".bak", 1)[0]
print("mv "+path+" "+restorepath)
print("echo Restored file: "+restorepath)
elif ( os.path.isdir( path ) ):
if ( ".bak" not in path ):
print("echo "+path+" is not a valid backup directory.")
else:
restorepath = path.split(".bak", 1)[0]
print("mv "+path+" "+restorepath)
print("echo Restored directory: "+restorepath)
exit()
elif ( active and len(sys.argv) > argiter+1 ):
print("echo Invalid directive: "+sys.argv[argiter+1])
exit()
# File Operations
5 years ago
if ( (not active and len(sys.argv) == 1) or (active and len(sys.argv) == 2) ):
# list the contents of the current directory
if ( not active ):
if ( os.path.isdir('.git') ):
print(list_git_directory)
else:
print(list_directory)
5 years ago
# print the working directory (active)
elif ( active ):
print(print_dir)
elif ( (not active and len(sys.argv) == 2) or (active and len(sys.argv) == 3) ):
# if directory, list its contents
if ( os.path.isdir(path) and not active ):
if ( os.path.isdir(path+"/.git") ):
print(list_git_directory+" "+path)
else:
print(list_directory+" "+path)
5 years ago
# if directory, change into it (active)
elif ( os.path.isdir(path) and active ):
print(change_dir+" "+path)
# if file, display its contents
elif ( os.path.isfile(path) and not active ):
# check if file is binary
if ( is_binary_file(path) ):
filemime = mime.from_file(path)
print("echo Binary file: "+filemime)
if ( filemime == "inode/symlink" ):
print("echo Symlink location: "+os.path.realpath(path))
else:
trows, tcolumns = os.popen('stty size', 'r').read().split()
5 years ago
# if file is taller than the terminal, pipe it to a pretty-print display
if ( int(trows) - 5 < int(file_len(path)) ):
set_runtime_var('LESSOPEN', '| /usr/share/source-highlight/src-hilite-lesspipe.sh %s')
set_runtime_var('LESS', ' -R ')
print(pretty_print_file+" "+path)
5 years ago
# if file is shorter than the terminal, print its contents
else:
print(print_file+" "+path)
5 years ago
# if file, open in editor (active)
elif ( os.path.isfile(path) and active ):
if ( is_binary_file(path) ):
print(open_file+" "+path)
5 years ago
else:
if ( os.access(path, os.W_OK) ):
print(edit_file+" "+path)
else:
print("sudo "+edit_file+" "+path)
else:
5 years ago
# check if file is a path program, then list using which/man on active
path_has = env_has(filearg)
5 years ago
# print the location of the program
if ( path_has and not active ):
print(path_locator+" "+filearg)
5 years ago
# display the help page for the program (active)
elif ( path_has and active ):
5 years ago
print(help_command+" "+filearg)
else:
5 years ago
print("echo Unknown file/directory.")