diff -r 8f2446858dd3 MoinMoin/Page.py
--- a/MoinMoin/Page.py	Mon Mar 01 00:23:21 2010 +0100
+++ b/MoinMoin/Page.py	Mon Oct 11 14:51:23 2010 -0400
@@ -1017,6 +1017,8 @@
             media = 'screen'
         self.hilite_re = (keywords.get('hilite_re') or
                           request.values.get('highlight'))
+        # yuck
+        self.print_mode = print_mode
 
         # count hit?
         if keywords.get('count_hit', 0):
@@ -1265,7 +1267,7 @@
             return getattr(parser, 'caching', False)
         return False
 
-    def send_page_content(self, request, body, format='wiki', format_args='', do_cache=1, **kw):
+    def send_page_content(self, request, body, format='wiki', format_args='', do_cache=False, **kw):
         """ Output the formatted wiki page, using caching if possible
 
         @param request: the request object
@@ -1279,7 +1281,11 @@
         Parser = wikiutil.searchAndImportPlugin(request.cfg, "parser", format)
         parser = Parser(body, request, format_args=format_args, **kw)
 
-        if not (do_cache and self.canUseCache(Parser)):
+        # 3.08.08 by Taras
+        # For section editing workaround
+        #
+        #if not (do_cache and self.canUseCache(Parser)):
+        if True:
             self.format(parser)
         else:
             try:
diff -r 8f2446858dd3 MoinMoin/PageEditor.py
--- a/MoinMoin/PageEditor.py	Mon Mar 01 00:23:21 2010 +0100
+++ b/MoinMoin/PageEditor.py	Mon Oct 11 14:51:23 2010 -0400
@@ -159,6 +159,31 @@
         edit_lock_message = None
         preview = kw.get('preview', None)
         staytop = kw.get('staytop', 0)
+      
+      # for section editing
+        issectionedit = kw.get('issectionedit', 1)
+        pagetext = kw.get('pagetext', None)
+        startline = int(request.values.get('startline', '0'))
+        endline = int(request.values.get('endline', '0'))
+
+        srev = int(request.values.get('srev', '0'))
+        
+        if startline or endline:
+            if not startline:
+                startline = 1
+        
+            if not endline:
+                endline = -1    
+        else:
+            issectionedit = 0
+
+        if issectionedit:
+            # need to add config
+            self._allow_section_edit = self.cfg.allow_section_edit
+            # self._allow_section_edit = 1
+
+        # end of section editing
+        
 
         from MoinMoin.formatter.text_html import Formatter
         request.formatter = Formatter(request, store_pagelinks=1)
@@ -222,7 +247,16 @@
             title = _('Preview of "%(pagename)s"')
             # Propagate original revision
             rev = request.rev
-            self.set_raw_body(preview, modified=1)
+            
+            # section-editing
+            
+            #self.set_raw_body(preview, modified=1)
+            if issectionedit and pagetext is not None:
+                self.set_raw_body(pagetext, modified=1)
+            else:
+                self.set_raw_body(preview, modified=1)
+
+            # end of section-editing
 
         # send header stuff
         lock_timeout = self.lock.timeout / 60
@@ -254,10 +288,28 @@
             if conflict_msg:
                 # We don't show preview when in conflict
                 preview = None
+                # section-editing
+                
+                # no section-editing any more
+                if issectionedit:
+                    conflict_msg = u'%s %s' % (conflict_msg, _('Section editing is canceled.'))
+                issectionedit = 0
+
+                # end of section-editing
+                
 
         elif self.exists():
             # revision of existing page
             rev = self.current_rev()
+            
+            # section-editing
+
+            if issectionedit and preview is None:
+                if not (srev and srev == rev):
+                    conflict_msg = u'%s %s' % (_('Section editing is canceled.'), _('Someone else updated this page. You are editing the updated revision.'))
+                    issectionedit = 0
+
+            # end of section-editing
         else:
             # page creation
             rev = 0
@@ -329,6 +381,17 @@
         # Generate default content for new pages
         if not raw_body:
             raw_body = _('Describe %s here.') % (self.page_name, )
+        # section-editing
+        
+        elif issectionedit:
+            # for section editing
+            if pagetext is not None:
+                raw_body = preview
+            else:
+                raw_body = self.fetchsection(raw_body, startline, endline)
+
+        # end of section-editing
+        
 
         # send form
         request.write('<form id="editor" method="post" action="%s#preview" onSubmit="flgChange = false;">' % (
@@ -344,6 +407,15 @@
 
         # Send revision of the page our edit is based on
         request.write('<input type="hidden" name="rev" value="%d">' % (rev, ))
+        # section-editing
+
+        # Send section startline and endline for section-editing
+        if issectionedit:
+            self.request.write('<input type="hidden" name="startline" value="%d">' % startline)
+            self.request.write('<input type="hidden" name="endline" value="%d">' % endline)
+        
+        # end of section-editing
+        
 
         # Create and send a ticket, so we can check the POST
         request.write('<input type="hidden" name="ticket" value="%s">' % wikiutil.createTicket(request))
@@ -483,7 +555,14 @@
 
         badwords_re = None
         if preview is not None:
-            if 'button_spellcheck' in form or 'button_newwords' in form:
+            # section-editing
+            
+            if issectionedit:
+                self.set_raw_body(preview)
+            
+            # end of section-editing    
+ 
+	    if 'button_spellcheck' in form or 'button_newwords' in form:
                 badwords, badwords_re, msg = SpellCheck.checkSpelling(self, request, own_form=0)
                 request.write("<p>%s</p>" % msg)
         request.write('</fieldset>')
@@ -503,7 +582,17 @@
                 content_id = 'previewbelow'
             else:
                 content_id = 'preview'
-            self.send_page(content_id=content_id, content_only=1, hilite_re=badwords_re)
+            
+            # section-editing
+            
+            #self.send_page(content_id=content_id, content_only=1,hilite_re=badwords_re)
+
+            if issectionedit:
+                self.send_page(content_id=content_id, content_only=1, hilite_re=badwords_re, do_cache=False)
+            else:
+                self.send_page(content_id=content_id, content_only=1, hilite_re=badwords_re)
+
+            # end of section-editing
 
         request.write(request.formatter.endContent())
         request.theme.send_footer(self.page_name)
@@ -1162,6 +1251,20 @@
         self.lock.release(force=not msg) # XXX does "not msg" make any sense?
 
         return msg
+    # section-editing
+    
+    def fetchsection(self, pagetext, startline, endline):
+        
+        pagetext = pagetext.split('\n')
+        if endline == -1:
+            sectiontext = u'\n'.join(pagetext[startline-1:])
+        else:
+            sectiontext = u'\n'.join(pagetext[startline-1:endline])
+        
+        return sectiontext
+    
+    # end of section-editing
+
 
 
 class PageLock:
diff -r 8f2446858dd3 MoinMoin/PageGraphicalEditor.py
--- a/MoinMoin/PageGraphicalEditor.py	Mon Mar 01 00:23:21 2010 +0100
+++ b/MoinMoin/PageGraphicalEditor.py	Mon Oct 11 14:51:23 2010 -0400
@@ -58,6 +58,28 @@
         edit_lock_message = None
         preview = kw.get('preview', None)
         staytop = kw.get('staytop', 0)
+        # for section editing
+        issectionedit = kw.get('issectionedit', 1)
+        pagetext = kw.get('pagetext', None)
+        startline = int(form.get('startline', ['0'])[0])
+        endline = int(form.get('endline', ['0'])[0])
+        srev = int(form.get('srev', ['0'])[0])
+        
+        if startline or endline:
+            if not startline:
+                startline = 1
+        
+            if not endline:
+                endline = -1    
+        else:
+            issectionedit = 0
+
+        if issectionedit:
+            # need to add config
+            self._allow_section_edit = self.cfg.allow_section_edit
+            # self._allow_section_edit = 1  
+
+        # end of section editing
 
         # check edit permissions
         if not request.user.may.write(self.page_name):
@@ -112,8 +134,13 @@
             title = _('Preview of "%(pagename)s"')
             # Propagate original revision
             rev = request.rev
-            self.set_raw_body(preview, modified=1)
-
+            #self.set_raw_body(preview, modified=1)
+            
+            if issectionedit and pagetext is not None:
+                self.set_raw_body(pagetext, modified=1)
+            else:
+                self.set_raw_body(preview, modified=1)
+ 
         # send header stuff
         lock_timeout = self.lock.timeout / 60
         lock_page = wikiutil.escape(self.page_name, quote=1)
@@ -144,10 +171,19 @@
             if conflict_msg:
                 # We don't show preview when in conflict
                 preview = None
+                # no section-editing any more
+                if issectionedit:
+                    conflict_msg = u'%s %s' % (conflict_msg, _('Section editing is canceled.'))
+                issectionedit = 0
 
         elif self.exists():
             # revision of existing page
             rev = self.current_rev()
+            
+            if issectionedit and preview is None:
+                if not (srev and srev == rev):
+                    conflict_msg = u'%s %s' % (_('Section editing is canceled.'), _('Someone else updated this page. You are editing the updated revision.'))
+                    issectionedit = 0
         else:
             # page creation
             rev = 0
@@ -221,7 +257,14 @@
         # Generate default content for new pages
         if not raw_body:
             raw_body = _('Describe %s here.') % (self.page_name, )
-
+        elif issectionedit:
+            # for section editing
+            if pagetext is not None:
+                raw_body = preview
+            else:
+                raw_body = self.fetchsection(raw_body, startline, endline)
+        
+ 
         # send form
         request.write('<form id="editor" method="post" action="%s#preview">' % (
                 request.href(self.page_name)
@@ -243,6 +286,11 @@
 
         # Create and send a ticket, so we can check the POST
         request.write('<input type="hidden" name="ticket" value="%s">' % wikiutil.createTicket(request))
+        # Send section startline and endline for section-editing
+        if issectionedit:
+            self.request.write('<input type="hidden" name="startline" value="%d">' % startline)
+            self.request.write('<input type="hidden" name="endline" value="%d">' % endline)
+        
 
         # Save backto in a hidden input
         backto = request.values.get('backto')
@@ -390,6 +438,10 @@
 
         badwords_re = None
         if preview is not None:
+        
+            if issectionedit:
+                self.set_raw_body(preview)
+
             if 'button_spellcheck' in form or 'button_newwords' in form:
                 badwords, badwords_re, msg = SpellCheck.checkSpelling(self, request, own_form=0)
                 request.write("<p>%s</p>" % msg)
@@ -401,8 +453,12 @@
                 content_id = 'previewbelow'
             else:
                 content_id = 'preview'
-            self.send_page(content_id=content_id, content_only=1, hilite_re=badwords_re)
-
+#            self.send_page(content_id=content_id, content_only=1, hilite_re=badwords_re)
+            if issectionedit:
+                self.send_page(content_id=content_id, content_only=1, hilite_re=badwords_re, do_cache=False)
+            else:
+                self.send_page(content_id=content_id, content_only=1, hilite_re=badwords_re)
+ 
         request.write(request.formatter.endContent()) # end content div
         request.theme.send_footer(self.page_name)
         request.theme.send_closing_html()
diff -r 8f2446858dd3 MoinMoin/action/edit.py
--- a/MoinMoin/action/edit.py	Mon Mar 01 00:23:21 2010 +0100
+++ b/MoinMoin/action/edit.py	Mon Oct 11 14:51:23 2010 -0400
@@ -12,6 +12,9 @@
 from MoinMoin.Page import Page
 from MoinMoin.web.utils import check_surge_protect
 
+from MoinMoin import log
+logging = log.getLogger(__name__)
+
 def execute(pagename, request):
     """ edit a page """
     _ = request.getText
@@ -105,6 +108,32 @@
         # we don't want to throw an exception if user cancelled anyway
         if not cancelled:
             raise
+    # section editing
+
+    startline = request.form.get('startline', '0')
+    endline = request.form.get('endline', '0')
+
+    startline = int(startline)
+    endline = int(endline)
+
+    if startline or endline:
+        issectionedit = 1
+        
+        if not startline:
+            startline = 1
+        
+        if not endline:
+            endline = -1    
+
+    else:
+        issectionedit = 0
+
+    if issectionedit:
+        savetext = pg.normalizeText(savetext, stripspaces=rstrip)
+        sectiontext = savetext
+        savetext = mergesection(pg.get_raw_body(), savetext, startline, endline)
+
+
 
     if cancelled:
         pg.sendCancel(savetext or "", rev)
@@ -151,12 +180,23 @@
     if ('button_preview' in request.form or
         'button_spellcheck' in request.form or
         'button_newwords' in request.form):
-        pg.sendEditor(preview=savetext, comment=comment)
+        #pg.sendEditor(preview=savetext, comment=comment)
+        
+        if issectionedit:
+            pg.sendEditor(preview=sectiontext, comment=comment, pagetext=savetext)
+        else:
+            pg.sendEditor(preview=savetext, comment=comment)
+     
 
     # Preview with mode switch
     elif 'button_switch' in request.form:
-        pg.sendEditor(preview=savetext, comment=comment, staytop=1)
-
+        #pg.sendEditor(preview=savetext, comment=comment, staytop=1)
+        
+        if issectionedit:
+            pg.sendEditor(preview=sectiontext, comment=comment, staytop=1, pagetext=savetext)
+        else:
+            pg.sendEditor(preview=savetext, comment=comment, staytop=1)
+ 
     # Save new text
     else:
         try:
@@ -172,7 +212,13 @@
 
             pg.mergeEditConflict(rev)
             # We don't send preview when we do merge conflict
-            pg.sendEditor(msg=msg, comment=comment)
+#            pg.sendEditor(msg=msg, comment=comment)
+                
+            if issectionedit:
+                msg = u'%s %s' % (msg, _('Section editing is canceled.'))
+
+            pg.sendEditor(msg=msg, comment=comment, issectionedit=0)
+                
             return
 
         except pg.SaveError, msg:
@@ -187,3 +233,17 @@
         request.rev = 0
         request.theme.add_msg(savemsg, "info")
         pg.send_page()
+
+def mergesection(pagetext, newsectiontext, startline, endline):
+    
+    pagetext = pagetext.split('\n')
+    
+    prevtext = u'%s\n' % u'\n'.join(pagetext[:startline-1])
+    if endline == -1:
+        nexttext = ''
+    else:
+        nexttext = u'\n%s' % u'\n'.join(pagetext[endline:])
+    
+    return u'%s%s%s' % (prevtext, newsectiontext, nexttext)
+
+
diff -r 8f2446858dd3 MoinMoin/config/multiconfig.py
--- a/MoinMoin/config/multiconfig.py	Mon Mar 01 00:23:21 2010 +0100
+++ b/MoinMoin/config/multiconfig.py	Mon Oct 11 14:51:23 2010 -0400
@@ -897,6 +897,7 @@
      "if True, show user names in the revision history and on Recent``Changes. Set to False to hide them."),
     ('show_section_numbers', False,
      'show section numbers in headings by default'),
+    ('allow_section_edit', True, 'allow section editing'),
     ('show_timings', False, "show some timing values at bottom of a page"),
     ('show_version', False, "show moin's version at the bottom of a page"),
 
diff -r 8f2446858dd3 MoinMoin/formatter/text_html.py
--- a/MoinMoin/formatter/text_html.py	Mon Mar 01 00:23:21 2010 +0100
+++ b/MoinMoin/formatter/text_html.py	Mon Oct 11 14:51:23 2010 -0400
@@ -195,6 +195,16 @@
         self.request = request
         self.cfg = request.cfg
         self.no_magic = kw.get('no_magic', False) # disabled tag auto closing
+        # for section editing
+        self._allow_section_edit = None
+        if not hasattr(request, 'sectionindex'):
+            self.request.sectionindex = 0
+        
+        self.sectionstack = []
+        self.sectionpool = {}
+        self.sectionlastdepth = 0
+        self.lineno = 0
+        
 
         if not hasattr(request, '_fmt_hd_counters'):
             request._fmt_hd_counters = []
@@ -563,6 +573,7 @@
         return '<span class="anchor" id="%s"></span>' % id
 
     def line_anchordef(self, lineno):
+        self.lineno = lineno
         if line_anchors:
             return self.anchordef("line-%d" % lineno)
         else:
@@ -1133,6 +1144,21 @@
         # remember depth of first heading, and adapt counting depth accordingly
         if not self._base_depth:
             self._base_depth = depth
+        # section editing configuration
+        if self._allow_section_edit is None:
+            # need to add config
+            self._allow_section_edit = self.cfg.allow_section_edit
+            # self._allow_section_edit = 1
+            sectionediting = self.request.getPragma('section-edit', '').lower()
+            if sectionediting in ['off']:
+                self._allow_section_edit = 0
+            elif sectionediting in ['on']:
+                self._allow_section_edit = 1
+
+        if self._allow_section_edit:
+            if not hasattr(self, "page") or \
+                    not self.request.user.may.write(self.page.page_name):
+                self._allow_section_edit = 0
 
         count_depth = max(depth - (self._base_depth - 1), 1)
 
@@ -1152,8 +1178,36 @@
 
         # closing tag, with empty line after, to make source more readable
         if not on:
-            return self._close('h%d' % heading_depth) + '\n'
+            # section-editing
+            #return self._close('h%d' % heading_depth) + '\n'
+            result = self._close('h%d' % heading_depth) + '\n'
+            
+            sectionscript = ''
+            if self._allow_section_edit and not getattr(self.page, "print_mode", 0):
+                
+                self.request.sectionindex += 1
+                sectionindex = self.request.sectionindex
+                sectionscript = self.savesectioninfor(sectionindex, depth, self.lineno)
+                
+                section_attr = 'sectionedit%d' % sectionindex
+                
+                backto = u''
+                if self._is_included and hasattr(self.request, "_Include_backto"):
+                    backto = u'&backto=%s' % wikiutil.quoteWikinameURL(self.request._Include_backto)
+                
+                sectioneditpage = u'%s/%s' % (self.request.getScriptname(), wikiutil.quoteWikinameURL(self.page.page_name))
+                srev = self.page.current_rev()
+                querystring = u'%s?action=edit%s&srev=%d&startline=%d' % (sectioneditpage, backto, srev, self.lineno)
+                
+                result = ('%s%s%s%s' %
+                    (self.url(1, querystring, unescaped=1, title='Edit this section', id=section_attr,css='sectionedit'),
+                     '[Edit]',
+                     self.url(0),
+                     result))
 
+            return ' %s%s' % (result, sectionscript)
+            # end of section-editing
+ 
         # create section number
         number = ''
         if self._show_section_numbers:
@@ -1277,7 +1331,56 @@
                              allowed_attrs=self._allowed_table_attrs['row'],
                              **kw)
         return self._close(tag) + '\n'
+    
+    # section-editing
+    
+    def savesectioninfor(self, index, depth, lineno, save=1):
+        # store section information
+        section = {}
+        sectionscriptlist = []
+        sectionscript = u'document.getElementById("sectionedit%d").href += "&endline=%d";'
+        scriptresult = ''
+        
+        lastdepth = self.sectionlastdepth
+        sectionindex = index
+        
+        if lastdepth >= depth:
+            while 1:
+                if len(self.sectionstack):
+                    lastsection = self.sectionstack.pop()
+                    lastdepth = lastsection['depth']    
+                    if lastdepth >= depth:
+                        self.sectionpool[lastsection['index']]['endlineno'] = lineno - 1
+                        sectionscriptlist.append(sectionscript % (lastsection['index'], lineno - 1))
+                    else:
+                        self.sectionstack.append(lastsection)
+                        break
+                else:
+                    break
+                    
+        if save:
+            section['index'] = sectionindex
+            section['startlineno'] = lineno
+            section['depth'] = depth
+            section['endlineno'] = -1
+            self.sectionlastdepth = depth
+            self.sectionpool[sectionindex] = section
+            self.sectionstack.append(section)
+        
+        if len(sectionscriptlist) > 0:
+            
+            scriptresult = u"""
+<script type="text/javascript">
+<!--
+%s
+//-->
+</script>
+""" % u'\n'.join(sectionscriptlist)
 
+        return scriptresult
+
+    # end of section-editing 
+ 
     def table_cell(self, on, attrs=None, **kw):
         tag = 'td'
         if on:
diff -r 8f2446858dd3 MoinMoin/macro/Include.py
--- a/MoinMoin/macro/Include.py	Mon Mar 01 00:23:21 2010 +0100
+++ b/MoinMoin/macro/Include.py	Mon Oct 11 14:51:23 2010 -0400
@@ -206,7 +206,7 @@
         try:
             inc_page.send_page(content_only=True,
                                omit_footnotes=True,
-                               count_hit=False)
+                               count_hit=False,do_cache=False)
             result.append(strfile.getvalue())
         finally:
             request.redirect()
