liveConsole 1.5.3__py3-none-any.whl → 1.6.1__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: liveConsole
3
- Version: 1.5.3
3
+ Version: 1.6.1
4
4
  Summary: An IDLE-like debugger to allow for real-time command injection for debugging and testing python code
5
5
  Author-email: Tzur Soffer <tzur.soffer@gmail.com>
6
6
  License: MIT
@@ -127,11 +127,9 @@ pysole.probe()
127
127
 
128
128
  ## Customization
129
129
 
130
- * **Appearance mode**: Dark mode is default (`ctk.set_appearance_mode("dark")`)
131
-
132
- * **Font**: Consolas, 12pt by default, configurable in `InteractiveConsoleText` constructor
133
-
134
- * **Syntax Highlighting Style**: Change Pygments style by modifying `get_style_by_name("monokai")`
130
+ * **Appearance mode**: Dark mode is default, but can be changed via files menu
131
+
132
+ * **Themes**: Pysole has multiple preconfigured themes. You can choose a theme via the Theme Picker, which updates the console colors and appearance. Preconfigured themes are loaded from themes.json and the selected theme is saved in settings.json so it persists across sessions.
135
133
 
136
134
 
137
135
 
@@ -0,0 +1,18 @@
1
+ liveconsole-1.6.1.dist-info/licenses/LICENSE,sha256=7dZ0zL72aGaFE0C9DxacOpnaSkC5jajhG6iL7lqhWmU,1064
2
+ pysole/__init__.py,sha256=SfaSBmFVSmhyf55UedBCqhi2Ss6Tre-BCKtZb3bSr2k,60
3
+ pysole/__main__.py,sha256=QvVFH8J2yzgQaF9MosQ6ajCW67uiRbYliePsTEUCIAg,82
4
+ pysole/commandHistory.py,sha256=xJtWbJ_vgJo2QGgaZJsApTOi_Hm8Yz0V9_zqQUCItj8,1084
5
+ pysole/helpTab.py,sha256=o0uSY-8sw7FuuBrt0FQwcgK6ljNVx3IgRnW7heZ6GvY,2454
6
+ pysole/liveConsole.py,sha256=lzS3dphAQ1i8pQC4E2FY-FyMMSKi-dAN0xr6XUgrNmo,168
7
+ pysole/mainConsole.py,sha256=9Kdjpe9rQzx3Nk9aBaECR3PlwAXszgRt4VfIJmVJnRw,13141
8
+ pysole/pysole.py,sha256=vTmPvS4nzapVudNPtf2JrnwBWB-x_n-XxBsr4jW7MK8,9230
9
+ pysole/settings.json,sha256=6wCdMlemV6PblPKeQQsIiCrGWPLDLOMFD3hLMVAXL24,687
10
+ pysole/styledTextbox.py,sha256=zpbaN0qX5FduhNyuWGU7y8Ll8J9p9YqczpSuRLo4PX0,2120
11
+ pysole/suggestionManager.py,sha256=EUFeCQoZnLS8EjPPNuZpzjY0BR07m2KP5TloyaMDVGY,6457
12
+ pysole/themes.json,sha256=2RG3ohn2ZBc2-h9bdooQZD6hW5pD41a5c2jdaKDA4MA,2385
13
+ pysole/utils.py,sha256=VN42ukHMJpOvGb7ZV-qhF_zRUt13hzJKV_uRn9t6580,155
14
+ liveconsole-1.6.1.dist-info/METADATA,sha256=ScK9vL5BuDsaRSoUZicUfWx2wDDqYlonVtJlH5Di_f0,4011
15
+ liveconsole-1.6.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ liveconsole-1.6.1.dist-info/entry_points.txt,sha256=qtvuJHcex4QqM97x_UawFWJYnfhQRl0jhqLcWRpnAGo,84
17
+ liveconsole-1.6.1.dist-info/top_level.txt,sha256=DlpA93ScJbRZcF8kGSc5YoO8Ntu1ib1_MEZMb4xea_Q,7
18
+ liveconsole-1.6.1.dist-info/RECORD,,
@@ -0,0 +1 @@
1
+ pysole
pysole/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from .pysole import probe, _standalone, InteractiveConsole
pysole/__main__.py ADDED
@@ -0,0 +1,4 @@
1
+ from .pysole import _standalone
2
+
3
+ if __name__ == "__main__":
4
+ _standalone()
@@ -2,12 +2,12 @@ import sys
2
2
  import io
