python3izing scripts

This commit is contained in:
Ville Rantanen
2020-10-12 11:28:07 +03:00
parent db3e281df6
commit 877acc0d35
4 changed files with 422 additions and 337 deletions

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
import os, sys import os, sys
import math, shutil, re import math, shutil, re
@@ -6,25 +6,62 @@ from random import shuffle
VERSION = "0.1" VERSION = "0.1"
def setup_options(): def setup_options():
''' Setup the command line options ''' """ Setup the command line options """
from argparse import ArgumentParser from argparse import ArgumentParser
parser = ArgumentParser(description="Splits files to subfolders equally.") parser = ArgumentParser(description="Splits files to subfolders equally.")
parser.add_argument("--order",'-o',type=str,action='store', dest='order',default="sequence", parser.add_argument(
"--order",
"-o",
type=str,
action="store",
dest="order",
default="sequence",
help="Splitting method.", help="Splitting method.",
choices=['sequence','sparse','regexp','random']) choices=["sequence", "sparse", "regexp", "random"],
parser.add_argument("-m",action='store_true', dest='move',default=False, )
help="Move entries instead of hardlink.") parser.add_argument(
parser.add_argument("-f",action='store_true', dest='files',default=False, "-m",
help="Split files only, skipping folders") action="store_true",
parser.add_argument("-r",'--regexp',type=str,action='store', dest='regexp',default="", dest="move",
help="Regular expression for splitting. When set, order regexp used, -n not used.") default=False,
parser.add_argument("-n",'-N',type=int,action='store', dest='n', help="Move entries instead of hardlink.",
help="Number of subfolders to split into.") )
parser.add_argument("path",type=str,action="store",default=".",nargs="?", parser.add_argument(
help="Folder to split.") "-f",
action="store_true",
dest="files",
default=False,
help="Split files only, skipping folders",
)
parser.add_argument(
"-r",
"--regexp",
type=str,
action="store",
dest="regexp",
default="",
help="Regular expression for splitting. When set, order regexp used, -n not used.",
)
parser.add_argument(
"-n",
"-N",
type=int,
action="store",
dest="n",
help="Number of subfolders to split into.",
)
parser.add_argument(
"path",
type=str,
action="store",
default=".",
nargs="?",
help="Folder to split.",
)
options = parser.parse_args() options = parser.parse_args()
if options.n == None and options.regexp == "": if options.n == None and options.regexp == "":
parser.print_help() parser.print_help()
@@ -33,6 +70,7 @@ def setup_options():
options.order = "regexp" options.order = "regexp"
return options return options
def linktree(src, dst): def linktree(src, dst):
"""Recursively link a directory tree using os.link. """Recursively link a directory tree using os.link.
Modified from shutil.copytree Modified from shutil.copytree
@@ -49,16 +87,17 @@ def linktree(src, dst):
else: else:
# Will raise a SpecialFileError for unsupported file types # Will raise a SpecialFileError for unsupported file types
os.link(srcname, dstname) os.link(srcname, dstname)
except Error, err: except Error as err:
errors.extend(err.args[0]) errors.extend(err.args[0])
except EnvironmentError, why: except EnvironmentError as why:
errors.append((srcname, dstname, str(why))) errors.append((srcname, dstname, str(why)))
if errors: if errors:
raise Error, errors raise Error(errors)
def copyfileorfolder(basename, source, target, move): def copyfileorfolder(basename, source, target, move):
''' Copies a file or folder structure under target folder ''' """ Copies a file or folder structure under target folder """
if move: if move:
shutil.move(os.path.join(source, basename), os.path.join(target, basename)) shutil.move(os.path.join(source, basename), os.path.join(target, basename))
return return
@@ -68,10 +107,11 @@ def copyfileorfolder(basename,source,target,move):
if os.path.isdir(os.path.join(source, basename)): if os.path.isdir(os.path.join(source, basename)):
linktree(os.path.join(source, basename), os.path.join(target, basename)) linktree(os.path.join(source, basename), os.path.join(target, basename))
return return
raise RuntimeError(source+' was neither file nor folder.') raise RuntimeError(source + " was neither file nor folder.")
def portorder(inFiles, inFolder, outFolders, N, link): def portorder(inFiles, inFolder, outFolders, N, link):
''' Copy files in port order (sparse) ''' """ Copy files in port order (sparse) """
outidx = 0 outidx = 0
for row in inFiles: for row in inFiles:
copyfileorfolder(row, inFolder, outFolders[outidx], link) copyfileorfolder(row, inFolder, outFolders[outidx], link)
@@ -79,8 +119,9 @@ def portorder(inFiles,inFolder,outFolders,N,link):
if outidx + 1 > N: if outidx + 1 > N:
outidx = 0 outidx = 0
def fileorder(inFiles, inFolder, outFolders, N, link): def fileorder(inFiles, inFolder, outFolders, N, link):
''' Copy files in input file order (sequnce) ''' """ Copy files in input file order (sequnce) """
bins = [int(math.floor(float(len(inFiles)) / float(N)))] * int(N) bins = [int(math.floor(float(len(inFiles)) / float(N)))] * int(N)
binidx = 0 binidx = 0
@@ -94,8 +135,9 @@ def fileorder(inFiles,inFolder,outFolders,N,link):
for f in range(offsets[outidx], offsets[outidx] + bins[outidx]): for f in range(offsets[outidx], offsets[outidx] + bins[outidx]):
copyfileorfolder(inFiles[f], inFolder, outFolders[outidx], link) copyfileorfolder(inFiles[f], inFolder, outFolders[outidx], link)
def regexorder(inFiles, inFolder, outFolders, matcher, uniqlabel, link): def regexorder(inFiles, inFolder, outFolders, matcher, uniqlabel, link):
''' Copy files by regex match ''' """ Copy files by regex match """
for f in inFiles: for f in inFiles:
m = matcher.search(f) m = matcher.search(f)
@@ -103,6 +145,7 @@ def regexorder(inFiles,inFolder,outFolders,matcher,uniqlabel,link):
outidx = uniqlabel.index(m.group(1)) outidx = uniqlabel.index(m.group(1))
copyfileorfolder(f, inFolder, outFolders[outidx], link) copyfileorfolder(f, inFolder, outFolders[outidx], link)
def regexmatches(inFiles, opts): def regexmatches(inFiles, opts):
matcher = re.compile(opts.regexp) matcher = re.compile(opts.regexp)
matches = [] matches = []
@@ -120,44 +163,47 @@ def regexmatches(inFiles, opts):
outFolders.append(os.path.join(opts.path, x)) outFolders.append(os.path.join(opts.path, x))
return (outFolders, uniqlabel, matcher) return (outFolders, uniqlabel, matcher)
def offset(it): def offset(it):
total = 0 total = 0
for x in it: for x in it:
total += x total += x
yield total yield total
def report(outFolders): def report(outFolders):
for x in outFolders: for x in outFolders:
n = len(os.listdir(x)) n = len(os.listdir(x))
print(os.path.basename(x) + ":" + str(n)) print(os.path.basename(x) + ":" + str(n))
''' Splits a folder input in N outputs '''
""" Splits a folder input in N outputs """
options = setup_options() options = setup_options()
outFolders = [] outFolders = []
method = options.order.lower().strip() method = options.order.lower().strip()
# list files, and remove hidden (.files) # list files, and remove hidden (.files)
inFiles=sorted(filter(lambda x: not x.startswith('.'), os.listdir(options.path))) inFiles = sorted(filter(lambda x: not x.startswith("."), os.listdir(options.path)))
if options.files: if options.files:
inFiles = [f for f in inFiles if os.path.isfile(os.path.join(options.path, f))] inFiles = [f for f in inFiles if os.path.isfile(os.path.join(options.path, f))]
if method=='regexp': if method == "regexp":
(outFolders, uniqlabel, matcher) = regexmatches(inFiles, options) (outFolders, uniqlabel, matcher) = regexmatches(inFiles, options)
raw_input("correct?") input("correct?")
else: else:
for x in range(options.n): for x in range(options.n):
outFolders.append(os.path.join(options.path,'folder'+str(x+1))) outFolders.append(os.path.join(options.path, "folder" + str(x + 1)))
for x in outFolders: for x in outFolders:
if not os.path.isdir(x): if not os.path.isdir(x):
os.mkdir(x) os.mkdir(x)
if method=='random': if method == "random":
shuffle(inFiles) shuffle(inFiles)
portorder(inFiles, options.path, outFolders, options.n, options.move) portorder(inFiles, options.path, outFolders, options.n, options.move)
if method=='regexp': if method == "regexp":
regexorder(inFiles, options.path, outFolders, matcher, uniqlabel, options.move) regexorder(inFiles, options.path, outFolders, matcher, uniqlabel, options.move)
if method=='sparse': if method == "sparse":
portorder(inFiles, options.path, outFolders, options.n, options.move) portorder(inFiles, options.path, outFolders, options.n, options.move)
if method=='sequence': if method == "sequence":
fileorder(inFiles, options.path, outFolders, options.n, options.move) fileorder(inFiles, options.path, outFolders, options.n, options.move)

