Skip to content
This repository has been archived by the owner on Aug 8, 2019. It is now read-only.

Commit

Permalink
introduce zenify which reduces selection to abbreviation
Browse files Browse the repository at this point in the history
  • Loading branch information
fmarcia committed May 25, 2010
1 parent 2c43760 commit 96a8f9c
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 10 deletions.
154 changes: 144 additions & 10 deletions zencoding/html_navigation.py
Expand Up @@ -24,8 +24,41 @@

import re

def factorize(zen_children):

zen_children = filter(lambda s: s, zen_children)

if len(zen_children) > 1:

zen_count = [1 for x in range(0, len(zen_children))]
index = 0
previous_child = ''

for zen_child in zen_children:
if zen_child == previous_child:
zen_count[index] = zen_count[index - 1] + 1
zen_count[index - 1] = 0
zen_children[index - 1] = ''
previous_child = zen_child
index += 1

index = 0
for zen_child in zen_children:
if zen_count[index] > 1:
parts = zen_child.split('>')
zen_children[index] = parts[0] + '*' + repr(zen_count[index])
if len(parts) > 1:
zen_children[index] += '>' + '>'.join(parts[1:])
index += 1

zen_children = filter(lambda s: s, zen_children)

return zen_children


class Node ():

tag_types_basic = ['tag', 'empty-tag']
tag_types = ['tag', 'empty-tag', 'question-tag', 'exclam-tag', 'comment', 'cdata']
data_types = [ 'data', 'value' ]
other_types = [ 'root', 'attribute' ]
Expand Down Expand Up @@ -61,10 +94,11 @@ def first_child_data(self):
return child
return None

def first_child_tag(self):
def first_child_tag(self, basic = False):
tag_types = Node.tag_types_basic if basic else Node.tag_types
if len(self.children) > 0:
for child in self.children:
if child.type in Node.tag_types:
if child.type in tag_types:
return child
return None

Expand All @@ -76,13 +110,14 @@ def next_sibling(self):
return siblings[index + 1]
return None

def next_sibling_tag(self):
def next_sibling_tag(self, basic = False):
tag_types = Node.tag_types_basic if basic else Node.tag_types
if self.parent:
siblings = self.parent.children
index = siblings.index(self)
while index < len(siblings) - 1:
index += 1
if siblings[index].type in Node.tag_types:
if siblings[index].type in tag_types:
return siblings[index]
return None

Expand All @@ -91,11 +126,12 @@ def last_child(self):
return self.children[-1]
return None

def last_child_tag(self):
def last_child_tag(self, basic = False):
tag_types = Node.tag_types_basic if basic else Node.tag_types
index = len(self.children)
while index > 0:
index -= 1
if self.children[index].type in Node.tag_types:
if self.children[index].type in tag_types:
return self.children[index]
return None

Expand All @@ -107,24 +143,42 @@ def previous_sibling(self):
return siblings[index - 1]
return None

def previous_sibling_tag(self):
def previous_sibling_tag(self, basic = False):
tag_types = Node.tag_types_basic if basic else Node.tag_types
if self.parent:
siblings = self.parent.children
index = siblings.index(self)
while index > 0:
index -= 1
if siblings[index].type in Node.tag_types:
if siblings[index].type in tag_types:
return siblings[index]
return None

def parent_tag(self):
def parent_tag(self, basic = False):
test = self
tag_types = Node.tag_types_basic if basic else Node.tag_types
while True:
test = test.parent
if test and test.type in Node.tag_types:
if test and test.type in tag_types:
return test
return None

def is_child_of(self, node):
parent = self.parent
while parent:
if parent == node:
return True
parent = parent.parent
return False

def is_sibling_of(self, node):
if self.parent and self.parent.children:
children = self.parent.children
for child in children:
if child == node:
return True
return False

def inner_bounds(self, offset_start, offset_end):

if self.type in ['data', 'attribute'] and self.parent:
Expand Down Expand Up @@ -170,6 +224,44 @@ def outer_bounds(self, offset_start, offset_end):

return None, None

def zenify(self, content):

result = ''

if self.type not in Node.tag_types_basic:
return ''

zen_id = ''
zen_class = ''
zen_children = []
for child in self.children:
name = child.name.lower()
if child.type == 'attribute' and name in ['id', 'class']:
for grand_child in child.children:
if grand_child.type == 'value' and grand_child.start < grand_child.end and not grand_child.children:
if name == 'id':
zen_id = '#' + content[grand_child.start:grand_child.end]
elif name == 'class':
zen_class = '.' + '.'.join(filter(lambda s: s, re.split(' +', content[grand_child.start:grand_child.end])))
if child.type in Node.tag_types_basic:
zen_children.append(child.zenify(content))

zen_children = filter(lambda s: s, zen_children)

zen_children = factorize(zen_children)

