Skip to content

Instantly share code, notes, and snippets.

@oglops
Last active July 15, 2016 08:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oglops/c706fc6bb47df00e166a11c7b3ad27d5 to your computer and use it in GitHub Desktop.
Save oglops/c706fc6bb47df00e166a11c7b3ad27d5 to your computer and use it in GitHub Desktop.
intercept maya hotkey, add ctrl+/ comment toggle and hack ctrl+e , tab / shift+tab
from PyQt4.QtCore import Qt,QObject,QEvent
from PyQt4.QtGui import QTextCursor,qApp
import maya.cmds as mc
import maya.mel as mel
import maya.OpenMayaUI as apiUI
import sip
class CustomFilter(QObject):
def __init__(self,parent=None):
super(CustomFilter,self).__init__(parent)
self.textedit=None
self.comment_string='#'
def eventFilter(self, obj, event):
if event.type() == QEvent.KeyPress:
if 'scriptEditorPanel' in mc.getPanel(up=1):
self.get_text_edit()
# print event.key(),event.modifiers()
if event.key() == Qt.Key_Slash and event.modifiers() == Qt.ControlModifier:
print 'ctrl+/ pressed'
self.toggle_comment()
return True
elif event.key() == Qt.Key_Tab and event.modifiers() == Qt.NoModifier:
print 'tab pressed'
self.tab('tab')
return True
elif event.key() == Qt.Key_Backtab and event.modifiers() == Qt.ShiftModifier:
print 'shift+tab pressed'
self.tab('shift_tab')
return True
elif event.key() == Qt.Key_D and event.modifiers() == Qt.ControlModifier:
print 'ctrl+d pressed'
self.test('delete_line')
return True
elif event.key() == Qt.Key_E and event.modifiers() == Qt.ControlModifier:
print 'ctrl+e pressed'
self.test('execute')
return True
return False
def get_text_edit(self):
# what is current tab?
tabIdx = mc.tabLayout(gCommandExecuterTabs, q=1, st=1)
print 'current tab:', tabIdx
cmd_executer = mc.layout(tabIdx,q=1,ca=1)[0]
ptr=apiUI.MQtUtil.findControl(cmd_executer)
self.textedit=sip.wrapinstance(long(ptr),QObject)
def moveToPosition(self, pos):
cursor = self.textedit.textCursor()
cursor.movePosition(QTextCursor.Start, QTextCursor.MoveAnchor)
cursor.movePosition(QTextCursor.Right, QTextCursor.MoveAnchor, pos)
self.textedit.setTextCursor(cursor)
def restore_selection(fn):
from functools import wraps
@wraps(fn)
def wrapper(self,*args, **kw):
print 'before'
self.test('get_range')
fn(self,*args, **kw)
print 'after'
self.test('load_range')
return wrapper
@restore_selection
def toggle_comment(self,*args):
self.last_change='toggle_comment'
self.test('multi_line_comment')
@restore_selection
def tab(self,mode='tab',*args):
self.test(mode)
def position_in_block(self,cursor):
# this can be replaced with cursor.positionInBlock after qt 4.7
pos = cursor.position()-cursor.block().position()
return pos
def get_line_range(self,cursor,start_pos,end_pos):
# if start_pos!=end_pos:
# find which line is left most
cursor.setPosition(end_pos)
last_line = cursor.block().blockNumber()
if cursor.atBlockStart() and start_pos != end_pos:
print 'start_pos:',start_pos,'end_pos:',end_pos
last_line -= 1
cursor.setPosition(start_pos)
first_line = cursor.block().blockNumber()
return (first_line,last_line)
def get_min_indent(self,cursor,start_pos,first_line,last_line):
# find the leftmost line and get its position
cursor.setPosition(start_pos)
indents = []
for _line_nb in range(first_line, last_line+1):
text = str(cursor.block().text())
indent = len(text)-len(text.lstrip())
# print 'line:',_line_nb,'indent:',indent
indents.append(indent)
cursor.movePosition(QTextCursor.NextBlock)
min_indent = min(indents)
print 'min_indent:', min_indent
return min_indent
def test(self, mode='current_pos'):
cursor = self.textedit.textCursor()
if mode == 'current_pos':
print 'current pos:', cursor.position()
elif mode == 'single_line_comment':
cursor.movePosition(
QTextCursor.StartOfBlock, QTextCursor.MoveAnchor)
self.textedit.setTextCursor(cursor)
cursor.insertText('# ')
elif mode == 'get_range':
start_pos, end_pos = [cursor.selectionStart(),
cursor.selectionEnd()]
print 'range:', start_pos, end_pos
self.sel_range = (start_pos, end_pos)
elif mode == 'load_range':
start_pos, end_pos = self.sel_range
print 'load range:', start_pos, end_pos
self.moveToPosition(start_pos)
cursor = self.textedit.textCursor()
cursor.movePosition(
QTextCursor.Right, QTextCursor.KeepAnchor, end_pos - start_pos)
self.textedit.setTextCursor(cursor)
elif mode == 'multi_line_comment':
# find selected lines
start_pos, end_pos = [cursor.selectionStart(),
cursor.selectionEnd()]
first_line,last_line = self.get_line_range(cursor,start_pos, end_pos)
# If the selection contains only commented lines and surrounding
# whitespace, uncomment. Otherwise, comment.
is_comment_or_whitespace = True
at_least_one_comment = False
for _line_nb in range(first_line, last_line+1):
text = str(cursor.block().text()).lstrip()
print 'dealing text:', text
is_comment = text.startswith(self.comment_string)
is_whitespace = (text == '')
is_comment_or_whitespace *= (is_comment or is_whitespace)
if is_comment:
at_least_one_comment = True
cursor.movePosition(QTextCursor.NextBlock)
min_indent = self.get_min_indent(cursor,start_pos,first_line,last_line)
cursor.beginEditBlock()
if is_comment_or_whitespace and at_least_one_comment:
print 'need to uncomment'
cursor.setPosition(start_pos)
for _line_nb in range(first_line, last_line+1):
if _line_nb==first_line:
self.moveToPosition(start_pos)
if self.position_in_block(cursor)>min_indent:
start_pos-=2
cursor.movePosition(QTextCursor.StartOfLine)
cursor.movePosition(
QTextCursor.Right, QTextCursor.MoveAnchor, min_indent)
self.textedit.setTextCursor(cursor)
cursor.deleteChar()
end_pos-=1
next_char = cursor.block().text()[self.position_in_block(cursor)]
print 'next char:', next_char
if next_char == ' ':
cursor.deleteChar()
end_pos-=1
cursor.movePosition(QTextCursor.NextBlock)
self.sel_range=(start_pos,end_pos)
else:
print 'need to comment'
cursor.setPosition(start_pos)
for _line_nb in range(first_line, last_line+1):
if _line_nb==first_line:
self.moveToPosition(start_pos)
if self.position_in_block(cursor)>min_indent:
start_pos+=2
cursor.movePosition(QTextCursor.StartOfLine)
cursor.movePosition(
QTextCursor.Right, QTextCursor.MoveAnchor, min_indent)
self.textedit.setTextCursor(cursor)
cursor.insertText('%s ' % self.comment_string)
end_pos+=2
cursor.movePosition(QTextCursor.NextBlock)
self.sel_range=(start_pos,end_pos)
cursor.endEditBlock()
elif mode == 'get_text_cur_pos':
print 'get cur pos text'
cursor = self.textedit.textCursor()
positionInBlock = self.position_in_block(cursor)
print 'block pos:', positionInBlock
print 'block text:', cursor.block().text()
print cursor.block().text()[positionInBlock]
elif mode == 'tab':
print 'tab'
start_pos, end_pos = [cursor.selectionStart(),
cursor.selectionEnd()]
# get last first line
first_line,last_line = self.get_line_range(cursor,start_pos, end_pos)
print 'tab key:',first_line,last_line,range(first_line, last_line+1)
start_pos+=4
# indent 4 spaces
for _line_nb in range(first_line, last_line+1):
cursor.movePosition(QTextCursor.StartOfLine)
self.textedit.setTextCursor(cursor)
# skip empty line
if len(str(cursor.block().text()).strip()):
cursor.insertText(' '*4)
end_pos+=4
cursor.movePosition(QTextCursor.NextBlock)
self.sel_range=(start_pos,end_pos)
elif mode == 'shift_tab':
print 'shift_tab'
start_pos, end_pos = [cursor.selectionStart(),
cursor.selectionEnd()]
# get last first line
first_line,last_line = self.get_line_range(cursor,start_pos, end_pos)
for _line_nb in range(first_line, last_line+1):
cursor.movePosition(QTextCursor.StartOfLine)
if _line_nb==first_line:
for i in range(4):
next_char = cursor.block().text()[self.position_in_block(cursor)]
if next_char == ' ':
cursor.deleteChar()
start_pos-=1
end_pos-=1
else:
for i in range(4):
next_char = cursor.block().text()
if next_char:
next_char = next_char[self.position_in_block(cursor)]
else:
break
if next_char == ' ':
cursor.deleteChar()
end_pos-=1
self.textedit.setTextCursor(cursor)
cursor.movePosition(QTextCursor.NextBlock)
self.sel_range=(start_pos,end_pos)
elif mode == 'undo':
print 'undo'
# if self.last_change=='toggle_comment':
# self.toggle_comment()
self.textedit.undo()
elif mode == 'delete_line':
print 'delete_line'
cursor.beginEditBlock()
cursor.select(QTextCursor.LineUnderCursor)
cursor.removeSelectedText()
cursor.deleteChar()
cursor.endEditBlock()
elif mode == 'execute':
print 'execute'
# if self.lastnge=='toggle_comment':
# self.toggle_comment()
# if something selected, run it
start_pos, end_pos = [cursor.selectionStart(),
cursor.selectionEnd()]
if start_pos== end_pos:
# run all
cmd = self.textedit.toPlainText()
else:
cmd = cursor.selectedText()
# print cmd.__class__
# print cmd.toUtf8()
# cmd = '\n'.join(str(cmd.toUtf8()).splitlines())
cmd = str(cmd.toUtf8())
print 'before dedent cmd:\n',cmd[32],cmd[32] is u'\u2029'
# import textwrap
# cmd = textwrap.dedent(cmd)
cmd = self.dedent_code(cmd)
print 'will run cmd:\n',cmd
# exec(cmd)
def dedent_code(self,code):
indents=[]
for line in code.splitlines():
print '--->',line
spaces = len(line)-len(line.lstrip(' '))
indents.append(spaces)
indent = min(indents)
print 'min indents',indent
new_code=''
for line in code.splitlines():
if len(line)>indent:
print 'working on:',line
new_code+=line[indent:]+'\n'
else:
new_code+=line+'\n'
return new_code
def get_mel_global(var):
return mel.eval('$tmp_var=%s' % var)
gCommandExecuterTabs = get_mel_global('$gCommandExecuterTabs')
filter = CustomFilter()
#qApp.removeEventFilter(filter)
qApp.installEventFilter(filter)
# This can remove the filter we installed
# qApp.removeEventFilter(filter)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment