[prev in list] [next in list] [prev in thread] [next in thread]
List: kwrite-devel
Subject: XML indentation mode
From: Laurence Withers <lwithers () users ! sourceforge ! net>
Date: 2004-09-30 9:29:47
Message-ID: 200409301029.53014.lwithers () users ! sf ! net
[Download RAW message or body]
[Attachment #2 (multipart/signed)]
[Attachment #4 (multipart/mixed)]
Hi,
Working with Anders, I have developed an XML indentation mode. This mode
will indent once per open element, so you end up with documents like:
<a>
<b>
<c>Some text and stuff <d>blah</d>
</c>
</b>
</a>
It ignores empty elements, processing instructions and CDATA sections
(these shouldn't affect the indentation). However, it also won't
recognise multi-line open or close tags (both of which are legal
according to the XML spec). This is a limitation caused by the use of
regular expressions.
I will maintain this mode as necessary, but it is useful as-is and I
would appreciate the feedback from users before making any further
changes.
Bye for now,
--
Laurence Withers, lwithers@users.sf.net, jabber:l.withers@jabber.org
http://www.personal.rdg.ac.uk/~sis04lw/
["katepart-xmlindent.patch" (text/x-diff)]
diff -ru part/kateautoindent.cpp katepart-xmlindent/kateautoindent.cpp
--- part/kateautoindent.cpp 2004-06-22 18:36:33.000000000 +0100
+++ katepart-xmlindent/kateautoindent.cpp 2004-09-30 10:26:51.036860750 +0100
@@ -33,6 +33,8 @@
return new KateCSmartIndent (doc);
else if (mode == KateDocumentConfig::imPythonStyle)
return new KatePythonIndent (doc);
+ else if (mode == KateDocumentConfig::imXmlStyle)
+ return new KateXmlIndent (doc);
return new KateAutoIndent (doc);
}
@@ -44,6 +46,7 @@
l << modeDescription(KateDocumentConfig::imNormal);
l << modeDescription(KateDocumentConfig::imCStyle);
l << modeDescription(KateDocumentConfig::imPythonStyle);
+ l << modeDescription(KateDocumentConfig::imXmlStyle);
return l;
}
@@ -54,6 +57,8 @@
return QString ("cstyle");
else if (mode == KateDocumentConfig::imPythonStyle)
return QString ("python");
+ else if (mode == KateDocumentConfig::imXmlStyle)
+ return QString ("xml");
return QString ("normal");
}
@@ -64,6 +69,8 @@
return i18n ("C Style");
else if (mode == KateDocumentConfig::imPythonStyle)
return i18n ("Python Style");
+ else if (mode == KateDocumentConfig::imXmlStyle)
+ return i18n ("XML Style");
return i18n ("Normal");
}
@@ -74,6 +81,8 @@
return KateDocumentConfig::imCStyle;
else if (modeName(KateDocumentConfig::imPythonStyle) == name)
return KateDocumentConfig::imPythonStyle;
+ else if (modeName(KateDocumentConfig::imXmlStyle) == name)
+ return KateDocumentConfig::imPythonStyle;
return KateDocumentConfig::imNormal;
}
@@ -1006,4 +1015,167 @@
// END
+// BEGIN KateXmlIndent
+
+QRegExp KateXmlIndent::openTag = QRegExp( "(<[^\?!/][^>]*[^/]>)|(<[^\?!/>]>)" );
+QRegExp KateXmlIndent::closeTag = QRegExp( "</[^>]*>" );
+QRegExp KateXmlIndent::startsWithCloseTag = QRegExp( "^[ \t]*</" );
+QRegExp KateXmlIndent::openOrCloseTag = QRegExp( "(<[^\?!][^>]*[^/]>)|(<[^\?!/>]>)" );
+
+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 = begin.line();
+ int prevIndent = 0;
+
+ while(line--) {
+ if( (prevIndent = doc->plainKateTextLine(line)->firstChar()) != -1) break;
+ }
+
+ if(prevIndent < 0) prevIndent = 0;
+ else prevIndent = doc->plainKateTextLine(line)->cursorX(prevIndent, tabWidth);
+
+ // now count the number of open and close tags on the previous (i.e.
+ // just-entered) line
+ QString l = doc->plainKateTextLine(begin.line() - 1)->string();
+ int length = l.length(), offset = 0, numOpen = 0, numClose = 0;
+
+ for(offset = 0; offset < length; ++numOpen) {
+ int match = openTag.search(l, offset);
+ if(match == -1) break;
+ offset = match + 1;
+ }
+
+ for(offset = 0; offset < length; ++numClose) {
+ int match = closeTag.search(l, offset);
+ if(match == -1) break;
+ offset = match + 1;
+ }
+
+ // special exception: if the previous line starts with a close tag,
+ // we want to align with it
+ if(startsWithCloseTag.search(l) != -1) --numClose;
+
+ // calculate the new indent
+ int indent = prevIndent + (numOpen - numClose) * indentWidth;
+ if(indent < 0) indent = 0;
+
+ // apply
+ QString filler = tabString (indent);
+ doc->insertText (begin.line(), 0, filler);
+ begin.setCol(filler.length());
+}
+
+void KateXmlIndent::processChar (QChar c)
+{
+ if(c != '/') return;
+
+ // only alter lines that start with a close element
+ KateView *view = doc->activeView();
+ if(startsWithCloseTag.search(
+ doc->plainKateTextLine(view->cursorLine())->string()
+ ) == -1) return;
+
+ // process it
+ processLine(view->cursorLine());
+}
+
+void KateXmlIndent::processLine (KateDocCursor &line)
+{
+ processLine (line.line());
+}
+
+void KateXmlIndent::processSection (KateDocCursor &begin, KateDocCursor &end)
+{
+ uint endLine = end.line();
+ for(uint line = begin.line(); line <= endLine; ++line) processLine(line);
+}
+
+void KateXmlIndent::processLine (uint line)
+{
+ KateTextLine::Ptr kateLine = doc->plainKateTextLine(line);
+
+ // compute new indent based on previous indent
+ uint prevIndent = 0, numOpen = 0;
+ if(line) findOpeningElemIndent(line - 1, prevIndent, numOpen);
+ uint indent = prevIndent + numOpen * indentWidth;
+
+ // unindent lines that start with a close tag
+ if(indent) {
+ int firstChar = kateLine->firstChar();
+ if(kateLine->getChar(firstChar) == '<' && kateLine->getChar(firstChar + 1) == '/') {
+ if(indent > indentWidth) indent -= indentWidth;
+ else indent = 0;
+ }
+ }
+
+ // apply new indent
+ doc->removeText(line, 0, line, kateLine->firstChar());
+ QString filler = tabString(indent);
+ if (indent > 0) doc->insertText(line, 0, filler);
+}
+
+void KateXmlIndent::findOpeningElemIndent (uint line, uint &indent, uint &numOpened)
+{
+ int depth = 1, pos;
+ KateTextLine::Ptr kateLine;
+ QString ln;
+
+ indent = 0;
+ numOpened = 0;
+
+ do {
+ kateLine = doc->plainKateTextLine(line);
+ ln = kateLine->string();
+
+ pos = 0;
+ do {
+
+ pos = openOrCloseTag.searchRev(ln, pos - 1);
+ if(pos == -1) break;
+ if(ln.at(pos + 1).unicode() == '/') {
+ // we found a closing tag
+ ++depth;
+
+ } else {
+ // we found an opening tag
+ if(!--depth) {
+ // tag is unmatched
+
+ // retrieve the indent of this line
+ indent = kateLine->cursorX(kateLine->firstChar(), tabWidth);
+
+ // count the number of (unclosed) open elements
+ for(int pos2 = -1; pos2 != pos; ) {
+ pos2 = openOrCloseTag.search(ln, pos2 + 1);
+ if(ln.at(pos2 + 1).unicode() == '/') {
+ if(numOpened) --numOpened;
+ } else {
+ ++numOpened;
+ }
+ }
+
+ return;
+ }
+
+ }
+
+ }while(pos);
+
+ }while(line--);
+
+ // reached start of document
+}
+
+// END
+
// kate: space-indent on; indent-width 2; replace-tabs on;
diff -ru part/kateautoindent.h katepart-xmlindent/kateautoindent.h
--- 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;
};
+class KateXmlIndent : public KateAutoIndent
+{
+ public:
+ KateXmlIndent (KateDocument *doc);
+ ~KateXmlIndent ();
+
+ virtual uint modeNumber () const { return KateDocumentConfig::imXmlStyle; }
+ 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);
+
+ private:
+ static QRegExp openTag;
+ static QRegExp closeTag;
+ static QRegExp startsWithCloseTag;
+ static QRegExp openOrCloseTag;
+
+ // sets the indentation of a single line based on previous lines
+ void processLine (uint line);
+
+ // 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
// kate: space-indent on; indent-width 2; replace-tabs on;
diff -ru part/kateconfig.h katepart-xmlindent/kateconfig.h
--- 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 = 0,
imCStyle = 1,
- imPythonStyle = 2
+ imPythonStyle = 2,
+ imXmlStyle = 3
};
uint indentationMode () const;
[Attachment #8 (application/pgp-signature)]
_______________________________________________
KWrite-Devel mailing list
KWrite-Devel@kde.org
https://mail.kde.org/mailman/listinfo/kwrite-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic