Skip to content

Commit 7fc51a0

Browse files
committed
initial code indentation and completion test
1 parent 467d933 commit 7fc51a0

File tree

1 file changed

+114
-4
lines changed

1 file changed

+114
-4
lines changed

QCodeEditor.py

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
'''
1212

1313
import binaryninjaui
14-
from binaryninja import log_warn
14+
from binaryninja import log_warn, bncompleter
1515
if "qt_major_version" in binaryninjaui.__dict__ and binaryninjaui.qt_major_version == 6:
1616
from PySide6.QtCore import Qt, QRect, QRegularExpression
1717
from PySide6.QtWidgets import QWidget, QTextEdit, QPlainTextEdit
18-
from PySide6.QtGui import (QPainter, QFont, QSyntaxHighlighter, QTextFormat, QTextCharFormat, QColor)
18+
from PySide6.QtGui import (QPainter, QFont, QSyntaxHighlighter, QTextFormat, QTextCharFormat, QColor, QTextCursor)
1919
else:
2020
from PySide2.QtCore import Qt, QRect, QRegularExpression
2121
from PySide2.QtWidgets import QWidget, QTextEdit, QPlainTextEdit
22-
from PySide2.QtGui import (QPainter, QFont, QSyntaxHighlighter, QTextFormat, QTextCharFormat, QColor)
22+
from PySide2.QtGui import (QPainter, QFont, QSyntaxHighlighter, QTextFormat, QTextCharFormat, QColor, QTextCursor)
2323
from binaryninjaui import (getMonospaceFont, getThemeColor, ThemeColor)
2424
from pygments import highlight, token
2525
from pygments.lexers import *
@@ -216,13 +216,18 @@ def updateContents(self, rect, scroll):
216216

217217

218218
def __init__(self, DISPLAY_LINE_NUMBERS=True, HIGHLIGHT_CURRENT_LINE=True,
219-
SyntaxHighlighter=Pylighter, lang="python", font_size=11, *args):
219+
SyntaxHighlighter=Pylighter, lang="python", font_size=11, delimeter=" ", *args):
220220
super(QCodeEditor, self).__init__()
221221

222222
font = getMonospaceFont(self)
223223
font.setPointSize(font_size)
224224
self.setFont(font)
225225
self.setLineWrapMode(QPlainTextEdit.NoWrap)
226+
self.completionState = 0
227+
self.completing = False
228+
self.delimeter = delimeter
229+
self.completer = bncompleter.Completer()
230+
self.cursorPositionChanged.connect(self.resetCompletion)
226231

227232
self.DISPLAY_LINE_NUMBERS = DISPLAY_LINE_NUMBERS
228233

@@ -232,6 +237,111 @@ def __init__(self, DISPLAY_LINE_NUMBERS=True, HIGHLIGHT_CURRENT_LINE=True,
232237
if SyntaxHighlighter is not None: # add highlighter to textdocument
233238
self.highlighter = SyntaxHighlighter(self.document(), lang)
234239

240+
def resetCompletion(self):
241+
if not self.completing:
242+
self.completionState = 0
243+
244+
def isStart(self):
245+
tempCursor = self.textCursor()
246+
if tempCursor.positionInBlock() == 0:
247+
return True
248+
startText = tempCursor.block().text()[0:tempCursor.positionInBlock()]
249+
delim = set(self.delimeter)
250+
if set(startText) - delim == set():
251+
#only delimeters before cursor, not worrying about varying lengths of spaces for now
252+
return True
253+
return False
254+
255+
def keyPressEvent(self, event):
256+
if event.key() == Qt.Key_Backtab and self.textCursor().hasSelection():
257+
startCursor = self.textCursor()
258+
startCursor.beginEditBlock()
259+
startPos = startCursor.selectionStart()
260+
startCursor.setPosition(startPos)
261+
startCursor.movePosition(QTextCursor.StartOfLine, QTextCursor.MoveAnchor)
262+
startCursor.clearSelection()
263+
264+
endCursor = self.textCursor()
265+
endPos = endCursor.selectionEnd()
266+
endCursor.setPosition(endPos)
267+
endCursor.movePosition(QTextCursor.StartOfLine)
268+
269+
while startCursor.anchor() != endCursor.position():
270+
startCursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor, len(self.delimeter))
271+
if startCursor.selectedText() == self.delimeter:
272+
startCursor.removeSelectedText()
273+
startCursor.movePosition(QTextCursor.NextBlock, QTextCursor.MoveAnchor)
274+
startCursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor, len(self.delimeter))
275+
if startCursor.selectedText() == self.delimeter:
276+
startCursor.removeSelectedText()
277+
startCursor.endEditBlock()
278+
return
279+
280+
if event.key() == Qt.Key_Tab and self.textCursor().hasSelection():
281+
startCursor = self.textCursor()
282+
startCursor.beginEditBlock()
283+
startPos = startCursor.selectionStart()
284+
startCursor.setPosition(startPos)
285+
startCursor.movePosition(QTextCursor.StartOfLine)
286+
287+
endCursor = self.textCursor()
288+
endPos = endCursor.selectionEnd()
289+
endCursor.setPosition(endPos)
290+
endCursor.movePosition(QTextCursor.StartOfLine)
291+
292+
while startCursor.position() != endCursor.position():
293+
startCursor.insertText(self.delimeter)
294+
startCursor.movePosition(QTextCursor.NextBlock)
295+
296+
startCursor.insertText(self.delimeter)
297+
startCursor.endEditBlock()
298+
return
299+
300+
if event.key() == Qt.Key_Escape and self.completionState > 0:
301+
self.completionState = 0
302+
cursor = self.textCursor()
303+
cursor.beginEditBlock()
304+
cursor.select(QTextCursor.BlockUnderCursor)
305+
cursor.removeSelectedText()
306+
cursor.insertText("\n" + self.origText)
307+
cursor.endEditBlock()
308+
self.origText == None
309+
return
310+
311+
if event.key() == Qt.Key_Tab:
312+
if self.isStart():
313+
self.textCursor().insertText(self.delimeter)
314+
else:
315+
cursor = self.textCursor()
316+
cursor.beginEditBlock()
317+
self.completing = True
318+
if self.completionState == 0:
319+
self.origText = self.textCursor().block().text()
320+
if self.completionState > 0:
321+
cursor.select(QTextCursor.BlockUnderCursor)
322+
cursor.removeSelectedText()
323+
cursor.insertText("\n" + self.origText)
324+
newText = self.completer.complete(self.origText, self.completionState)
325+
if newText:
326+
if newText.find("(") > 0:
327+
newText = newText[0:newText.find("(") + 1]
328+
self.completionState += 1
329+
cursor.select(QTextCursor.BlockUnderCursor)
330+
cursor.removeSelectedText()
331+
cursor.insertText("\n" + newText)
332+
else:
333+
self.completionState = 0
334+
cursor.select(QTextCursor.BlockUnderCursor)
335+
cursor.removeSelectedText()
336+
cursor.insertText("\n" + self.origText)
337+
self.origText == None
338+
cursor.endEditBlock()
339+
self.completing = False
340+
return
341+
342+
return super().keyPressEvent(event)
343+
344+
235345
def resizeEvent(self, *e):
236346
'''overload resizeEvent handler'''
237347

0 commit comments

Comments
 (0)