3
3
  from pygments.styles import get_style_by_name
4
4
  import customtkinter as ctk
5
- from styledTextbox import StyledTextWindow
5
+ from .styledTextbox import StyledTextWindow
6
6
 
7
7
  class HelpTab(ctk.CTkFrame):
8
8
  """A right-hand help tab with closable and updateable text content."""
9
9
 
10
- def __init__(self, parent, width=500, title="Help", **kwargs):
10
+ def __init__(self, parent, theme, font, width=500, title="Help", **kwargs):
11
11
  super().__init__(parent, width=width, **kwargs)
12
12
  self.parent = parent
13
13
  self.visible = False
@@ -18,16 +18,16 @@ class HelpTab(ctk.CTkFrame):
18
18
  # Header frame with title and close button
19
19
  headerFrame = ctk.CTkFrame(self, height=30)
20
20
  headerFrame.pack(fill="x")
21
- self.style = get_style_by_name("monokai")
21
+ self.style = get_style_by_name(theme["LEXER_STYLE"])
22
22
 
23
- self.titleLabel = ctk.CTkLabel(headerFrame, text=title, font=("Consolas", 12, "bold"))
23
+ self.titleLabel = ctk.CTkLabel(headerFrame, text=title, font=(font["FONT"], font["FONT_SIZE"], "bold"))
24
24
  self.titleLabel.pack(side="left", padx=5)
25
25
 
26
26
  self.closeButton = ctk.CTkButton(headerFrame, text="X", height=20, command=self.close)
27
27
  self.closeButton.pack(side="right", padx=5)
28
28
 
29
29
  # Scrollable text area
30
- self.textBox = StyledTextWindow(self, wrap="word", font=("Consolas", 11), bg="#2e2e2e")
30
+ self.textBox = StyledTextWindow(self, theme, {"FONT": font["FONT"], "FONT_SIZE": max(0, (font["FONT_SIZE"]-1))}, wrap="word", bg="#2e2e2e")
31
31
  self.textBox.pack(fill="both", expand=True, padx=5, pady=5)
32
32
  self.textBox.configure(state="disabled") # read-only
33
33
 
@@ -5,4 +5,4 @@ warnings.warn(
5
5
  stacklevel=2
6
6
  )
7
7
 
8
- from pysole import *
8
+ from .pysole import *
@@ -1,22 +1,21 @@
1
1
  import threading
2
2
  import traceback
3
- from suggestionManager import CodeSuggestionManager
4
- from commandHistory import CommandHistory
5
- from styledTextbox import StyledTextWindow
3
+ from .suggestionManager import CodeSuggestionManager
4
+ from .commandHistory import CommandHistory
5
+ from .styledTextbox import StyledTextWindow
6
6
 
7
7
  import tkinter as tk
8
8
 
9
9
  class InteractiveConsoleText(StyledTextWindow):
10
10
  """TBD"""
11
-
12
- PROMPT = ">>> "
13
- PROMPT_LENGTH = 4
14
-
15
- def __init__(self, master, helpTab, userLocals=None, userGlobals=None, **kwargs):
16
- super().__init__(master, **kwargs)
11
+ def __init__(self, master, helpTab, theme, font, behavior, userLocals=None, userGlobals=None, **kwargs):
12
+ super().__init__(master, theme=theme, font=font, **kwargs)
13
+ self.font=(font["FONT"], font["FONT_SIZE"])
17
14
 
18
15
  # Initialize components
19
- self.suggestionManager = CodeSuggestionManager(self, userLocals=userLocals, userGlobals=userGlobals)
16
+ self.PROMPT = behavior["PRIMARY_PROMPT"]
17
+ self.PROMPT_LENGTH = len(self.PROMPT)
18
+ self.suggestionManager = CodeSuggestionManager(self, userLocals=userLocals, userGlobals=userGlobals, theme=theme, font=font)
20
19
  self.helpTab = helpTab
21
20
 
22
21
  self.navigatingHistory = False
