Skip to content

Commit bdaa0fa

Browse files
committed
add file context menu and cleanup imports
1 parent 8640fe4 commit bdaa0fa

File tree

1 file changed

+44
-11
lines changed

1 file changed

+44
-11
lines changed

__init__.py

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,24 @@
99
from datetime import datetime
1010
from pathlib import Path
1111

12-
import binaryninjaui
13-
from binaryninjaui import (getMonospaceFont, UIAction, UIActionHandler, Menu, UIContext)
14-
from PySide6.QtWidgets import (QLineEdit, QPushButton, QApplication, QWidget,
15-
QVBoxLayout, QHBoxLayout, QDialog, QFileSystemModel, QTreeView, QLabel, QSplitter,
16-
QInputDialog, QMessageBox, QHeaderView, QKeySequenceEdit, QCheckBox)
17-
from PySide6.QtCore import (QDir, Qt, QFileInfo, QItemSelectionModel, QSettings, QUrl)
18-
from PySide6.QtGui import (QFontMetrics, QDesktopServices, QKeySequence, QIcon, QColor)
1912
from binaryninja import user_plugin_path, core_version
2013
from binaryninja.plugin import BackgroundTaskThread
2114
from binaryninja.log import (log_error, log_debug, log_alert, log_warn)
2215
from binaryninja.settings import Settings
2316
from binaryninja.interaction import get_directory_name_input
24-
import numbers
17+
import binaryninjaui
18+
from binaryninjaui import (getMonospaceFont, UIAction, UIActionHandler, Menu, UIContext)
19+
from PySide6.QtWidgets import (QLineEdit, QPushButton, QApplication, QWidget,
20+
QVBoxLayout, QHBoxLayout, QDialog, QFileSystemModel, QTreeView, QLabel, QSplitter,
21+
QInputDialog, QMessageBox, QHeaderView, QKeySequenceEdit, QCheckBox, QMenu)
22+
from PySide6.QtCore import (QDir, Qt, QFileInfo, QItemSelectionModel, QSettings, QUrl)
23+
from PySide6.QtGui import (QFontMetrics, QDesktopServices, QKeySequence, QIcon, QColor, QAction)
2524
from .QCodeEditor import QCodeEditor, Pylighter
2625

2726
Settings().register_group("snippets", "Snippets")
2827
Settings().register_setting("snippets.syntaxHighlight", """
2928
{
30-
"title" : "Syntax highlighting for snippets",
29+
"title" : "Syntax Highlighting",
3130
"type" : "boolean",
3231
"default" : true,
3332
"description" : "Whether to syntax highlight (may be performance problems with very large snippets and the current highlighting implementation.)",
@@ -36,7 +35,7 @@
3635
""")
3736
Settings().register_setting("snippets.indentation", """
3837
{
39-
"title" : "Indentation Syntax highlighting for snippets",
38+
"title" : "Indentation Syntax Highlighting",
4039
"type" : "string",
4140
"default" : " ",
4241
"description" : "String to use for indentation in snippets (tip: to use a tab, copy/paste a tab from another text field and paste here)",
@@ -129,7 +128,7 @@ def setupGlobals(context):
129128
snippetGlobals['current_basic_block'] = None
130129
snippetGlobals['current_address'] = context.address
131130
snippetGlobals['here'] = context.address
132-
if context.address is not None and isinstance(context.length, numbers.Integral):
131+
if context.address is not None and isinstance(context.length, int):
133132
snippetGlobals['current_selection'] = (context.address, context.address+context.length)
134133
else:
135134
snippetGlobals['current_selection'] = None
@@ -249,6 +248,8 @@ def __init__(self, context, parent=None):
249248
self.tree = QTreeView()
250249
self.tree.setModel(self.files)
251250
self.tree.setSortingEnabled(True)
251+
self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
252+
self.tree.customContextMenuRequested.connect(self.contextMenu)
252253
self.tree.hideColumn(2)
253254
self.tree.sortByColumn(0, Qt.AscendingOrder)
254255
self.tree.setRootIndex(self.files.index(snippetPath))
@@ -496,6 +497,30 @@ def deleteSnippet(self):
496497
self.files.remove(selection)
497498
self.registerAllSnippets()
498499

500+
def duplicateSnippet(self):
501+
selection = self.tree.selectedIndexes()[::self.columns][0] #treeview returns each selected element in the row
502+
snippetName = self.files.fileName(selection)
503+
(newname, ok) = QInputDialog.getText(self, self.tr("New Snippet Name"), self.tr("New Snippet Name:"))
504+
if ok and snippetName:
505+
(snippetDescription, snippetKeys, snippetCode) = loadSnippetFromFile(self.currentFile)
506+
if not snippetName.endswith(".py"):
507+
snippetName += ".py"
508+
index = self.tree.selectionModel().currentIndex()
509+
selection = self.files.filePath(index)
510+
if QFileInfo(selection).isDir():
511+
path = os.path.join(selection, snippetName)
512+
else:
513+
path = os.path.join(snippetPath, snippetName)
514+
self.readOnly(False)
515+
open(path, "w").close()
516+
self.snippetName.setText(os.path.basename(self.currentFile))
517+
self.snippetDescription.setText(snippetDescription) if snippetDescription else self.snippetDescription.setText("")
518+
self.keySequenceEdit.setKeySequence(snippetKeys) if snippetKeys else self.keySequenceEdit.setKeySequence(QKeySequence(""))
519+
self.edit.setPlainText(snippetCode) if snippetCode else self.edit.setPlainText("")
520+
self.save()
521+
self.tree.setCurrentIndex(self.files.index(path))
522+
self.registerAllSnippets()
523+
499524
def snippetChanged(self):
500525
if (self.currentFile == "" or QFileInfo(self.currentFile).isDir()):
501526
return False
@@ -691,6 +716,14 @@ def main(bv):
691716
def clearHotkey(self):
692717
self.keySequenceEdit.clear()
693718

719+
def contextMenu(self, position):
720+
menu = QMenu()
721+
delete = menu.addAction("Delete")
722+
delete.triggered.connect(self.deleteSnippet)
723+
duplicate = menu.addAction("Duplicate")
724+
duplicate.triggered.connect(self.duplicateSnippet)
725+
menu.exec_(self.mapToGlobal(position))
726+
694727

695728
snippets = None
696729

0 commit comments

Comments
 (0)