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.
- {developer_assistant-0.3.6/developer_assistant.egg-info → developer_assistant-0.3.7}/PKG-INFO +7 -2
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/PYPI.md +6 -1
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/README.md +6 -1
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/interface.py +92 -47
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/intro.md +9 -3
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/modules/config_manager.py +5 -2
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/modules/opener.py +3 -1
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/modules/projects_manager.py +34 -24
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/modules/version_logic.py +66 -27
- {developer_assistant-0.3.6 → developer_assistant-0.3.7/developer_assistant.egg-info}/PKG-INFO +7 -2
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/pyproject.toml +1 -1
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/LICENSE +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/__init__.py +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/default/default-changelog.md +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/default/default-memory.ini +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/default/test-project.ini +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/modules/__init__.py +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/templates/changelog_template.txt +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/templates/entry_template.txt +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/da/templates/header_template.txt +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/SOURCES.txt +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/dependency_links.txt +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/entry_points.txt +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/requires.txt +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/top_level.txt +0 -0
- {developer_assistant-0.3.6 → developer_assistant-0.3.7}/setup.cfg +0 -0
{developer_assistant-0.3.6/developer_assistant.egg-info → developer_assistant-0.3.7}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: developer-assistant
|
|
3
|
-
Version: 0.3.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
21
|
-
self.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
|
|
26
|
+
os.system(f"title {title}")
|
|
27
27
|
else:
|
|
28
|
-
print(f
|
|
28
|
+
print(f"\33]0;{title}\a", end="", flush=True)
|
|
29
29
|
|
|
30
|
-
self.config = ConfigManager(
|
|
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(
|
|
61
|
-
print(
|
|
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(
|
|
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(
|
|
112
|
+
print(
|
|
113
|
+
colored(
|
|
114
|
+
f"{self.active_profile}", f"{self.color}")
|
|
115
|
+
+ " / Main menu"
|
|
116
|
+
)
|
|
107
117
|
print(self.header)
|
|
108
|
-
print("
|
|
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() == "
|
|
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(
|
|
149
|
+
print(
|
|
150
|
+
colored(f"{self.active_profile}", f"{self.color}")
|
|
151
|
+
+ " / Main menu / Settings"
|
|
152
|
+
)
|
|
141
153
|
print(self.header)
|
|
142
|
-
print("
|
|
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() == "
|
|
167
|
+
if choice.lower() == "q":
|
|
156
168
|
return
|
|
157
|
-
#elif choice == "1":
|
|
158
|
-
|
|
159
|
-
#elif choice == "2":
|
|
160
|
-
|
|
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(
|
|
186
|
+
print(
|
|
187
|
+
colored(f"{self.active_profile}", f"{self.color}")
|
|
188
|
+
+ " / Main menu / Profiles"
|
|
189
|
+
)
|
|
176
190
|
print(self.header)
|
|
177
|
-
print("
|
|
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() == "
|
|
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(
|
|
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(
|
|
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(
|
|
280
|
-
self.user_path = os.environ.get(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
>
|
|
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
|
-
|
|
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
|
-
|
|
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,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(
|
|
28
|
+
print(
|
|
29
|
+
colored(f"{self.active_profile}", f"{self.color}")
|
|
30
|
+
+ " / Main menu / Projects"
|
|
31
|
+
)
|
|
29
32
|
print(self.header)
|
|
30
|
-
print("
|
|
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() == "
|
|
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("
|
|
93
|
+
print("Q. Abort/back")
|
|
94
|
+
print("[*] - Optional\n")
|
|
91
95
|
|
|
92
96
|
name = prompt("Enter new project name > ")
|
|
93
|
-
if name.lower() == "
|
|
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
|
|
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(
|
|
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("
|
|
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() == "
|
|
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(
|
|
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("
|
|
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() == "
|
|
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(
|
|
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("
|
|
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() == "
|
|
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
|
|
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("\
|
|
134
|
-
print("
|
|
135
|
-
confirm = input("\nConfirm[Enter] or abort[
|
|
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() == "
|
|
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(
|
|
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("
|
|
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
|
|
216
|
+
if type_choice == "q":
|
|
203
217
|
if os.path.exists(self.templog_path):
|
|
204
|
-
|
|
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
|
-
|
|
232
|
+
|
|
233
|
+
elif type_choice == "o":
|
|
209
234
|
Opener.open(self.templog_path)
|
|
210
|
-
|
|
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
|
|
253
|
-
if choice.lower() == "
|
|
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(
|
|
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() == "
|
|
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
|
|
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
|
-
|
|
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...
|
|
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):
|
{developer_assistant-0.3.6 → developer_assistant-0.3.7/developer_assistant.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: developer-assistant
|
|
3
|
-
Version: 0.3.
|
|
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
|
|
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
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/requires.txt
RENAMED
|
File without changes
|
{developer_assistant-0.3.6 → developer_assistant-0.3.7}/developer_assistant.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|