liveConsole 1.4.0__py3-none-any.whl → 1.5.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.
- __init__.py +1 -0
- commandHistory.py +34 -0
- helpTab.py +64 -0
- liveConsole.py +8 -752
- {liveconsole-1.4.0.dist-info → liveconsole-1.5.0.dist-info}/METADATA +20 -5
- liveconsole-1.5.0.dist-info/RECORD +14 -0
- liveconsole-1.5.0.dist-info/entry_points.txt +2 -0
- liveconsole-1.5.0.dist-info/top_level.txt +8 -0
- mainConsole.py +354 -0
- pysole.py +132 -0
- styledTextbox.py +51 -0
- suggestionManager.py +165 -0
- liveconsole-1.4.0.dist-info/RECORD +0 -7
- liveconsole-1.4.0.dist-info/top_level.txt +0 -2
- {liveconsole-1.4.0.dist-info → liveconsole-1.5.0.dist-info}/WHEEL +0 -0
- {liveconsole-1.4.0.dist-info → liveconsole-1.5.0.dist-info}/licenses/LICENSE +0 -0
suggestionManager.py
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
import keyword
|
2
|
+
import builtins
|
3
|
+
import tkinter as tk
|
4
|
+
|
5
|
+
class CodeSuggestionManager:
|
6
|
+
"""Manages code suggestions and autocomplete functionality."""
|
7
|
+
|
8
|
+
def __init__(self, textWidget, userLocals, userGlobals):
|
9
|
+
self.userLocals = userLocals
|
10
|
+
self.userGlobals = userGlobals
|
11
|
+
self.textWidget = textWidget
|
12
|
+
self.suggestionWindow = None
|
13
|
+
self.suggestionListbox = None
|
14
|
+
self.suggestions = []
|
15
|
+
self.selectedSuggestion = 0
|
16
|
+
|
17
|
+
# Build suggestion sources
|
18
|
+
self.keywords = keyword.kwlist
|
19
|
+
self.builtins = [name for name in dir(builtins) if not name.startswith('_')]
|
20
|
+
|
21
|
+
def getCurrentWord(self):
|
22
|
+
"""Extract the word being typed at cursor position and suggest dir() if applicable."""
|
23
|
+
suggestions = []
|
24
|
+
cursorPos = self.textWidget.index(tk.INSERT)
|
25
|
+
lineStart = self.textWidget.index(f"{cursorPos} linestart")
|
26
|
+
currentLine = self.textWidget.get(lineStart, cursorPos)
|
27
|
+
|
28
|
+
# Find the current word
|
29
|
+
words = currentLine.split()
|
30
|
+
if not words:
|
31
|
+
return("", suggestions)
|
32
|
+
|
33
|
+
currentWord = words[-1]
|
34
|
+
|
35
|
+
|
36
|
+
# If the word contains a dot, try to evaluate the base and get its dir()
|
37
|
+
if '.' in currentWord:
|
38
|
+
try:
|
39
|
+
base_expr = '.'.join(currentWord.split('.')[:-1])
|
40
|
+
obj = eval(base_expr, self.userLocals, self.userGlobals)
|
41
|
+
suggestions = dir(obj)
|
42
|
+
except:
|
43
|
+
pass
|
44
|
+
for char in "([{,.":
|
45
|
+
if char in currentWord:
|
46
|
+
currentWord = currentWord.split(char)[-1]
|
47
|
+
|
48
|
+
return(currentWord, suggestions)
|
49
|
+
|
50
|
+
def getSuggestions(self, partialWord, suggestions=[]):
|
51
|
+
"""Get code suggestions for partial word."""
|
52
|
+
if len(partialWord) < 2:
|
53
|
+
return(suggestions)
|
54
|
+
|
55
|
+
if suggestions != []:
|
56
|
+
suggestions = [suggestion for suggestion in suggestions if suggestion.lower().startswith(partialWord.lower())]
|
57
|
+
else:
|
58
|
+
# Add matching keywords
|
59
|
+
for kw in self.keywords:
|
60
|
+
if kw.startswith(partialWord.lower()):
|
61
|
+
suggestions.append(kw)
|
62
|
+
|
63
|
+
# Add matching builtins
|
64
|
+
for builtin in self.builtins:
|
65
|
+
if builtin.startswith(partialWord):
|
66
|
+
suggestions.append(builtin)
|
67
|
+
|
68
|
+
# Add matching variables from namespace
|
69
|
+
master = self.textWidget.master
|
70
|
+
if hasattr(master, 'userLocals'):
|
71
|
+
for var in master.userLocals:
|
72
|
+
if var.startswith(partialWord) and not var.startswith('_'):
|
73
|
+
suggestions.append(var)
|
74
|
+
|
75
|
+
if hasattr(master, 'userGlobals'):
|
76
|
+
for var in master.userGlobals:
|
77
|
+
if var.startswith(partialWord) and not var.startswith('_'):
|
78
|
+
suggestions.append(var)
|
79
|
+
|
80
|
+
# Remove duplicates and sort
|
81
|
+
return(sorted(list(set(suggestions))))
|
82
|
+
|
83
|
+
def showSuggestions(self):
|
84
|
+
"""Display the suggestions popup."""
|
85
|
+
currentWord, extraSuggestions = self.getCurrentWord()
|
86
|
+
suggestions = self.getSuggestions(currentWord, extraSuggestions)
|
87
|
+
|
88
|
+
if not suggestions:
|
89
|
+
self.hideSuggestions()
|
90
|
+
return
|
91
|
+
|
92
|
+
self.suggestions = suggestions
|
93
|
+
self.selectedSuggestion = 0
|
94
|
+
|
95
|
+
# Create suggestion window if needed
|
96
|
+
if not self.suggestionWindow:
|
97
|
+
self._createSuggestionWindow()
|
98
|
+
|
99
|
+
# Update listbox content
|
100
|
+
self.suggestionListbox.delete(0, tk.END)
|
101
|
+
for suggestion in suggestions:
|
102
|
+
self.suggestionListbox.insert(tk.END, suggestion)
|
103
|
+
|
104
|
+
self.suggestionListbox.selection_set(0)
|
105
|
+
|
106
|
+
# Position window near cursor
|
107
|
+
self._positionSuggestionWindow()
|
108
|
+
self.suggestionWindow.deiconify()
|
109
|
+
|
110
|
+
def _createSuggestionWindow(self):
|
111
|
+
"""Create the suggestion popup window."""
|
112
|
+
self.suggestionWindow = tk.Toplevel(self.textWidget)
|
113
|
+
self.suggestionWindow.wm_overrideredirect(True)
|
114
|
+
self.suggestionWindow.configure(bg="#2d2d2d")
|
115
|
+
|
116
|
+
self.suggestionListbox = tk.Listbox(
|
117
|
+
self.suggestionWindow,
|
118
|
+
bg="#2d2d2d",
|
119
|
+
fg="white",
|
120
|
+
selectbackground="#0066cc",
|
121
|
+
font=("Consolas", 10),
|
122
|
+
height=8
|
123
|
+
)
|
124
|
+
self.suggestionListbox.pack()
|
125
|
+
|
126
|
+
def _positionSuggestionWindow(self):
|
127
|
+
"""Position the suggestion window near the cursor."""
|
128
|
+
cursorPos = self.textWidget.index(tk.INSERT)
|
129
|
+
x, y, _, _ = self.textWidget.bbox(cursorPos)
|
130
|
+
x += self.textWidget.winfo_rootx()
|
131
|
+
y += self.textWidget.winfo_rooty() + 20
|
132
|
+
self.suggestionWindow.geometry(f"+{x}+{y}")
|
133
|
+
|
134
|
+
def hideSuggestions(self):
|
135
|
+
"""Hide the suggestions popup."""
|
136
|
+
if self.suggestionWindow:
|
137
|
+
self.suggestionWindow.withdraw()
|
138
|
+
|
139
|
+
def applySuggestion(self, suggestion=None):
|
140
|
+
"""Apply the selected suggestion at cursor position."""
|
141
|
+
if not suggestion and self.suggestions:
|
142
|
+
suggestion = self.suggestions[self.selectedSuggestion]
|
143
|
+
if not suggestion:
|
144
|
+
return
|
145
|
+
|
146
|
+
currentWord, _ = self.getCurrentWord()
|
147
|
+
# Only insert the missing part
|
148
|
+
missingPart = suggestion[len(currentWord):]
|
149
|
+
cursorPos = self.textWidget.index(tk.INSERT)
|
150
|
+
self.textWidget.insert(cursorPos, missingPart)
|
151
|
+
|
152
|
+
self.hideSuggestions()
|
153
|
+
|
154
|
+
def handleNavigation(self, direction):
|
155
|
+
"""Handle up/down navigation in suggestions."""
|
156
|
+
if not self.suggestions:
|
157
|
+
return
|
158
|
+
|
159
|
+
if direction == "down":
|
160
|
+
self.selectedSuggestion = min(self.selectedSuggestion + 1, len(self.suggestions) - 1)
|
161
|
+
else: # up
|
162
|
+
self.selectedSuggestion = max(self.selectedSuggestion - 1, 0)
|
163
|
+
|
164
|
+
self.suggestionListbox.selection_clear(0, tk.END)
|
165
|
+
self.suggestionListbox.selection_set(self.selectedSuggestion)
|
@@ -1,7 +0,0 @@
|
|
1
|
-
__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
liveConsole.py,sha256=2O7tq06LWI8lfb0KaLR_pYEEHG5x591_tiN4hNgHc9I,26891
|
3
|
-
liveconsole-1.4.0.dist-info/licenses/LICENSE,sha256=7dZ0zL72aGaFE0C9DxacOpnaSkC5jajhG6iL7lqhWmU,1064
|
4
|
-
liveconsole-1.4.0.dist-info/METADATA,sha256=LgLUoeKAQokjvsQmeUKHGXK_jTSM85xRM73JJ441m70,3252
|
5
|
-
liveconsole-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
6
|
-
liveconsole-1.4.0.dist-info/top_level.txt,sha256=0gva5OCe9lWcj5T88SwGimDDbqsdVqIGQNs98NBH1K0,21
|
7
|
-
liveconsole-1.4.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|