Created
March 19, 2011 01:33
-
-
Save chergert/877130 to your computer and use it in GitHub Desktop.
try to get spacing/formatting right for my C style with gtksourceview
This file contains hidden or 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
#!/usr/bin/env python | |
""" | |
A simple editor built for live editing in GLib'ish manner. | |
""" | |
from gi.repository import GLib | |
from gi.repository import GObject | |
from gi.repository import Gtk | |
from gi.repository import GtkSource | |
from gi.repository import Pango | |
def getLastCharacter(iter, char, syncChar=None): | |
""" | |
Looks for last occurance of @char. If @syncChar is found, an equal | |
number of @char characters will be skipped. | |
""" | |
toSkip = 0 | |
iter = iter.copy() | |
while iter.backward_char(): | |
if iter.get_char() == syncChar: | |
toSkip += 1 | |
if iter.get_char() == char: | |
if toSkip: | |
toSkip -= 1 | |
else: | |
return iter.get_line(), iter.get_line_offset() | |
return -1, -1 | |
class AutoIndenter(GObject.Object): | |
__gtype_name__ = 'GbAutoIndenter' | |
def __init__(self, sourceView): | |
GObject.Object.__init__(self) | |
self.sourceView = sourceView | |
self.sourceBuffer = sourceView.get_buffer() | |
self.sourceBuffer.connect('insert-text', self.insertText) | |
def insertText(self, | |
sourceBuffer, | |
insertLocation, | |
insertText, | |
insertTextLenght, | |
userData=None): | |
""" | |
Handle insertion of text into the source buffer. | |
If the inserted text is a newline, then we will try to determine | |
where the next line of text should begin and properly space to | |
that position. | |
""" | |
line = insertLocation.get_line() | |
if insertText == '\n': | |
insertLocation.forward_chars(len(insertText) - 1) | |
predent, postdent = self.getIndentText(insertLocation.get_line()) | |
sourceBuffer.insert(insertLocation, predent) | |
origLine = insertLocation.get_line() | |
origLineOffset = insertLocation.get_line_offset() | |
sourceBuffer.insert(insertLocation, postdent) | |
insertLocation.set_line(origLine) | |
insertLocation.set_line_offset(origLineOffset) | |
elif insertText == '}': | |
line = insertLocation.get_line() | |
if not self.getLineText(line).strip(): | |
line, offset = getLastCharacter(insertLocation, '{', '}') | |
if line >= 0 and offset >= 0: | |
predent = '' | |
lineText = self.getLineText(line) | |
for i in lineText: | |
if i in (' ', '\t'): | |
predent += i | |
continue | |
break | |
startIter = insertLocation.copy() | |
startIter.set_line_offset(0) | |
sourceBuffer.delete(startIter, insertLocation) | |
sourceBuffer.insert(insertLocation, predent) | |
elif insertText == '/': | |
iter = insertLocation.copy() | |
iter.backward_char() | |
if iter.get_char() == ' ': | |
iter.backward_char() | |
if iter.get_char() == '*': | |
iter.forward_char() | |
sourceBuffer.delete(iter, insertLocation) | |
def getLineText(self, line): | |
if line < 0: | |
return "" | |
startIter = self.sourceBuffer.get_iter_at_line(line) | |
endIter = startIter.copy() | |
endIter.forward_to_line_end() | |
return self.sourceBuffer.get_slice(startIter, endIter, True) | |
def lineEndsDeclaration(self, line): | |
lineText = self.getLineText(line) | |
if lineText.strip().endswith(')'): | |
# Get the line that started this paranthesis | |
iter = self.sourceBuffer.get_iter_at_line(line) | |
iter.forward_to_line_end() | |
iter.backward_char() | |
cLine, cOffset = getLastCharacter(iter, '(', ')') | |
if cLine >= 0 and cOffset >= 0: | |
# If this line has content at offset 0, it is a function | |
cText = self.getLineText(cLine) | |
if cText[0] not in (' ', '\t'): | |
return True | |
def getIndentText(self, line): | |
""" | |
Retrieves the indentation text for the next line. Returns a two-part | |
tuple containing the data to add before the insertion and the data | |
to insert after the insertion. | |
For example, a tuple of: | |
('\n{', '\t\n}') | |
would indicate that adding { and tabbing in one level. | |
""" | |
if self.lineEndsDeclaration(line): | |
return ('\n{', '\t') | |
lineText = self.getLineText(line) | |
if lineText.strip() == '*/': | |
return ('', lineText[:lineText.index('*') - 1]) | |
if lineText.endswith(','): | |
if '(' in lineText: | |
predent = '' | |
iter = self.sourceBuffer.get_iter_at_line(line) | |
iter.forward_to_line_end() | |
cLine, cOffset = getLastCharacter(iter, '(', ')') | |
cLineText = self.getLineText(cLine) | |
for i in cLineText: | |
if i in (' ', '\t'): | |
predent += i | |
else: | |
break | |
predent += ' ' * cOffset | |
if cLine == line: | |
predent += ' ' | |
return ('', predent) | |
if lineText.strip()[:2] in ('*', '* ', '/*'): | |
return ('', lineText[:lineText.index('*')].replace('/', ' ') + '* ') | |
o = 0 | |
for i in lineText: | |
if i not in (' ', '\t'): | |
add = '' | |
if lineText.endswith('{') \ | |
and not lineText.strip().startswith('switch '): | |
add = '\t' | |
elif lineText.endswith(':') \ | |
and lineText.strip().startswith('case'): | |
add = '\t' | |
return ('', lineText[:o] + add) | |
o += 1 | |
return ('', lineText[:o]) | |
class FunctionStyler(GObject.Object): | |
__gtype_name__ = 'GbFunctionStyler' | |
def __init__(self, sourceView): | |
GObject.Object.__init__(self) | |
self.sourceView = sourceView | |
self.sourceBuffer = sourceView.get_buffer() | |
self.sourceBuffer.connect('insert-text', self.insertText) | |
def insertText(self, | |
sourceBuffer, | |
insertLocation, | |
insertText, | |
insertTextLenght, | |
userData=None): | |
if insertText == ')': | |
line, offset = getLastCharacter(insertLocation, '(', ')') | |
if line >= 0 and offset >= 0: | |
startIter = sourceBuffer.get_iter_at_line_offset(line, offset) | |
startIter.forward_char() | |
text = sourceBuffer.get_slice(startIter, insertLocation, True) | |
args = self.parseFuncDeclArgs(text) | |
if args: | |
self.reformatFuncDeclArgs(startIter, insertLocation, args) | |
def reformatFuncDeclArgs(self, startIter, endIter, args): | |
longestType = max([len(a) for a,b,c in args]) | |
longestDeref = max([len(b) for a,b,c in args]) | |
parts = [] | |
if longestDeref > 0: | |
formatString = '%%-%ds %%%ds%%s' % (longestType, longestDeref) | |
for arg in args: | |
parts.append(formatString % arg) | |
else: | |
formatString = '%%-%ds %%s' % longestType | |
for a,b,c in args: | |
parts.append(formatString % (a, c)) | |
offset = startIter.get_line_offset() | |
self.sourceBuffer.delete(startIter, endIter) | |
space = ' ' * offset | |
text = (',\n' + space).join(parts) | |
self.sourceBuffer.insert(endIter, text) | |
def parseFuncDeclArgs(self, text): | |
try: | |
args = [] | |
parts = [a.strip() for a in text.split(',')] | |
for part in parts: | |
tn = '' | |
dr = '' | |
nm = '' | |
if '*' in part: | |
tn_and_dr = part[:part.rindex('*') + 1] | |
nm = part[part.rindex('*') + 1:] | |
else: | |
t = part.replace('\t', ' ') | |
tn_and_dr, nm = [a.strip() for a in t.split(' ', 2)] | |
dr = '*' * tn_and_dr.count('*') | |
tn = tn_and_dr.replace('*','') | |
args.append((tn.strip(), dr.strip(), nm.strip())) | |
if len(args): | |
return args | |
except Exception, err: | |
print err | |
if __name__ == '__main__': | |
w = Gtk.Window() | |
w.props.title = 'ChergsEdit' | |
w.props.window_position = Gtk.WindowPosition.CENTER | |
w.set_default_size(700, 800) | |
s = Gtk.ScrolledWindow(visible=True) | |
w.add(s) | |
lm = GtkSource.LanguageManager.get_default() | |
cm = GtkSource.StyleSchemeManager.get_default() | |
b = GtkSource.Buffer(language=lm.get_language("c"), | |
style_scheme=cm.get_scheme("tango")) | |
v = GtkSource.View(**{ | |
'visible': True, | |
'buffer': b, | |
'auto-indent': False, | |
'indent-width': 4, | |
'tab-width': 4, | |
'right-margin-position': 80, | |
'highlight-current-line': True, | |
'show-line-numbers': True, | |
'show-right-margin': True, | |
}) | |
s.add(v) | |
ai = AutoIndenter(v) | |
fs = FunctionStyler(v) | |
fd = Pango.FontDescription() | |
fd.set_family("Monospace") | |
fd.set_size(Pango.SCALE * 10) | |
v.override_font(fd) | |
w.connect('delete-event', lambda *_: Gtk.main_quit()) | |
w.present() | |
Gtk.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment