From kwrite-devel Thu Sep 30 09:29:47 2004 From: Laurence Withers Date: Thu, 30 Sep 2004 09:29:47 +0000 To: kwrite-devel Subject: XML indentation mode Message-Id: <200409301029.53014.lwithers () users ! sf ! net> X-MARC-Message: https://marc.info/?l=kwrite-devel&m=109653661519177 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--===============1019117308==" --===============1019117308== Content-Type: multipart/signed; boundary="nextPart5191323.knLGCFAPea"; protocol="application/pgp-signature"; micalg=pgp-sha1 Content-Transfer-Encoding: 7bit --nextPart5191323.knLGCFAPea Content-Type: multipart/mixed; boundary="Boundary-01=_LI9WBi4RPGzXia4" Content-Transfer-Encoding: 7bit Content-Disposition: inline --Boundary-01=_LI9WBi4RPGzXia4 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Hi, Working with Anders, I have developed an XML indentation mode. This mode=20 will indent once per open element, so you end up with documents like: Some text and stuff blah It ignores empty elements, processing instructions and CDATA sections=20 (these shouldn't affect the indentation). However, it also won't=20 recognise multi-line open or close tags (both of which are legal=20 according to the XML spec). This is a limitation caused by the use of=20 regular expressions. I will maintain this mode as necessary, but it is useful as-is and I=20 would appreciate the feedback from users before making any further=20 changes. Bye for now, =2D-=20 Laurence Withers, lwithers@users.sf.net, jabber:l.withers@jabber.org http://www.personal.rdg.ac.uk/~sis04lw/ --Boundary-01=_LI9WBi4RPGzXia4 Content-Type: text/x-diff; charset="us-ascii"; name="katepart-xmlindent.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="katepart-xmlindent.patch" diff -ru part/kateautoindent.cpp katepart-xmlindent/kateautoindent.cpp =2D-- part/kateautoindent.cpp 2004-06-22 18:36:33.000000000 +0100 +++ katepart-xmlindent/kateautoindent.cpp 2004-09-30 10:26:51.036860750 +01= 00 @@ -33,6 +33,8 @@ return new KateCSmartIndent (doc); else if (mode =3D=3D KateDocumentConfig::imPythonStyle) return new KatePythonIndent (doc); + else if (mode =3D=3D KateDocumentConfig::imXmlStyle) + return new KateXmlIndent (doc); =20 return new KateAutoIndent (doc); } @@ -44,6 +46,7 @@ l << modeDescription(KateDocumentConfig::imNormal); l << modeDescription(KateDocumentConfig::imCStyle); l << modeDescription(KateDocumentConfig::imPythonStyle); + l << modeDescription(KateDocumentConfig::imXmlStyle); =20 return l; } @@ -54,6 +57,8 @@ return QString ("cstyle"); else if (mode =3D=3D KateDocumentConfig::imPythonStyle) return QString ("python"); + else if (mode =3D=3D KateDocumentConfig::imXmlStyle) + return QString ("xml"); =20 return QString ("normal"); } @@ -64,6 +69,8 @@ return i18n ("C Style"); else if (mode =3D=3D KateDocumentConfig::imPythonStyle) return i18n ("Python Style"); + else if (mode =3D=3D KateDocumentConfig::imXmlStyle) + return i18n ("XML Style"); =20 return i18n ("Normal"); } @@ -74,6 +81,8 @@ return KateDocumentConfig::imCStyle; else if (modeName(KateDocumentConfig::imPythonStyle) =3D=3D name) return KateDocumentConfig::imPythonStyle; + else if (modeName(KateDocumentConfig::imXmlStyle) =3D=3D name) + return KateDocumentConfig::imPythonStyle; =20 return KateDocumentConfig::imNormal; } @@ -1006,4 +1015,167 @@ =20 // END =20 +// BEGIN KateXmlIndent + +QRegExp KateXmlIndent::openTag =3D QRegExp( "(<[^\?!/][^>]*[^/]>)|(<[^\?!/= >]>)" ); +QRegExp KateXmlIndent::closeTag =3D QRegExp( "]*>" ); +QRegExp KateXmlIndent::startsWithCloseTag =3D QRegExp( "^[ \t]*]*[^/]>)|(<= [^\?!/>]>)" ); + +KateXmlIndent::KateXmlIndent (KateDocument *doc) + : KateAutoIndent (doc) +{ +} + +KateXmlIndent::~KateXmlIndent () +{ +} + +void KateXmlIndent::processNewline (KateDocCursor &begin, bool /*newline*/) +{ + // get indent from the previous non-empty line + int line =3D begin.line(); + int prevIndent =3D 0; + =20 + while(line--) { + if( (prevIndent =3D doc->plainKateTextLine(line)->firstChar()) !=3D -1= ) break; + } + =20 + if(prevIndent < 0) prevIndent =3D 0; + else prevIndent =3D doc->plainKateTextLine(line)->cursorX(prevIndent, ta= bWidth); + =20 + // now count the number of open and close tags on the previous (i.e.=20 + // just-entered) line + QString l =3D doc->plainKateTextLine(begin.line() - 1)->string(); + int length =3D l.length(), offset =3D 0, numOpen =3D 0, numClose =3D 0; + =20 + for(offset =3D 0; offset < length; ++numOpen) { + int match =3D openTag.search(l, offset); + if(match =3D=3D -1) break; + offset =3D match + 1; + } + =20 + for(offset =3D 0; offset < length; ++numClose) { + int match =3D closeTag.search(l, offset); + if(match =3D=3D -1) break; + offset =3D match + 1; + } + =20 + // special exception: if the previous line starts with a close tag, + // we want to align with it + if(startsWithCloseTag.search(l) !=3D -1) --numClose; + =20 + // calculate the new indent + int indent =3D prevIndent + (numOpen - numClose) * indentWidth; + if(indent < 0) indent =3D 0; + =20 + // apply + QString filler =3D tabString (indent); + doc->insertText (begin.line(), 0, filler); + begin.setCol(filler.length()); +} + +void KateXmlIndent::processChar (QChar c) +{ + if(c !=3D '/') return; + + // only alter lines that start with a close element + KateView *view =3D doc->activeView(); + if(startsWithCloseTag.search( + doc->plainKateTextLine(view->cursorLine())->string() + ) =3D=3D -1) return; + + // process it + processLine(view->cursorLine()); +} + +void KateXmlIndent::processLine (KateDocCursor &line) +{ + processLine (line.line()); +} + +void KateXmlIndent::processSection (KateDocCursor &begin, KateDocCursor &e= nd) +{ + uint endLine =3D end.line(); + for(uint line =3D begin.line(); line <=3D endLine; ++line) processLine(l= ine); +} + +void KateXmlIndent::processLine (uint line) +{ + KateTextLine::Ptr kateLine =3D doc->plainKateTextLine(line); + + // compute new indent based on previous indent + uint prevIndent =3D 0, numOpen =3D 0; + if(line) findOpeningElemIndent(line - 1, prevIndent, numOpen); + uint indent =3D prevIndent + numOpen * indentWidth; + =20 + // unindent lines that start with a close tag + if(indent) { + int firstChar =3D kateLine->firstChar(); + if(kateLine->getChar(firstChar) =3D=3D '<' && kateLine->getChar(firstC= har + 1) =3D=3D '/') { + if(indent > indentWidth) indent -=3D indentWidth; + else indent =3D 0; + } + } + =20 + // apply new indent + doc->removeText(line, 0, line, kateLine->firstChar()); + QString filler =3D tabString(indent); + if (indent > 0) doc->insertText(line, 0, filler); +} + +void KateXmlIndent::findOpeningElemIndent (uint line, uint &indent, uint &= numOpened) +{ + int depth =3D 1, pos; + KateTextLine::Ptr kateLine; + QString ln; + =20 + indent =3D 0; + numOpened =3D 0; + =20 + do { + kateLine =3D doc->plainKateTextLine(line); + ln =3D kateLine->string(); + =20 + pos =3D 0; + do { + =20 + pos =3D openOrCloseTag.searchRev(ln, pos - 1); + if(pos =3D=3D -1) break; + if(ln.at(pos + 1).unicode() =3D=3D '/') { + // we found a closing tag + ++depth; + =20 + } else { + // we found an opening tag + if(!--depth) { + // tag is unmatched + =20 + // retrieve the indent of this line + indent =3D kateLine->cursorX(kateLine->firstChar(), tabWidth); + + // count the number of (unclosed) open elements + for(int pos2 =3D -1; pos2 !=3D pos; ) { + pos2 =3D openOrCloseTag.search(ln, pos2 + 1); + if(ln.at(pos2 + 1).unicode() =3D=3D '/') { + if(numOpened) --numOpened; + } else { + ++numOpened; + } + } + + return; + } + =20 + } + =20 + }while(pos); + =20 + }while(line--); + =20 + // reached start of document +} + +// END + // kate: space-indent on; indent-width 2; replace-tabs on; diff -ru part/kateautoindent.h katepart-xmlindent/kateautoindent.h =2D-- part/kateautoindent.h 2004-06-22 18:36:33.000000000 +0100 +++ katepart-xmlindent/kateautoindent.h 2004-09-30 02:06:55.323830791 +0100 @@ -228,6 +228,33 @@ static QRegExp blockBegin; }; =20 +class KateXmlIndent : public KateAutoIndent +{ + public: + KateXmlIndent (KateDocument *doc); + ~KateXmlIndent (); + =20 + virtual uint modeNumber () const { return KateDocumentConfig::imXmlSty= le; } + virtual void processNewline (KateDocCursor &begin, bool needContinue); + virtual void processChar (QChar c); + virtual void processLine (KateDocCursor &line); + virtual bool canProcessLine() { return true; } + virtual void processSection (KateDocCursor &begin, KateDocCursor &end); + =20 + private: + static QRegExp openTag; + static QRegExp closeTag; + static QRegExp startsWithCloseTag; + static QRegExp openOrCloseTag; + =20 + // sets the indentation of a single line based on previous lines + void processLine (uint line); + =20 + // returns the indentation of the last line with an opening element, + // plus the number of elements that were opened + void findOpeningElemIndent (uint line, uint &indent, uint &numOpened); +}; + #endif =20 // kate: space-indent on; indent-width 2; replace-tabs on; diff -ru part/kateconfig.h katepart-xmlindent/kateconfig.h =2D-- part/kateconfig.h 2004-06-22 18:36:33.000000000 +0100 +++ katepart-xmlindent/kateconfig.h 2004-09-29 22:03:17.230472674 +0100 @@ -136,7 +136,8 @@ { imNormal =3D 0, imCStyle =3D 1, =2D imPythonStyle =3D 2 + imPythonStyle =3D 2, + imXmlStyle =3D 3 }; =20 uint indentationMode () const; --Boundary-01=_LI9WBi4RPGzXia4-- --nextPart5191323.knLGCFAPea Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.9.8 (GNU/Linux) iD8DBQBBW9IQUdhclgSmRuoRAoWrAJ0b6blhxxNcEvYeeM7YxhEMID2DiQCgj64C 0Nhc1/AYPif6y92iZus4EUg= =NybF -----END PGP SIGNATURE----- --nextPart5191323.knLGCFAPea-- --===============1019117308== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ KWrite-Devel mailing list KWrite-Devel@kde.org https://mail.kde.org/mailman/listinfo/kwrite-devel --===============1019117308==--