spiceditor 0.0.4__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 spiceditor might be problematic. Click here for more details.

Files changed (51) hide show
  1. pyspice/__init__.py +0 -0
  2. pyspice/dialogs.py +103 -0
  3. pyspice/editor_widget.py +196 -0
  4. pyspice/file_browser.py +143 -0
  5. pyspice/highlighter.py +74 -0
  6. pyspice/line_number_text_edit.py +54 -0
  7. pyspice/magic_scrollbar.py +11 -0
  8. pyspice/main.py +435 -0
  9. pyspice/resources.py +1120 -0
  10. pyspice/spice_console.py +282 -0
  11. pyspice/spice_magic_editor.py +389 -0
  12. pyspice/splitter.py +118 -0
  13. pyspice/term.py +63 -0
  14. pyspice/textract.py +597 -0
  15. pyspice/utils.py +33 -0
  16. spiceditor/__init__.py +0 -0
  17. spiceditor/dialogs.py +103 -0
  18. spiceditor/editor_widget.py +196 -0
  19. spiceditor/file_browser.py +143 -0
  20. spiceditor/highlighter.py +74 -0
  21. spiceditor/line_number_text_edit.py +54 -0
  22. spiceditor/magic_scrollbar.py +11 -0
  23. spiceditor/main.py +435 -0
  24. spiceditor/resources.py +1120 -0
  25. spiceditor/spice_console.py +282 -0
  26. spiceditor/spice_magic_editor.py +389 -0
  27. spiceditor/splitter.py +118 -0
  28. spiceditor/term.py +63 -0
  29. spiceditor/textract.py +597 -0
  30. spiceditor/utils.py +33 -0
  31. spiceditor-0.0.4.dist-info/LICENSE +674 -0
  32. spiceditor-0.0.4.dist-info/METADATA +31 -0
  33. spiceditor-0.0.4.dist-info/RECORD +51 -0
  34. spiceditor-0.0.4.dist-info/WHEEL +5 -0
  35. spiceditor-0.0.4.dist-info/entry_points.txt +2 -0
  36. spiceditor-0.0.4.dist-info/top_level.txt +1 -0
  37. spyce/__init__.py +0 -0
  38. spyce/dialogs.py +103 -0
  39. spyce/editor_widget.py +196 -0
  40. spyce/file_browser.py +143 -0
  41. spyce/highlighter.py +74 -0
  42. spyce/line_number_text_edit.py +54 -0
  43. spyce/magic_scrollbar.py +11 -0
  44. spyce/main.py +435 -0
  45. spyce/resources.py +1120 -0
  46. spyce/spice_console.py +282 -0
  47. spyce/spice_magic_editor.py +389 -0
  48. spyce/splitter.py +118 -0
  49. spyce/term.py +63 -0
  50. spyce/textract.py +597 -0
  51. spyce/utils.py +33 -0