View File

@@ -3,6 +3,7 @@ import sys,re,os
from argparse import ArgumentParser from argparse import ArgumentParser
from argparse import RawTextHelpFormatter from argparse import RawTextHelpFormatter
def setup_options(): def setup_options():
parser = ArgumentParser( parser = ArgumentParser(
description="""Template Filler description="""Template Filler
@@ -15,33 +16,30 @@ def setup_options():
[[name]]=John [[name]]=John
[[letter]]=@letter.txt [[letter]]=@letter.txt
""", """,
formatter_class = RawTextHelpFormatter formatter_class=RawTextHelpFormatter,
) )
parser.add_argument( parser.add_argument(
"-e", "-e",
action="store_true", action="store_true",
dest="env", dest="env",
default=False, default=False,
help = "Use the environment to replace ${env} style variables." help="Use the environment to replace ${env} style variables.",
) )
parser.add_argument( parser.add_argument(
"-f", "-f", action="store", dest="file", help="File name to read keys/values."
action = "store",
dest = "file",
help = "File name to read keys/values."
) )
parser.add_argument( parser.add_argument(
"-p", "-p",
action="append", action="append",
dest="values", dest="values",
default=[], default=[],
help = "key=value pairs. This option may be issued several times." help="key=value pairs. This option may be issued several times.",
) )
parser.add_argument( parser.add_argument(
'template', "template",
action="store", action="store",
nargs = '?', nargs="?",
help = "Template file to be filled. If not defined, stdin used." help="Template file to be filled. If not defined, stdin used.",
) )
options = parser.parse_args() options = parser.parse_args()
return options return options
@@ -54,19 +52,25 @@ def parse_file(filename):
l = l.rstrip("\n\r") l = l.rstrip("\n\r")
if len(l) == 0: if len(l) == 0:
continue continue
tokens = l.split('=', 1) tokens = l.split("=", 1)
if len(tokens) != 2: if len(tokens) != 2:
print("File %s:%i key=value pair '%s' does not parse"%( print(
filename, i+1, l, "File %s:%i key=value pair '%s' does not parse"
)) % (
filename,
i + 1,
l,
)
)
sys.exit(1) sys.exit(1)
pairs.append((tokens[0], tokens[1])) pairs.append((tokens[0], tokens[1]))
return pairs return pairs
def parse_arguments(args): def parse_arguments(args):
pairs = [] pairs = []
for p in args: for p in args:
tokens = p.split('=', 1) tokens = p.split("=", 1)
if len(tokens) != 2: if len(tokens) != 2:
print("Argument key=value pair '%s' does not parse" % (p,)) print("Argument key=value pair '%s' does not parse" % (p,))
sys.exit(1) sys.exit(1)
@@ -75,7 +79,7 @@ def parse_arguments(args):
if __name__ == "__main__": if __name__ == "__main__":
options = setup_options(); options = setup_options()
pairs = [] pairs = []
if options.file != None: if options.file != None:
pairs.extend(parse_file(options.file)) pairs.extend(parse_file(options.file))
@@ -83,18 +87,18 @@ if __name__ == "__main__":
if options.template == None: if options.template == None:
in_reader = sys.stdin in_reader = sys.stdin
else: else:
in_reader = open(options.template, 'rb') in_reader = open(options.template, "rb")
for l in in_reader: for l in in_reader:
for p in pairs: for p in pairs:
value = p[1] value = p[1]
if len(value) > 0: if len(value) > 0:
if value[0] == "@": if value[0] == "@":
value = open(value[1:], 'rt').read() value = open(value[1:], "rt").read()
elif value[0:2] == "\\@": elif value[0:2] == "\\@":
value = value[1:] value = value[1:]
l = l.replace(p[0].encode('utf-8'), value.encode('utf-8')) l = l.replace(p[0].encode("utf-8"), value.encode("utf-8"))
if options.env: if options.env:
var_list = [m.group(0) for m in re.finditer('\${[^ ]+}', l)] var_list = [m.group(0) for m in re.finditer("\${[^ ]+}", l)]
for v in var_list: for v in var_list:
l = l.replace(v, os.environ.get(v[:-1][2:], "")) l = l.replace(v, os.environ.get(v[:-1][2:], ""))
sys.stdout.write(l.decode('utf-8')) sys.stdout.write(l.decode("utf-8"))

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
import math import math
import os import os
@@ -10,57 +10,125 @@ import time
import tty import tty
readline.parse_and_bind('tab: complete') readline.parse_and_bind("tab: complete")
readline.parse_and_bind('set editing-mode vi') readline.parse_and_bind("set editing-mode vi")
MENUFILE = '.foldermenu' MENUFILE = ".foldermenu"
DEFAULTFILE = os.path.expanduser(os.path.join('~','.config','foldermenu','default')) DEFAULTFILE = os.path.expanduser(os.path.join("~", ".config", "foldermenu", "default"))
VERSION = "0.5" VERSION = "0.5"
DEBUG = False DEBUG = False
def setup_options(): def setup_options():
''' Setup the command line options ''' """ Setup the command line options """
from argparse import ArgumentParser from argparse import ArgumentParser
parser=ArgumentParser(description="Prints folder specific shell commands stored in '" + MENUFILE + parser = ArgumentParser(
"' file, and in addition the executables in the current folder. " + description="Prints folder specific shell commands stored in '"
"Menufile format for each line: 'description:command'. " + + MENUFILE
"If the command ends in '&' it is run in the background. " + + "' file, and in addition the executables in the current folder. "
"If the command ends in '/' it is a folder, and selecting will enter. " + + "Menufile format for each line: 'description:command'. "
"Extra keyboard shortcuts: / Edit, $ Shell ") + "If the command ends in '&' it is run in the background. "
parser.add_argument("-1","--one-shot",action = 'store_true', dest = 'once', default = False, + "If the command ends in '/' it is a folder, and selecting will enter. "
help = "Launch only once, then exit") + "Extra keyboard shortcuts: / Edit, $ Shell "
parser.add_argument("-b","--no-banner", action='store_false', dest='banner', default=True, )
help="Do not show banners. Banners are ## starting lines in the file") parser.add_argument(
parser.add_argument("-d","--no-defaults",action='store_false', dest='defaults',default=True, "-1",
help="Do not show default entries from "+DEFAULTFILE) "--one-shot",
parser.add_argument("-x","--no-exec",action='store_false', dest='executables',default=True, action="store_true",
help="Do not show executables in the listing.") dest="once",
parser.add_argument("--columns",'-f','-C',type=int,action='store', dest='columns',default=0, default=False,
help="Number of columns. 0 for automatic") help="Launch only once, then exit",
parser.add_argument("-l","--list",action='store_true', dest='list',default=False, )
help="Print the list, don't wait for keypress.") parser.add_argument(
parser.add_argument("--command",'-c',type=str,action='store', dest='command', "-b",
help="Command to run (1-9a-z..), any argumets after -- are forwarded to the command ") "--no-banner",
parser.add_argument("--no-colors",'--nc',action="store_false",dest="colors",default=True, action="store_false",
help="Disable colored output") dest="banner",
parser.add_argument("--horizontal",'-H',action="store_true",dest="horizontal",default=False, default=True,
help="Horizontal order of items, only valid for -l listing.") help="Do not show banners. Banners are ## starting lines in the file",
parser.add_argument("--version",action='version', version=VERSION) )
parser.add_argument("args",type=str,action="store",default="",nargs="?", parser.add_argument(
help="Arguments for the command, if -c used. The string will be re-parsed with shutils. Use '--' to skip local parsing.") "-d",
"--no-defaults",
action="store_false",
dest="defaults",
default=True,
help="Do not show default entries from " + DEFAULTFILE,
)
parser.add_argument(
"-x",
"--no-exec",
action="store_false",
dest="executables",
default=True,
help="Do not show executables in the listing.",
)
parser.add_argument(
"--columns",
"-f",
"-C",
type=int,
action="store",
dest="columns",
default=0,
help="Number of columns. 0 for automatic",
)
parser.add_argument(
"-l",
"--list",
action="store_true",
dest="list",
default=False,
help="Print the list, don't wait for keypress.",
)
parser.add_argument(
"--command",
"-c",
type=str,
action="store",
dest="command",
help="Command to run (1-9a-z..), any argumets after -- are forwarded to the command ",
)
parser.add_argument(
"--no-colors",
"--nc",
action="store_false",
dest="colors",
default=True,
help="Disable colored output",
)
parser.add_argument(
"--horizontal",
"-H",
action="store_true",
dest="horizontal",
default=False,
help="Horizontal order of items, only valid for -l listing.",
)
parser.add_argument("--version", action="version", version=VERSION)
parser.add_argument(
"args",
type=str,
action="store",
default="",
nargs="?",
help="Arguments for the command, if -c used. The string will be re-parsed with shutils. Use '--' to skip local parsing.",
)
options = parser.parse_args() options = parser.parse_args()
if not os.path.exists(DEFAULTFILE): if not os.path.exists(DEFAULTFILE):
options.defaults = False options.defaults = False
return options return options
def termsize(): def termsize():
rows, columns = os.popen('stty size', 'r').read().split() rows, columns = os.popen("stty size", "r").read().split()
return (int(rows), int(columns)) return (int(rows), int(columns))
def ichr(i): def ichr(i):
''' convert integer to 1-9, a-z, A-Z, omitting q,x ''' """ convert integer to 1-9, a-z, A-Z, omitting q,x """
if i < 10: if i < 10:
return str(i) return str(i)
@@ -73,30 +141,31 @@ def ichr(i):
i += 64 - 122 i += 64 - 122
return chr(i) return chr(i)
class bc: class bc:
MAG = '\033[35m' MAG = "\033[35m"
BLU = '\033[34m' BLU = "\033[34m"
GRE = '\033[32m' GRE = "\033[32m"
YEL = '\033[33m' YEL = "\033[33m"
RED = '\033[31m' RED = "\033[31m"
CYA = '\033[36m' CYA = "\033[36m"
WHI = '\033[1m' WHI = "\033[1m"
BG_BLK = '\033[40m' BG_BLK = "\033[40m"
END = '\033[0m' END = "\033[0m"
CLR = '\033[2J' CLR = "\033[2J"
INV = '\033[7m' INV = "\033[7m"
def disable(self): def disable(self):
self.MAG = '' self.MAG = ""
self.BLU = '' self.BLU = ""
self.GRE = '' self.GRE = ""
self.YEL = '' self.YEL = ""
self.RED = '' self.RED = ""
self.CYA = '' self.CYA = ""
self.WHI = '' self.WHI = ""
self.END = '' self.END = ""
self.BG_BLK = '' self.BG_BLK = ""
self.INV = '' self.INV = ""
def pos(self, y, x): def pos(self, y, x):
return "\033[%s;%sH" % (y, x) return "\033[%s;%sH" % (y, x)
@@ -122,18 +191,21 @@ class getch:
class launch_item: class launch_item:
''' Class for launchable items ''' """ Class for launchable items """
def __init__(self, command, description, launcher): def __init__(self, command, description, launcher):
self.command = command self.command = command
self.description = description self.description = description
self.launcher = launcher self.launcher = launcher
class entry_collection: class entry_collection:
''' Object containing the list items, and the printing methods ''' """ Object containing the list items, and the printing methods """
def __init__(self, options): def __init__(self, options):
self.options = options self.options = options
self.menu_keys = [ichr(i + 1) for i in range(60)] self.menu_keys = [ichr(i + 1) for i in range(60)]
self.args = '' self.args = ""
self.co = bc() self.co = bc()
self.dir_mode = False self.dir_mode = False
self.max_length = 0 self.max_length = 0
@@ -161,20 +233,18 @@ class entry_collection:
self.args = args self.args = args
def read_menu(self, menu_file=MENUFILE): def read_menu(self, menu_file=MENUFILE):
''' Read the menu file ''' """ Read the menu file """
if os.path.exists(menu_file): if os.path.exists(menu_file):
with open(menu_file, 'rt') as f: with open(menu_file, "rt") as f:
for row in f: for row in f:
if row.strip() == '': if row.strip() == "":
continue continue
if row[0:2] == '##': if row[0:2] == "##":
self.banner.append( self.banner.append(row[2:].replace("\n", "").replace("\r", ""))
row[2:].replace("\n","").replace("\r","")
)
continue continue
if row[0] == '#': if row[0] == "#":
continue continue
row = row.strip().split(':',1) row = row.strip().split(":", 1)
if len(row) == 1: if len(row) == 1:
row = [row[0].strip(), row[0]] row = [row[0].strip(), row[0]]
else: else:
@@ -182,54 +252,38 @@ class entry_collection:
if len(row[1]) == 0: if len(row[1]) == 0:
row[1] = " " row[1] = " "
launcher = "menu" launcher = "menu"
if row[1][-1] == '/' and os.path.isdir(row[1]): if row[1][-1] == "/" and os.path.isdir(row[1]):
launcher = "dir" launcher = "dir"
if row[0][-1] != "/": if row[0][-1] != "/":
row[0] += "/" row[0] += "/"
self.entries.append( self.entries.append(
launch_item( launch_item(
command = row[1], command=row[1], description=row[0], launcher=launcher
description = row[0],
launcher = launcher
) )
) )
def read_folder(self): def read_folder(self):
''' Read folder contents, return executable files and dirs ''' """ Read folder contents, return executable files and dirs """
self.dirs.append( self.dirs.append(launch_item(command="..", description="..", launcher="dir"))
launch_item(
command = '..',
description = '..',
launcher = "dir"
)
)
dirs = [] dirs = []
executables = [] executables = []
for f in os.listdir('.'): for f in os.listdir("."):
if os.path.isfile(f): if os.path.isfile(f):
if os.access(f, os.X_OK): if os.access(f, os.X_OK):
executables.append(f) executables.append(f)
if os.path.isdir(f) and f[0] != '.': if os.path.isdir(f) and f[0] != ".":
dirs.append(f) dirs.append(f)
dirs.sort() dirs.sort()
for d in dirs: for d in dirs:
self.dirs.append( self.dirs.append(
launch_item( launch_item(command=d, description=d + "/", launcher="dir")
command = d,
description = d + "/",
launcher = "dir"
)
) )
if self.options.executables: if self.options.executables:
executables.sort() executables.sort()
for e in executables: for e in executables:
self.entries.append( self.entries.append(
launch_item( launch_item(command=e, description=e, launcher="exec")
command = e,
description = e,
launcher = "exec"
)
) )
def entry_color(self, launcher): def entry_color(self, launcher):
@@ -246,11 +300,11 @@ class entry_collection:
helptext = "[.]commands" helptext = "[.]commands"
my_entries = self.dirs my_entries = self.dirs
else: else:
helptext = '[.]folders [-]args %s(%s%s%s)'%( helptext = "[.]folders [-]args %s(%s%s%s)" % (
self.co.END + self.co.MAG, self.co.END + self.co.MAG,
self.co.END, self.co.END,
self.args, self.args,
self.co.MAG self.co.MAG,
) )
my_entries = self.entries my_entries = self.entries
@@ -273,28 +327,15 @@ class entry_collection:
blen = len(banner) blen = len(banner)
cwd = os.path.basename(os.getcwd())[0:15] cwd = os.path.basename(os.getcwd())[0:15]
self.co.posprint( self.co.posprint(1, 1, self.co.END + self.co.CLR)
1,
1,
self.co.END + self.co.CLR
)
self.co.posprint( self.co.posprint(
1, 1,
3, 3,
"%s%s%s [q/x]exit %s%s"%( "%s%s%s [q/x]exit %s%s"
self.co.WHI, % (self.co.WHI, cwd, self.co.MAG, helptext, self.co.END),
cwd,
self.co.MAG,
helptext,
self.co.END
)
) )
for i, e in enumerate(banner): for i, e in enumerate(banner):
self.co.posprint( self.co.posprint(i + 2, 0, e)
i+2,
0,
e
)
rows = int(math.ceil(len(my_entries) / pars)) rows = int(math.ceil(len(my_entries) / pars))
while rows > maxrows: while rows > maxrows:
pars += 1 pars += 1
@@ -314,15 +355,16 @@ class entry_collection:
border = "" border = ""
else: else:
column = maxcolumns * (par - 1) column = maxcolumns * (par - 1)
border = '| ' border = "| "
if self.selected == index: if self.selected == index:
highlight = self.co.INV + ">" highlight = self.co.INV + ">"
else: else:
highlight = ' ' highlight = " "
self.co.posprint( self.co.posprint(
r + 1, r + 1,
column, column,
"%s%s%s%s%s%s%s%s"%( "%s%s%s%s%s%s%s%s"
% (
border, border,
self.co.WHI, self.co.WHI,
key, key,
@@ -330,16 +372,13 @@ class entry_collection:
self.entry_color(entry.launcher), self.entry_color(entry.launcher),
highlight, highlight,
printline, printline,
self.co.END self.co.END,
) ),
) )
r += 1 r += 1
self.co.posprint( self.co.posprint(rows + 2 + blen, 0, "#")
rows + 2 + blen,
0,
"#"
)
self.rows = rows self.rows = rows
sys.stdout.flush()
def list(self): def list(self):
""" draws the list at cursor """ """ draws the list at cursor """
@@ -350,12 +389,7 @@ class entry_collection:
if self.options.columns == 0: if self.options.columns == 0:
pars = 1.0 pars = 1.0
if len(self.entries) > 9: if len(self.entries) > 9:
pars = max( pars = max(1.0, math.floor(maxcolumns / float(self.max_length)))
1.0,
math.floor(
maxcolumns / float(self.max_length)
)
)
while len(self.entries) / pars < pars: while len(self.entries) / pars < pars:
pars -= 1 pars -= 1
else: else:
@@ -380,9 +414,9 @@ class entry_collection:
for r in range(int(rows)): for r in range(int(rows)):
formatted.append([]) formatted.append([])
for p in range(int(pars)): for p in range(int(pars)):
formatted[r].append(' '*(self.max_length)) formatted[r].append(" " * (self.max_length))
if self.options.horizontal: if self.options.horizontal:
formatted[r][p] += ' ' formatted[r][p] += " "
r = 0 r = 0
par = 0 par = 0
for entry, key in zip(self.entries, self.menu_keys): for entry, key in zip(self.entries, self.menu_keys):
@@ -390,14 +424,14 @@ class entry_collection:
par += 1 par += 1
r = 0 r = 0
printline = entry.description[: (maxcolumns - 3)] printline = entry.description[: (maxcolumns - 3)]
printline += ' '*(self.max_length-len(printline)-1) printline += " " * (self.max_length - len(printline) - 1)
formatted[r][par] = "%s%s%s %s%s%s" % ( formatted[r][par] = "%s%s%s %s%s%s" % (
self.co.WHI, self.co.WHI,
key, key,
self.co.END, self.co.END,
self.entry_color(entry.launcher), self.entry_color(entry.launcher),
printline, printline,
self.co.END self.co.END,
) )
r += 1 r += 1
if self.options.horizontal: if self.options.horizontal:
@@ -407,10 +441,10 @@ class entry_collection:
if self.banner: if self.banner:
print("\n".join(self.banner)) print("\n".join(self.banner))
for row in formatted: for row in formatted:
print('|'.join(row)) print("|".join(row))
def launch(self, key): def launch(self, key):
''' launch the given entry ''' """ launch the given entry """
bg = False bg = False
idx = self.menu_keys.index(key) idx = self.menu_keys.index(key)
@@ -428,14 +462,14 @@ class entry_collection:
self.selected = -1 self.selected = -1
return return
if command_str[-1] == '&': if command_str[-1] == "&":
# Run the program in background # Run the program in background
command_str = command_str[:-1] command_str = command_str[:-1]
bg = True bg = True
if len(self.args) > 0: if len(self.args) > 0:
command_str += ' ' + self.args command_str += " " + self.args
if self.entries[idx].launcher == 'exec': if self.entries[idx].launcher == "exec":
command_str = './' + command_str command_str = "./" + command_str
if not self.options.command: if not self.options.command:
print(command_str) print(command_str)
@@ -445,20 +479,20 @@ class entry_collection:
command_str, command_str,
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
shell=True, shell=True,
executable="/bin/bash" executable="/bin/bash",
) )
else: else:
subprocess.call( subprocess.call(
command_str, command_str,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
shell=True, shell=True,
executable = "/bin/bash" executable="/bin/bash",
) )
except: except:
print('Non-zero exit code: "' + command_str + '"') print('Non-zero exit code: "' + command_str + '"')
if not (self.options.command or self.options.once or bg): if not (self.options.command or self.options.once or bg):
print('Press any key...') print("Press any key...")
ch = getch() ch = getch()
inkey = ord(ch.get()) inkey = ord(ch.get())
@@ -474,10 +508,10 @@ class entry_collection:
try: try:
idx = self.menu_keys.index(key) idx = self.menu_keys.index(key)
except ValueError: except ValueError:
return (False, 'Not a possible key') return (False, "Not a possible key")
if idx + 1 > my_len: if idx + 1 > my_len:
return (False, 'No such entry') return (False, "No such entry")
return (True, '') return (True, "")
def select_move(self, delta): def select_move(self, delta):
new_value = self.selected + delta new_value = self.selected + delta
@@ -496,7 +530,7 @@ class entry_collection:
"vim %s" % (MENUFILE,), "vim %s" % (MENUFILE,),
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
shell=True, shell=True,
executable = "/bin/bash" executable="/bin/bash",
) )
self.initialize() self.initialize()
@@ -507,16 +541,13 @@ class entry_collection:
"bash --rcfile <(cat ~/.bashrc; echo \"PS1='folderMenu: '\$PS1\") -i", "bash --rcfile <(cat ~/.bashrc; echo \"PS1='folderMenu: '\$PS1\") -i",
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
shell=True, shell=True,
executable = "/bin/bash" executable="/bin/bash",
) )
self.initialize() self.initialize()
def debug_code_print(c): def debug_code_print(c):
print("- code: %d, str: %s -"%( print("- code: %d, str: %s -" % (c, str(c)))
c,
str(c)
))
time.sleep(1) time.sleep(1)
@@ -569,12 +600,12 @@ def start_engines():
# ~ sys.exit(0) # ~ sys.exit(0)
if inkey in (113, 120, 3, 24, 4): # q, x if inkey in (113, 120, 3, 24, 4): # q, x
print('Exited in: ' + os.getcwd()) print("Exited in: " + os.getcwd())
sys.exit(0) sys.exit(0)
if inkey == 45: # - if inkey == 45: # -
print('') print("")
readline.set_startup_hook(lambda: readline.insert_text(entries.args)) readline.set_startup_hook(lambda: readline.insert_text(entries.args))
args = raw_input('args: ') args = raw_input("args: ")
entries.set_args(args) entries.set_args(args)
readline.set_startup_hook(None) readline.set_startup_hook(None)
if inkey == 46: # . if inkey == 46: # .
@@ -592,7 +623,6 @@ def start_engines():
sys.exit(0) sys.exit(0)
entries.initialize() entries.initialize()
if __name__ == "__main__": if __name__ == "__main__":
start_engines() start_engines()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
import sys, os, re import sys, os, re
import difflib as dl import difflib as dl
@@ -10,61 +10,65 @@ Reset = "\033[0m"
# Available shortcut keys # Available shortcut keys
key_list = "1234567890qwertyuiop" key_list = "1234567890qwertyuiop"
class getch: class getch:
def get(self): def get(self):
import termios, tty import termios, tty
fd = sys.stdin.fileno() fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd) old_settings = termios.tcgetattr(fd)
try: try:
tty.setraw(sys.stdin.fileno()) tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1) ch = sys.stdin.read(1)
finally: finally:
termios.tcsetattr( termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
fd,
termios.TCSADRAIN,
old_settings
)
return ch return ch
def printerr(s): def printerr(s):
sys.stderr.write(s + "\n") sys.stderr.write(s + "\n")
sys.stderr.flush() sys.stderr.flush()
def errexit(s): def errexit(s):
printerr(s) printerr(s)
sys.exit(1) sys.exit(1)
def colorize_matches(directories, repl): def colorize_matches(directories, repl):
return [repl.sub("%s\g<1>%s" % (Green, Reset), d) for d in directories] return [repl.sub("%s\g<1>%s" % (Green, Reset), d) for d in directories]
def search_close_match(directories, key): def search_close_match(directories, key):
""" Return a list of Components whose name closely matches key """ """ Return a list of Components whose name closely matches key """
match = [] match = []
key = key.lower() key = key.lower()
for name in directories: for name in directories:
s = dl.SequenceMatcher( s = dl.SequenceMatcher(None, name.lower(), key)
None,
name.lower(),
key
)
if s.ratio() > 0: if s.ratio() > 0:
match.append((s.ratio(), name)) match.append((s.ratio(), name))
match.sort(key=lambda x: x[0], reverse=True) match.sort(key=lambda x: x[0], reverse=True)
best_matches = [x[1] for x in match[0:10]] best_matches = [x[1] for x in match[0:10]]
return best_matches return best_matches
def get_dirs(pat_dir): def get_dirs(pat_dir):
# list sub-folders in the folder # list sub-folders in the folder
current_folders = [d for d in os.listdir(pat_dir) if os.path.isdir(os.path.join(pat_dir, d))] current_folders = [
d for d in os.listdir(pat_dir) if os.path.isdir(os.path.join(pat_dir, d))
]
current_folders = [d for d in current_folders if not d.startswith(".")] current_folders = [d for d in current_folders if not d.startswith(".")]
current_folders.sort() current_folders.sort()
return current_folders return current_folders
def main(): def main():
# Print help # Print help
if len(sys.argv) == 1 or sys.argv[-1] == "-h": if len(sys.argv) == 1 or sys.argv[-1] == "-h":
errexit("Guess cd: Find first match in folder, interactive if multiple matches\n Arguments: [dir/]pattern_to_match_folders") errexit(
"Guess cd: Find first match in folder, interactive if multiple matches\n Arguments: [dir/]pattern_to_match_folders"
)
pattern = ".".join(sys.argv[1:]) pattern = ".".join(sys.argv[1:])
pat_base = os.path.basename(pattern) pat_base = os.path.basename(pattern)
@@ -124,5 +128,6 @@ def main():
print(os.path.join(pat_dir, key_match)) print(os.path.join(pat_dir, key_match))
if __name__ == "__main__": if __name__ == "__main__":
main() main()