Skip to content

Commit

Permalink
Moved Coda's Zen Editor outside zencoding package, upgraded ZC core t…
Browse files Browse the repository at this point in the history
…o most recent version
  • Loading branch information
sergeche committed Feb 17, 2010
1 parent 5bdb06f commit dc99b00
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 99 deletions.
197 changes: 197 additions & 0 deletions src/Support/Library/zen_editor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
'''
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 zen_core as zen_coding
from zencoding import html_matcher
import re

class ZenEditor():
def __init__(self, context=None):
self._context = None
if context:
self.set_context(context)

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_coding.set_newline(tea.get_line_ending(context))
zen_coding.zen_settings['variables']['indentation'] = 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_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))
"""
text, rng = tea.get_line(self._context)
return rng.location, rng.location + rng.length

def get_caret_pos(self):
""" Returns current caret position """
return self.get_selection_range()[0]

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
"""
text, rng = tea.get_line(self._context)
return text

def replace_content(self, value, start=None, end=None):
"""
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)
value = self.add_placeholders(value)

cursor_loc = value.find('$0')
if cursor_loc != -1:
select_range = tea.new_range(cursor_loc + rng.location, 0)
value = value.replace('$0', '')
tea.insert_text_and_select(self._context, value, rng, select_range)
else:
tea.insert_text(self._context, value, rng)

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
"""
doc_type = 'html'
css_exts = ['css', 'less']
xsl_exts = ['xsl', 'xslt']
path = self._context.path()
if path is not None:
pos = path.rfind('.')
if pos != -1:
pos += 1
ext = path[pos:]
if ext in css_exts:
doc_type = 'css'
elif ext in xsl_exts:
doc_type = 'xsl'
elif ext == 'haml':
doc_type = 'haml'
elif ext == 'xml':
doc_type = 'xml'
# No luck with the extension; check for inline style tags
if doc_type == 'html':
range = tea.get_range(self._context)
caret_pos = self.get_caret_pos()

pair = html_matcher.get_tags(self.get_content(), caret_pos)
if pair and pair[0] and pair[0].type == 'tag'and pair[0].name.lower() == 'style':
# check that we're actually inside the tag
if pair[0].end <= caret_pos and pair[1].start >= caret_pos:
doc_type = 'css'

return doc_type

def get_profile_name(self):
"""
Returns current output profile name (@see zen_coding#setup_profile)
@return {String}
"""
syntax = self.get_syntax()
if syntax == 'xsl' or syntax == 'xml':
return 'xml'
else:
return 'xhtml'

def add_placeholders(self, text):
_ix = [0]

def get_ix(m):
if not _ix[0]:
_ix[0] += 1
return '$0'
else:
return ''

text = re.sub(r'\$', '\\$', text)
return re.sub(zen_coding.get_caret_placeholder(), get_ix, text)
2 changes: 1 addition & 1 deletion src/Support/Library/zencoding/html_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

def set_mode(new_mode):
global cur_mode
if new_mode != 'html': new_mode = 'xhtml'
cur_mode = new_mode

def make_map(elems):
Expand Down Expand Up @@ -181,7 +182,6 @@ def _find_pair(html, start_ix, mode='xhtml', action=make_range):
closing_tag = None
html_len = len(html)

if mode != 'html': mode = 'xhtml'
set_mode(mode)

def has_match(substr, start=None):
Expand Down
Loading

0 comments on commit dc99b00

Please sign in to comment.