spyce/spice_console.py ADDED
@@ -0,0 +1,282 @@
1
+ import sys
2
+
3
+ from PyQt5.QtCore import QTimer, pyqtSignal
4
+ from PyQt5.QtGui import QFont
5
+ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication
6
+ from easyconfig2.easyconfig import EasyConfig2
7
+ from qtconsole.manager import QtKernelManager
8
+ from qtconsole.rich_jupyter_widget import RichJupyterWidget
9
+ from termqt import Terminal
10
+
11
+
12
+ # from qtpyTerminal import qtpyTerminal
13
+
14
+ class SpiceConsole(QWidget):
15
+ done = pyqtSignal()
16
+
17
+ def __init__(self, config):
18
+ super().__init__()
19
+ self.keep_code = False
20
+ self.config = config
21
+
22
+ def execute(self, code, clear=True):
23
+ pass
24
+
25
+ def clear(self):
26
+ pass
27
+
28
+ def set_dark_mode(self, value):
29
+ pass
30
+
31
+ def set_font_size(self, size):
32
+ pass
33
+
34
+ def set_config(self, config):
35
+ self.config = config
36
+
37
+ def config_read(self):
38
+ pass
39
+
40
+ def set_keep_code(self, value):
41
+ self.keep_code = value
42
+
43
+ def get_file_extension(self):
44
+ return ".py"
45
+
46
+ def update_config(self, **kwargs):
47
+ pass
48
+
49
+
50
+ class JupyterConsole(SpiceConsole):
51
+
52
+ def __init__(self, config):
53
+ super().__init__(config)
54
+
55
+ kernel_manager = QtKernelManager(kernel_name='python3')
56
+ kernel_manager.start_kernel()
57
+ kernel_client = kernel_manager.client()
58
+ kernel_client.start_channels()
59
+
60
+ self.jupyter_widget = RichJupyterWidget()
61
+ font = QFont("Monospace")
62
+ font.setStyleHint(QFont.TypeWriter)
63
+ font.setPixelSize(18)
64
+ self.jupyter_widget.font = font
65
+
66
+ # self.jupyter_widget._set_font()
67
+ self.jupyter_widget.kernel_manager = kernel_manager
68
+ self.jupyter_widget.kernel_client = kernel_client
69
+
70
+ # Customize the prompt
71
+ self.jupyter_widget.include_other_output = False
72
+ self.jupyter_widget.banner = "" # Remove banner
73
+ self.jupyter_widget.input_prompt = "" # Remove input prompt
74
+ self.jupyter_widget.output_prompt = "" # Remove output prompt
75
+ self.jupyter_widget.set_default_style(colors='linux')
76
+
77
+ self.editor = self.jupyter_widget._control
78
+
79
+ layout = QVBoxLayout()
80
+ layout.addWidget(self.jupyter_widget)
81
+ self.setLayout(layout)
82
+ self.timer = QTimer()
83
+ self.timer.setSingleShot(True)
84
+ self.timer.timeout.connect(self.done.emit)
85
+
86
+ def config_read(self):
87
+ pass
88
+
89
+ def update_config(self, **kwargs):
90
+ path = self.config.progs_path.get()
91
+ if path:
92
+ self.jupyter_widget.execute("cd " + path, hidden=True)
93
+
94
+ size = self.config.font_size.get()
95
+
96
+ if size>=0:
97
+ self.set_font_size(size + 10)
98
+
99
+ def set_dark_mode(self, value):
100
+ if value:
101
+ self.jupyter_widget.set_default_style(colors='linux')
102
+ else:
103
+ self.jupyter_widget.set_default_style(colors='lightbg')
104
+
105
+ def execute(self, code, clear=True):
106
+
107
+
108
+ # self.jupyter_widget._control.setText("")
109
+ # def filtering():
110
+ # text = self.editor.toPlainText()
111
+ # if text.endswith(" ...: "):
112
+ # if clear:
113
+ # self.editor.clear()
114
+ #
115
+ # # pattern = r"In \[\d+\]:"
116
+ # # if re.search(pattern, text[-10:]):
117
+ # # self.timer.stop()
118
+ # # self.timer.start(250)
119
+ #
120
+ # self.editor.textChanged.connect(filtering)
121
+ # # self.jupyter_widget._control.setFocus()
122
+ # if "input" in code:
123
+ # self.jupyter_widget._control.setFocus()
124
+ # QApplication.processEvents()
125
+
126
+ def run():
127
+ if code.strip():
128
+ code_reset = code
129
+ self.jupyter_widget.execute(code_reset, interactive=True)
130
+ if clear:
131
+ self.jupyter_widget._control.clear()
132
+
133
+ clearer = '''
134
+ import sys
135
+ import os
136
+ import importlib
137
+
138
+ cwd = os.getcwd()
139
+
140
+ # Identify modules that are imported from the current directory
141
+ user_modules = [m for m in sys.modules if hasattr(
142
+ sys.modules[m], '__file__') and sys.modules[m].__file__ and sys.modules[m].__file__.startswith(cwd)]
143
+
144
+ for m in user_modules:
145
+ print("Reloading ", m, type(m))
146
+ importlib.reload(sys.modules[m])
147
+
148
+
149
+ '''
150
+ self.jupyter_widget.execute(clearer, hidden=True)
151
+ QTimer.singleShot(100, run)
152
+
153
+ def clear(self):
154
+ pass # self.jupyter_widget.execute("%clear")
155
+
156
+ def set_font_size(self, font_size):
157
+ font = QFont("Monospace")
158
+ font.setStyleHint(QFont.TypeWriter)
159
+ font.setPixelSize(font_size)
160
+ self.jupyter_widget._control.setFont(font)
161
+
162
+
163
+ import platform
164
+
165
+
166
+ class TermQtConsole(SpiceConsole):
167
+ def __init__(self, config):
168
+ super().__init__(config)
169
+ self.terminal = Terminal(400, 600, font_size=18)
170
+ layout = QVBoxLayout()
171
+ layout.addWidget(self.terminal)
172
+ self.setLayout(layout)
173
+
174
+ my_platform = platform.system()
175
+
176
+ if my_platform in ["Linux", "Darwin"]:
177
+ bin = "/bin/bash"
178
+
179
+ from termqt import TerminalPOSIXExecIO
180
+ terminal_io = TerminalPOSIXExecIO(
181
+ self.terminal.row_len,
182
+ self.terminal.col_len,
183
+ bin
184
+ )
185
+ elif my_platform == "Windows":
186
+ bin = "cmd"
187
+
188
+ from termqt import TerminalWinptyIO
189
+ terminal_io = TerminalWinptyIO(
190
+ self.terminal.row_len,
191
+ self.terminal.col_len,
192
+ bin
193
+ )
194
+
195
+ # it turned out that cmd prefers to handle resize by itself
196
+ # see https://github.com/TerryGeng/termqt/issues/7
197
+ auto_wrap_enabled = False
198
+ else:
199
+ sys.exit(-1)
200
+
201
+ self.terminal.enable_auto_wrap(True)
202
+
203
+ terminal_io.stdout_callback = self.terminal.stdout
204
+ self.terminal.stdin_callback = terminal_io.write
205
+ self.terminal.resize_callback = terminal_io.resize
206
+ terminal_io.spawn()
207
+ # self.terminal.input("python")
208
+
209
+ def set_config(self, config: EasyConfig2):
210
+ super().set_config(config)
211
+ terminal = config.root().addSubSection("Terminal")
212
+ self.init = terminal.addString("init", pretty="Init command (e.g. python)")
213
+ self.temp_file = terminal.addString("temp_file", pretty="Temp file name")
214
+ self.command = terminal.addString("command", pretty="Command")
215
+ self.file_extension = terminal.addCombobox("file_extension", pretty="File extension", items=[".py", ".pas"])
216
+
217
+ def config_read(self):
218
+ super().config_read()
219
+ init = self.init.get_value()
220
+ if init is not None:
221
+ init += "\n"
222
+ self.terminal.input(init.encode("utf-8"))
223
+
224
+ def execute(self, code, clear=True):
225
+ temp_file = self.temp_file.get_value()
226
+ if temp_file is not None and temp_file.strip():
227
+ with open(temp_file, "w") as f:
228
+ f.write(code)
229
+ else:
230
+ self.terminal.input(code.encode("utf-8"))
231
+
232
+ command = self.command.get_value()
233
+ if command is not None and command.strip():
234
+ command += "\r\n"
235
+ self.terminal.input(command.encode("utf-8"))
236
+
237
+ def clear(self):
238
+ self.terminal.input("clear\r\n".encode("utf-8"))
239
+
240
+ def get_file_extension(self):
241
+ return self.file_extension.get_item(self.file_extension.get(0))
242
+
243
+ def set_font_size(self, size):
244
+ try:
245
+ self.terminal.font_size = int(size * 0.75)
246
+ font = QFont("Monospace")
247
+ font.setStyleHint(QFont.Monospace)
248
+ font.setPointSize(size)
249
+ self.terminal.set_font(font)
250
+ # self.terminal.input("clear\r\n".encode("utf-8"))
251
+ except:
252
+ pass
253
+
254
+ def update_config(self):
255
+ font_size = self.config.root().get_child("font_size").get_value()
256
+ if font_size is not None:
257
+ self.set_font_size(font_size + 10)
258
+
259
+ def resizeEvent(self, a0):
260
+ # TODO: self.terminal.set_canvas_size(self.width(), self.height())
261
+ pass
262
+
263
+ # class Console2(SpiceTerminal):
264
+ # def __init__(self):
265
+ # super().__init__()
266
+ # self.terminal = qtpyTerminal()
267
+ # self.terminal.term.setFont(QFont("Monospace", 14))
268
+ # self.terminal.term.setMinimumWidth(200)
269
+ # self.terminal.setMinimumWidth(200)
270
+ #
271
+ # layout = QVBoxLayout()
272
+ # layout.addWidget(self.terminal)
273
+ # self.setLayout(layout)
274
+ # self.terminal.start()
275
+ #
276
+ # def execute(self, code, clear=True):
277
+ # with open("output.pas", "w") as f:
278
+ # f.write(code)
279
+ # self.terminal.push("fpc output.pas && ./output\n")
280
+ #
281
+ # def clear(self):
282
+ # self.terminal.push("clear\n")
@@ -0,0 +1,389 @@
1
+ import random
2
+ import re
3
+
4
+ import autopep8
5
+ from PyQt5 import QtGui
6
+ from PyQt5.QtCore import pyqtSignal, Qt, QTimer
7
+ from PyQt5.QtGui import QFont, QFontMetrics, QColor, QPainter, QTextCursor
8
+ from PyQt5.QtWidgets import QTextEdit, QHBoxLayout, QScrollBar, QApplication
9
+
10
+ from spiceditor.line_number_text_edit import LineNumberTextEdit
11
+ from spiceditor.magic_scrollbar import MagicScrollBar
12
+
13
+
14
+ class SpiceMagicEditor(QTextEdit):
15
+ ctrl_enter = pyqtSignal()
16
+ info = pyqtSignal(str, int, int)
17
+
18
+ def __init__(self, highlighter=None, font_size=18):
19
+ super().__init__()
20
+ self.highlighter = highlighter
21
+ self.suggestion = None
22
+ self.candidates = []
23
+ self.count = 0
24
+ self.mode = 0
25
+ self.code = ""
26
+ self.delay = 0.01
27
+ self.autocomplete_words = []
28
+
29
+ self.line_number_area = LineNumberTextEdit(self)
30
+ self.line_number_area.verticalScrollBar().valueChanged.connect(self.verticalScrollBar().setValue)
31
+ self.line_number_area.document().setDocumentMargin(0)
32
+
33
+ self.setContentsMargins(0, 0, 0, 0)
34
+ self.document().setDocumentMargin(0)
35
+ self.setViewportMargins(60, 0, 0, 0)
36
+ self.setLineWrapMode(QTextEdit.NoWrap)
37
+ self.setPlaceholderText("Write Python code here...")
38
+
39
+ self.setHorizontalScrollBar(MagicScrollBar())
40
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
41
+
42
+ self.textChanged.connect(self.text_changed)
43
+ self.verticalScrollBar().valueChanged.connect(self.line_number_area.verticalScrollBar().setValue)
44
+ self.horizontalScrollBar().rangeChanged.connect(self.text_changed)
45
+
46
+ self.cursorPositionChanged.connect(
47
+ lambda: self.line_number_area.highlight_line(self.textCursor().blockNumber()))
48
+
49
+ if self.highlighter:
50
+ self.highlighter.setDocument(self.document())
51
+
52
+ self.set_font_size(font_size)
53
+
54
+ def set_font_size(self, font_size):
55
+ font = QFont("Courier New")
56
+ # font.setStyleHint(QFont.TypeWriter)
57
+ font.setPixelSize(font_size)
58
+ self.setFont(font)
59
+ self.line_number_area.setFont(font)
60
+ three_numbers_width = QFontMetrics(font).width("000")
61
+ self.line_number_area.setFixedWidth(int(three_numbers_width + 12))
62
+ self.setViewportMargins(three_numbers_width + 15, 0, 0, 0)
63
+
64
+ def show_code(self):
65
+ self.show_all_code()
66
+
67
+ def set_dark_mode(self, dark):
68
+ self.line_number_area.set_dark_mode(dark)
69
+ self.highlighter.set_dark_mode(dark)
70
+ self.highlighter.setDocument(self.document())
71
+
72
+ def set_text(self, text):
73
+ self.setPlainText(text)
74
+ self.text_changed()
75
+
76
+ def text_changed(self):
77
+ text = self.toPlainText()
78
+ lines = text.split("\n")
79
+ v1 = self.line_number_area.verticalScrollBar().value()
80
+ self.line_number_area.blockSignals(True)
81
+ self.line_number_area.clear()
82
+ text = str()
83
+ for i in range(len(lines)):
84
+ text += "{:3d}\n".format(i + 1)
85
+
86
+ self.line_number_area.setPlainText(text)
87
+ self.line_number_area.setFixedHeight(self.height())
88
+ self.line_number_area.verticalScrollBar().setMaximum(self.verticalScrollBar().maximum())
89
+ self.line_number_area.verticalScrollBar().setValue(v1)
90
+ self.line_number_area.blockSignals(False)
91
+
92
+ def resizeEvent(self, a0) -> None:
93
+ self.text_changed()
94
+ self.blockSignals(True)
95
+ super().resizeEvent(a0)
96
+ self.blockSignals(False)
97
+
98
+ def format_code(self):
99
+ self.format_code()
100
+
101
+ def get_text(self):
102
+ return self.toPlainText()
103
+
104
+ def clear(self):
105
+ self.set_code("")
106
+ self.setPlainText("")
107
+ self.count = 0
108
+ self.set_mode(0)
109
+
110
+ def get_code(self):
111
+ return self.code
112
+
113
+ def get_remaining_chars(self):
114
+ diff = len(self.get_code()) - self.count
115
+ return diff
116
+
117
+ def set_delay(self, delay):
118
+ self.delay = delay
119
+
120
+ def append_autocomplete(self, words, clear=False):
121
+ if clear:
122
+ self.autocomplete_words.clear()
123
+ self.autocomplete_words += words if words else ""
124
+
125
+ def set_code(self, code):
126
+ self.setText("")
127
+ self.count = 0
128
+ self.code = code
129
+ self.set_mode(1)
130
+ self.setFocus()
131
+
132
+ def set_mode(self, mode):
133
+ self.mode = mode
134
+ self.setCursorWidth(3 if self.mode == 1 else 1)
135
+ # self.setReadOnly(self.mode == 1)
136
+ self.update()
137
+
138
+ def on_return_key(self, e):
139
+ return False
140
+
141
+ def complete_line(self, sleep=True):
142
+ self.info.emit(self.get_next_line(), self.get_remaining_chars(), 20)
143
+ if self.count < len(self.code):
144
+ # self.setText(self.toPlainText() + self.code[self.count])
145
+ self.insertPlainText(self.code[self.count])
146
+ self.moveCursor(QtGui.QTextCursor.End)
147
+ self.count += 1
148
+
149
+ if self.code[self.count - 1] == "\n":
150
+ # if next line is empty continue
151
+ # and show that line too
152
+ if len(self.get_rest_of_line()) > 0:
153
+ return True
154
+
155
+ QApplication.processEvents()
156
+ delay = int(self.delay) + random.randint(0, int(self.delay))
157
+ QTimer.singleShot(delay, self.complete_line)
158
+
159
+ def get_rest_of_line(self):
160
+ count = self.count
161
+ text = ""
162
+ while count < len(self.code):
163
+ text += self.code[count]
164
+ count += 1
165
+ if self.code[count - 1] == "\n":
166
+ return text[1:]
167
+ return ""
168
+
169
+ def get_spaces(self, line):
170
+ spaces = 0
171
+ for c in line:
172
+ if c == " ":
173
+ spaces += 1
174
+ else:
175
+ break
176
+ return spaces
177
+
178
+ def get_current_line(self):
179
+ cursor = self.textCursor()
180
+ cursor.movePosition(QtGui.QTextCursor.StartOfLine)
181
+ cursor.movePosition(QtGui.QTextCursor.EndOfLine, QtGui.QTextCursor.KeepAnchor)
182
+ current_line = cursor.selectedText()
183
+ return current_line
184
+
185
+ def append_next_char(self):
186
+ self.count += 1
187
+ self.setText(self.code[:self.count])
188
+ self.moveCursor(QtGui.QTextCursor.End)
189
+
190
+ def show_all_code(self):
191
+ self.setText(self.code)
192
+ self.set_mode(0)
193
+ self.moveCursor(QtGui.QTextCursor.End)
194
+
195
+ def get_current_line_text(self):
196
+ # Get the QTextCursor
197
+ cursor = self.textCursor()
198
+
199
+ # Move the cursor to the start and end of the current line
200
+ cursor.select(cursor.LineUnderCursor)
201
+
202
+ # Get the selected text
203
+ return cursor.selectedText()
204
+
205
+ def keyPressEvent(self, e: QtGui.QKeyEvent) -> None:
206
+ self.setFocusPolicy(Qt.StrongFocus)
207
+
208
+ if e.key() == Qt.Key_Escape:
209
+ self.set_mode(0 if self.mode == 1 else 0)
210
+
211
+ if self.mode == 1:
212
+
213
+ if e.key() == Qt.Key_Down:
214
+ self.show_all_code()
215
+ elif e.key() == Qt.Key_Control:
216
+ return
217
+ elif e.key() == Qt.Key_End:
218
+ while self.complete_line(False):
219
+ pass
220
+ self.set_mode(0)
221
+ elif e.key() == Qt.Key_Tab:
222
+ if e.modifiers() == Qt.ControlModifier:
223
+ while self.complete_line():
224
+ pass
225
+ self.set_mode(0)
226
+ else:
227
+ self.complete_line()
228
+ elif self.count < len(self.code):
229
+ self.info.emit(self.get_rest_of_line(), self.get_remaining_chars(), 1000)
230
+ self.append_next_char()
231
+ elif e.key() == Qt.Key_Return:
232
+ self.set_mode(0)
233
+ super().keyPressEvent(e)
234
+ elif e.key() == Qt.Key_Backspace:
235
+ self.set_mode(0)
236
+ else:
237
+ self.setText(self.toPlainText() + "\n")
238
+ self.moveCursor(QtGui.QTextCursor.End)
239
+
240
+ elif self.mode == 0:
241
+
242
+ if e.key() == Qt.Key_Tab:
243
+ self.tab_pressed()
244
+ elif e.key() == Qt.Key_Backspace:
245
+ self.suggestion = None
246
+ if self.get_current_line_text().endswith(" "):
247
+ for i in range(4):
248
+ self.textCursor().deletePreviousChar()
249
+ else:
250
+ super().keyPressEvent(e)
251
+ elif e.key() == Qt.Key_Return:
252
+ self.suggestion = None
253
+ if e.modifiers() == Qt.ControlModifier:
254
+ self.ctrl_enter.emit()
255
+ elif self.on_return_key(e):
256
+ pass
257
+ else:
258
+ super().keyPressEvent(e)
259
+ else:
260
+ self.suggestion = None
261
+ super().keyPressEvent(e)
262
+ self.cursorPositionChanged.emit()
263
+
264
+ def indent_selected(self):
265
+ cursor = self.textCursor()
266
+
267
+ if not cursor.hasSelection():
268
+ return # No selection, do nothing
269
+
270
+ # Get selected text (preserve newlines)
271
+ selected_text = cursor.selection().toPlainText()
272
+
273
+ # Add 4 spaces to each line
274
+ indented_text = "\n".join(" " + line for line in selected_text.splitlines())
275
+
276
+ # Replace selected text with indented version
277
+ cursor.beginEditBlock() # Start undo-able action
278
+ cursor.insertText(indented_text)
279
+ cursor.endEditBlock() # End undo-able action
280
+
281
+ def get_text_before_cursor(self):
282
+ cursor = self.textCursor()
283
+ cursor.movePosition(QTextCursor.StartOfBlock, QTextCursor.KeepAnchor) # Selecciona desde el inicio de la línea
284
+ return cursor.selectedText()
285
+
286
+ def tab_pressed(self):
287
+
288
+ if self.textCursor().hasSelection():
289
+ self.indent_selected()
290
+ return
291
+
292
+ # Let see if we have some autocomplete candidates
293
+ if self.suggestion is None:
294
+ current_words = re.split(r'\W+', self.toPlainText())
295
+ text_before_cursor = self.get_text_before_cursor()
296
+ words_before_cursos = re.split(r"[+\-*/= ]", text_before_cursor)
297
+ self.candidates = []
298
+ if words_before_cursos[-1] != "":
299
+ word_set = list(set(current_words + self.highlighter.get_keywords() + self.autocomplete_words))
300
+ self.candidates = [word for word in word_set if word.startswith(words_before_cursos[-1])]
301
+ if words_before_cursos[-1] in self.candidates:
302
+ self.candidates.remove(words_before_cursos[-1])
303
+ self.candidates.append(words_before_cursos[-1])
304
+ self.suggestion = words_before_cursos[-1]
305
+
306
+ if len(self.candidates) > 1:
307
+ # Remove the current suggestion
308
+ for _ in range(len(self.suggestion)):
309
+ self.textCursor().deletePreviousChar()
310
+ self.candidates.append(self.suggestion)
311
+ self.suggestion = self.candidates.pop(0)
312
+ self.insertPlainText(self.suggestion)
313
+ else:
314
+ self.insertPlainText(" ")
315
+
316
+
317
+
318
+ # if len(self.candidates) > 0:
319
+
320
+ # current_line = self.get_current_line_text()
321
+ #
322
+ # # it was just a tab
323
+ # if len(current_line) == 0 or current_line.endswith(" "):
324
+ # self.insertPlainText(" ")
325
+ # self.moveCursor(QtGui.QTextCursor.End)
326
+ # self.suggestion = None
327
+ # return
328
+ #
329
+ # # it was just a tab
330
+ # if len(current_line) > 0 and current_line[-1] in " (:)":
331
+ # self.suggestion = None
332
+ # return
333
+ #
334
+ # if self.suggestion is None:
335
+ #
336
+ # if len(self.candidates) == 0:
337
+ # self.insertPlainText(" ")
338
+ # return
339
+ # elif len(self.candidates) == 1:
340
+ # self.insertPlainText(self.candidates[0][len(unfinished_word):])
341
+ # self.moveCursor(QtGui.QTextCursor.End)
342
+ # return
343
+ # else:
344
+ # self.suggestion = unfinished_word
345
+ #
346
+ # for _ in range(len(self.suggestion)):
347
+ # self.textCursor().deletePreviousChar()
348
+ # self.candidates.append(self.suggestion)
349
+ # self.suggestion = self.candidates.pop(0)
350
+ # self.insertPlainText(self.suggestion)
351
+
352
+ def get_next_line(self):
353
+ count = self.count
354
+ remaining = self.code[count:]
355
+ remaining = remaining.split("\n")
356
+ remaining = remaining[1:]
357
+ remaining = [x for x in remaining if x.strip()]
358
+ if remaining:
359
+ return remaining[0]
360
+
361
+
362
+ class PascalEditor(SpiceMagicEditor):
363
+ pass
364
+
365
+
366
+ class PythonEditor(SpiceMagicEditor):
367
+ def format_code(self):
368
+ code = self.toPlainText()
369
+ if not code.endswith("\n"):
370
+ code += "\n"
371
+ self.setPlainText(autopep8.fix_code(code))
372
+ self.moveCursor(QtGui.QTextCursor.End)
373
+
374
+ def on_return_key(self, e):
375
+ current_line = self.get_current_line()
376
+ spaces = self.get_spaces(current_line)
377
+ if current_line.endswith(":"):
378
+ if self.textCursor().positionInBlock() == len(current_line):
379
+ self.insertPlainText("\n" + " " * (spaces + 4))
380
+ return True
381
+ return False
382
+
383
+ elif current_line.startswith(" "):
384
+ if current_line.strip():
385
+ self.insertPlainText("\n" + " " * spaces)
386
+ else:
387
+ self.insertPlainText("\n" + " " * (max(spaces - 4, 0)))
388
+ return True
389
+ return False