Bläddra i källkod

Add auto complete feature

Zhilong Li 5 år sedan
förälder
incheckning
805e3ae7b7
4 ändrade filer med 199 tillägg och 34 borttagningar
  1. 105 32
      Jt.py
  2. 47 0
      color_printing.py
  3. 45 0
      completer.py
  4. 2 2
      test_coord.py

+ 105 - 32
Jt.py

@@ -1,3 +1,6 @@
+
+from sys import flags
+from color_printing import ERROR, INFO, STATUS, WARNING, cstr, log_print
 import datetime
 import pickle
 import random
@@ -30,12 +33,14 @@ class Entry(Base):
         else:
             self.title: str = title
 
-        self.content: str = "在这里输入事项内容"
+        self.__content: str = "事项内容"
         self.set_priority()
 
         self.set_start_date()
         self.set_deadline(self.create_date + datetime.timedelta(days=7))
-        self.sub_entries_dict: dict = {}
+        self.time_total : datetime.timedelta = self.deadline-self.start_date
+        self.time_left : datetime.timedelta = self.deadline - datetime.datetime.today()
+        # self.sub_entries_dict: dict = {}
 
     def set_priority(self, priority: float = 0):
         if priority < -10:
@@ -69,7 +74,7 @@ class Entry(Base):
             self.start_date = start_date
 
     def set_content(self, content: str):