pysole/pysole.py ADDED
@@ -0,0 +1,250 @@
1
+ import customtkinter as ctk
2
+ import tkinter as tk
3
+ from tkinter import messagebox
4
+ import inspect
5
+ import sys
6
+ import io
7
+ import json
8
+
9
+ from .utils import settingsPath, themesPath
10
+ from .helpTab import HelpTab
11
+ from .mainConsole import InteractiveConsoleText
12
+
13
+ class StdoutRedirect(io.StringIO):
14
+ """Redirects stdout/stderr to a callback function."""
15
+
16
+ def __init__(self, writeCallback):
17
+ super().__init__()
18
+ self.writeCallback = writeCallback
19
+
20
+ def write(self, s):
21
+ if s.strip():
22
+ self.writeCallback(s, "output")
23
+
24
+ def flush(self):
25
+ pass
26
+
27
+ class StdinRedirect(io.StringIO):
28
+ """Redirects stdin to capture input() from the console."""
29
+ def __init__(self, readCallback):
30
+ super().__init__()
31
+ self.readCallback = readCallback
32
+
33
+ def readline(self, *args, **kwargs):
34
+ return(self.readCallback())
35
+
36
+ class InteractiveConsole(ctk.CTk):
37
+ """Main console window application."""
38
+
39
+ def __init__(self, userGlobals=None, userLocals=None, callerFrame=None, theme=None, defaultSize=None, primaryPrompt=None):
40
+ super().__init__()
41
+ with open(settingsPath, "r") as f:
42
+ settings = json.load(f)
43
+ self.THEME = settings["THEME"]
44
+ self.FONT = self.THEME["FONT"]
45
+ self.BEHAVIOR = settings["BEHAVIOR"]
46
+
47
+ if primaryPrompt != None:
48
+ self.BEHAVIOR["PRIMARY_PROMPT"] = primaryPrompt
49
+ if defaultSize != None:
50
+ self.BEHAVIOR["DEFAULT_SIZE"] = defaultSize
51
+
52
+ self.title("Live Interactive Console")
53
+ self.geometry(self.BEHAVIOR["DEFAULT_SIZE"])
54
+
55
+ ctk.set_appearance_mode(self.THEME["APPEARANCE"])
56
+ ctk.set_default_color_theme("blue")
57
+
58
+ # Get namespace from caller if not provided
59
+ if userGlobals is None or userLocals is None:
60
+ if callerFrame == None:
61
+ callerFrame = inspect.currentframe().f_back
62
+ if userGlobals is None:
63
+ userGlobals = callerFrame.f_globals
64
+ if userLocals is None:
65
+ userLocals = callerFrame.f_locals
66
+
67
+ self.userGlobals = userGlobals
68
+ self.userLocals = userLocals
69
+
70
+ # Create UI
71
+ self._createMenu()
72
+ self._createUi()
73
+
74
+ # Redirect stdout/stderr
75
+ self._setupOutputRedirect()
76
+ self._setupInputRedirect()
77
+
78
+ def _createMenu(self):
79
+ """Create a menu bar using CTkOptionMenu."""
80
+ menuBar = ctk.CTkFrame(self, fg_color=self.THEME["BACKGROUND"])
81
+ menuBar.pack(side="top", fill="x")
82
+
83
+ self.menu_var = ctk.StringVar(value="File")
84
+ fileMenu = ctk.CTkOptionMenu(menuBar,
85
+ values=["Edit Settings", "Load Theme"],
86
+ variable=self.menu_var,
87
+ command=self._handleMenu,
88
+ fg_color=self.THEME["BACKGROUND"],
89
+ button_color=self.THEME["BACKGROUND"],
90
+ button_hover_color=self.THEME["HIGHLIGHTED_BACKGROUND"],
91
+ dropdown_fg_color=self.THEME["BACKGROUND"],
92
+ dropdown_hover_color=self.THEME["HIGHLIGHTED_BACKGROUND"],
93
+ dropdown_text_color=self.THEME["FOREGROUND"],
94
+ text_color=self.THEME["FOREGROUND"])
95
+ fileMenu.pack(side="left", padx=5, pady=2)
96
+
97
+ def _handleMenu(self, choice):
98
+ if choice == "Edit Settings":
99
+ self._editSettings()
100
+ elif choice == "Load Theme":
101
+ self._loadTheme()
102
+
103
+ def _loadTheme(self):
104
+ """
105
+ Open a CTk popup to let the user choose a theme from themes.json.
106
+ The chosen theme will override the THEME key in settings.json
107
+ and apply immediately.
108
+ """
109
+
110
+ # Load themes from themes.json
111
+ try:
112
+ with open(themesPath, "r") as f:
113
+ themes = json.load(f)
114
+ except Exception as e:
115
+ messagebox.showerror("Error", f"Failed to load themes.json:\n{e}")
116
+ return
117
+
118
+ if not themes:
119
+ messagebox.showerror("Error", "No themes found in themes.json")
120
+ return
121
+
122
+ # Create the CTk popup window
123
+ popup = ctk.CTkToplevel(self)
124
+ popup.title("Select Theme")
125
+ popup.geometry("300x150")
126
+ popup.grab_set()
127
+
128
+ ctk.CTkLabel(popup, text="Choose a theme:").pack(pady=(10, 5))
129
+
130
+ # Dropdown with theme keys
131
+ themeVar = tk.StringVar(value=list(themes.keys())[0])
132
+ themeDropdown = ctk.CTkOptionMenu(popup, values=list(themes.keys()), variable=themeVar)
133
+ themeDropdown.pack(pady=5)
134
+
135
+ def applyTheme():
136
+ chosenKey = themeVar.get()
137
+ chosenTheme = themes[chosenKey]
138
+
139
+ # Update self.THEME
140
+ self.THEME = chosenTheme
141
+
142
+ # Save to settings.json
143
+ try:
144
+ with open(settingsPath, "r") as f:
145
+ settings = json.load(f)
146
+ settings["THEME"] = chosenTheme
147
+ with open(settingsPath, "w") as f:
148
+ json.dump(settings, f, indent=4)
149
+ except Exception as e:
150
+ messagebox.showerror("Error", f"Failed to save settings.json:\n{e}")
151
+ return
152
+
153
+ messagebox.showinfo("Theme Applied", f"Theme '{chosenKey}' applied successfully, relaunch app for changes to take effect!")
154
+ popup.destroy()
155
+
156
+ applyBtn = ctk.CTkButton(popup, text="Apply", command=applyTheme)
157
+ applyBtn.pack(pady=(10, 10))
158
+
159
+ def _editSettings(self):
160
+ """Open a simple JSON editor for settings.json."""
161
+ editor = ctk.CTkToplevel(self)
162
+ editor.title("Edit Settings")
163
+ editor.geometry("500x400")
164
+
165
+ try:
166
+ with open(settingsPath, "r") as f:
167
+ jsonText = f.read()
168
+ except Exception as e:
169
+ jsonText = f"{{}}\n\n# Failed to load settings.json:\n{e}"
170
+
171
+ textbox = ctk.CTkTextbox(editor)
172
+ textbox.pack(fill="both", expand=True, padx=10, pady=10)
173
+ textbox.insert("0.0", jsonText)
174
+
175
+ def saveSettings():
176
+ try:
177
+ newSettings = json.loads(textbox.get("0.0", "end-1c"))
178
+ with open("settings.json", "w") as f:
179
+ json.dump(newSettings, f, indent=4)
180
+ messagebox.showinfo("Success", "Settings saved!")
181
+ editor.destroy()
182
+ except Exception as e:
183
+ messagebox.showerror("Error", f"Invalid JSON:\n{e}")
184
+
185
+ saveBtn = ctk.CTkButton(editor, text="Save", command=saveSettings)
186
+ saveBtn.pack(pady=5)
187
+
188
+ def _createUi(self):
189
+ """Create UI with console and help tab."""
190
+ frame = ctk.CTkFrame(self)
191
+ frame.pack(padx=10, pady=10, fill="both", expand=True)
192
+
193
+ # Horizontal frame
194
+ self.horizFrame = ctk.CTkFrame(frame)
195
+ self.horizFrame.pack(fill="both", expand=True)
196
+
197
+ # Right: Help Tab
198
+ self.helpTab = HelpTab(self.horizFrame, theme=self.THEME, font=self.FONT, width=500)
199
+
200
+ # Left: Console
201
+ self.consoleFrame = ctk.CTkFrame(self.horizFrame, width=600)
202
+ self.consoleFrame.pack(side="left", fill="both", expand=True)
203
+ self.consoleFrame.pack_propagate(False) # prevent shrinking to fit contents
204
+
205
+ self.console = InteractiveConsoleText(
206
+ self.consoleFrame,
207
+ self.helpTab,
208
+ userGlobals=self.userGlobals,
209
+ userLocals=self.userLocals,
210
+ theme=self.THEME,
211
+ font=self.FONT,
212
+ behavior=self.BEHAVIOR,
213
+ wrap="word",
214
+ bg=self.THEME["BACKGROUND"],
215
+ fg=self.THEME["FOREGROUND"],
216
+ insertbackground=self.THEME["INSERTBACKGROUND"]
217
+ )
218
+ self.console.pack(fill="both", expand=True, padx=5, pady=5)
219
+ self.console.master = self
220
+
221
+
222
+ def _setupOutputRedirect(self):
223
+ """Setup stdout/stderr redirection to console."""
224
+ sys.stdout = StdoutRedirect(self.console.writeOutput)
225
+ sys.stderr = StdoutRedirect(
226
+ lambda text, tag: self.console.writeOutput(text, "error")
227
+ )
228
+
229
+ def _setupInputRedirect(self):
230
+ """Setup stdin redirection to console."""
231
+ sys.stdin = StdinRedirect(self.console.readInput)
232
+
233
+ def probe(self, *args, **kwargs):
234
+ """Start the console main loop."""
235
+ self.mainloop(*args, **kwargs)
236
+
237
+ def probe(userGlobals=None, userLocals=None, callerFrame=None):
238
+ if callerFrame == None:
239
+ callerFrame = inspect.currentframe().f_back
240
+ InteractiveConsole(userGlobals=userGlobals,
241
+ userLocals=userLocals,
242
+ callerFrame=callerFrame).probe()
243
+
244
+ def _standalone():
245
+ import pysole
246
+ pysole.probe(callerFrame=inspect.currentframe().f_back)
247
+
248
+ # Example usage
249
+ if __name__ == "__main__":
250
+ _standalone()
pysole/settings.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "THEME": {
3
+ "APPEARANCE": "dark",
4
+ "LEXER_STYLE": "monokai",
5
+ "BACKGROUND": "#1e1e1e",
6
+ "HIGHLIGHTED_BACKGROUND": "#0078d7",
7
+ "FOREGROUND": "white",
8
+ "HIGHLIGHTED_FOREGROUND": "black",
9
+ "INSERTBACKGROUND": "white",
10
+ "PROMPT": "#00ff00",
11
+ "OUTPUT": "#ffffff",
12
+ "ERROR": "#ff0000",
13
+ "RESULT": "#66ccff",
14
+ "SUGGESTION_BOX_BG": "#2d2d2d",
15
+ "SUGGESTION_BOX_SELECTION_BG": "#0066cc",
16
+ "FONT": {
17
+ "FONT": "Consolas",
18
+ "FONT_SIZE": 12
19
+ }
20
+ },
21
+ "BEHAVIOR": {
22
+ "DEFAULT_SIZE": "900x600",
23
+ "PRIMARY_PROMPT": ">>> "
24
+ }
25
+ }
@@ -4,29 +4,28 @@ from pygments.lexers import PythonLexer
4
4
  from pygments.styles import get_style_by_name
