Last active
July 15, 2016 08:16
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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