-        self.content = content
+        self.__content = content
 
     def timestamp_converter(self, time_in):
         """This function can convert timestamp to date string and do reversely.
@@ -86,6 +91,32 @@ class Entry(Base):
         except ValueError:
             return time.mktime(time.strptime(time_in, "%Y/%m/%d %H:%M"))
 
+    def str_to_date(self, date_in: str) -> datetime.datetime:
+        """Convert date string like "%Y/%m/%d %H:%M" or "%Y/%m/%d %H:%M" to datetime structure
+
+        Args:
+            date_in (str): "%Y/%m/%d %H:%M", 2020/07/03 18:23
+
+        Returns:
+            datetime
+        """
+        try:
+            date = datetime.datetime.strptime(date_in, "%Y/%m/%d")
+            return date
+        except ValueError:
+            date = datetime.datetime.strptime(date_in, "%Y/%m/%d %H:%M")
+            return date
+
+    def date_input(self) -> datetime.datetime:
+        while 1:
+            try:
+                str_in = input(
+                    cstr("Type in the date (%Y/%m/%d or %Y/%m/%d %H:%M): ", "g"))
+                date :datetime.datetime = self.str_to_date(str_in)
+                return date
+            except:
+                print("Care the correct date format.")
+            
 
 class Coordinate(Base):
     def __init__(self):
@@ -136,45 +167,61 @@ class Interface:
             "entry": self.__new_entry,
             "chcrd": self.__coord_changer,
         }
+        self.command_list: list = list(self.func_dict.keys())
 
     def start(self):
-        print(
-            "*******************************\n*Welcome to Jt mission manager*\n*******************************\n"
-        )
-        self.__coord_changer([])
-        while not (self.exit):
-            command = input("\033[1;32m> \033[0m").split()
+        try:
+            print(
+                "*******************************\n*Welcome to Jt mission manager*\n*******************************\n"
+            )
             try:
-                func_name = command[0]
+                import completer
+                completer.start_completer(self.command_list)
+                log_print(STATUS, 'Auto complete: ON')
+                # print("\033[1;32mAuto complete: ON\033[0m")
+            except ModuleNotFoundError:
+                log_print(WARNING, 'Auto complete: OFF. Module Not Found')
+                # print("\033[1;31mWARNING: Auto complete: OFF. Module Not Found\033[0m")
+            self.__coord_changer([])
+            while not (self.exit):
+                command = input("\033[1;32m> \033[0m").split()
                 try:
-                    func = self.func_dict[func_name]
-                    func(command[1:])
-                except KeyError:
-                    print("\033[1;31mERROR: Command not found\033[0m")
-            except IndexError:
-                pass
+                    func_name = command[0]
+                    try:
+                        func = self.func_dict[func_name]
+                        func(command[1:])
+                    except KeyError:
+                        print("\033[1;31mERROR: Command not found\033[0m")
+                except IndexError:
+                    pass
+        except KeyboardInterrupt:
+            self.__exit(1)
 
     def __open_coord(self, coord_file: str):
         with open(coord_file, "rb") as f:
             self.now_coord: Coordinate = pickle.load(f)
 
-    def __list_coord(self):
+    def __list_coord(self, arg):
+        """Detect the coord folder if there are any files. 
+
+        Args:
+            arg (none): Meaningless, just give 1 or anything
+
+        Returns:
+            int: If multiple files exist, return 0, if empty, return -1, if only one, return 1.
+        """
         self.files = listdir("coord")
+        if len(self.files) == 1:
+            print(cstr(f"Only one coordinate was found.\n{self.files}", 'y'))
+            return 1
         if self.files:
             i = 0
             for f in self.files:
                 print(i, f)
                 i += 1
-
-    def __save_now_coord(self):
-        save_or_not: str = input("Save the opened coordinate? Y/n")
-        if save_or_not in ["Y", "y", "1"]:
-            self.now_coord.save_coord()
-            return 0
-        elif save_or_not in ["N", "n", "0"]:
             return 0
         else:
-            self.__save_now_coord()
+            return -1
 
     def __coord_changer(self, arg: list):
         try:
@@ -182,18 +229,41 @@ class Interface:
             self.__save_now_coord()
         except AttributeError:
             pass
-        print("Select a coordinate to open:")
-        self.__list_coord()
-        coord_file = self.files[
-            int(input("\033[1;32mType in the coordinate number:\033[0m"))
-        ]
-        self.__open_coord("coord/" + coord_file)
+
+        list_result = self.__list_coord(0)
+        
+        if list_result==0:
+            print("Select a coordinate to open:")
+            coord_file = self.files[
+                int(input("\033[1;32mType in the coordinate number:\033[0m"))
+            ]
+            self.__open_coord("coord/" + coord_file)
+        elif list_result==1:
+            print(cstr("Opening default coordinate.",'b'))
+            self.__open_coord('coord/'+ self.files[0])
+        elif list_result==-1:
+            print(cstr('No coordinate exist','r'))
+
+    def __save_now_coord(self, save_withou_asking:bool = False):
+        if save_withou_asking:
+            save_or_not = 'y'
+        else:
+            save_or_not: str = input("Save the opened coordinate? Y/n")
+        if save_or_not in ["Y", "y", "1"]:
+            self.now_coord.save_coord()
+            return 0
+        elif save_or_not in ["N", "n", "0"]:
+            return 0
+        else:
+            self.__save_now_coord()
 
     def __new_entry(self, arg: list):
         e = Entry(arg[0])
-        print("Input the content of this entry, use \"Ctrl+D\" to end.\n")
+        e.set_deadline(e.date_input())
+        print(cstr("Input the content of this entry, use \"Ctrl+D\" to end.\n", 'g'))
         e.content = "\n".join(sys.stdin.readlines())
         print(e.content)
+        print(e.time_left)
 
     def __new_coord(self, arg: list):
         c = Coordinate()
@@ -210,6 +280,9 @@ class Interface:
             print("\033[1;31mERROR: It's already in there\033[0m")
 
     def __exit(self, arg):
+        log_print(WARNING, "Exiting...")
+        self.__save_now_coord(True)
+        log_print(INFO, "Coordinate saved.")
         self.exit = True
 
 

+ 47 - 0
color_printing.py

@@ -0,0 +1,47 @@
+from functools import wraps
+import time
+def cprint(text_in: str, color: str):
+    """[summary]
+
+    Args:
+        text_in (str): Any text string you want to print.
+        color (str): 'dark_gray', 'r', 'g', 'y', 'b', 'p', 'c', 'gray'
+    """
+
+    color_dict = {'dark_gray': '30', 'r': '31', 'g': '32',
+                  'y': '33', 'b': '34', 'p': '35', 'c': '36', 'gray': '37'}
+    header = f'\033[1;{color_dict[color]}m'
+    end = '\033[0m'
+    print(header+text_in+end)
+
+def cstr(text_in: str, color: str):
+    """[summary]
+
+    Args:
+        text_in (str): Any text string you want to return with color.
+        color (str): 'dark_gray', 'r', 'g', 'y', 'b', 'p', 'c', 'gray'
+    """
+
+    color_dict = {'dark_gray': '30', 'r': '31', 'g': '32',
+                  'y': '33', 'b': '34', 'p': '35', 'c': '36', 'gray': '37'}
+    header = f'\033[1;{color_dict[color]}m'
+    end = '\033[0m'
+    return header+text_in+end
+
+
+INFO = "INFO"
+WARNING = "WARNING"
+ERROR = "ERROR"
+STATUS = "STATUS"
+
+
+def log_print(p_type: str, text_in):
+    """Print colorful log message on screen
+
+    Args:
+        p_type (str): Three types: INFO, WARNING, ERROR
+        text_in (str): Any text message you want to print.
+    """
+    type_dict: dict = {"INFO": 'y', "WARNING": 'b',
+                       "ERROR": 'r', "STATUS": 'c'}
+    cprint('\n'+p_type+': '+text_in, type_dict[p_type])

+ 45 - 0
completer.py

@@ -0,0 +1,45 @@
+import readline
+
+
+class SimpleCompleter:
+
+    def __init__(self, options):
+        self.options = sorted(options)
+
+    def complete(self, text, state):
+        response = None
+        if state == 0:
+            # 这是此文本的第一次,因此建立一个匹配列表。
+            if text:
+                self.matches = [
+                    s
+                    for s in self.options
+                    if s and s.startswith(text)
+                ]
+
+            else:
+                self.matches = self.options[:]
+
+
+        # 如果有那么多,从匹配列表中返回状态项。
+        try:
+            response = self.matches[state]
+        except IndexError:
+            response = None
+
+        return response
+
+
+def input_loop():
+    line = ''
+    while line != 'stop':
+        line = input('Prompt ("stop" to quit): ')
+        print('Dispatch {}'.format(line))
+
+def start_completer(command_list:list):
+    # 注册完成功能
+    OPTIONS = command_list
+    readline.set_completer(SimpleCompleter(OPTIONS).complete)
+
+    # 使用 Tab 键完成
+    readline.parse_and_bind('tab: complete')

+ 2 - 2
test_coord.py

@@ -9,12 +9,12 @@ def test_save_and_load():
         print("Removing existing test file...")
         os.remove("coord/testCoord.crd")
     c = Coordinate()
-    c.name = "testCoord"
+    c.name = "testCoord1"
     c.save_coord()
 
     with open("coord/" + c.name + ".crd", "rb") as f:
         cc = pickle.load(f)
 
     # os.remove("coord/testCoord.crd")
-    assert cc.name == "testCoord"
+    assert cc.name == "testCoord1"