From 74e3c86977b345a25c2be352f3e9d49122c1d0e2 Mon Sep 17 00:00:00 2001 From: Mohit Kumar Date: Fri, 21 Aug 2020 15:10:43 +0530 Subject: [PATCH 1/7] add getch file to use getch() --- getch.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 getch.py diff --git a/getch.py b/getch.py new file mode 100644 index 0000000..576ba97 --- /dev/null +++ b/getch.py @@ -0,0 +1,74 @@ +import os +class _Getch: + """Gets a single character from standard input. Does not echo to the +screen.""" + + def __init__(self): + try: + self.impl = _GetchWindows() + except ImportError: + self.impl = _GetchUnix() + + def __call__(self): return self.impl() + + +class _GetchUnix: + def __init__(self): + import tty + import sys + + def __call__(self): + import sys + import tty + import termios + fd = sys.stdin.fileno() + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(sys.stdin.fileno()) + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + return ch + + +class _GetchWindows: + def __init__(self): + import msvcrt + + def __call__(self): + import msvcrt + return msvcrt.getch() + +color = { + "red": "\033[31m", # for errors + "green": "\033[32m", + "yellow": "\033[33m", # for input + "blue": "\033[34m", # for indication + "magenta": "\033[35m", + "cyan": "\033[36m", + "reset": "\033[0m", +} + + +getch = _Getch() + +# if __name__ == '__main__': +# print('press a key') +# k = getch().decode('UTF-8') +# selected = False +# while k == ' ': +# os.system('cls' if os.name == 'nt' else 'clear') +# if selected: +# print(color['yellow'],'(',color['green'],'*',color['yellow'],')',sep='') +# else: +# print('( )') + +# selected = not selected +# k = getch().decode('UTF-8') +# print(color['reset']) + + +# if __name__ == '__main__': +# print('press a key') +# k = getch().decode('UTF-8') +# print(k) From 0ae569774664a258a27e337bbc35de93f398e0ff Mon Sep 17 00:00:00 2001 From: Mohit Kumar Date: Fri, 21 Aug 2020 15:14:18 +0530 Subject: [PATCH 2/7] Add all required code to implement file explorer mode --- script.py | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) diff --git a/script.py b/script.py index 60c9524..1c93ef1 100755 --- a/script.py +++ b/script.py @@ -14,6 +14,309 @@ "reset": "\033[0m", } +class Interactive_operations: + def __init__(self,files): + self.files = files + + def move(self): + if not self.files: + print(color["red"] + "ERROR No file selected") + return 0 + tomove = self.files + for i in tomove: + path = input("where to move (path/same) >> ") + shutil.move(i, path) + + def rename(self): + while True: + if not self.files: + print(color["red"] + "ERROR No file selected" + color["reset"]) + break + print(color["yellow"]) + dont_over = ( + input("Overwrite prexisting files [y]/n?").strip().lower() + == "n" + ) + torename = self.files + for _file in torename: + newname = str(input("Rename '" + _file + "' as>> ")) + if dont_over: + if os.path.exists(newname): + if ( + input(_file + " already exists overwrite y/[n]?") + .strip() + .lower() + == "y" + ): + try: + os.rename(_file, newname) + except IsADirectoryError as e: + print(color["red"] + e + color["yellow"]) + except NotADirectoryError as e: + print(color["red"] + e + color["yellow"]) + + else: + continue + else: + try: + os.rename(_file, newname) + except IsADirectoryError as e: + print(color["red"] + e + color["yellow"]) + except NotADirectoryError as e: + print(color["red"] + e + color["yellow"]) + break + + def delete(self): + while True: + if len(self.files) is None: + print(color["red"] + "ERROR No file selected" + color["reset"]) + continue + if len(self.files) == -1: + break + + todelete = self.files + print(color["yellow"]) + del_confirm = ( + input("Ask confirmaton to delete y/[n]?").strip().lower() == "y" + ) + deleted = [] + for i in todelete: + if os.path.isdir(i): + if del_confirm: + if ( + input("Delete directory " + i + " [y]/n?") + .strip() + .lower() + == "n" + ): + continue + shutil.rmtree(i, ignore_errors=True) + deleted.append(i) + else: + if del_confirm: + if ( + input("Delete file " + i + " [y]/n?") + .strip() + .lower() + == "n" + ): + continue + os.remove(i) + deleted.append(i) + break + + return deleted + + def copy(self): + if self.files is None: + print(color["red"] + "ERROR No file selected") + return 0 + tocopy = self.files + for i in tocopy: + path = str(input("where to copy (path/same) >> ")) + shutil.copy(i, path) + + @staticmethod + def create(): + print( + color["yellow"] + + "Select 1. to create Directories\n" + + " 2. to create files\n" + ) + ask = int(input(">> ")) + index = int(input("How many folders to create>> ")) + for i in range(index): + if ask == 1: + os.mkdir(input("Enter name of folder [{}]>> ".format(i + 1))) + elif ask == 2: + fname = input("Enter name of file along with extension>> ") + if not os.path.exists(fname): + with open(fname, "w+"): + pass + else: + print(color["red"] + "ERROR File already exists") + +def selection_pointer(isSelected): + temp = color['reset']+"["+color['green']+"{0:>{ind}}"+ color['reset'] + '] ' + return temp.format("*" if isSelected else " ", ind=1) + +def interactive_show_dirs(path=os.getcwd()): + """ + opens a terminal to use all operation sin an interactive way. + + Parameters: + path (str): Path of the directory (default = os.getcwd()) + """ + print(color["blue"]+'Contents of the directory') + filelist = os.listdir(path) + filelist.sort(key=lambda x: x.lower()) + # index padding + # ind = len(filelist) + # if ind >= 1000: + # ind = 4 + # elif ind >= 100: + # ind = 3 + # elif ind >= 10: + # ind = 2 + # else: + # ind = 1 + + scr_width = int(os.get_terminal_size()[0]) + try: + mlen = ( + max( + len(word) + 1 if os.path.isdir(word) else len(word) + for word in filelist + ) + + 1 + ) + except ValueError: + mlen = 1 + cols = scr_width // mlen + + noOfColumns = scr_width // (mlen + 5) + + if scr_width < mlen: + mlen = scr_width + + selected__files = [] + currentIndex = 0 + + while True: + os.system('cls' if os.name == 'nt' else 'clear') + ####################### DISPLAYING FILES ###################### + line = "" + lst = [] + for _file in filelist: + last = True # last line + # directories(cyan) + if os.path.isdir(path + os.sep + _file): + _fileM = _file + os.sep + st = selection_pointer(_file in selected__files)+color['reset' if filelist[currentIndex] == _file else 'cyan'] +"{0:<{mlen}}".format(_fileM,mlen=mlen) + # st = "({0:>{ind}} {1:<{mlen}}".format( + # str(count), _file, mlen=mlen, ind=ind + # ) + if scr_width - (abs(len(line) - cols * 5) % scr_width) > len(st): + line = line + st + else: + lst.append(line) + line = st + last = False + # executeable files(yellow) + elif os.access(path + os.sep + _file, os.X_OK): + + st = selection_pointer(_file in selected__files)+color['reset' if filelist[currentIndex] == _file else 'yellow'] + "{0:<{mlen}}".format(_file, mlen=mlen) + + if scr_width - (abs(len(line) - cols * 5) % scr_width) > len(st): + line = line+ st + else: + lst.append(line) + line = st + last = False + # other files(green) + else: + st = selection_pointer(_file in selected__files)+color['reset' if filelist[currentIndex] == _file else 'green'] + "{0:<{mlen}}".format(_file, mlen=mlen) + + if scr_width - (abs(len(line) - cols * 5) % scr_width) > len(st): + line = line+ st + else: + lst.append(line) + line = st + last = False + # append the last line to the list + if last: + lst.append(line) + + print("\n".join(lst)) + ############################################################### + print('mlen = ',mlen) + print('screen width',scr_width) + print('value of cols',cols) + print('no of columns',noOfColumns) + print(path) + + k = getch().decode('UTF-8').lower() + + if k == 'a': + if not currentIndex <= -1: + currentIndex -= 1 + else: + currentIndex = len(filelist) -1 + if k == 's': + if not currentIndex >= len(filelist)-1: + currentIndex += 1 + else: + currentIndex = 0 + if k == ' ': + if filelist[currentIndex] in selected__files: + selected__files.remove(filelist[currentIndex]) + else: + selected__files.append(filelist[currentIndex]) + if k == 'd': + return 'delete',selected__files,path + if k == 'c': + return 'copy',selected__files,path + if k == 'r': + return 'rename',selected__files,path + if k == 'e': + return 'change',filelist[currentIndex],path + if k == 'b': + return 'back',[],path + if k == 'm': + return 'move',selected__files,path + if k == 'w': + return 'make',[],path + if k == 'q': + return 'quit',[],path + +def file_explorer(): + print(color['magenta'],'welcome to file explorer mode') + print( + "[a] Move backwards", + "[s] Move forwards", + "[ ] 'SPACE' to select or unselect" + "[d] Delete selected files or folders", + "[c] To copy files or folders", + "[m] To move files or folders", + "[r] Rename files or folders", + "[e] Enter a directory", + "[b] Navigate to previous directory", + "[w] Make files/ folders", + "[q] To quit File Explorer mode", + sep="\n" + ) + print("Press ANY key to continue...") + getch() + path = os.getcwd() + while True: + o,files,path = interactive_show_dirs(path) + if o == 'delete': + oper_files = Interactive_operations(files) + oper_files.delete() + if o == 'copy': + oper_files = Interactive_operations(files) + oper_files.copy() + if o == 'rename': + oper_files = Interactive_operations(files) + oper_files.rename() + if o == 'change': + path = str(path) + os.sep + files + os.chdir(path) + if o == 'back': + i = str(path).rfind(os.sep) + path = path[0:i] + os.chdir(path) + if o == 'move': + oper_files = Interactive_operations(files) + oper_files.move() + if o == 'make': + oper_files = Interactive_operations.create() + if o == 'quit': + break + + print('Have a good day!!') + + # TODO: catch permission errors # TODO: add usage of a global variable to hold the path global_path = "" From 199589807b46cac562638d5ab558fa6394a22dce Mon Sep 17 00:00:00 2001 From: Mohit Kumar Date: Fri, 21 Aug 2020 15:17:39 +0530 Subject: [PATCH 3/7] Added file explorer mode in the operations list --> option 8 --- script.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/script.py b/script.py index 1c93ef1..ca89a17 100755 --- a/script.py +++ b/script.py @@ -511,6 +511,7 @@ def select_op(): " 5. Create new folder/s, file/s", " 6. Enter a directory", " 7. Enter navigation mode", + " 8. Enter File Explorer Mode", " 9. Change directory", "99. EXIT", sep="\n", @@ -737,6 +738,8 @@ def main(path=os.getcwd()): filelist = os.listdir(path) filelist.sort(key=lambda x: x.lower()) oper_files = Operations(filelist) + elif oprselection == 8: + file_explorer() elif oprselection == 9: directory_ask(True) show_dirs(os.getcwd()) From a09bfca03c698b2acd955ccb62b66e1a96a0a95a Mon Sep 17 00:00:00 2001 From: Mohit Kumar Date: Fri, 21 Aug 2020 15:20:03 +0530 Subject: [PATCH 4/7] imported getch --- script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script.py b/script.py index ca89a17..f77f0ec 100755 --- a/script.py +++ b/script.py @@ -2,7 +2,7 @@ import os import shutil import sys - +from getch import getch color = { "red": "\033[31m", # for errors From c07539878eae0e332ae9a281a0822b8a5a8b14ad Mon Sep 17 00:00:00 2001 From: Mohit Kumar Date: Sat, 22 Aug 2020 13:09:20 +0530 Subject: [PATCH 5/7] Bug fix in user input through getch() in linux --- script.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/script.py b/script.py index f77f0ec..9b9e5e0 100755 --- a/script.py +++ b/script.py @@ -150,16 +150,6 @@ def interactive_show_dirs(path=os.getcwd()): print(color["blue"]+'Contents of the directory') filelist = os.listdir(path) filelist.sort(key=lambda x: x.lower()) - # index padding - # ind = len(filelist) - # if ind >= 1000: - # ind = 4 - # elif ind >= 100: - # ind = 3 - # elif ind >= 10: - # ind = 2 - # else: - # ind = 1 scr_width = int(os.get_terminal_size()[0]) try: @@ -235,7 +225,10 @@ def interactive_show_dirs(path=os.getcwd()): print('no of columns',noOfColumns) print(path) - k = getch().decode('UTF-8').lower() + if os.name == 'nt': + k = getch().decode('UTF-8').lower() + else: + k = getch().lower() if k == 'a': if not currentIndex <= -1: From 9a6ede6721c28f09e3b4658460e651f2515f26c7 Mon Sep 17 00:00:00 2001 From: Mohit Kumar Date: Sat, 22 Aug 2020 13:28:10 +0530 Subject: [PATCH 6/7] appearance changed for selected file or folder --- script.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/script.py b/script.py index 9b9e5e0..3b78826 100755 --- a/script.py +++ b/script.py @@ -13,6 +13,9 @@ "cyan": "\033[36m", "reset": "\033[0m", } +def rich_text(style=0,text_color=37,background=40): + st = "\033[{style};{text_color};{background}m".format(style=style,text_color=text_color,background=background) + return st class Interactive_operations: def __init__(self,files): @@ -137,8 +140,8 @@ def create(): print(color["red"] + "ERROR File already exists") def selection_pointer(isSelected): - temp = color['reset']+"["+color['green']+"{0:>{ind}}"+ color['reset'] + '] ' - return temp.format("*" if isSelected else " ", ind=1) + temp = rich_text()+"["+(rich_text(1,32,42) if isSelected else rich_text(0,37,40))+"{0}"+rich_text()+"]" + return temp.format("*" if isSelected else " ") def interactive_show_dirs(path=os.getcwd()): """ @@ -182,7 +185,7 @@ def interactive_show_dirs(path=os.getcwd()): # directories(cyan) if os.path.isdir(path + os.sep + _file): _fileM = _file + os.sep - st = selection_pointer(_file in selected__files)+color['reset' if filelist[currentIndex] == _file else 'cyan'] +"{0:<{mlen}}".format(_fileM,mlen=mlen) + st = selection_pointer(_file in selected__files)+ (rich_text(1,35,47) if filelist[currentIndex] == _file else rich_text(0,36,40)) +"{0:<{mlen}}".format(_fileM,mlen=mlen)+rich_text() # st = "({0:>{ind}} {1:<{mlen}}".format( # str(count), _file, mlen=mlen, ind=ind # ) @@ -195,7 +198,7 @@ def interactive_show_dirs(path=os.getcwd()): # executeable files(yellow) elif os.access(path + os.sep + _file, os.X_OK): - st = selection_pointer(_file in selected__files)+color['reset' if filelist[currentIndex] == _file else 'yellow'] + "{0:<{mlen}}".format(_file, mlen=mlen) + st = selection_pointer(_file in selected__files)+(rich_text(1,35,47) if filelist[currentIndex] == _file else rich_text(0,33,40)) + "{0:<{mlen}}".format(_file, mlen=mlen)+rich_text() if scr_width - (abs(len(line) - cols * 5) % scr_width) > len(st): line = line+ st @@ -205,7 +208,7 @@ def interactive_show_dirs(path=os.getcwd()): last = False # other files(green) else: - st = selection_pointer(_file in selected__files)+color['reset' if filelist[currentIndex] == _file else 'green'] + "{0:<{mlen}}".format(_file, mlen=mlen) + st = selection_pointer(_file in selected__files)+(rich_text(1,35,47) if filelist[currentIndex] == _file else rich_text(0,32,40)) + "{0:<{mlen}}".format(_file, mlen=mlen)+rich_text() if scr_width - (abs(len(line) - cols * 5) % scr_width) > len(st): line = line+ st From 80d8612dd232ca967fb143f32c48d9976cf9b302 Mon Sep 17 00:00:00 2001 From: Mohit Kumar Date: Sat, 22 Aug 2020 13:58:10 +0530 Subject: [PATCH 7/7] removed unnecessary code --- getch.py | 32 -------------------------------- script.py | 47 +++++++++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 52 deletions(-) diff --git a/getch.py b/getch.py index 576ba97..4f42749 100644 --- a/getch.py +++ b/getch.py @@ -39,36 +39,4 @@ def __call__(self): import msvcrt return msvcrt.getch() -color = { - "red": "\033[31m", # for errors - "green": "\033[32m", - "yellow": "\033[33m", # for input - "blue": "\033[34m", # for indication - "magenta": "\033[35m", - "cyan": "\033[36m", - "reset": "\033[0m", -} - - getch = _Getch() - -# if __name__ == '__main__': -# print('press a key') -# k = getch().decode('UTF-8') -# selected = False -# while k == ' ': -# os.system('cls' if os.name == 'nt' else 'clear') -# if selected: -# print(color['yellow'],'(',color['green'],'*',color['yellow'],')',sep='') -# else: -# print('( )') - -# selected = not selected -# k = getch().decode('UTF-8') -# print(color['reset']) - - -# if __name__ == '__main__': -# print('press a key') -# k = getch().decode('UTF-8') -# print(k) diff --git a/script.py b/script.py index 3b78826..959f6be 100755 --- a/script.py +++ b/script.py @@ -17,6 +17,8 @@ def rich_text(style=0,text_color=37,background=40): st = "\033[{style};{text_color};{background}m".format(style=style,text_color=text_color,background=background) return st + + class Interactive_operations: def __init__(self,files): self.files = files @@ -24,7 +26,7 @@ def __init__(self,files): def move(self): if not self.files: print(color["red"] + "ERROR No file selected") - return 0 + return None tomove = self.files for i in tomove: path = input("where to move (path/same) >> ") @@ -34,7 +36,7 @@ def rename(self): while True: if not self.files: print(color["red"] + "ERROR No file selected" + color["reset"]) - break + return None print(color["yellow"]) dont_over = ( input("Overwrite prexisting files [y]/n?").strip().lower() @@ -71,11 +73,9 @@ def rename(self): def delete(self): while True: - if len(self.files) is None: + if not self.files: print(color["red"] + "ERROR No file selected" + color["reset"]) - continue - if len(self.files) == -1: - break + return None todelete = self.files print(color["yellow"]) @@ -111,9 +111,9 @@ def delete(self): return deleted def copy(self): - if self.files is None: + if not self.files: print(color["red"] + "ERROR No file selected") - return 0 + return None tocopy = self.files for i in tocopy: path = str(input("where to copy (path/same) >> ")) @@ -139,18 +139,23 @@ def create(): else: print(color["red"] + "ERROR File already exists") + + + def selection_pointer(isSelected): temp = rich_text()+"["+(rich_text(1,32,42) if isSelected else rich_text(0,37,40))+"{0}"+rich_text()+"]" return temp.format("*" if isSelected else " ") + + def interactive_show_dirs(path=os.getcwd()): """ - opens a terminal to use all operation sin an interactive way. + opens a terminal to use all operations in an interactive way. Parameters: path (str): Path of the directory (default = os.getcwd()) """ - print(color["blue"]+'Contents of the directory') + filelist = os.listdir(path) filelist.sort(key=lambda x: x.lower()) @@ -167,8 +172,6 @@ def interactive_show_dirs(path=os.getcwd()): mlen = 1 cols = scr_width // mlen - noOfColumns = scr_width // (mlen + 5) - if scr_width < mlen: mlen = scr_width @@ -177,24 +180,25 @@ def interactive_show_dirs(path=os.getcwd()): while True: os.system('cls' if os.name == 'nt' else 'clear') + ####################### DISPLAYING FILES ###################### line = "" lst = [] for _file in filelist: last = True # last line + # directories(cyan) if os.path.isdir(path + os.sep + _file): _fileM = _file + os.sep st = selection_pointer(_file in selected__files)+ (rich_text(1,35,47) if filelist[currentIndex] == _file else rich_text(0,36,40)) +"{0:<{mlen}}".format(_fileM,mlen=mlen)+rich_text() - # st = "({0:>{ind}} {1:<{mlen}}".format( - # str(count), _file, mlen=mlen, ind=ind - # ) + if scr_width - (abs(len(line) - cols * 5) % scr_width) > len(st): line = line + st else: lst.append(line) line = st last = False + # executeable files(yellow) elif os.access(path + os.sep + _file, os.X_OK): @@ -206,6 +210,7 @@ def interactive_show_dirs(path=os.getcwd()): lst.append(line) line = st last = False + # other files(green) else: st = selection_pointer(_file in selected__files)+(rich_text(1,35,47) if filelist[currentIndex] == _file else rich_text(0,32,40)) + "{0:<{mlen}}".format(_file, mlen=mlen)+rich_text() @@ -217,16 +222,14 @@ def interactive_show_dirs(path=os.getcwd()): line = st last = False # append the last line to the list + if last: lst.append(line) print("\n".join(lst)) ############################################################### - print('mlen = ',mlen) - print('screen width',scr_width) - print('value of cols',cols) - print('no of columns',noOfColumns) - print(path) + + print(color["magenta"],"\nPATH->",color["blue"],path,color["reset"]) if os.name == 'nt': k = getch().decode('UTF-8').lower() @@ -265,6 +268,8 @@ def interactive_show_dirs(path=os.getcwd()): if k == 'q': return 'quit',[],path + + def file_explorer(): print(color['magenta'],'welcome to file explorer mode') print( @@ -313,6 +318,8 @@ def file_explorer(): print('Have a good day!!') + + # TODO: catch permission errors # TODO: add usage of a global variable to hold the path global_path = ""