liveConsole 1.6.1__py3-none-any.whl → 1.7.0__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.
Potentially problematic release.
This version of liveConsole might be problematic. Click here for more details.
- {liveconsole-1.6.1.dist-info → liveconsole-1.7.0.dist-info}/METADATA +21 -1
- liveconsole-1.7.0.dist-info/RECORD +18 -0
- pysole/mainConsole.py +77 -26
- pysole/pysole.py +54 -14
- pysole/settings.json +1 -0
- pysole/styledTextbox.py +1 -0
- pysole/themes.json +4 -0
- pysole/utils.py +6 -0
- liveconsole-1.6.1.dist-info/RECORD +0 -18
- {liveconsole-1.6.1.dist-info → liveconsole-1.7.0.dist-info}/WHEEL +0 -0
- {liveconsole-1.6.1.dist-info → liveconsole-1.7.0.dist-info}/entry_points.txt +0 -0
- {liveconsole-1.6.1.dist-info → liveconsole-1.7.0.dist-info}/licenses/LICENSE +0 -0
- {liveconsole-1.6.1.dist-info → liveconsole-1.7.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: liveConsole
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.0
|
|
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
|
|
@@ -21,6 +21,8 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
|
|
|
21
21
|
* Python syntax highlighting via **Pygments**
|
|
22
22
|
|
|
23
23
|
* Autocomplete for **keywords, built-ins, and local/global variables**
|
|
24
|
+
|
|
25
|
+
* Run code at startup for easier debugging
|
|
24
26
|
|
|
25
27
|
* Thread-safe execution of Python code
|
|
26
28
|
|
|
@@ -52,6 +54,15 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
|
|
|
52
54
|
|
|
53
55
|
* Highlights Python keywords, built-ins, and expressions in the console.
|
|
54
56
|
|
|
57
|
+
### Run Code at Startup
|
|
58
|
+
|
|
59
|
+
* Pysole can automatically execute Python code when the console launches.
|
|
60
|
+
|
|
61
|
+
* Use the runRemainingCode=True argument in pysole.probe() to run all remaining lines in the calling script after the probe() call.
|
|
62
|
+
|
|
63
|
+
* The printStartupCode flag controls whether these lines are printed in the console as they execute (True) or run silently (False).
|
|
64
|
+
|
|
65
|
+
* Useful for initializing variables, importing libraries, or setting up your environment automatically.
|
|
55
66
|
|
|
56
67
|
### Autocomplete
|
|
57
68
|
|
|
@@ -110,6 +121,15 @@ A fully-featured, **live Python console GUI** built with **CustomTkinter** and *
|
|
|
110
121
|
import pysole
|
|
111
122
|
pysole.probe()
|
|
112
123
|
```
|
|
124
|
+
or for also running some code at the startup of the pysole
|
|
125
|
+
```
|
|
126
|
+
import pysole
|
|
127
|
+
pysole.probe(runRemainingCode=True, #< for executing the code below probe
|
|
128
|
+
printStartupCode=True #< for printing the command as well as it output
|
|
129
|
+
)
|
|
130
|
+
x = 1 #< initialize some variable
|
|
131
|
+
print(x) #< print the variable on the console
|
|
132
|
+
```
|
|
113
133
|
|
|
114
134
|
* Type Python commands in the `>>>` prompt and see live output.
|
|
115
135
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
liveconsole-1.7.0.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=AzAUSP5W1jUhYnnGUNOG8LUGPkRW8jOqOHlk-pJC_V4,15053
|
|
8
|
+
pysole/pysole.py,sha256=klQHCIRTE9uAIRA2DqUEtOh0521ht-g2KswA50Nw0no,10923
|
|
9
|
+
pysole/settings.json,sha256=oFguWetRe_vGXUrqWSFUvY3JmGIArUZYpSiA8YZgRU8,722
|
|
10
|
+
pysole/styledTextbox.py,sha256=qWnwGAKjl7R2HYPXQOr8GrGYIr4JC8PzmeioOCH7hGo,2236
|
|
11
|
+
pysole/suggestionManager.py,sha256=EUFeCQoZnLS8EjPPNuZpzjY0BR07m2KP5TloyaMDVGY,6457
|
|
12
|
+
pysole/themes.json,sha256=wv56r5XOV-ao7dY4_5Yjsio9VvJ58vHOI9nT7MEbXKY,2525
|
|
13
|
+
pysole/utils.py,sha256=-mGHAp0MkbMPQ9eYzPmo5AGHDLuQ9NfPio_2_iaiCuY,294
|
|
14
|
+
liveconsole-1.7.0.dist-info/METADATA,sha256=4-QotGWSs2WNGUrb-PGLm2e1ZR2mHEkEMpO-s62guxI,4955
|
|
15
|
+
liveconsole-1.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
16
|
+
liveconsole-1.7.0.dist-info/entry_points.txt,sha256=qtvuJHcex4QqM97x_UawFWJYnfhQRl0jhqLcWRpnAGo,84
|
|
17
|
+
liveconsole-1.7.0.dist-info/top_level.txt,sha256=DlpA93ScJbRZcF8kGSc5YoO8Ntu1ib1_MEZMb4xea_Q,7
|
|
18
|
+
liveconsole-1.7.0.dist-info/RECORD,,
|
pysole/mainConsole.py
CHANGED
|
@@ -3,6 +3,7 @@ import traceback
|
|
|
3
3
|
from .suggestionManager import CodeSuggestionManager
|
|
4
4
|
from .commandHistory import CommandHistory
|
|
5
5
|
from .styledTextbox import StyledTextWindow
|
|
6
|
+
from .utils import stdPrint
|
|
6
7
|
|
|
7
8
|
import tkinter as tk
|
|
8
9
|
|
|
@@ -11,26 +12,27 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
11
12
|
def __init__(self, master, helpTab, theme, font, behavior, userLocals=None, userGlobals=None, **kwargs):
|
|
12
13
|
super().__init__(master, theme=theme, font=font, **kwargs)
|
|
13
14
|
self.font=(font["FONT"], font["FONT_SIZE"])
|
|
14
|
-
|
|
15
|
+
|
|
15
16
|
# Initialize components
|
|
16
17
|
self.PROMPT = behavior["PRIMARY_PROMPT"]
|
|
17
18
|
self.PROMPT_LENGTH = len(self.PROMPT)
|
|
18
19
|
self.suggestionManager = CodeSuggestionManager(self, userLocals=userLocals, userGlobals=userGlobals, theme=theme, font=font)
|
|
19
20
|
self.helpTab = helpTab
|
|
20
|
-
|
|
21
|
+
|
|
21
22
|
self.navigatingHistory = False
|
|
22
23
|
self.history = CommandHistory()
|
|
23
|
-
|
|
24
|
+
|
|
24
25
|
self.inputVar = tk.StringVar()
|
|
25
26
|
self.waitingForInput = False
|
|
27
|
+
self.inputLine = "1.0"
|
|
26
28
|
|
|
27
29
|
# Track current command
|
|
28
30
|
self.currentCommandLine = 1
|
|
29
31
|
self.isExecuting = False
|
|
30
|
-
|
|
32
|
+
|
|
31
33
|
# Setup bindings
|
|
32
34
|
self._setupBindings()
|
|
33
|
-
|
|
35
|
+
|
|
34
36
|
# Initialize with first prompt
|
|
35
37
|
self.addPrompt()
|
|
36
38
|
|
|
@@ -41,6 +43,7 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
41
43
|
self.bind("<Control-c>", self.cancel)
|
|
42
44
|
self.bind("<Tab>", self.onTab)
|
|
43
45
|
self.bind("<BackSpace>", self.onBackspace)
|
|
46
|
+
self.bind("<Delete>", self.onDelete)
|
|
44
47
|
self.bind("<KeyRelease>", self.onKeyRelease)
|
|
45
48
|
self.bind("<KeyPress>", self.onKeyPress)
|
|
46
49
|
self.bind("<Button-1>", self.onClick)
|
|
@@ -50,11 +53,14 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
50
53
|
def getCurrentLineNumber(self):
|
|
51
54
|
"""Get the line number where current command starts."""
|
|
52
55
|
return(int(self.index("end-1c").split(".")[0]))
|
|
53
|
-
|
|
56
|
+
|
|
57
|
+
def resetCurrentLineNumber(self):
|
|
58
|
+
self.currentCommandLine = self.getCurrentLineNumber()
|
|
59
|
+
|
|
54
60
|
def getCommandStartPosition(self):
|
|
55
61
|
"""Get the starting position of the current command."""
|
|
56
62
|
return(f"{self.currentCommandLine}.0")
|
|
57
|
-
|
|
63
|
+
|
|
58
64
|
def replaceCurrentCommand(self, newCommand):
|
|
59
65
|
"""Replace the current command with new text."""
|
|
60
66
|
if self.isExecuting:
|
|
@@ -64,9 +70,23 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
64
70
|
end = "end-1c"
|
|
65
71
|
|
|
66
72
|
self.delete(start, end)
|
|
67
|
-
|
|
73
|
+
if newCommand:
|
|
74
|
+
self.insert(start, newCommand)
|
|
75
|
+
self.mark_set("insert", "end")
|
|
68
76
|
self.see("end")
|
|
69
|
-
|
|
77
|
+
# Ensure styling/lexer applied after programmatic change:
|
|
78
|
+
self.updateStyling(start=self.getPromptPosition())
|
|
79
|
+
|
|
80
|
+
def runCommand(self, command, printCommand=False):
|
|
81
|
+
"""Insert code into the console prompt and execute it as if Enter was pressed."""
|
|
82
|
+
if self.isExecuting:
|
|
83
|
+
return(False)
|
|
84
|
+
if printCommand:
|
|
85
|
+
self.replaceCurrentCommand(command) #< Replace current command with the new code
|
|
86
|
+
self.onEnter(None) #< Simulate pressing Enter to run the command
|
|
87
|
+
else:
|
|
88
|
+
self.executeCommandThreaded(command, addPrompt=False)
|
|
89
|
+
|
|
70
90
|
def isCursorInEditableArea(self):
|
|
71
91
|
"""Check if cursor is in the editable command area."""
|
|
72
92
|
if self.isExecuting:
|
|
@@ -88,25 +108,26 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
88
108
|
self.inputVar.set(line)
|
|
89
109
|
self.waitingForInput = False
|
|
90
110
|
return("break")
|
|
91
|
-
|
|
111
|
+
|
|
92
112
|
if self.isExecuting:
|
|
93
113
|
return("break")
|
|
94
|
-
|
|
114
|
+
|
|
95
115
|
command = self.getCurrentCommand()
|
|
96
|
-
|
|
116
|
+
# print(command)
|
|
117
|
+
|
|
97
118
|
if not command.strip():
|
|
98
119
|
return("break")
|
|
99
|
-
|
|
120
|
+
|
|
100
121
|
# Check if statement is incomplete
|
|
101
122
|
if self.isIncompleteStatement(command):
|
|
102
123
|
return(self.onShiftEnter(event))
|
|
103
|
-
|
|
124
|
+
|
|
104
125
|
# Execute the command
|
|
105
126
|
self.history.add(command)
|
|
106
127
|
self.mark_set("insert", "end")
|
|
107
128
|
self.insert("end", "\n")
|
|
108
129
|
self.see("end")
|
|
109
|
-
|
|
130
|
+
|
|
110
131
|
# Execute in thread
|
|
111
132
|
self.isExecuting = True
|
|
112
133
|
threading.Thread(
|
|
@@ -114,16 +135,17 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
114
135
|
args=(command,),
|
|
115
136
|
daemon=True
|
|
116
137
|
).start()
|
|
117
|
-
|
|
138
|
+
|
|
118
139
|
return("break")
|
|
119
140
|
|
|
120
141
|
def readInput(self):
|
|
121
142
|
"""Return the last entered line when input() is called."""
|
|
122
143
|
self.waitingForInput = True
|
|
144
|
+
self.inputLine = self.index("end -1c")
|
|
123
145
|
self.wait_variable(self.inputVar) #< waits until Enter is pressed
|
|
124
146
|
line = self.inputVar.get()
|
|
125
147
|
self.inputVar.set("") #< reset
|
|
126
|
-
return(line)
|
|
148
|
+
return(line or "\n")
|
|
127
149
|
|
|
128
150
|
def onShiftEnter(self, event):
|
|
129
151
|
"""Handle Shift+Enter - new line with auto-indent."""
|
|
@@ -162,15 +184,35 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
162
184
|
|
|
163
185
|
def onBackspace(self, event):
|
|
164
186
|
"""Prevent backspace from deleting the prompt."""
|
|
187
|
+
|
|
188
|
+
if self.waitingForInput: #< During input mode, only allow editing after input start
|
|
189
|
+
if self.compare("insert", "<=", self.inputLine):
|
|
190
|
+
return "break"
|
|
191
|
+
return None
|
|
192
|
+
|
|
165
193
|
if not self.isCursorInEditableArea():
|
|
166
|
-
return
|
|
194
|
+
return "break"
|
|
167
195
|
|
|
168
196
|
# Check if we're at the prompt boundary
|
|
169
197
|
cursorPos = self.index("insert")
|
|
170
198
|
promptPos = self.getPromptPosition()
|
|
171
199
|
|
|
172
200
|
if self.compare(cursorPos, "<=", promptPos):
|
|
201
|
+
return "break"
|
|
202
|
+
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
def onDelete(self, event):
|
|
206
|
+
"""Prevent delete from deleting protected content."""
|
|
207
|
+
if self.waitingForInput: #< During input mode, only allow editing after input start
|
|
208
|
+
if self.compare("insert", "<=", self.inputLine):
|
|
209
|
+
return("break")
|
|
210
|
+
return(None)
|
|
211
|
+
|
|
212
|
+
if not self.isCursorInEditableArea():
|
|
173
213
|
return("break")
|
|
214
|
+
|
|
215
|
+
return(None)
|
|
174
216
|
|
|
175
217
|
def onClick(self, event):
|
|
176
218
|
"""Handle mouse clicks - Ctrl+Click opens help for the clicked word."""
|
|
@@ -206,7 +248,11 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
206
248
|
|
|
207
249
|
def onKeyPress(self, event):
|
|
208
250
|
"""Handle key press events."""
|
|
209
|
-
|
|
251
|
+
if self.waitingForInput: #< During input mode, only allow editing after input start
|
|
252
|
+
if (self.compare("insert", "<=", self.inputLine) and event.keysym == "Left"):
|
|
253
|
+
return("break")
|
|
254
|
+
return(None)
|
|
255
|
+
|
|
210
256
|
if self.suggestionManager.suggestionWindow and \
|
|
211
257
|
self.suggestionManager.suggestionWindow.winfo_viewable():
|
|
212
258
|
if event.keysym == "Escape":
|
|
@@ -293,13 +339,17 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
293
339
|
|
|
294
340
|
return(currentIndent)
|
|
295
341
|
|
|
296
|
-
def writeOutput(self, text, tag="output"):
|
|
342
|
+
def writeOutput(self, text, tag="output", loc="end"):
|
|
297
343
|
"""Write output to the console (thread-safe)."""
|
|
298
344
|
def _write():
|
|
299
|
-
self.insert(
|
|
345
|
+
self.insert(loc, text + "\n", tag)
|
|
300
346
|
self.see("end")
|
|
301
347
|
|
|
302
348
|
self.after(0, _write)
|
|
349
|
+
|
|
350
|
+
def newline(self):
|
|
351
|
+
"""Insert a newline at the end."""
|
|
352
|
+
self.writeOutput("")
|
|
303
353
|
|
|
304
354
|
def getPromptPosition(self):
|
|
305
355
|
"""Get the position right after the prompt on current command line."""
|
|
@@ -326,16 +376,15 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
326
376
|
self.mark_set("insert", "end")
|
|
327
377
|
self.see("end")
|
|
328
378
|
self.isExecuting = False
|
|
329
|
-
|
|
379
|
+
|
|
330
380
|
if self.isExecuting:
|
|
331
381
|
self.after(0, _add)
|
|
332
382
|
else:
|
|
333
383
|
_add()
|
|
334
384
|
|
|
335
|
-
def executeCommandThreaded(self, command):
|
|
385
|
+
def executeCommandThreaded(self, command, addPrompt=True):
|
|
336
386
|
"""Execute a command in a separate thread."""
|
|
337
387
|
try:
|
|
338
|
-
# Try eval first for expressions
|
|
339
388
|
result = eval(command, self.master.userGlobals, self.master.userLocals)
|
|
340
389
|
if result is not None:
|
|
341
390
|
self.writeOutput(str(result), "result")
|
|
@@ -349,5 +398,7 @@ class InteractiveConsoleText(StyledTextWindow):
|
|
|
349
398
|
except Exception:
|
|
350
399
|
self.writeOutput(traceback.format_exc(), "error")
|
|
351
400
|
|
|
352
|
-
|
|
353
|
-
|
|
401
|
+
if addPrompt:
|
|
402
|
+
self.addPrompt()
|
|
403
|
+
else:
|
|
404
|
+
self.isExecuting = False
|
pysole/pysole.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
import time
|
|
1
3
|
import customtkinter as ctk
|
|
2
4
|
import tkinter as tk
|
|
3
5
|
from tkinter import messagebox
|
|
@@ -6,7 +8,7 @@ import sys
|
|
|
6
8
|
import io
|
|
7
9
|
import json
|
|
8
10
|
|
|
9
|
-
from .utils import settingsPath, themesPath
|
|
11
|
+
from .utils import settingsPath, themesPath, stdPrint
|
|
10
12
|
from .helpTab import HelpTab
|
|
11
13
|
from .mainConsole import InteractiveConsoleText
|
|
12
14
|
|
|
@@ -35,15 +37,17 @@ class StdinRedirect(io.StringIO):
|
|
|
35
37
|
|
|
36
38
|
class InteractiveConsole(ctk.CTk):
|
|
37
39
|
"""Main console window application."""
|
|
38
|
-
|
|
39
|
-
def __init__(self, userGlobals=None, userLocals=None, callerFrame=None,
|
|
40
|
+
|
|
41
|
+
def __init__(self, userGlobals=None, userLocals=None, callerFrame=None,
|
|
42
|
+
defaultSize=None, primaryPrompt=None,
|
|
43
|
+
runRemainingCode=False, printStartupCode=True):
|
|
40
44
|
super().__init__()
|
|
41
45
|
with open(settingsPath, "r") as f:
|
|
42
46
|
settings = json.load(f)
|
|
43
47
|
self.THEME = settings["THEME"]
|
|
44
48
|
self.FONT = self.THEME["FONT"]
|
|
45
49
|
self.BEHAVIOR = settings["BEHAVIOR"]
|
|
46
|
-
|
|
50
|
+
|
|
47
51
|
if primaryPrompt != None:
|
|
48
52
|
self.BEHAVIOR["PRIMARY_PROMPT"] = primaryPrompt
|
|
49
53
|
if defaultSize != None:
|
|
@@ -51,7 +55,7 @@ class InteractiveConsole(ctk.CTk):
|
|
|
51
55
|
|
|
52
56
|
self.title("Live Interactive Console")
|
|
53
57
|
self.geometry(self.BEHAVIOR["DEFAULT_SIZE"])
|
|
54
|
-
|
|
58
|
+
|
|
55
59
|
ctk.set_appearance_mode(self.THEME["APPEARANCE"])
|
|
56
60
|
ctk.set_default_color_theme("blue")
|
|
57
61
|
|
|
@@ -63,17 +67,30 @@ class InteractiveConsole(ctk.CTk):
|
|
|
63
67
|
userGlobals = callerFrame.f_globals
|
|
64
68
|
if userLocals is None:
|
|
65
69
|
userLocals = callerFrame.f_locals
|
|
66
|
-
|
|
70
|
+
|
|
67
71
|
self.userGlobals = userGlobals
|
|
68
72
|
self.userLocals = userLocals
|
|
69
|
-
|
|
73
|
+
|
|
70
74
|
# Create UI
|
|
71
75
|
self._createMenu()
|
|
72
76
|
self._createUi()
|
|
73
|
-
|
|
77
|
+
|
|
74
78
|
# Redirect stdout/stderr
|
|
75
79
|
self._setupOutputRedirect()
|
|
76
80
|
self._setupInputRedirect()
|
|
81
|
+
|
|
82
|
+
self.printStartupCode = printStartupCode
|
|
83
|
+
self.startupCode = ()
|
|
84
|
+
if runRemainingCode:
|
|
85
|
+
code_obj = callerFrame.f_code
|
|
86
|
+
filename = code_obj.co_filename
|
|
87
|
+
|
|
88
|
+
# Read the rest of the file after the call to probe()
|
|
89
|
+
with open(filename, "r", encoding="utf-8") as f:
|
|
90
|
+
lines = f.readlines()
|
|
91
|
+
|
|
92
|
+
startLine = callerFrame.f_lineno
|
|
93
|
+
self.startupCode = lines[startLine:]
|
|
77
94
|
|
|
78
95
|
def _createMenu(self):
|
|
79
96
|
"""Create a menu bar using CTkOptionMenu."""
|
|
@@ -99,7 +116,7 @@ class InteractiveConsole(ctk.CTk):
|
|
|
99
116
|
self._editSettings()
|
|
100
117
|
elif choice == "Load Theme":
|
|
101
118
|
self._loadTheme()
|
|
102
|
-
|
|
119
|
+
|
|
103
120
|
def _loadTheme(self):
|
|
104
121
|
"""
|
|
105
122
|
Open a CTk popup to let the user choose a theme from themes.json.
|
|
@@ -218,28 +235,51 @@ class InteractiveConsole(ctk.CTk):
|
|
|
218
235
|
self.console.pack(fill="both", expand=True, padx=5, pady=5)
|
|
219
236
|
self.console.master = self
|
|
220
237
|
|
|
221
|
-
|
|
222
238
|
def _setupOutputRedirect(self):
|
|
223
239
|
"""Setup stdout/stderr redirection to console."""
|
|
224
240
|
sys.stdout = StdoutRedirect(self.console.writeOutput)
|
|
225
241
|
sys.stderr = StdoutRedirect(
|
|
226
|
-
lambda text, tag: self.console.writeOutput(text, "error")
|
|
242
|
+
lambda text, tag: self.console.writeOutput(text, "error", "end")
|
|
227
243
|
)
|
|
228
244
|
|
|
229
245
|
def _setupInputRedirect(self):
|
|
230
246
|
"""Setup stdin redirection to console."""
|
|
231
247
|
sys.stdin = StdinRedirect(self.console.readInput)
|
|
232
|
-
|
|
248
|
+
|
|
249
|
+
def onClose(self):
|
|
250
|
+
sys.stdout = sys.__stdout__
|
|
251
|
+
sys.stderr = sys.__stderr__
|
|
252
|
+
self.destroy()
|
|
253
|
+
|
|
233
254
|
def probe(self, *args, **kwargs):
|
|
234
255
|
"""Start the console main loop."""
|
|
256
|
+
def runStartup():
|
|
257
|
+
self.console.newline()
|
|
258
|
+
self.console.writeOutput("Welcome to Pysole, if you find me useful, please star me on github:\nhttps://github.com/TzurSoffer/Pysole", "instruction")
|
|
259
|
+
for line in self.startupCode:
|
|
260
|
+
line = line.rstrip()
|
|
261
|
+
while self.console.isExecuting:
|
|
262
|
+
time.sleep(0.01)
|
|
263
|
+
if self.printStartupCode:
|
|
264
|
+
self.console.runCommand(line, printCommand=True)
|
|
265
|
+
else:
|
|
266
|
+
self.console.runCommand(line, printCommand=False)
|
|
267
|
+
|
|
268
|
+
if self.printStartupCode == False:
|
|
269
|
+
self.console.resetCurrentLineNumber()
|
|
270
|
+
self.console.addPrompt()
|
|
271
|
+
threading.Thread(target=runStartup).start()
|
|
235
272
|
self.mainloop(*args, **kwargs)
|
|
236
273
|
|
|
237
|
-
def probe(userGlobals=None, userLocals=None, callerFrame=None):
|
|
274
|
+
def probe(userGlobals=None, userLocals=None, callerFrame=None, runRemainingCode=False, printStartupCode=False, **kwargs):
|
|
238
275
|
if callerFrame == None:
|
|
239
276
|
callerFrame = inspect.currentframe().f_back
|
|
240
277
|
InteractiveConsole(userGlobals=userGlobals,
|
|
241
278
|
userLocals=userLocals,
|
|
242
|
-
callerFrame=callerFrame
|
|
279
|
+
callerFrame=callerFrame,
|
|
280
|
+
runRemainingCode=runRemainingCode,
|
|
281
|
+
printStartupCode=printStartupCode,
|
|
282
|
+
**kwargs).probe()
|
|
243
283
|
|
|
244
284
|
def _standalone():
|
|
245
285
|
import pysole
|
pysole/settings.json
CHANGED
pysole/styledTextbox.py
CHANGED
|
@@ -19,6 +19,7 @@ class StyledTextWindow(tk.Text):
|
|
|
19
19
|
self.tag_configure("output", foreground=theme["OUTPUT"], font=(font["FONT"], font["FONT_SIZE"]))
|
|
20
20
|
self.tag_configure("error", foreground=theme["ERROR"], font=(font["FONT"], font["FONT_SIZE"]))
|
|
21
21
|
self.tag_configure("result", foreground=theme["RESULT"], font=(font["FONT"], font["FONT_SIZE"]))
|
|
22
|
+
self.tag_configure("instruction", foreground=theme["INSTRUCTION"], font=(font["FONT"], font["FONT_SIZE"]))
|
|
22
23
|
|
|
23
24
|
# Configure syntax highlighting tags
|
|
24
25
|
for token, style in self.style:
|
pysole/themes.json
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"OUTPUT": "#ffffff",
|
|
12
12
|
"ERROR": "#ff0000",
|
|
13
13
|
"RESULT": "#66ccff",
|
|
14
|
+
"INSTRUCTION": "#ffff00",
|
|
14
15
|
"SUGGESTION_BOX_BG": "#2d2d2d",
|
|
15
16
|
"SUGGESTION_BOX_SELECTION_BG": "#0066cc",
|
|
16
17
|
"FONT": {
|
|
@@ -30,6 +31,7 @@
|
|
|
30
31
|
"OUTPUT": "#000000",
|
|
31
32
|
"ERROR": "#ff0000",
|
|
32
33
|
"RESULT": "#0066cc",
|
|
34
|
+
"INSTRUCTION": "#ffff00",
|
|
33
35
|
"SUGGESTION_BOX_BG": "#f0f0f0",
|
|
34
36
|
"SUGGESTION_BOX_SELECTION_BG": "#cce6ff",
|
|
35
37
|
"FONT": {
|
|
@@ -49,6 +51,7 @@
|
|
|
49
51
|
"OUTPUT": "#586e75",
|
|
50
52
|
"ERROR": "#dc322f",
|
|
51
53
|
"RESULT": "#2aa198",
|
|
54
|
+
"INSTRUCTION": "#ffff00",
|
|
52
55
|
"SUGGESTION_BOX_BG": "#eee8d5",
|
|
53
56
|
"SUGGESTION_BOX_SELECTION_BG": "#b58900",
|
|
54
57
|
"FONT": {
|
|
@@ -68,6 +71,7 @@
|
|
|
68
71
|
"OUTPUT": "#f8f8f2",
|
|
69
72
|
"ERROR": "#ff5555",
|
|
70
73
|
"RESULT": "#8be9fd",
|
|
74
|
+
"INSTRUCTION": "#ffff00",
|
|
71
75
|
"SUGGESTION_BOX_BG": "#44475a",
|
|
72
76
|
"SUGGESTION_BOX_SELECTION_BG": "#6272a4",
|
|
73
77
|
"FONT": {
|
pysole/utils.py
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import sys
|
|
2
3
|
|
|
3
4
|
settingsPath = os.path.join(os.path.dirname(__file__), "settings.json")
|
|
4
5
|
themesPath = os.path.join(os.path.dirname(__file__), "themes.json")
|
|
6
|
+
|
|
7
|
+
def stdPrint(text):
|
|
8
|
+
"""Print text to the terminal."""
|
|
9
|
+
sys.__stdout__.write(f"{text}\n")
|
|
10
|
+
sys.__stdout__.flush()
|
|
@@ -1,18 +0,0 @@
|
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|