5
5
 
6
6
  class StyledTextWindow(tk.Text):
7
- def __init__(self, master, **kwargs):
7
+ def __init__(self, master, theme, font, **kwargs):
8
8
  super().__init__(master, **kwargs)
9
9
 
10
10
  # Syntax highlighting setup
11
11
  self.lexer = PythonLexer()
12
- self.style = get_style_by_name("monokai")
13
-
14
- # Setup tags
15
- self._setupTags()
12
+ self.style = get_style_by_name(theme["LEXER_STYLE"])
13
+
14
+ self._setupTags(theme, font)
16
15
 
17
- def _setupTags(self):
16
+ def _setupTags(self, theme, font):
18
17
  """Configure text tags for different output types."""
19
- self.tag_configure("prompt", foreground="#00ff00", font=("Consolas", 12, "bold"))
20
- self.tag_configure("output", foreground="#ffffff", font=("Consolas", 12))
21
- self.tag_configure("error", foreground="#ff6666", font=("Consolas", 12))
22
- self.tag_configure("result", foreground="#66ccff", font=("Consolas", 12))
18
+ self.tag_configure("prompt", foreground=theme["PROMPT"], font=(font["FONT"], font["FONT_SIZE"], "bold"))
19
+ self.tag_configure("output", foreground=theme["OUTPUT"], font=(font["FONT"], font["FONT_SIZE"]))
20
+ self.tag_configure("error", foreground=theme["ERROR"], font=(font["FONT"], font["FONT_SIZE"]))
21
+ self.tag_configure("result", foreground=theme["RESULT"], font=(font["FONT"], font["FONT_SIZE"]))
23
22
 
