developer-assistant 0.3.6__tar.gz → 0.3.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. {developer_assistant-0.3.6/developer_assistant.egg-info → developer_assistant-0.3.7}/PKG-INFO +7 -2
  2. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/PYPI.md +6 -1
  3. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/README.md +6 -1
  4. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/interface.py +92 -47
  5. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/intro.md +9 -3
  6. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/modules/config_manager.py +5 -2
  7. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/modules/opener.py +3 -1
  8. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/modules/projects_manager.py +34 -24
  9. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/modules/version_logic.py +66 -27
  10. {developer_assistant-0.3.6 → developer_assistant-0.3.7/developer_assistant.egg-info}/PKG-INFO +7 -2
  11. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/pyproject.toml +1 -1
  12. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/LICENSE +0 -0
  13. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/__init__.py +0 -0
  14. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/default/default-changelog.md +0 -0
  15. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/default/default-memory.ini +0 -0
  16. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/default/test-project.ini +0 -0
  17. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/modules/__init__.py +0 -0
  18. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/templates/changelog_template.txt +0 -0
  19. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/templates/entry_template.txt +0 -0
  20. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/templates/header_template.txt +0 -0
  21. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/SOURCES.txt +0 -0
  22. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/dependency_links.txt +0 -0
  23. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/entry_points.txt +0 -0
  24. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/requires.txt +0 -0
  25. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/top_level.txt +0 -0
  26. {developer_assistant-0.3.6 → developer_assistant-0.3.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: developer-assistant
3
- Version: 0.3.6
3
+ Version: 0.3.7
4
4
  Summary: A lightweight TUI app for managing and simplifying your Markdown changelogs.
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/Ivory-Hubert/Developer-Assistant
@@ -55,7 +55,7 @@ Developer Assistant is a lightweight TUI for simplifying and managing your chang
55
55
 
56
56
  You can create as many profiles as you need. Each profile gets its own **project specific** `.ini` files, created automatically through the menu based on the information you provide. These act as links that tell DA where your changelogs are, which profile owns them and what's the last version number.
57
57
 
58
- Each project `.ini` can also hold a custom terminal command, that is run in that projects folder. So you can easly integrate updating your changelogs in DA with Git commands for example.
58
+ Each project `.ini` can also hold a custom terminal command, that's run in the projects folder. So you can easly integrate updating your changelogs in DA with Git commands for example.
59
59
 
60
60
  **Your files are kept safe at all times.** Before adding new changes, your existing `CHANGELOG.md` is automatically backed up. While editing, all changes are written to a temporary file first and only prepended to & replaced with your real changelog once you confirm them.
61
61
 
@@ -121,6 +121,11 @@ New changes are first written to a temporary file and only prepended to & replac
121
121
  This ensures your existing changelog is never overwritten or corrupted, and you always have a fallback copy.
122
122
  If the temporary changelog is present on startup you are prompted to remove or keep it.
123
123
 
124
+ Furthermore, you can safely work on one changelog in separate sessions, your changes are staged in the temporary log file and only deleted with your confirmation.
125
+
126
+ > **Note:**
127
+ > DA can only keep **one** projects WIP changes staged, switching projects with staged changes appends the same file. If you update/reinstall the program with unsaved changes they are lost for good, so it's **not** long-term storage.
128
+
124
129
 
125
130
  **Ease of navigation**
126
131
 
@@ -35,7 +35,7 @@ Developer Assistant is a lightweight TUI for simplifying and managing your chang
35
35
 
36
36
  You can create as many profiles as you need. Each profile gets its own **project specific** `.ini` files, created automatically through the menu based on the information you provide. These act as links that tell DA where your changelogs are, which profile owns them and what's the last version number.
37
37
 
38
- Each project `.ini` can also hold a custom terminal command, that is run in that projects folder. So you can easly integrate updating your changelogs in DA with Git commands for example.
38
+ Each project `.ini` can also hold a custom terminal command, that's run in the projects folder. So you can easly integrate updating your changelogs in DA with Git commands for example.
39
39
 
40
40
  **Your files are kept safe at all times.** Before adding new changes, your existing `CHANGELOG.md` is automatically backed up. While editing, all changes are written to a temporary file first and only prepended to & replaced with your real changelog once you confirm them.
41
41
 
@@ -101,6 +101,11 @@ New changes are first written to a temporary file and only prepended to & replac
101
101
  This ensures your existing changelog is never overwritten or corrupted, and you always have a fallback copy.
102
102
  If the temporary changelog is present on startup you are prompted to remove or keep it.
103
103
 
104
+ Furthermore, you can safely work on one changelog in separate sessions, your changes are staged in the temporary log file and only deleted with your confirmation.
105
+
106
+ > **Note:**
107
+ > DA can only keep **one** projects WIP changes staged, switching projects with staged changes appends the same file. If you update/reinstall the program with unsaved changes they are lost for good, so it's **not** long-term storage.
108
+
104
109
 
105
110
  **Ease of navigation**
106
111
 
@@ -38,7 +38,7 @@ Developer Assistant is a lightweight TUI for simplifying and managing your chang
38
38
 
39
39
  You can create as many profiles as you need. Each profile gets its own **project specific** `.ini` files, created automatically through the menu based on the information you provide. These act as links that tell DA where your changelogs are, which profile owns them and what's the last version number.
40
40
 
41
- Each project `.ini` can also hold a custom terminal command, that is run in that projects folder. So you can easly integrate updating your changelogs in DA with Git commands for example.
41
+ Each project `.ini` can also hold a custom terminal command, that's run in the projects folder. So you can easly integrate updating your changelogs in DA with Git commands for example.
42
42
 
43
43
  **Your files are kept safe at all times.** Before adding new changes, your existing `CHANGELOG.md` is automatically backed up. While editing, all changes are written to a temporary file first and only prepended to & replaced with your real changelog once you confirm them.
44
44
 
@@ -106,6 +106,11 @@ New changes are first written to a temporary file and only prepended to & replac
106
106
  This ensures your existing changelog is never overwritten or corrupted, and you always have a fallback copy.
107
107
  If the temporary changelog is present on startup you are prompted to remove or keep it.
108
108
 
109
+ Furthermore, you can safely work on one changelog in separate sessions, your changes are staged in the temporary log file and only deleted with your confirmation.
110
+
111
+ > [!NOTE]
112
+ > DA can only keep **one** projects WIP changes staged, switching projects with staged changes appends the same file. If you update/reinstall the program with unsaved changes they are lost for good, so it's **not** long-term storage.
113
+
109
114
 
110
115
  **Ease of navigation**
111
116
 
@@ -1,33 +1,33 @@
1
1
  import os, sys
2
- import time
3
2
  import platform
4
- import subprocess
5
3
  import shutil
4
+ import time
5
+ from importlib import resources
6
6
  from pathlib import Path
7
7
 
8
- from termcolor import colored
9
- from rich.progress import track
10
8
  from rich.console import Console
11
9
  from rich.markdown import Markdown
10
+ from rich.progress import track
11
+ from termcolor import colored
12
12
 
13
- from da.modules.projects_manager import ProjectsManager
14
13
  from da.modules.config_manager import ConfigManager
15
14
  from da.modules.opener import Opener
16
- from importlib import resources
15
+ from da.modules.projects_manager import ProjectsManager
16
+
17
17
 
18
18
  class Interface:
19
19
  def __init__(self):
20
- self.version = "0.3.6"
21
- self.clear = 'cls' if platform.system() == 'Windows' else 'clear'
20
+ self.version = "0.3.7"
21
+ self.clear = "cls" if platform.system() == "Windows" else "clear"
22
22
 
23
23
  title = f"DA - {self.version}"
24
24
 
25
25
  if platform.system() == "Windows":
26
- os.system(f'title {title}')
26
+ os.system(f"title {title}")
27
27
  else:
28
- print(f'\33]0;{title}\a', end='', flush=True)
28
+ print(f"\33]0;{title}\a", end="", flush=True)
29
29
 
30
- self.config = ConfigManager('memory.ini', profile="Default")
30
+ self.config = ConfigManager("memory.ini", profile="Default")
31
31
 
32
32
  self.memory = None
33
33
  self.color = None
@@ -35,11 +35,12 @@ class Interface:
35
35
  self.user_path = None
36
36
 
37
37
  self.first_run = False
38
-
38
+
39
+
39
40
  def run(self):
40
41
  steps = [
41
42
  ("Initializing runtime...", self.runtime_init),
42
- ("Checking configuration...", self.config.data_check)
43
+ ("Checking configuration...", self.config.data_check),
43
44
  ]
44
45
 
45
46
  for label, step in track(steps):
@@ -57,8 +58,13 @@ class Interface:
57
58
  if os.path.exists(temp_log):
58
59
  while True:
59
60
  os.system(self.clear)
60
- print(colored(f"Temporary changelog detected from your last session!\n", "yellow"))
61
- print(colored("D", "light_red") + "elete or " + colored("K", "light_red") + "eep?\n")
61
+ print(colored("Unsaved changes detected from your last session!\n", "yellow",))
62
+ print(
63
+ colored("D", "light_red")
64
+ + "elete or "
65
+ + colored("K", "light_red")
66
+ + "eep?\n"
67
+ )
62
68
  choice = input(f"{self.user_path}> ").lower()
63
69
  if choice == "d":
64
70
  os.remove(temp_log)
@@ -68,7 +74,7 @@ class Interface:
68
74
  else:
69
75
  print(colored("\nPlease make a valid choice.", "light_red"))
70
76
  time.sleep(0.5)
71
-
77
+
72
78
  state = "intro" if self.first_run else "menu"
73
79
 
74
80
  while state != "exit":
@@ -90,22 +96,26 @@ class Interface:
90
96
  state = "exit"
91
97
 
92
98
  def menu(self):
93
- self.active_profile = self.memory.get('profile')
99
+ self.active_profile = self.memory.get("profile")
100
+ last_project = self.memory.get("last_project")
94
101
 
95
102
  projects_manager = ProjectsManager(
96
103
  config=self.config,
97
104
  color=self.color,
98
105
  header=self.header,
99
106
  cls=self.clear,
100
- user_path=self.user_path
107
+ user_path=self.user_path,
101
108
  )
102
109
 
103
- last_project = self.memory.get('last_project')
104
110
  while True:
105
111
  os.system(self.clear)
106
- print(colored(f"{self.active_profile}", f"{self.color}") + " / Main menu")
112
+ print(
113
+ colored(
114
+ f"{self.active_profile}", f"{self.color}")
115
+ + " / Main menu"
116
+ )
107
117
  print(self.header)
108
- print("E. Exit\n")
118
+ print("Q. Exit\n")
109
119
  print("Last project:")
110
120
  print(colored(last_project, f"{self.color}"))
111
121
  print("\n1. Projects")
@@ -114,7 +124,7 @@ class Interface:
114
124
 
115
125
  choice = input(f"{self.user_path}> ").strip()
116
126
 
117
- if choice.lower() == "e":
127
+ if choice.lower() == "q":
118
128
  os.system(self.clear)
119
129
  print(self.header)
120
130
  print("Bye!")
@@ -130,16 +140,18 @@ class Interface:
130
140
  elif choice == "3":
131
141
  return "settings"
132
142
  else:
133
- print("")
134
- print(colored("Unknown option...", "light_red", attrs=["bold"]))
143
+ print(colored("\nUnknown option...", "light_red", attrs=["bold"]))
135
144
  time.sleep(0.5)
136
-
145
+
137
146
  def settings(self):
138
147
  while True:
139
148
  os.system(self.clear)
140
- print(colored(f"{self.active_profile}", f"{self.color}") + " / Main menu / Settings")
149
+ print(
150
+ colored(f"{self.active_profile}", f"{self.color}")
151
+ + " / Main menu / Settings"
152
+ )
141
153
  print(self.header)
142
- print("E. Back\n")
154
+ print("Q. Back\n")
143
155
 
144
156
  print(colored("Configuration options", attrs=["underline"]))
145
157
  print("1. Edit pinned projects [WIP]")
@@ -152,12 +164,12 @@ class Interface:
152
164
 
153
165
  choice = input(f"{self.user_path}> ").strip()
154
166
 
155
- if choice.lower() == "e":
167
+ if choice.lower() == "q":
156
168
  return
157
- #elif choice == "1":
158
- #pass
159
- #elif choice == "2":
160
- #pass
169
+ # elif choice == "1":
170
+ # pass
171
+ # elif choice == "2":
172
+ # pass
161
173
  elif choice == "3":
162
174
  Opener.open(self.config.memory_ini)
163
175
  elif choice == "4":
@@ -165,16 +177,18 @@ class Interface:
165
177
  elif choice == "5":
166
178
  Opener.open(self.config.templates_folder)
167
179
  else:
168
- print("")
169
- print(colored("Unknown option...", "light_red", attrs=["bold"]))
180
+ print(colored("\nUnknown option...", "light_red", attrs=["bold"]))
170
181
  time.sleep(0.5)
171
182
 
172
183
  def profiles(self):
173
184
  while True:
174
185
  os.system(self.clear)
175
- print(colored(f"{self.active_profile}", f"{self.color}") + " / Main menu / Profiles")
186
+ print(
187
+ colored(f"{self.active_profile}", f"{self.color}")
188
+ + " / Main menu / Profiles"
189
+ )
176
190
  print(self.header)
177
- print("E. Back\n")
191
+ print("Q. Back\n")
178
192
 
179
193
  print("1. Switch profiles\n")
180
194
 
@@ -183,7 +197,7 @@ class Interface:
183
197
 
184
198
  choice = input(f"{self.user_path}> ").strip()
185
199
 
186
- if choice.lower() == "e":
200
+ if choice.lower() == "q":
187
201
  return
188
202
  elif choice == "1":
189
203
  self.switch_profile()
@@ -192,8 +206,7 @@ class Interface:
192
206
  elif choice == "3":
193
207
  self.delete_profile()
194
208
  else:
195
- print("")
196
- print(colored("Unknown option...", "light_red", attrs=["bold"]))
209
+ print(colored("\nUnknown option...", "light_red", attrs=["bold"]))
197
210
  time.sleep(0.5)
198
211
 
199
212
  def switch_profile(self):
@@ -259,11 +272,11 @@ class Interface:
259
272
 
260
273
  self.memory = self.config.load_memory()
261
274
 
262
- profile = self.memory.get('profile')
275
+ profile = self.memory.get("profile")
263
276
  self.config = ConfigManager("memory.ini", profile=profile)
264
277
 
265
278
  self.memory = self.config.load_memory()
266
- self.active_profile = self.memory.get('profile')
279
+ self.active_profile = self.memory.get("profile")
267
280
 
268
281
  def runtime_init(self):
269
282
  if not self.config.memory_ini.exists():
@@ -276,10 +289,11 @@ class Interface:
276
289
  self.config = ConfigManager("memory.ini", profile=active_profile)
277
290
  self.memory = self.config.load_memory()
278
291
 
279
- self.color = self.memory.get('color') or "light_blue"
280
- self.user_path = os.environ.get('USERPROFILE') or os.environ.get('HOME', 'User')
292
+ self.color = self.memory.get("color") or "light_blue"
293
+ self.user_path = os.environ.get("USERPROFILE") or os.environ.get("HOME", "User")
281
294
 
282
- brand = (colored(" Developer Assistant ", f"{self.color}"))
295
+
296
+ brand = colored(" Developer Assistant ", f"{self.color}")
283
297
  text = " Developer Assistant "
284
298
 
285
299
  columns, _ = shutil.get_terminal_size()
@@ -289,7 +303,7 @@ class Interface:
289
303
  self.header = f"{bars}{brand}{bars}"
290
304
 
291
305
  def local_init(self):
292
- #==Works together with ConfigManager.data_check==
306
+ # Works together with ConfigManager.data_check()
293
307
  default_files = resources.files("da.default")
294
308
  dest = self.config.memory_ini
295
309
 
@@ -306,7 +320,11 @@ class Interface:
306
320
 
307
321
  def intro(self):
308
322
  os.system(self.clear)
309
- print(colored("Welcome to the Developer Assistant\n", f"{self.color}", attrs=["bold"]))
323
+ print(
324
+ colored("Welcome to the Developer Assistant\n",
325
+ f"{self.color}", attrs=["bold"]
326
+ )
327
+ )
310
328
  print("Here's everything you need to get started...\n")
311
329
 
312
330
  time.sleep(2)
@@ -319,13 +337,40 @@ class Interface:
319
337
 
320
338
  input("\nContinue..." + colored("[Enter]", f"{self.color}"))
321
339
 
340
+ # [WIP code, implementation could change]
341
+
342
+ # print(colored("\nChoose an accent colour.\n", attrs=["underline"]))
343
+ # print("1. Default - " + colored("light blue", f"{self.color}"))
344
+ #
345
+ # print("\n2. " + colored("red", "red"))
346
+ # print("3. " + colored("green", "green"))
347
+ # print("4. " + colored("blue", "blue"))
348
+ # print("5. " + colored("yellow", "yellow"))
349
+ # print("6. " + colored("cyan", "cyan"))
350
+ # print("7. " + colored("magenta", "magenta"))
351
+ #
352
+ # print("\n8. " + colored("light green", "light_green"))
353
+ # print("9. " + colored("light yellow", "light_yellow"))
354
+ # print("10. " + colored("light magenta", "light_magenta"))
355
+ # print("11. " + colored("light cyan", "light_cyan"))
356
+ #
357
+ # choice = input("\nChoice > ").strip()
358
+ #
359
+ # key_map = {
360
+ # "1": "",
361
+ # "2": "red",
362
+ # }
363
+
322
364
  def main():
323
365
  try:
324
366
  app = Interface()
325
367
  app.run()
326
368
  os.system(app.clear)
327
369
  except KeyboardInterrupt:
328
- print("\n\n" + colored("Execution interrupted. Exiting...", "cyan", attrs=["bold"]))
370
+ print(
371
+ "\n\n"
372
+ + colored("Execution interrupted. Exiting...", "cyan", attrs=["bold"])
373
+ )
329
374
  time.sleep(0.5)
330
375
  os.system(app.clear)
331
376
  sys.exit(0)
@@ -31,14 +31,14 @@ Don't change the folder structure or modify variable names inside `.ini` files.
31
31
 
32
32
  The `da-ui/` folder and subfolders will be created automatically.
33
33
 
34
- > Tip:
34
+ > **Tip:**
35
35
  > You can access its content quickly when going to: `Main menu / Settings`
36
36
 
37
37
  **Profiles for seperate projects and templates**
38
38
 
39
39
  The program comes with the "Default" profile, you can choose to either stick with this one or create your own profiles in `Main menu / Profiles`. Each profile has seperate projects and they can't be accessed by other profiles. You can choose to customize the templates seperately too.
40
40
 
41
- > Note:
41
+ > **Note:**
42
42
  > Migrating a project or template from one profile to another is currently manual, **make sure to also change the "*owner*" value in `.ini` files accordingly**.
43
43
 
44
44
  ---
@@ -74,6 +74,11 @@ New changes are first written to a temporary file and only prepended to & replac
74
74
  This ensures your existing changelog is never overwritten or corrupted, and you always have a fallback copy.
75
75
  If the temporary changelog is present on startup you are prompted to remove or keep it.
76
76
 
77
+ Furthermore, you can safely work on one changelog in separate sessions, your changes are staged in the temporary log file and only deleted with your confirmation.
78
+
79
+ > **Note:**
80
+ > DA can only keep **one** projects WIP changes staged, switching projects with staged changes appends the same file. If you update/reinstall the program with unsaved changes they are lost for good, so it's **not** long-term storage.
81
+
77
82
 
78
83
  **Ease of navigation**
79
84
 
@@ -94,4 +99,5 @@ The `memory.ini` file does exactly what you'd expect, it features:
94
99
 
95
100
  Last project & active profile get updated automatically, the rest are up to you.
96
101
 
97
- > **`Ctrl+C` works everywhere to quickly exit DA.**
102
+ > **Tip:**
103
+ > `Ctrl+C` works everywhere to quickly exit DA.
@@ -9,6 +9,7 @@ from platformdirs import user_config_path
9
9
 
10
10
  from importlib import resources
11
11
 
12
+
12
13
  class ConfigManager:
13
14
  def __init__(self, config_file, profile=None):
14
15
  if not profile:
@@ -30,6 +31,7 @@ class ConfigManager:
30
31
 
31
32
  self.update_last_project = Path(config_file).stem
32
33
 
34
+
33
35
  def load_memory(self):
34
36
  self.config.read(self.memory_ini)
35
37
  prj = self.config['ITEMS']
@@ -117,7 +119,8 @@ class ConfigManager:
117
119
  default_templates = resources.files("da.templates")
118
120
 
119
121
  messages = []
120
- #==Always ensure fallback profile exists, not just on first run==
122
+
123
+ # Always ensure fallback profile exists, not just on first run
121
124
  if not (self.profile_dir / "Default").exists():
122
125
  default = self.profile_dir / "Default"
123
126
  default.mkdir()
@@ -146,7 +149,7 @@ class ConfigManager:
146
149
  shutil.move(str(old_projects), str(self.projects_folder))
147
150
  messages.append(f"Migrated Projects folder to: {self.projects_folder}")
148
151
 
149
- #==Always ensure default templates exist, no matter what profile is active==
152
+ # Always ensure default templates exist, no matter what profile is active
150
153
  if not self.templates_folder.exists():
151
154
  user_templates = self.templates_folder
152
155
 
@@ -1,9 +1,11 @@
1
+ import os
1
2
  import subprocess
2
3
  import platform
3
- import os
4
4
  import time
5
+
5
6
  from termcolor import colored
6
7
 
8
+
7
9
  class Opener:
8
10
  @staticmethod
9
11
  def open(path):
@@ -1,7 +1,5 @@
1
1
  import os, sys
2
2
  import time
3
- import subprocess
4
- import platform
5
3
  from pathlib import Path
6
4
  from datetime import datetime
7
5
 
@@ -12,6 +10,7 @@ from da.modules.config_manager import ConfigManager
12
10
  from da.modules.version_logic import VersionLogic
13
11
  from da.modules.opener import Opener
14
12
 
13
+
15
14
  class ProjectsManager:
16
15
  def __init__(self, config, color, header, cls, user_path):
17
16
  self.config = config
@@ -20,14 +19,19 @@ class ProjectsManager:
20
19
  self.clear = cls
21
20
  self.user_path = user_path
22
21
 
22
+
23
23
  def projects(self, profile):
24
24
  self.active_profile = profile
25
25
  while True:
26
26
  self.memory = self.config.load_memory()
27
27
  os.system(self.clear)
28
- print(colored(f"{self.active_profile}", f"{self.color}") + " / Main menu / Projects")
28
+ print(
29
+ colored(f"{self.active_profile}", f"{self.color}")
30
+ + " / Main menu / Projects"
31
+ )
29
32
  print(self.header)
30
- print("E. Back\n")
33
+ print("Q. Back\n")
34
+
31
35
  print(colored("1. Last project:", attrs=["underline"]))
32
36
  print(colored(self.memory.get('last_project'), f"{self.color}"))
33
37
 
@@ -43,7 +47,7 @@ class ProjectsManager:
43
47
  print("")
44
48
  choice = input(f"{self.user_path}> ").strip()
45
49
 
46
- if choice.lower() == "e":
50
+ if choice.lower() == "q":
47
51
  return
48
52
 
49
53
  elif choice == "1":
@@ -76,8 +80,7 @@ class ProjectsManager:
76
80
  elif choice == "3":
77
81
  self.prf_projects()
78
82
  else:
79
- print("")
80
- print(colored("Unknown option...", "light_red", attrs=["bold"]))
83
+ print(colored("\nUnknown option...", "light_red", attrs=["bold"]))
81
84
  time.sleep(0.5)
82
85
 
83
86
  def new_project(self):
@@ -87,10 +90,11 @@ class ProjectsManager:
87
90
  today = now.strftime("%Y-%m-%d")
88
91
 
89
92
  print(self.header)
90
- print("E. Abort/back\n")
93
+ print("Q. Abort/back")
94
+ print("[*] - Optional\n")
91
95
 
92
96
  name = prompt("Enter new project name > ")
93
- if name.lower() == "e":
97
+ if name.lower() == "q":
94
98
  return
95
99
  path = prompt("\nEnter project path > ")
96
100
 
@@ -98,9 +102,9 @@ class ProjectsManager:
98
102
 
99
103
  version = prompt("\nCurrent project version > ")
100
104
 
101
- command = prompt("\nCustom commit command > ")
105
+ command = prompt("\nCustom commit command* > ")
102
106
 
103
- #cloud = prompt("\nCloud service (not required) > ")
107
+ #cloud = prompt("\nCloud service* > ")
104
108
 
105
109
  confirm = input("\nConfirm(Y) or abort(E) > ").strip()
106
110
  if confirm.lower() == "e":
@@ -121,17 +125,19 @@ class ProjectsManager:
121
125
  return
122
126
 
123
127
  else:
124
- print("")
125
- print(colored("Unknown option, try again...", "light_red", attrs=["bold"]))
128
+ print(colored("\nUnknown option, try again...", "light_red", attrs=["bold"]))
126
129
  time.sleep(1)
127
130
  return
128
131
 
129
132
  def prf_projects(self):
130
133
  while True:
131
134
  os.system(self.clear)
132
- print(colored(f"{self.active_profile}", f"{self.color}") + " / Main menu / Projects / Profile projects")
135
+ print(
136
+ colored(f"{self.active_profile}", f"{self.color}")
137
+ + " / Main menu / Projects / Profile projects"
138
+ )
133
139
  print(self.header)
134
- print("E. Back\n")
140
+ print("Q. Back\n")
135
141
  prof_prj = self.config.projects_folder
136
142
  contents = os.listdir(prof_prj)
137
143
 
@@ -147,7 +153,7 @@ class ProjectsManager:
147
153
 
148
154
  project = input("\nProject name > ").strip()
149
155
 
150
- if project.lower() == "e":
156
+ if project.lower() == "q":
151
157
  return
152
158
  elif project in projects:
153
159
  self.load_project(project)
@@ -191,22 +197,27 @@ class ProjectsManager:
191
197
  suffix = " days ago"
192
198
 
193
199
  os.system(self.clear)
194
- print(colored(f"{self.active_profile}", f"{self.color}") + " / Main menu / Projects / Project menu")
200
+ print(
201
+ colored(f"{self.active_profile}", f"{self.color}")
202
+ + " / Main menu / Projects / Project menu"
203
+ )
195
204
  print(self.header)
196
- print("E. Back\n")
205
+ print("Q. Back\n")
206
+
197
207
  print(colored("Chosen project:", attrs=["underline"]))
198
208
  print(colored(project, f"{self.color}"))
199
209
  print("Last edit " + colored(days, f"{self.color}") + f"{suffix}")
210
+
200
211
  print("\n1. Open project folder")
201
212
  print("2. Manage the changelog")
202
213
 
203
214
  print("\n3. Open project configurations")
204
- print("4. Restore backup changelog")
205
- print("5. Backup to the cloud [WIP]\n")
215
+ print("4. Restore backup changelog\n")
216
+ # print("5. Backup to the cloud [WIP]\n")
206
217
 
207
218
  choice = input(f"{self.user_path}> ").strip()
208
219
 
209
- if choice.lower() == "e":
220
+ if choice.lower() == "q":
210
221
  return
211
222
 
212
223
  elif choice == "1":
@@ -222,7 +233,7 @@ class ProjectsManager:
222
233
  elif choice == "4":
223
234
  changelog = Path(setting.get('changelog'))
224
235
  if os.path.exists(changelog):
225
- print(colored("\nThis action will overwrite your existing changelog!\n", "yellow"))
236
+ print(colored("\nThis action will overwrite your existing changelog!\n", "yellow", attrs=["bold"]))
226
237
  input("Acknowledge..." + colored("[Enter]", f"{self.color}"))
227
238
 
228
239
  self.rest_bak(setting, changelog, project)
@@ -230,8 +241,7 @@ class ProjectsManager:
230
241
  #elif choice == "5":
231
242
 
232
243
  else:
233
- print("")
234
- print(colored("Unknown option...", "light_red", attrs=["bold"]))
244
+ print(colored("\nUnknown option...", "light_red", attrs=["bold"]))
235
245
  time.sleep(1)
236
246
 
237
247
  def rest_bak(self, setting, changelog, project):
@@ -1,7 +1,6 @@
1
1
  import os, sys
2
2
  import time
3
3
  import subprocess
4
- import platform
5
4
  import shutil
6
5
  from datetime import datetime
7
6
  from pathlib import Path
@@ -15,6 +14,7 @@ from rich.markdown import Markdown
15
14
  from da.modules.config_manager import ConfigManager
16
15
  from da.modules.opener import Opener
17
16
 
17
+
18
18
  class VersionLogic:
19
19
  def __init__(self, config, color, header, cls, user_path):
20
20
  self.config = config
@@ -26,6 +26,7 @@ class VersionLogic:
26
26
  self.memory = self.config.load_memory()
27
27
  self.console = Console()
28
28
 
29
+
29
30
  def project_menu(self, project, profile):
30
31
  self.active_project = project
31
32
  self.active_profile = profile
@@ -47,12 +48,17 @@ class VersionLogic:
47
48
  self.prj_path = Path(self.setting.get('path'))
48
49
 
49
50
  os.system(self.clear)
50
- print(colored(f"{self.active_profile}", f"{self.color}") + " / Main menu / Projects / Project menu / Changelog")
51
+ print(
52
+ colored(f"{self.active_profile}", f"{self.color}")
53
+ + " / Main menu / Projects / Project menu / Changelog"
54
+ )
51
55
  print(self.header)
52
- print("E. Back\n")
56
+ print("Q. Back\n")
57
+
53
58
  print(colored("Chosen project:", attrs=["underline"]))
54
59
  print(colored(self.active_project, f"{self.color}"))
55
60
  print("Version: " + colored(self.prj_ver, f"{self.color}"))
61
+
56
62
  print("\n1. Format & commit")
57
63
  print("2. Add new changes")
58
64
  print("\n3. Open the changelog")
@@ -60,7 +66,7 @@ class VersionLogic:
60
66
 
61
67
  choice = input(f"{self.user_path}> ").strip()
62
68
 
63
- if choice.lower() == "e":
69
+ if choice.lower() == "q":
64
70
  return
65
71
 
66
72
  elif choice == "1":
@@ -72,7 +78,7 @@ class VersionLogic:
72
78
 
73
79
  elif choice == "2":
74
80
  if not os.path.exists(self.prj_path):
75
- print(colored("\nSystem cannot find the path to this project.", "light_red"))
81
+ print(colored("\nSystem cannot find the project path.", "light_red"))
76
82
  time.sleep(1)
77
83
  else:
78
84
  self.update_changelog()
@@ -100,8 +106,7 @@ class VersionLogic:
100
106
  self.view_md(log_content)
101
107
 
102
108
  else:
103
- print("")
104
- print(colored("Unknown option...", "light_red", attrs=["bold"]))
109
+ print(colored("\nUnknown option...", "light_red", attrs=["bold"]))
105
110
  time.sleep(0.5)
106
111
 
107
112
  def finalise(self):
@@ -130,12 +135,12 @@ class VersionLogic:
130
135
  cmd = self.setting.get('command')
131
136
 
132
137
  if cmd.strip():
133
- print("\nwill run: " + colored(f"{cmd}", f"{self.color}"))
134
- print("in folder: " + colored(f"{self.prj_path}", f"{self.color}"))
135
- confirm = input("\nConfirm[Enter] or abort[E] > ").strip()
138
+ print("\nWill run: " + colored(f"{cmd}", f"{self.color}"))
139
+ print("In folder: " + colored(f"{self.prj_path}", f"{self.color}"))
140
+ confirm = input("\nConfirm[Enter] or abort[Q] > ").strip()
136
141
  print("")
137
142
 
138
- if confirm.lower() == "e":
143
+ if confirm.lower() == "q":
139
144
  return
140
145
  try:
141
146
  subprocess.run(cmd, cwd=self.prj_path, shell=True, check=True)
@@ -160,12 +165,21 @@ class VersionLogic:
160
165
  self.comment = None
161
166
  while True:
162
167
  os.system(self.clear)
163
- print(colored(f"{self.active_profile}", f"{self.color}") + " / Main menu / Projects / Project menu / Changelog / Add changes")
168
+ print(
169
+ colored(f"{self.active_profile}", f"{self.color}")
170
+ + " / Main menu / Projects / Project menu / Changelog / Add changes"
171
+ )
164
172
  print(self.header)
165
- print("E. Back/abort")
173
+ print("Q. Back (stash/abort)")
166
174
  print("O. Open templog for fixes")
167
175
  print("S. Review changes & save\n")
168
176
 
177
+ if os.path.exists(self.templog_path):
178
+ print(
179
+ colored("There are unsaved changes for a project.\n", "light_yellow", attrs=["bold"])
180
+ + "(Open templog to review)\n"
181
+ )
182
+
169
183
  print(colored("Chosen project:", attrs=["underline"]))
170
184
  print(colored(self.active_project, f"{self.color}"))
171
185
  print("Version: " + colored(self.prj_ver, f"{self.color}"))
@@ -186,7 +200,7 @@ class VersionLogic:
186
200
  print("Change: " + self.change)
187
201
  print("Comment: " + self.comment + "\n")
188
202
 
189
- type_choice = input(f"{self.user_path}> ").strip()
203
+ type_choice = input(f"{self.user_path}> ").strip().lower()
190
204
 
191
205
  type_map = {
192
206
  "1": "Added",
@@ -199,19 +213,30 @@ class VersionLogic:
199
213
 
200
214
  self.change_type = type_map.get(type_choice.lower())
201
215
 
202
- if type_choice.lower() == "e":
216
+ if type_choice == "q":
203
217
  if os.path.exists(self.templog_path):
204
- os.remove(self.templog_path)
218
+ print(colored("\nNote: This stash slot is shared between all projects.", "light_yellow"))
219
+ choice = input(
220
+ colored("\nK", "light_red")
221
+ + "eep or "
222
+ + colored("D", "light_red")
223
+ + "iscard changes? > "
224
+ ).strip().lower()
225
+
226
+ if choice == "d":
227
+ os.remove(self.templog_path)
205
228
  return
229
+
206
230
  elif type_choice in ("1", "2", "3", "4", "5", "6"):
207
231
  self.prepend_changes()
208
- elif type_choice.lower() == "o":
232
+
233
+ elif type_choice == "o":
209
234
  Opener.open(self.templog_path)
210
- elif type_choice.lower() == "s":
235
+
236
+ elif type_choice == "s":
211
237
  self.save_changes()
212
238
  else:
213
- print("")
214
- print(colored("Unknown option...", "light_red", attrs=["bold"]))
239
+ print(colored("\nUnknown option...", "light_red", attrs=["bold"]))
215
240
  time.sleep(0.5)
216
241
 
217
242
  def prepend_changes(self):
@@ -249,8 +274,8 @@ class VersionLogic:
249
274
  with open(self.templog_path, "a", encoding="utf-8") as f:
250
275
  f.write(rendered + "\n")
251
276
 
252
- choice = input("\nNew type [E] or add more [Enter] > ").strip()
253
- if choice.lower() == "e":
277
+ choice = input("\nNew type[Q] or add more[Enter] > ").strip()
278
+ if choice.lower() == "q":
254
279
  return
255
280
 
256
281
  def save_changes(self):
@@ -271,13 +296,16 @@ class VersionLogic:
271
296
  time.sleep(0.5)
272
297
  return
273
298
 
274
- choice = input("\nContinue" + colored("[Enter]", f"{self.color}") + " or add more" + colored("[E] ", f"{self.color}"))
299
+ choice = input(
300
+ "\nContinue" + colored("[Enter]", f"{self.color}")
301
+ + " or add more" + colored("[Q] ", f"{self.color}")
302
+ )
275
303
 
276
- if choice.lower() == "e":
304
+ if choice.lower() == "q":
277
305
  return
278
306
 
279
307
  print("\nCurrent version: " + colored(self.prj_ver, f"{self.color}"))
280
- version = input("\nNew version number: ").strip()
308
+ version = input("\nNew version number > ").strip()
281
309
 
282
310
  print("\nWorking...")
283
311
 
@@ -335,14 +363,17 @@ class VersionLogic:
335
363
  return
336
364
 
337
365
  def view_md(self, log_content, message=None):
366
+ # Callers: self.project_menu() & self.save_changes()
338
367
  flag = 0
339
368
  if not message:
369
+ # Only check size when caller is self.project_menu()
340
370
  method = self.check_size()
341
371
  if method == "reject":
342
372
  return
343
373
  elif method == "print":
344
374
  flag = 1
345
375
 
376
+ # Display the passed down message or full UI
346
377
  if message:
347
378
  print(message)
348
379
  else:
@@ -350,15 +381,23 @@ class VersionLogic:
350
381
  print(self.header)
351
382
  print("")
352
383
 
384
+ # Respect self.check_size() verdict
353
385
  if flag:
354
- print(log_content)
386
+ with self.console.pager():
387
+ self.console.print(log_content)
388
+
355
389
  print(colored("\nThis log is too large to render in Markdown! (Max 10MB)", "yellow"))
390
+ input("\nReturn...[Enter]")
391
+ return
356
392
  else:
357
393
  md = Markdown(log_content)
358
394
  self.console.print(md)
359
395
 
360
396
  if not message:
361
- input("\nReturn..." + colored("[Enter]", f"{self.color}"))
397
+ choice = input("\nReturn...[Enter] / [P]ager view (Q - return) > ").strip().lower()
398
+ if choice == "p":
399
+ with self.console.pager():
400
+ self.console.print(md)
362
401
  return
363
402
 
364
403
  def check_size(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: developer-assistant
3
- Version: 0.3.6
3
+ Version: 0.3.7
4
4
  Summary: A lightweight TUI app for managing and simplifying your Markdown changelogs.
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/Ivory-Hubert/Developer-Assistant
@@ -55,7 +55,7 @@ Developer Assistant is a lightweight TUI for simplifying and managing your chang
55
55
 
56
56
  You can create as many profiles as you need. Each profile gets its own **project specific** `.ini` files, created automatically through the menu based on the information you provide. These act as links that tell DA where your changelogs are, which profile owns them and what's the last version number.
57
57
 
58
- Each project `.ini` can also hold a custom terminal command, that is run in that projects folder. So you can easly integrate updating your changelogs in DA with Git commands for example.
58
+ Each project `.ini` can also hold a custom terminal command, that's run in the projects folder. So you can easly integrate updating your changelogs in DA with Git commands for example.
59
59
 
60
60
  **Your files are kept safe at all times.** Before adding new changes, your existing `CHANGELOG.md` is automatically backed up. While editing, all changes are written to a temporary file first and only prepended to & replaced with your real changelog once you confirm them.
61
61
 
@@ -121,6 +121,11 @@ New changes are first written to a temporary file and only prepended to & replac
121
121
  This ensures your existing changelog is never overwritten or corrupted, and you always have a fallback copy.
122
122
  If the temporary changelog is present on startup you are prompted to remove or keep it.
123
123
 
124
+ Furthermore, you can safely work on one changelog in separate sessions, your changes are staged in the temporary log file and only deleted with your confirmation.
125
+
126
+ > **Note:**
127
+ > DA can only keep **one** projects WIP changes staged, switching projects with staged changes appends the same file. If you update/reinstall the program with unsaved changes they are lost for good, so it's **not** long-term storage.
128
+
124
129
 
125
130
  **Ease of navigation**
126
131
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "developer-assistant"
3
- version = "0.3.6"
3
+ version = "0.3.7"
4
4
  description = "A lightweight TUI app for managing and simplifying your Markdown changelogs."
5
5
  readme = "PYPI.md"
6
6
  requires-python = ">=3.10"