if len(zen_children) == 0:
zen_children_string = ''
elif len(zen_children) == 1:
zen_children_string = '>' + zen_children[0]
else:
zen_children_string = '>(' + '+'.join(zen_children) + ')'

if zen_children_string:
return '(' + self.name + zen_id + zen_class + zen_children_string + ')'
else:
return self.name + zen_id + zen_class

def show(self, level = 0):
children = ''
for child in self.children:
Expand Down Expand Up @@ -498,6 +590,48 @@ def outer_bounds(self, offset_start, offset_end, content):
return current.outer_bounds(offset_start, offset_end)
return None, None

def zenify(self, offset_start, offset_end, content):

current_start = self._prepare(offset_start, offset_start, content)
while current_start.type not in Node.tag_types_basic:
if current_start.parent:
current_start = current_start.parent
else:
current_start = self._prepare(0, 0, content)
break

if current_start.end == offset_end:
current_end = current_start

else:
current_end = self._prepare(offset_end, offset_end, content)
while current_end.type not in Node.tag_types_basic:
if current_end.parent:
current_end = current_end.parent
else:
current_end = self._prepare(len(content) - 1, len(content) - 1, content)
break

nodes = []
if current_end.is_child_of(current_start) or current_start == current_end:
nodes.append(current_start)
elif current_end.is_sibling_of(current_start):
while current_start and current_start != current_end:
if current_start.type in Node.tag_types_basic:
nodes.append(current_start)
current_start = current_start.next_sibling_tag(True)
nodes.append(current_end)
else:
offset_start, offset_end = self.outer_bounds(offset_start, offset_end, content)
nodes.append(self._prepare(offset_start, offset_end, content))

result = []
for node in nodes:
result.append(node.zenify(content))
result = factorize(result)
return '+'.join(result)


if __name__ == '__main__':

content = '''
Expand Down
6 changes: 6 additions & 0 deletions zencoding/plugin.py
Expand Up @@ -36,6 +36,8 @@
<menuitem name="ZenCodingExpandW" action="ZenCodingExpandWAction"/>
<menuitem name="ZenCodingWrap" action="ZenCodingWrapAction"/>
<separator/>
<menuitem name="ZenCodingZenify" action="ZenCodingZenifyAction"/>
<separator/>
<menuitem name="LoremIpsum" action="LoremIpsumAction"/>
<separator/>
<menuitem name="ZenCodingInward" action="ZenCodingInwardAction"/>
Expand Down Expand Up @@ -73,6 +75,7 @@ def activate(self, window):
('ZenCodingExpandAction', None, '_Expand abbreviation', '<Ctrl>E', "Expand abbreviation to raw HTML/CSS", self.expand_abbreviation),
('ZenCodingExpandWAction', None, 'E_xpand with abbreviation...', '<Ctrl><Alt>E', "Type in an abbreviation to expand", self.expand_with_abbreviation),
('ZenCodingWrapAction', None, '_Wrap with abbreviation...', '<Ctrl><Shift>E', "Wrap with code expanded from abbreviation", self.wrap_with_abbreviation),
('ZenCodingZenifyAction', None, '_Zenify...', '<Ctrl><Alt>Z', "Reduce to abbreviation", self.zenify),
('LoremIpsumAction', None, '_Lorem ipsum...', '<Ctrl><Alt>X', "Insert a lorem ipsum string", self.lorem_ipsum),
('ZenCodingInwardAction', None, 'Select _inward', '<Ctrl><Alt>I', "Select inner tag's content", self.match_pair_inward),
('ZenCodingOutwardAction', None, 'Select _outward', '<Ctrl><Alt>O', "Select outer tag's content", self.match_pair_outward),
Expand Down Expand Up @@ -129,6 +132,9 @@ def expand_with_abbreviation(self, action, window):
def wrap_with_abbreviation(self, action, window):
self.editor.wrap_with_abbreviation(window)

def zenify(self, action, window):
self.editor.zenify(window)

def lorem_ipsum(self, action, window):
self.editor.lorem_ipsum(window)

Expand Down
11 changes: 11 additions & 0 deletions zencoding/zen_editor.py
Expand Up @@ -339,6 +339,17 @@ def wrap_with_abbreviation(self, window):

#---------------------------------------------------------------------------------------

def zenify(self, window):
self.set_context(window)
offset_start, offset_end, content = self.prepare_nav(window)
result = self.html_navigation.zenify(offset_start, offset_end, content)
if result:
self.save_selection()
self.prompt(result)
self.restore_selection()

#---------------------------------------------------------------------------------------

def match_pair_inward(self, window):
offset_start, offset_end, content = self.prepare_nav(window)
offset_start, offset_end = self.html_navigation.inner_bounds(offset_start, offset_end, content)
Expand Down

0 comments on commit 96a8f9c

Please sign in to comment.