Permalink
Browse files

Implement an expansions w/ variadic parameters (including named).

Lot of improvements in my C++ expansions:
* class and structure definitions now have a template parameters list
* simplified namespaces generator
* refactorings to make it faster and simplier (shorter code)
  • Loading branch information...
1 parent 2a44586 commit 95dd05df2bd6a82156b5aec57d46f766955b51d3 @zaufi committed Jun 10, 2012
Showing with 140 additions and 119 deletions.
  1. +31 −16 expand/expand.py
  2. +109 −103 expand/text_x-c++src.expand
View
@@ -21,7 +21,7 @@ class ParseError(Exception):
def wordAtCursor(document, view=None):
view = view or document.activeView()
cursor = view.cursorPosition()
- line = unicode(document.line(cursor.line()))
+ line = document.line(cursor.line())
start, end = wordAtCursorPosition(line, cursor)
return line[start:end]
@@ -46,15 +46,15 @@ def wordAndArgumentAtCursor(document, view=None):
if word_range.isEmpty():
word = None
else:
- word = unicode(document.text(word_range))
+ word = document.text(word_range)
if not argument_range or argument_range.isEmpty():
argument = None
else:
- argument = unicode(document.text(argument_range))
+ argument = document.text(argument_range)
return word, argument
def wordAndArgumentAtCursorRanges(document, cursor):
- line = unicode(document.line(cursor.line()))
+ line = document.line(cursor.line())
column_position = cursor.column()
# special case: cursor past end of argument
argument_range = None
@@ -64,7 +64,7 @@ def wordAndArgumentAtCursorRanges(document, cursor):
argument_end.setColumn(argument_end.column() + 1)
argument_range = kate.KTextEditor.Range(argument_start, argument_end)
cursor = argument_start
- line = unicode(document.line(cursor.line()))
+ line = document.line(cursor.line())
start, end = wordAtCursorPosition(line, cursor)
word_range = kate.KTextEditor.Range(cursor.line(), start, cursor.line(), end)
word = line[start:end]
@@ -173,7 +173,7 @@ def indentationCharacters(document):
indentationCharacters.configurationIndentWidth = int(indentWidth) if indentWidth else 4
# indent with tabs or spaces
useTabs = True
- spaceIndent = unicode(v.variable('space-indent'))
+ spaceIndent = v.variable('space-indent')
if spaceIndent == 'on':
useTabs = False
elif spaceIndent == 'off':
@@ -184,7 +184,7 @@ def indentationCharacters(document):
if useTabs:
return '\t'
else:
- indentWidth = unicode(v.variable('indent-width'))
+ indentWidth = v.variable('indent-width')
if indentWidth and indentWidth.isdigit():
return ' ' * int(indentWidth)
else:
@@ -201,24 +201,39 @@ def expandAtCursor():
except ParseError, e:
kate.popup('Parse error:', e)
return
- word = unicode(document.text(word_range))
+ word = document.text(word_range)
mime = str(document.mimeType())
expansions = loadExpansions(mime)
try:
func = expansions[word]
except KeyError:
kate.gui.popup('Expansion "%s" not found :(' % word, timeout=3, icon='dialog-warning', minTextWidth=200)
return
- argument = ()
+ arguments = []
+ namedArgs = {}
if argument_range is not None:
# strip parentheses and split arguments by comma
- argument = tuple(unicode(document.text(argument_range))[1:-1].split(','))
- # map foo() => foo
- if argument == ('',):
- argument = ()
- # document.removeText(word_range)
+ preArgs = [arg.strip() for arg in document.text(argument_range)[1:-1].split(',') if bool(arg.strip())]
+ print(">> EXPAND: arguments = " + repr(arguments))
+ # form a dictionary from args w/ '=' character, leave others in a list
+ for arg in preArgs:
+ print(">> EXPAND: current arg = " + repr(arg))
+ if '=' in arg:
+ key, value = [item.strip() for item in arg.split('=')]
+ print(">> EXPAND: key = " + repr(key))
+ print(">> EXPAND: value = " + repr(value))
+ namedArgs[key] = value
+ else:
+ arguments.append(arg)
+ # Call user expand function w/ parsed arguments and
+ # possible w/ named params dict
try:
- replacement = func(*argument)
+ print(">> EXPAND: arguments = " + repr(arguments))
+ print(">> EXPAND: named arguments = " + repr(namedArgs))
+ if len(namedArgs):
+ replacement = func(*arguments, **namedArgs)
+ else:
+ replacement = func(*arguments)
except Exception, e:
# remove the top of the exception, it's our code
try:
@@ -258,7 +273,7 @@ def replaceAbsolutePathWithLinkCallback(match):
if '\n' + (indentCharacters * i) + '\t' in replacement:
replacement = replacement.replace('\n' + (indentCharacters * i) + '\t', '\n' + (indentCharacters * (i + 1)))
insertPosition = word_range.start()
- line = unicode(document.line(insertPosition.line()))
+ line = document.line(insertPosition.line())
# autoindent: add the line's leading whitespace for each newline
# in the expansion
whitespace = ''
@@ -1,117 +1,127 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+#
+# Expansions in this file:
+#
+# cl(name[, T0[, T1[, ...[, Tn]]]])
+# Insert a class definition, possible w/ template parameters
+#
+#
+# st(name[, T0[, T1[, ...[, Tn]]]])
+# Insert a structure definition, possible w/ template parameters
+#
+#
+# t(T0[, T1[, ...[, Tn]]])
+# Insert a `template <typename T0, ..., typename Tn>' string
+#
+#
+# brief
+# Render a Doxygen \brief header
+#
+#
+# gs(type, member-name[, ref = No])
+# Insert simple getter/setter implementation for given member and type
+#
+#
+# main
+# Insert simple main() function
+#
+#
+# ns([name[::nested[::name]]])
+# Insert namespace(s). If name ommited anonymous namespace will be rendered.
+#
+#
+
from libkatepate import ui
-def main():
- return \
-'''int main(int argc, const char* const argv[])
-{
- %{cursor}
- return 0;
-}
+_BRIEF_DOC_TPL = '''
+/**
+ * \\brief Class \c {0}
+ */'''
+_TEMPLATE_PARAMS_TPL = '''
+template <{1}>'''
+_CLASS_BODY_TPL = '''
+class {0}
+{{
+public:
+ /// Default constructor
+ %{{cursor}}explicit {0}()
+ {{
+ }}
+ /// Destructor
+ virtual ~{0}()
+ {{
+ }}
+}};
+'''
+_STRUCT_BODY_TPL = '''
+struct {0}
+{{
+}};
'''
-def fori(count):
- return 'for (int i = 0; i < ' + count + '; ++i)\n ${cursor}'
+_NS_TPL = '''namespace {0} {{
+%{{cursor}}
+{1}{2}// namespace {3}
+'''
-def fore(typename, name):
- template = \
-'''for (
- {0}::const_iterator it = {1}.begin()
- , last = {1}.end()
- ; it != last
- ; ++it
- )
-{{
- %{{cursor}}
-}}
+_ANONYMOUS_NS_TPL = '''namespace {{
+%{{cursor}}
+}} // anonymous namespace
'''
- return template.format(typename, name)
+
def st(name, *templateParams):
''' Insert a structure definition
A first mandatory parameter is a structure name.
Everything after that will be template parameters.
- Template parameter declaration may contain a default value:
- st(foo, T, U = T, V = int)
+ st(foo, T, U, V)
will expand into:
- template <typename T, typename U = T, typename V = int>
+ template <typename T, typename U, typename V>
struct foo
{
};
'''
+ params = [name]
if len(templateParams):
- template = \
-'''/**
- * \\brief {0}
- */
-template <{1}>
-struct {0}
-{{
-}};
-'''
- return template.format(name, 'typename ' + ', typename '.join(templateParams))
- template = \
-'''/**
- * \\brief {0}
- */
-struct {0}
-{{
-}};
-'''
- return template.format(name)
+ template = _BRIEF_DOC_TPL + _TEMPLATE_PARAMS_TPL + _STRUCT_BODY_TPL
+ params.append('typename ' + ', typename '.join(templateParams))
+ else:
+ template = _BRIEF_DOC_TPL + _STRUCT_BODY_TPL
+ return template.format(*params)
+
def cl(name, *templateParams):
''' Insert a class definition
TODO It would be neat to have syntax like this:
cl(test, T, U, d=v, cc=del, mv=def)
i.e. define a class 'test' w/ template params T and U,
- w/ virtual detor, w/ deleted copy ctor/assign and w/
+ w/ virtual dtor, w/ deleted copy ctor/assign and w/
defaulted move ctor/assign.
Isn't it?
'''
+ params = [name]
if len(templateParams):
- template = \
-'''/**
- * \\brief {0}
- */
-template <{1}>
-class {0}
-{{
- %{{cursor}}explicit {0}()
- {{
- }}
- virtual ~{0}()
- {{
- }}
-}};
-'''
- return template.format(name, 'typename ' + ', typename '.join(templateParams))
- template = \
-'''/**
- * \\brief {0}
- */
-class {0}
-{{
- %{{cursor}}explicit {0}()
- {{
- }}
- virtual ~{0}()
- {{
- }}
-}};
-'''
- return template.format(name)
+ template = _BRIEF_DOC_TPL + _TEMPLATE_PARAMS_TPL + _CLASS_BODY_TPL
+ params.append('typename ' + ', typename '.join(templateParams))
+ else:
+ template = _BRIEF_DOC_TPL + _CLASS_BODY_TPL
+ return template.format(*params)
-def t():
- return 'template <typename T>'
+
+def t(*params):
+ '''Render template header w/ given template parameters list
+ '''
+ return 'template <typename ' + ', typename '.join(params) + '>'
def brief():
+ ''' Render a Doxygen brief header
+ '''
return \
'''/**
* \\brief %{cursor}
@@ -121,36 +131,23 @@ def brief():
def ns(name = None):
''' Insert named or anonymous namespace
'''
+ params = []
if bool(name):
- nsList = name.split('::')
- if len(nsList) > 1:
- nsOpen = ''
- nsReverseNames = ''
- for ns in nsList:
- nsOpen += 'namespace ' + ns + ' { '
- if bool(nsReverseNames):
- nsReverseNames = ns + ', ' + nsReverseNames
- else:
- nsReverseNames = ns
- nsReverseNames = '}' * len(nsList) + ' ' * (60 - len(nsList)) + '// namespace ' + nsReverseNames
- return nsOpen + '\n\n' + nsReverseNames + '\n'
- else:
- template = \
-'''namespace {0} {{
-%{{cursor}}
-}} // namespace {0}
-'''
+ nsList = [ns.strip() for ns in name.split('::')]
+ params.append(' { namespace '.join(nsList)) # NS header
+ params.append('}' * len(nsList)) # NS close curve brackets
+ params.append(' ' * (60 - len(nsList))) # space padding before comment
+ params.append(', '.join(reversed(nsList))) # NS close comment line
+ template = _NS_TPL
else:
- name = 'anonymous'
- template = \
-'''namespace {{
-%{{cursor}}
-}} // {0} namespace
-'''
- return template.format(name)
+ template = _ANONYMOUS_NS_TPL
+ return template.format(*params)
def gs(typeT, name, ref = None):
- ''' Insert getter/setter for mem
+ ''' Insert getter/setter for member
+
+ NOTE If member has a one of "standard" prefix 'm_' or suffix '_',
+ accessor name will be w/o it!
'''
template = \
'''{0} {1}() const
@@ -175,3 +172,12 @@ void {1}({0} value)
pure_name = name
return template.format(arg, pure_name, name)
+
+def main():
+ return \
+'''int main(int argc, const char* const argv[])
+{
+ %{cursor}
+ return 0;
+}
+'''

0 comments on commit 95dd05d

Please sign in to comment.