Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implemented Zen Editor interface

  • Loading branch information...
commit 6c8d0825e65f6fc567f1e40b2f867a1506380195 1 parent e160acf
@sergeche authored
View
5 .pydevproject
@@ -3,8 +3,9 @@
<pydev_project>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
-<path>/tea-for-espresso/src</path>
+<path>/tea-for-espresso/src/Support/Library</path>
+<path>/tea-for-espresso/src/Support/Scripts</path>
</pydev_pathproperty>
-<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.5</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
</pydev_project>
View
337 src/Support/Library/zencoding/zen_actions.py
@@ -0,0 +1,337 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Middleware layer that communicates between editor and Zen Coding.
+This layer describes all available Zen Coding actions, like
+"Expand Abbreviation".
+@author Sergey Chikuyonok (serge.che@gmail.com)
+@link http://chikuyonok.ru
+"""
+import zen_core as zen
+import re
+import html_matcher
+
+def find_abbreviation(editor):
+ """
+ Search for abbreviation in editor from current caret position
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ @return: str
+ """
+ start, end = editor.get_selection_range()
+ if start != end:
+ # abbreviation is selected by user
+ return editor.get_content()[start, end];
+
+ # search for new abbreviation from current caret position
+ cur_line_start, cur_line_end = editor.get_current_line_range()
+ return zen.extract_abbreviation(editor.get_content()[cur_line_start, start])
+
+def expand_abbreviation(editor, syntax, profile_name='xhtml'):
+ """
+ Find from current caret position and expand abbreviation in editor
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ @param syntax: Syntax type (html, css, etc.)
+ @type syntax: str
+ @param profile_name: Output profile name (html, xml, xhtml)
+ @type profile_name: str
+ @return: True if abbreviation was expanded successfully
+ """
+ range_start, caret_pos = editor.get_selection_range()
+ abbr = find_abbreviation(editor)
+ content = ''
+
+ if abbr:
+ content = zen.expand_abbreviation(abbr, syntax, profile_name)
+ if content:
+ editor.replace_content(content, caret_pos - len(abbr), caret_pos)
+ return True
+
+ return False
+
+def expand_abbreviation_with_tab(editor, syntax, profile_name='xhtml'):
+ """
+ A special version of <code>expandAbbreviation</code> function: if it can't
+ find abbreviation, it will place Tab character at caret position
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ @param syntax: Syntax type (html, css, etc.)
+ @type syntax: str
+ @param profile_name: Output profile name (html, xml, xhtml)
+ @type profile_name: str
+ """
+ if not expand_abbreviation(editor, syntax, profile_name):
+ editor.replace_content('\t', editor.get_caret_pos())
+
+def match_pair(editor, direction='out'):
+ """
+ Find and select HTML tag pair
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ @param direction: Direction of pair matching: 'in' or 'out'.
+ @type direction: str
+ """
+ direction = direction.lower()
+
+ range_start, range_end = editor.get_selection_range()
+ cursor = range_end
+ content = editor.get_content()
+ range = None
+
+
+ old_open_tag = html_matcher.last_match['opening_tag']
+ old_close_tag = html_matcher.last_match['closing_tag']
+
+ if direction == 'in' and old_open_tag and range_start != range_end:
+# user has previously selected tag and wants to move inward
+ if not old_close_tag:
+# unary tag was selected, can't move inward
+ return False
+ elif old_open_tag['start'] == range_start:
+ raise Exception, 'search inward'
+ if content[old_open_tag['end']] == '<':
+# test if the first inward tag matches the entire parent tag's content
+ _r = html_matcher.find(content, old_open_tag['end'] + 1)
+ if _r[0] == old_open_tag['end'] and _r[1] == old_close_tag['start']:
+ range = html_matcher.match(content, old_open_tag['end'] + 1)
+ else:
+ range = (old_open_tag['end'], old_close_tag['start'])
+ else:
+ range = (old_open_tag['end'], old_close_tag['start'])
+ else:
+ new_cursor = content[0, old_close_tag['start']].find('<', old_open_tag['end'])
+ search_pos = new_cursor + 1 if new_cursor != -1 else old_open_tag['end']
+ range = html_matcher.match(content, search_pos)
+ else:
+ range = html_matcher.match(content, cursor)
+
+
+ if range[0] is not None:
+ editor.create_selection(range[0], range[1])
+ return True
+ else:
+ return False
+
+def wrap_with_abbreviation(editor, abbr, syntax, profile_name='xhtml'):
+ """
+ Wraps content with abbreviation
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ @param syntax: Syntax type (html, css, etc.)
+ @type syntax: str
+ @param profile_name: Output profile name (html, xml, xhtml)
+ @type profile_name: str
+ """
+ start_offset, end_offset = editor.get_selection_range()
+ content = editor.get_content()
+
+ if not abbr: return None
+
+ if start_offset == end_offset:
+ # no selection, find tag pair
+ range = html_matcher.match(content, start_offset)
+
+ if range[0] is None: # nothing to wrap
+ return None
+
+ start_offset = range[0]
+ end_offset = range[1]
+
+ # narrow down selection until first non-space character
+ while start_offset < end_offset:
+ if not content[start_offset].isspace(): break
+ start_offset += 1
+
+ while end_offset > start_offset:
+ end_offset -= 1
+ if not content[end_offset].isspace():
+ end_offset += 1
+ break
+
+ new_content = content[start_offset:end_offset]
+ result = zen.wrap_with_abbreviation(abbr, unindent(editor, new_content), syntax, profile_name)
+
+ if result:
+ editor.replace_content(result, start_offset, end_offset)
+
+def unindent(editor, text):
+ """
+ Unindent content, thus preparing text for tag wrapping
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ @param text: str
+ @return str
+ """
+ pad = get_current_line_padding(editor)
+ lines = zen.split_by_lines(text)
+
+ for i,line in enumerate(lines):
+ if line.find(pad) == 0:
+ lines[i] = line[len(pad):]
+
+ return zen.get_newline().join(lines)
+
+def get_current_line_padding(editor):
+ """
+ Returns padding of current editor's line
+ @return str
+ """
+ line = editor.get_current_line()
+ m = re.match(r'^(\s+)', line)
+ return m and m.group(0) or ''
+
+def find_new_edit_point(editor, inc=1, offset=0):
+ """
+ Search for new caret insertion point
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ @param inc: Search increment: -1 — search left, 1 — search right
+ @param offset: Initial offset relative to current caret position
+ @return: -1 if insertion point wasn't found
+ """
+ cur_point = editor.get_caret_pos() + offset
+ content = editor.get_content()
+ max_len = len(content)
+ next_point = -1
+ re_empty_line = r'^\s+$'
+
+ def get_line(ix):
+ start = ix
+ while start >= 0:
+ c = content[start]
+ if c == '\n' or c == '\r': break
+ start -= 1
+
+ return content[start:ix]
+
+ while cur_point < max_len and cur_point > 0:
+ cur_point += inc
+ cur_char = content[cur_point]
+ next_char = content[cur_point + 1]
+ prev_char = content[cur_point - 1]
+
+ if cur_char in '"\'':
+ if next_char == cur_char and prev_char == '=':
+ # empty attribute
+ next_point = cur_point + 1
+ elif cur_char == '>' and next_char == '<':
+ # between tags
+ next_point = cur_point + 1
+ elif cur_char in '\r\n':
+ # empty line
+ if re.search(re_empty_line, get_line(cur_point - 1)):
+ next_point = cur_point
+
+ if next_point != -1: break
+
+ return next_point
+
+def prev_edit_point(editor):
+ """
+ Move caret to previous edit point
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ """
+ cur_pos = editor.get_caret_pos()
+ new_point = find_new_edit_point(editor, -1)
+
+ if new_point == cur_pos:
+ # we're still in the same point, try searching from the other place
+ new_point = find_new_edit_point(editor, -1, -2)
+
+ if new_point != -1:
+ editor.set_caret_pos(new_point)
+
+def next_edit_point(editor):
+ """
+ Move caret to next edit point
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ """
+ new_point = find_new_edit_point(editor, 1)
+ if new_point != -1:
+ editor.set_caret_pos(new_point)
+
+def insert_formatted_newline(editor, mode='html'):
+ """
+ Inserts newline character with proper indentation
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ @param mode: Syntax mode (only 'html' is implemented)
+ @type mode: str
+ """
+ caret_pos = editor.get_caret_pos()
+
+ def insert_nl():
+ editor.replace_content('\n', caret_pos)
+
+ if mode == 'html':
+ # let's see if we're breaking newly created tag
+ pair = html_matcher.get_tags(editor.get_content(), editor.get_caret_pos())
+
+ if pair[0] and pair[1] and pair[0]['type'] == 'tag' and pair[0]['end'] == caret_pos and pair[1]['start'] == caret_pos:
+ editor.replace_content('\n\t|\n', caret_pos)
+ else:
+ insert_nl()
+ else:
+ insert_nl()
+
+def select_line(editor):
+ """
+ Select line under cursor
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ """
+ start, end = editor.get_current_line_range();
+ editor.create_selection(start, end)
+
+def go_to_matching_pair(editor):
+ """
+ Moves caret to matching opening or closing tag
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ """
+ content = editor.get_content()
+ caret_pos = editor.get_caret_pos()
+
+ if content[caret_pos] == '<':
+ # looks like caret is outside of tag pair
+ caret_pos += 1
+
+ range = html_matcher.match(content, caret_pos)
+
+ if range[0] is not None:
+ # match found
+ open_tag = html_matcher.last_match['opening_tag']
+ close_tag = html_matcher.last_match['closing_tag']
+
+ if close_tag: # exclude unary tags
+ if open_tag['start'] <= caret_pos and open_tag['end'] >= caret_pos:
+ editor.set_caret_pos(close_tag['start'])
+ elif close_tag['start'] <= caret_pos and close_tag['end'] >= caret_pos:
+ editor.set_caret_pos(open_tag['start'])
+
+
+def merge_lines(editor):
+ """
+ Merge lines spanned by user selection. If there's no selection, tries to find
+ matching tags and use them as selection
+ @param editor: Editor instance
+ @type editor: ZenEditor
+ """
+ start, end = editor.get_selection_range()
+ if start == end:
+ # find matching tag
+ pair = html_matcher.match(editor.get_content(), editor.get_caret_pos())
+ if pair and pair[0] is not None:
+ start, end = pair
+
+ if start != end:
+ # got range, merge lines
+ text = editor.get_content()[start, end]
+ lines = map(lambda s: re.sub(r'^\s+', '', s), zen.split_by_lines(text))
+ text = re.sub(r'\s{2,}', ' ', ''.join(lines))
+ editor.replace_content(text, start, end)
+ editor.create_selection(start, start + len(text))
View
194 src/Support/Library/zencoding/zen_core.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
-Core Zen Coding library. Contains various text manupulation functions:
+Core Zen Coding library. Contains various text manipulation functions:
== Expand abbreviation
Expands abbreviation like ul#nav>li*5>a into a XHTML string.
@@ -9,7 +9,7 @@
First, you have to extract current string (where cursor is) from your test
editor and use <code>find_abbr_in_line()</code> method to extract abbreviation.
If abbreviation was found, this method will return it as well as position index
-of abbreviation inside current line. If abbreation wasn't
+of abbreviation inside current line. If abbreviation wasn't
found, method returns empty string. With abbreviation found, you should call
<code>parse_into_tree()</code> method to transform abbreviation into a tag tree.
This method returns <code>Tag</code> object on success, None on failure. Then
@@ -90,7 +90,7 @@ def is_allowed_char(ch):
@type ch: str
@return: bool
"""
- return ch.isalnum() or ch in "#.>+*:$-_!@"
+ return ch.isalnum() or ch in "#.>+*:$-_!@[]"
def split_by_lines(text, remove_empty=False):
"""
@@ -144,6 +144,13 @@ def get_newline():
"""
return newline
+def set_newline(char):
+ """
+ Sets newline character used in Zen Coding
+ """
+ global newline
+ newline = char
+
def string_to_hash(text):
"""
Helper function that transforms string into hash
@@ -262,6 +269,122 @@ def get_settings_resource(res_type, abbr, res_name):
return zen_settings[v][res_name][abbr]
return None;
+def get_word(ix, text):
+ """
+ Get word, starting at <code>ix</code> character of <code>text</code>
+ @param ix: int
+ @param text: str
+ """
+ m = re.match(r'^[\w\-:\$]+', text[ix:])
+ return m.group(0) if m else ''
+
+def extract_attributes(attr_set):
+ """
+ Extract attributes and their values from attribute set
+ @param attr_set: str
+ """
+ attr_set = attr_set.strip()
+ loop_count = 100 # endless loop protection
+ re_string = r'^(["\'])((?:(?!\1)[^\\]|\\.)*)\1'
+ result = []
+
+ while attr_set and loop_count:
+ loop_count -= 1
+ attr_name = get_word(0, attr_set)
+ attr = None
+ if attr_name:
+ attr = {'name': attr_name, 'value': ''}
+
+ # let's see if attribute has value
+ ch = attr_set[len(attr_name)] if len(attr_set) > len(attr_name) else ''
+ if ch == '=':
+ ch2 = attr_set[len(attr_name) + 1]
+ if ch2 in '"\'':
+ # we have a quoted string
+ m = re.match(re_string, attr_set[len(attr_name) + 1:])
+ if m:
+ attr['value'] = m.group(2)
+ attr_set = attr_set[len(attr_name) + len(m.group(0)) + 1:].strip()
+ else:
+ # something wrong, break loop
+ attr_set = ''
+ else:
+ # unquoted string
+ m = re.match(r'^(.+?)(\s|$)', attr_set[len(attr_name) + 1:])
+ if m:
+ attr['value'] = m.group(1)
+ attr_set = attr_set[len(attr_name) + len(m.group(1)) + 1:].strip()
+ else:
+ # something wrong, break loop
+ attr_set = ''
+
+ else:
+ attr_set = attr_set[len(attr_name):].strip()
+ else:
+ # something wrong, can't extract attribute name
+ break
+
+ if attr: result.append(attr)
+
+ return result
+
+def parse_attributes(text):
+ """
+ Parses tag attributes extracted from abbreviation
+ """
+
+# Example of incoming data:
+# #header
+# .some.data
+# .some.data#header
+# [attr]
+# #item[attr=Hello other="World"].class
+
+ result = []
+ class_name = None
+ char_map = {'#': 'id', '.': 'class'}
+
+ # walk char-by-char
+ i = 0
+ il = len(text)
+
+ while i < il:
+ ch = text[i]
+
+ if ch == '#': # id
+ val = get_word(i, text[1:])
+ result.append({'name': char_map[ch], 'value': val})
+ i += len(val) + 1
+
+ elif ch == '.': #class
+ val = get_word(i, text[1:])
+ if not class_name:
+ # remember object pointer for value modification
+ class_name = {'name': char_map[ch], 'value': ''}
+ result.append(class_name)
+
+ if class_name['value']:
+ class_name['value'] += ' ' + val
+ else:
+ class_name['value'] = val
+
+ i += len(val) + 1
+
+ elif ch == '[': # begin attribute set
+ # search for end of set
+ end_ix = text.find(']', i)
+ if end_ix == -1:
+ # invalid attribute set, stop searching
+ i = len(text)
+ else:
+ result.extend(extract_attributes(text[i + 1:end_ix]))
+ i = end_ix
+ else:
+ i += 1
+
+
+ return result
+
def parse_into_tree(abbr, doc_type='html'):
"""
@@ -274,7 +397,8 @@ def parse_into_tree(abbr, doc_type='html'):
@return: Tag
"""
root = Tag('', 1, doc_type)
- token = re.compile(r'([\+>])?([a-z@\!][a-z0-9:\-]*)(#[\w\-\$]+)?((?:\.[\w\-\$]+)*)(\*(\d*))?', re.IGNORECASE)
+# token = re.compile(r'([\+>])?([a-z@\!][a-z0-9:\-]*)(#[\w\-\$]+)?((?:\.[\w\-\$]+)*)(\*(\d*))?(\+$)?', re.IGNORECASE)
+ token = re.compile(r'([\+>])?([a-z@\!][a-z0-9:\-]*)((?:(?:[#\.][\w\-\$]+)|(?:\[[^\]]+\]))+)?(\*(\d*))?(\+$)?', re.IGNORECASE)
if not abbr:
return None
@@ -284,16 +408,20 @@ def expando_replace(m):
a = get_abbreviation(doc_type, ex)
return a and a.value or ex
- def token_expander(operator, tag_name, id_attr, class_name, has_multiplier, multiplier):
+ def token_expander(operator, tag_name, attrs, has_multiplier, multiplier, has_expando):
multiply_by_lines = (has_multiplier and not multiplier)
multiplier = multiplier and int(multiplier) or 1
+
+ if has_expando:
+ tag_name += '+'
+
current = is_snippet(tag_name, doc_type) and Snippet(tag_name, multiplier, doc_type) or Tag(tag_name, multiplier, doc_type)
- if id_attr:
- current.add_attribute('id', id_attr[1:])
- if class_name:
- current.add_attribute('class', class_name[1:].replace('.', ' '))
+ if attrs:
+ attrs = parse_attributes(attrs)
+ for attr in attrs:
+ current.add_attribute(attr['name'], attr['value'])
# dive into tree
if operator == '>' and token_expander.last:
@@ -314,7 +442,9 @@ def token_expander(operator, tag_name, id_attr, class_name, has_multiplier, mult
token_expander.last = None
- abbr = re.sub(token, lambda m: token_expander(m.group(1), m.group(2), m.group(3), m.group(4), m.group(5), m.group(6)), abbr)
+# abbr = re.sub(token, lambda m: token_expander(m.group(1), m.group(2), m.group(3), m.group(4), m.group(5), m.group(6), m.group(7)), abbr)
+ # Issue from Einar Egilsson
+ abbr = token.sub(lambda m: token_expander(m.group(1), m.group(2), m.group(3), m.group(4), m.group(5), m.group(6)), abbr)
root.last = token_expander.last
@@ -357,6 +487,25 @@ def expand_abbreviation(abbr, doc_type = 'html', profile_name = 'plain'):
return ''
+def extract_abbreviation(text):
+ cur_offset = len(text)
+ start_index = -1
+
+ while True:
+ cur_offset -= 1
+ if cur_offset < 0:
+ # moved at string start
+ start_index = 0;
+ break
+
+ ch = text[cur_offset]
+
+ if not is_allowed_char(ch) or (ch == '>' and is_ends_with_tag(text[0, cur_offset + 1])):
+ start_index = cur_offset + 1
+ break
+
+ return text[start_index] if start_index != -1 else ''
+
def is_inside_tag(html, cursor_pos):
re_tag = re.compile(r'^<\/?\w[\w\:\-]*.*?>')
@@ -402,6 +551,9 @@ def wrap_with_abbreviation(abbr, text, doc_type='html', profile='plain'):
def update_settings(settings):
globals()['zen_settings'] = settings
+
+def set_insertion_point(ins_point):
+ globals()['insertion_point'] = ins_point
class Tag(object):
def __init__(self, name, count=1, doc_type='html'):
@@ -416,10 +568,11 @@ def __init__(self, name, count=1, doc_type='html'):
name = name.lower()
abbr = get_abbreviation(doc_type, name)
+
if abbr and abbr.type == stparser.TYPE_REFERENCE:
abbr = get_abbreviation(doc_type, abbr.value)
- self.name = abbr and abbr.value['name'] or name
+ self.name = abbr and abbr.value['name'] or name.replace('+', '')
self.count = count
self.children = []
self.attributes = []
@@ -527,10 +680,10 @@ def has_block_children(self):
return True
return False
- def set_content(self, content):
+ def set_content(self, content): #@DuplicatedSignature
self.__content = content
- def get_content(self):
+ def get_content(self): #@DuplicatedSignature
return self.__content
def find_deepest_child(self):
@@ -588,6 +741,9 @@ def to_string(self, profile_name):
cursor = profile['place_cursor'] and '|' or ''
self_closing = ''
+ is_empty = self.is_empty() and not self.children
+
+
if profile['self_closing_tag'] == 'xhtml':
self_closing = ' /'
elif profile['self_closing_tag'] == True:
@@ -608,7 +764,7 @@ def allow_newline(tag):
deepest_child = self.find_deepest_child()
# output children
- if not self.is_empty():
+ if not is_empty:
if deepest_child and self.repeat_by_lines:
deepest_child.set_content(content_placeholder)
@@ -622,7 +778,7 @@ def allow_newline(tag):
# define opening and closing tags
if self.name:
tag_name = profile['tag_case'] == 'upper' and self.name.upper() or self.name.lower()
- if self.is_empty():
+ if is_empty:
start_tag = '<%s%s%s>' % (tag_name, attrs, self_closing)
else:
start_tag, end_tag = '<%s%s>' % (tag_name, attrs), '</%s>' % tag_name
@@ -638,7 +794,7 @@ def allow_newline(tag):
if self.name:
if content:
content = pad_string(content, profile['indent'] and 1 or 0)
- elif not self.is_empty():
+ elif not is_empty:
start_tag += cursor
# repeat tag by lines count
@@ -745,5 +901,7 @@ def to_string(self, profile_name):
setup_profile('xml', {'self_closing_tag': True, 'tag_nl': True});
setup_profile('plain', {'tag_nl': False, 'indent': False, 'place_cursor': False});
-# init settings
-#zen_settings = stparser.get_settings()
+# This method call explicity loads default settings from zen_settings.py on start up
+# Comment this line if you want to load data from other resources (like editor's
+# native snippet)
+update_settings(stparser.get_settings())
View
167 src/Support/Library/zencoding/zen_editor.py
@@ -0,0 +1,167 @@
+'''
+High-level editor interface that communicates with underlying editor (like
+Espresso, Coda, etc.) or browser.
+Basically, you should call <code>set_context(obj)</code> method to
+set up undelying editor context before using any other method.
+
+This interface is used by <i>zen_actions.py</i> for performing different
+actions like <b>Expand abbreviation</b>
+
+@example
+import zen_editor
+zen_editor.set_context(obj);
+//now you are ready to use editor object
+zen_editor.get_selection_range();
+
+@author Sergey Chikuyonok (serge.che@gmail.com)
+@link http://chikuyonok.ru
+'''
+import tea_actions as tea
+from zencoding import settings_loader
+from zencoding import zen_core as zen
+
+class ZenEditor():
+ def __init__(self):
+ self._context = None
+ self.zen_settings = settings_loader.load_settings()
+ zen.update_settings(self.zen_settings)
+
+ # This allows us to use smart incrementing tab stops in zen snippets
+ point_ix = [0]
+ def place_ins_point(text):
+ point_ix[0] += 1
+ return '$%s' % point_ix[0]
+ zen.insertion_point = place_ins_point
+
+ def set_context(self, context):
+ """
+ Setup underlying editor context. You should call this method
+ <code>before</code> using any Zen Coding action.
+ @param context: context object
+ """
+ self._context = context
+ zen.newline = self.safe_str(tea.get_line_ending(context))
+ self.zen_settings['variables']['indentation'] = self.safe_str(tea.get_indentation_string(context))
+
+ def get_selection_range(self):
+ """
+ Returns character indexes of selected text
+ @return: list of start and end indexes
+ @example
+ start, end = zen_editor.get_selection_range();
+ print('%s, %s' % (start, end))
+ """
+ rng = tea.get_first_range(self._context)
+ return rng.location, rng.location + rng.length
+
+
+ def create_selection(self, start, end=None):
+ """
+ Creates selection from <code>start</code> to <code>end</code> character
+ indexes. If <code>end</code> is ommited, this method should place caret
+ and <code>start</code> index
+ @type start: int
+ @type end: int
+ @example
+ zen_editor.create_selection(10, 40)
+ # move caret to 15th character
+ zen_editor.create_selection(15)
+ """
+ if end is None: end = start
+ new_range = tea.new_range(start, end - start)
+ tea.set_selected_range(self._context, new_range)
+
+ def get_current_line_range(self):
+ """
+ Returns current line's start and end indexes
+ @return: list of start and end indexes
+ @example
+ start, end = zen_editor.get_current_line_range();
+ print('%s, %s' % (start, end))
+ """
+ rng = tea.get_ranges(self._context)[0]
+ text, rng = tea.get_line(self._context, rng)
+ return rng.location, rng.location + rng.length
+
+ def get_caret_pos(self):
+ """ Returns current caret position """
+ range = tea.get_ranges(self._context)[0]
+ return range.location
+
+ def set_caret_pos(self, pos):
+ """
+ Set new caret position
+ @type pos: int
+ """
+ self.create_selection(pos)
+
+ def get_current_line(self):
+ """
+ Returns content of current line
+ @return: str
+ """
+ rng = tea.get_ranges(self._context)[0]
+ text, rng = tea.get_line(self._context, rng)
+ return text
+
+ def replace_content(self, value, start=None, end=None, undo_name = 'Replace content'):
+ """
+ Replace editor's content or it's part (from <code>start</code> to
+ <code>end</code> index). If <code>value</code> contains
+ <code>caret_placeholder</code>, the editor will put caret into
+ this position. If you skip <code>start</code> and <code>end</code>
+ arguments, the whole target's content will be replaced with
+ <code>value</code>.
+
+ If you pass <code>start</code> argument only,
+ the <code>value</code> will be placed at <code>start</code> string
+ index of current content.
+
+ If you pass <code>start</code> and <code>end</code> arguments,
+ the corresponding substring of current target's content will be
+ replaced with <code>value</code>
+ @param value: Content you want to paste
+ @type value: str
+ @param start: Start index of editor's content
+ @type start: int
+ @param end: End index of editor's content
+ @type end: int
+ """
+ if start is None: start = 0
+ if end is None: end = len(self.get_content())
+ rng = tea.new_range(start, end - start)
+ tea.insert_text_over_range(self._context, value, rng, undo_name)
+
+
+ def get_content(self):
+ """
+ Returns editor's content
+ @return: str
+ """
+ return self._context.string()
+
+ def get_syntax(self):
+ """
+ Returns current editor's syntax mode
+ @return: str
+ """
+ zones = {
+ 'css, css *': 'css',
+ 'xsl, xsl *': 'xsl',
+ 'xml, xml *': 'xml'
+ }
+ rng = tea.get_first_range(self._context)
+ return tea.select_from_zones(self._context, rng, 'html', **zones)
+
+ def get_profile_name(self):
+ """
+ Returns current output profile name (@see zen_coding#setup_profile)
+ @return {String}
+ """
+ return 'xhtml'
+
+ def safe_str(self, text):
+ """
+ Creates safe string representation to deal with Python's encoding issues
+ """
+ return text.encode('utf-8')
Please sign in to comment.
Something went wrong with that request. Please try again.