24
23
  # Configure syntax highlighting tags
25
24
  for token, style in self.style:
26
25
  if style["color"]:
27
26
  fg = f"#{style['color']}"
28
- font = ("Consolas", 12, "bold" if style["bold"] else "normal")
29
- self.tag_configure(str(token), foreground=fg, font=font)
27
+ tagFont = (font["FONT"], font["FONT_SIZE"], "bold" if style["bold"] else "normal")
28
+ self.tag_configure(str(token), foreground=fg, font=tagFont)
30
29
 
31
30
 
32
31
  def updateStyling(self, start="1.0"):
@@ -5,7 +5,10 @@ import tkinter as tk
5
5
  class CodeSuggestionManager:
6
6
  """Manages code suggestions and autocomplete functionality."""
7
7
 
8
- def __init__(self, textWidget, userLocals, userGlobals):
8
+ def __init__(self, textWidget, userLocals, userGlobals, theme, font):
9
+ self.THEME = theme
10
+ self.FONT = font
11
+
9
12
  self.userLocals = userLocals
10
13
  self.userGlobals = userGlobals
11
14
  self.textWidget = textWidget
@@ -111,14 +114,14 @@ class CodeSuggestionManager:
111
114
  """Create the suggestion popup window."""
112
115
  self.suggestionWindow = tk.Toplevel(self.textWidget)
113
116
  self.suggestionWindow.wm_overrideredirect(True)
114
- self.suggestionWindow.configure(bg="#2d2d2d")
117
+ self.suggestionWindow.configure(bg=self.THEME["SUGGESTION_BOX_BG"])
115
118
 
116
119
  self.suggestionListbox = tk.Listbox(
117
120
  self.suggestionWindow,
118
- bg="#2d2d2d",
119
- fg="white",
120
- selectbackground="#0066cc",
121
- font=("Consolas", 10),
121
+ bg=self.THEME["SUGGESTION_BOX_BG"],
122
+ fg=self.THEME["FOREGROUND"],
123
+ selectbackground=self.THEME["SUGGESTION_BOX_SELECTION_BG"],
124
+ font=(self.FONT["FONT"], max(2, (self.FONT["FONT_SIZE"]-2))),
122
125
  height=8
123
126
  )
124
127
  self.suggestionListbox.pack()
pysole/themes.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "Dark": {
3
+ "APPEARANCE": "dark",
4
+ "LEXER_STYLE": "monokai",
5
+ "BACKGROUND": "#1e1e1e",
6
+ "HIGHLIGHTED_BACKGROUND": "#0078d7",
7
+ "FOREGROUND": "white",
8
+ "HIGHLIGHTED_FOREGROUND": "black",
9
+ "INSERTBACKGROUND": "white",
10
+ "PROMPT": "#00ff00",
11
+ "OUTPUT": "#ffffff",
12
+ "ERROR": "#ff0000",
13
+ "RESULT": "#66ccff",
14
+ "SUGGESTION_BOX_BG": "#2d2d2d",
15
+ "SUGGESTION_BOX_SELECTION_BG": "#0066cc",
16
+ "FONT": {
17
+ "FONT": "Consolas",
18
+ "FONT_SIZE": 12
19
+ }
20
+ },
21
+ "Light": {
22
+ "APPEARANCE": "light",
23
+ "LEXER_STYLE": "friendly",
24
+ "BACKGROUND": "#ffffff",
25
+ "HIGHLIGHTED_BACKGROUND": "#cce6ff",
26
+ "FOREGROUND": "#000000",
27
+ "HIGHLIGHTED_FOREGROUND": "#000000",
28
+ "INSERTBACKGROUND": "#000000",
29
+ "PROMPT": "#008000",
30
+ "OUTPUT": "#000000",
31
+ "ERROR": "#ff0000",
32
+ "RESULT": "#0066cc",
33
+ "SUGGESTION_BOX_BG": "#f0f0f0",
34
+ "SUGGESTION_BOX_SELECTION_BG": "#cce6ff",
35
+ "FONT": {
36
+ "FONT": "Consolas",
37
+ "FONT_SIZE": 12
38
+ }
39
+ },
40
+ "Solarized": {
41
+ "APPEARANCE": "light",
42
+ "LEXER_STYLE": "solarized-light",
43
+ "BACKGROUND": "#fdf6e3",
44
+ "HIGHLIGHTED_BACKGROUND": "#b58900",
45
+ "FOREGROUND": "#657b83",
46
+ "HIGHLIGHTED_FOREGROUND": "#fdf6e3",
47
+ "INSERTBACKGROUND": "#657b83",
48
+ "PROMPT": "#268bd2",
49
+ "OUTPUT": "#586e75",
50
+ "ERROR": "#dc322f",
51
+ "RESULT": "#2aa198",
52
+ "SUGGESTION_BOX_BG": "#eee8d5",
53
+ "SUGGESTION_BOX_SELECTION_BG": "#b58900",
54
+ "FONT": {
55
+ "FONT": "Consolas",
56
+ "FONT_SIZE": 12
57
+ }
58
+ },
59
+ "Dracula": {
60
+ "APPEARANCE": "dark",
61
+ "LEXER_STYLE": "dracula",
62
+ "BACKGROUND": "#282a36",
63
+ "HIGHLIGHTED_BACKGROUND": "#44475a",
64
+ "FOREGROUND": "#f8f8f2",
65
+ "HIGHLIGHTED_FOREGROUND": "#ffffff",
66
+ "INSERTBACKGROUND": "#f8f8f2",
67
+ "PROMPT": "#50fa7b",
68
+ "OUTPUT": "#f8f8f2",
69
+ "ERROR": "#ff5555",
70
+ "RESULT": "#8be9fd",
71
+ "SUGGESTION_BOX_BG": "#44475a",
72
+ "SUGGESTION_BOX_SELECTION_BG": "#6272a4",
73
+ "FONT": {
74
+ "FONT": "Consolas",
75
+ "FONT_SIZE": 12
76
+ }
77
+ }
78
+ }
pysole/utils.py ADDED
@@ -0,0 +1,4 @@
1
+ import os
2
+
3
+ settingsPath = os.path.join(os.path.dirname(__file__), "settings.json")
4
+ themesPath = os.path.join(os.path.dirname(__file__), "themes.json")
__init__.py DELETED
File without changes
@@ -1,14 +0,0 @@
1
- __init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- commandHistory.py,sha256=xJtWbJ_vgJo2QGgaZJsApTOi_Hm8Yz0V9_zqQUCItj8,1084
3
- helpTab.py,sha256=5Fxj_wTNTbuF6sBIN8GdbE6i_zbAEdlrFnbfhnDk5ms,2360
4
- liveConsole.py,sha256=dqYaCvBs_aDfqrbhXYBp5vLkksmAiUv0DWwsbu1R3B4,167
5
- mainConsole.py,sha256=MxgJJihgbPtKZ8FqXSFczj5neRVGRiM8RX4lcm0ewk0,12973
6
- pysole.py,sha256=bkwnzm2BLZMOiA63cI27FLnXmcOMpDdZVCnfOgP-GoU,4018
7
- styledTextbox.py,sha256=pc-7gaq_pGTZGZmtr_ARbPuKlKgJYqzD6HTR7tFhx7k,1989
8
- suggestionManager.py,sha256=GRde3c1gFAWt_3rvBoFt_-Xl0aOzzloBMD7MHJA2W8U,6256
9
- liveconsole-1.5.3.dist-info/licenses/LICENSE,sha256=7dZ0zL72aGaFE0C9DxacOpnaSkC5jajhG6iL7lqhWmU,1064
10
- liveconsole-1.5.3.dist-info/METADATA,sha256=Ad_v6Vo0ZFdUU9WDUftPe7tHVggvslTi94RUeNZbd1k,3936
11
- liveconsole-1.5.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
- liveconsole-1.5.3.dist-info/entry_points.txt,sha256=qtvuJHcex4QqM97x_UawFWJYnfhQRl0jhqLcWRpnAGo,84
13
- liveconsole-1.5.3.dist-info/top_level.txt,sha256=yEmcEVam34LgZbQWtT6RdrdJVzsXwElx6Wpsn3eR2as,95
14
- liveconsole-1.5.3.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- __init__
2
- commandHistory
3
- helpTab
4
- liveConsole
5
- mainConsole
6
- pysole
7
- styledTextbox
8
- suggestionManager
pysole.py DELETED
@@ -1,126 +0,0 @@
1
- import customtkinter as ctk
2
- import inspect
3
- import sys
4
- import io
5
-
6
- from helpTab import HelpTab
7
- from mainConsole import InteractiveConsoleText
8
-
9
-
10
- class StdoutRedirect(io.StringIO):
11
- """Redirects stdout/stderr to a callback function."""
12
-
13
- def __init__(self, writeCallback):
14
- super().__init__()
15
- self.writeCallback = writeCallback
16
-
17
- def write(self, s):
18
- if s.strip():
19
- self.writeCallback(s, "output")
20
-
21
- def flush(self):
22
- pass
23
-
24
- class StdinRedirect(io.StringIO):
25
- """Redirects stdin to capture input() from the console."""
26
- def __init__(self, readCallback):
27
- super().__init__()
28
- self.readCallback = readCallback
29
-
30
- def readline(self, *args, **kwargs):
31
- return(self.readCallback())
32
-
33
-
34
- class InteractiveConsole(ctk.CTk):
35
- """Main console window application."""
36
-
37
- def __init__(self, userGlobals=None, userLocals=None, callerFrame=None):
38
- super().__init__()
39
-
40
- # Window setup
41
- self.title("Live Interactive Console")
42
- self.geometry("900x600")
43
-
44
- ctk.set_appearance_mode("dark")
45
- ctk.set_default_color_theme("blue")
46
-
47
- # Get namespace from caller if not provided
48
- if userGlobals is None or userLocals is None:
49
- if callerFrame == None:
50
- callerFrame = inspect.currentframe().f_back
51
- if userGlobals is None:
52
- userGlobals = callerFrame.f_globals
53
- if userLocals is None:
54
- userLocals = callerFrame.f_locals
55
-
56
- self.userGlobals = userGlobals
57
- self.userLocals = userLocals
58
-
59
- # Create UI
60
- self._createUi()
61
-
62
- # Redirect stdout/stderr
63
- self._setupOutputRedirect()
64
- self._setupInputRedirect()
65
-
66
- def _createUi(self):
67
- """Create UI with console and help tab."""
68
- frame = ctk.CTkFrame(self)
69
- frame.pack(padx=10, pady=10, fill="both", expand=True)
70
-
71
- # Horizontal frame
72
- self.horizFrame = ctk.CTkFrame(frame)
73
- self.horizFrame.pack(fill="both", expand=True)
74
-
75
- # Right: Help Tab
76
- self.helpTab = HelpTab(self.horizFrame, width=500)
77
-
78
- # Left: Console
79
- self.consoleFrame = ctk.CTkFrame(self.horizFrame, width=600)
80
- self.consoleFrame.pack(side="left", fill="both", expand=True)
81
- self.consoleFrame.pack_propagate(False) # prevent shrinking to fit contents
82
-
83
- self.console = InteractiveConsoleText(
84
- self.consoleFrame,
85
- self.helpTab,
86
- userGlobals=self.userGlobals,
87
- userLocals=self.userLocals,
88
- wrap="word",
89
- bg="#1e1e1e",
90
- fg="white",
91
- insertbackground="white",
92
- font=("Consolas", 12)
93
- )
94
- self.console.pack(fill="both", expand=True, padx=5, pady=5)
95
- self.console.master = self
96
-
97
-
98
- def _setupOutputRedirect(self):
99
- """Setup stdout/stderr redirection to console."""
100
- sys.stdout = StdoutRedirect(self.console.writeOutput)
101
- sys.stderr = StdoutRedirect(
102
- lambda text, tag: self.console.writeOutput(text, "error")
103
- )
104
-
105
- def _setupInputRedirect(self):
106
- """Setup stdin redirection to console."""
107
- sys.stdin = StdinRedirect(self.console.readInput)
108
-
109
- def probe(self, *args, **kwargs):
110
- """Start the console main loop."""
111
- self.mainloop(*args, **kwargs)
112
-
113
- def probe(userGlobals=None, userLocals=None, callerFrame=None):
114
- if callerFrame == None:
115
- callerFrame = inspect.currentframe().f_back
116
- InteractiveConsole(userGlobals=userGlobals,
117
- userLocals=userLocals,
118
- callerFrame=callerFrame).probe()
119
-
120
- def _standalone():
121
- import pysole
122
- pysole.probe(callerFrame=inspect.currentframe().f_back)
123
-
124
- # Example usage
125
- if __name__ == "__main__":
126
- _standalone()
File without changes