diff options
Diffstat (limited to 'kate/part/kateautoindent.h')
-rw-r--r-- | kate/part/kateautoindent.h | 581 |
1 files changed, 581 insertions, 0 deletions
diff --git a/kate/part/kateautoindent.h b/kate/part/kateautoindent.h new file mode 100644 index 000000000..76ba14ee6 --- /dev/null +++ b/kate/part/kateautoindent.h @@ -0,0 +1,581 @@ +/* This file is part of the KDE libraries + Copyright (C) 2003 Jesse Yurkovich <yurkjes@iit.edu> + Copyright (C) 2004 >Anders Lund <anders@alweb.dk> (KateVarIndent class) + Copyright (C) 2005 Dominik Haumann <dhdev@gmx.de> (basic support for config page) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef __KATE_AUTO_INDENT_H__ +#define __KATE_AUTO_INDENT_H__ + +#include <qobject.h> + +#include "katecursor.h" +#include "kateconfig.h" +#include "katejscript.h" +class KateDocument; + +/** + * This widget will be embedded into a modal dialog when clicking + * the "Configure..." button in the indentation config page. + * To add a config page for an indenter there are several todos: + * - Derive a class from this class. This widget will be embedded into + * the config dialog. + * - Override the slot @p apply(), which is called when the configuration + * needs to be saved. + * - Override @p KateAutoIndent::configPage() to return an instance of + * this dialog. + * - Return @p true in @p KateAutoIndent::hasConfigPage() for the + * corresponding indenter id. + */ +class IndenterConfigPage : public QWidget +{ + Q_OBJECT + + public: + /** + * Standard constructor + * @param parent parent widget + * @param name name + */ + IndenterConfigPage ( QWidget *parent=0, const char *name=0 ) : QWidget(parent, name) {} + virtual ~IndenterConfigPage () {} + + public slots: + /** + * Apply the changes. Save options here, use @p kapp->config() and + * group [Kate Indenter MyIndenter]. + */ + virtual void apply () = 0; +}; + +/** + * Provides Auto-Indent functionality for katepart. + * This baseclass is a real dummy, does nothing beside remembering the document it belongs too, + * only to have the object around + */ +class KateAutoIndent : public QObject +{ + Q_OBJECT + + /** + * Static methods to create and list indention modes + */ + public: + /** + * Create an indenter + * @param doc document for the indenter + * @param mode indention mode wanted + * @return created autoindention object + */ + static KateAutoIndent *createIndenter (KateDocument *doc, uint mode); + + /** + * List all possible modes by name + * @return list of modes + */ + static QStringList listModes (); + + /** + * Return the mode name given the mode + * @param mode mode index + * @return name for this mode index + */ + static QString modeName (uint mode); + + /** + * Return the mode description + * @param mode mode index + * @return mode index + */ + static QString modeDescription (uint mode); + + /** + * Maps name -> index + * @param name mode name + * @return mode index + */ + static uint modeNumber (const QString &name); + + /** + * Config page support + * @param mode mode index + * @return true, if the indenter @p mode has a configuration page + */ + static bool hasConfigPage (uint mode); + + /** + * Support for a config page. + * @return config page or 0 if not available. + */ + static IndenterConfigPage* configPage(QWidget *parent, uint mode); + + public: + /** + * Constructor + * @param doc parent document + */ + KateAutoIndent (KateDocument *doc); + + /** + * Virtual Destructor for the baseclass + */ + virtual ~KateAutoIndent (); + + public slots: + /** + * Update indenter's configuration (indention width, attributes etc.) + */ + virtual void updateConfig () {}; + + public: + /** + * does this indenter support processNewLine + * @return can you do it? + */ + virtual bool canProcessNewLine () const { return false; } + + /** + * Called every time a newline character is inserted in the document. + * + * @param cur The position to start processing. Contains the new cursor position after the indention. + * @param needContinue Used to determine whether to calculate a continue indent or not. + */ + virtual void processNewline (KateDocCursor &cur, bool needContinue) { Q_UNUSED(cur); Q_UNUSED(needContinue); } + + /** + * Called every time a character is inserted into the document. + * @param c character inserted + */ + virtual void processChar (QChar c) { Q_UNUSED(c); } + + /** + * Aligns/indents the given line to the proper indent position. + */ + virtual void processLine (KateDocCursor &/*line*/) { } + + /** + * Processes a section of text, indenting each line in between. + */ + virtual void processSection (const KateDocCursor &/*begin*/, const KateDocCursor &/*end*/) { } + + /** + * Set to true if an actual implementation of 'processLine' is present. + * This is used to prevent a needless Undo action from being created. + */ + virtual bool canProcessLine() const { return false; } + + /** + * Mode index of this mode + * @return modeNumber + */ + virtual uint modeNumber () const { return KateDocumentConfig::imNone; }; + + protected: + KateDocument *doc; +}; + +/** + * This action provides a list of available indenters and gets plugged + * into the KateView's KActionCollection. + */ +class KateViewIndentationAction : public KActionMenu +{ + Q_OBJECT + + public: + KateViewIndentationAction(KateDocument *_doc, const QString& text, QObject* parent = 0, const char* name = 0); + + ~KateViewIndentationAction(){;}; + + private: + KateDocument* doc; + + public slots: + void slotAboutToShow(); + + private slots: + void setMode (int mode); +}; + +/** + * Provides Auto-Indent functionality for katepart. + */ +class KateNormalIndent : public KateAutoIndent +{ + Q_OBJECT + +public: + /** + * Constructor + * @param doc parent document + */ + KateNormalIndent (KateDocument *doc); + + /** + * Virtual Destructor for the baseclass + */ + virtual ~KateNormalIndent (); + +public slots: + /** + * Update indenter's configuration (indention width, attributes etc.) + */ + virtual void updateConfig (); + +public: + /** + * does this indenter support processNewLine + * @return can you do it? + */ + virtual bool canProcessNewLine () const { return true; } + + /** + * Called every time a newline character is inserted in the document. + * + * @param cur The position to start processing. Contains the new cursor position after the indention. + * @param needContinue Used to determine whether to calculate a continue indent or not. + */ + virtual void processNewline (KateDocCursor &cur, bool needContinue); + + /** + * Called every time a character is inserted into the document. + * @param c character inserted + */ + virtual void processChar (QChar c) { Q_UNUSED(c); } + + /** + * Aligns/indents the given line to the proper indent position. + */ + virtual void processLine (KateDocCursor &/*line*/) { } + + /** + * Processes a section of text, indenting each line in between. + */ + virtual void processSection (const KateDocCursor &/*begin*/, const KateDocCursor &/*end*/) { } + + /** + * Set to true if an actual implementation of 'processLine' is present. + * This is used to prevent a needless Undo action from being created. + */ + virtual bool canProcessLine() const { return false; } + + /** + * Mode index of this mode + * @return modeNumber + */ + virtual uint modeNumber () const { return KateDocumentConfig::imNormal; }; + +protected: + + /** + * Determines if the characters open and close are balanced between @p begin and @p end + * Fills in @p pos with the column position of first opened character if found. + * + * @param begin Beginning cursor position. + * @param end Ending cursor position where the processing will stop. + * @param open The open character. + * @param close The closing character which should be matched against @p open. + * @param pos Contains the position of the first @p open character in the line. + * @return True if @p open and @p close have an equal number of occurances between @p begin and @p end. False otherwise. + */ + bool isBalanced (KateDocCursor &begin, const KateDocCursor &end, QChar open, QChar close, uint &pos) const; + + /** + * Skip all whitespace starting at @p cur and ending at @p max. Spans lines if @p newline is set. + * @p cur is set to the current position afterwards. + * + * @param cur The current cursor position to start from. + * @param max The furthest cursor position that will be used for processing + * @param newline Whether we are allowed to span multiple lines when skipping blanks + * @return True if @p cur < @p max after processing. False otherwise. + */ + bool skipBlanks (KateDocCursor &cur, KateDocCursor &max, bool newline) const; + + /** + * Measures the indention of the current textline marked by cur + * @param cur The cursor position to measure the indent to. + * @return The length of the indention in characters. + */ + uint measureIndent (KateDocCursor &cur) const; + + /** + * Produces a string with the proper indentation characters for its length. + * + * @param length The length of the indention in characters. + * @return A QString representing @p length characters (factoring in tabs and spaces) + */ + QString tabString(uint length) const; + + uint tabWidth; //!< The number of characters simulated for a tab + uint indentWidth; //!< The number of characters used when tabs are replaced by spaces + +public: + // Attributes that we should skip over or otherwise know about + uchar commentAttrib; + uchar doxyCommentAttrib; + uchar regionAttrib; + uchar symbolAttrib; + uchar alertAttrib; + uchar tagAttrib; + uchar wordAttrib; + uchar keywordAttrib; + uchar normalAttrib; + uchar extensionAttrib; + uchar preprocessorAttrib; + uchar stringAttrib; + uchar charAttrib; + +protected: + bool useSpaces; //!< Should we use spaces or tabs to indent + bool mixedIndent; //!< Optimize indent by mixing spaces and tabs, ala emacs + bool keepProfile; //!< Always try to honor the leading whitespace of lines already in the file +}; + +class KateCSmartIndent : public KateNormalIndent +{ + Q_OBJECT + + public: + KateCSmartIndent (KateDocument *doc); + ~KateCSmartIndent (); + + virtual void processNewline (KateDocCursor &cur, bool needContinue); + virtual void processChar (QChar c); + + virtual void processLine (KateDocCursor &line); + virtual void processSection (const KateDocCursor &begin, const KateDocCursor &end); + + virtual bool canProcessLine() const { return true; } + + virtual uint modeNumber () const { return KateDocumentConfig::imCStyle; }; + + private: + uint calcIndent (KateDocCursor &begin, bool needContinue); + uint calcContinue (KateDocCursor &begin, KateDocCursor &end); + uint findOpeningBrace (KateDocCursor &start); + uint findOpeningParen (KateDocCursor &start); + uint findOpeningComment (KateDocCursor &start); + bool firstOpeningBrace (KateDocCursor &start); + bool handleDoxygen (KateDocCursor &begin); + + bool allowSemi; + bool processingBlock; +}; + +class KatePythonIndent : public KateNormalIndent +{ + Q_OBJECT + + public: + KatePythonIndent (KateDocument *doc); + ~KatePythonIndent (); + + virtual void processNewline (KateDocCursor &cur, bool needContinue); + + virtual uint modeNumber () const { return KateDocumentConfig::imPythonStyle; }; + + private: + int calcExtra (int &prevBlock, int &pos, KateDocCursor &end); + void traverseString( const QChar &stringChar, KateDocCursor &cur, KateDocCursor &end ); + + static QRegExp endWithColon; + static QRegExp stopStmt; + static QRegExp blockBegin; +}; + +class KateXmlIndent : public KateNormalIndent +{ + Q_OBJECT + + public: + KateXmlIndent (KateDocument *doc); + ~KateXmlIndent (); + + virtual uint modeNumber () const { return KateDocumentConfig::imXmlStyle; } + virtual void processNewline (KateDocCursor &cur, bool needContinue); + virtual void processChar (QChar c); + virtual void processLine (KateDocCursor &line); + virtual bool canProcessLine() const { return true; } + virtual void processSection (const KateDocCursor &begin, const KateDocCursor &end); + + private: + // sets the indentation of a single line based on previous line + // (returns indentation width) + uint processLine (uint line); + + // gets information about a line + void getLineInfo (uint line, uint &prevIndent, int &numTags, + uint &attrCol, bool &unclosedTag); + + // useful regular expressions + static const QRegExp startsWithCloseTag; + static const QRegExp unclosedDoctype; +}; + +class KateCSAndSIndent : public KateNormalIndent +{ + Q_OBJECT + + public: + KateCSAndSIndent (KateDocument *doc); + ~KateCSAndSIndent (); + + virtual void processNewline (KateDocCursor &begin, bool needContinue); + virtual void processChar (QChar c); + + virtual void processLine (KateDocCursor &line); + virtual void processSection (const KateDocCursor &begin, const KateDocCursor &end); + + virtual bool canProcessLine() const { return true; } + + virtual uint modeNumber () const { return KateDocumentConfig::imCSAndS; }; + + private: + void updateIndentString(); + + bool inForStatement( int line ); + int lastNonCommentChar( const KateDocCursor &line ); + bool startsWithLabel( int line ); + bool inStatement( const KateDocCursor &begin ); + QString continuationIndent( const KateDocCursor &begin ); + + QString calcIndent (const KateDocCursor &begin); + QString calcIndentAfterKeyword(const KateDocCursor &indentCursor, const KateDocCursor &keywordCursor, int keywordPos, bool blockKeyword); + QString calcIndentInBracket(const KateDocCursor &indentCursor, const KateDocCursor &bracketCursor, int bracketPos); + QString calcIndentInBrace(const KateDocCursor &indentCursor, const KateDocCursor &braceCursor, int bracePos); + + bool handleDoxygen (KateDocCursor &begin); + QString findOpeningCommentIndentation (const KateDocCursor &start); + + QString indentString; +}; + +/** + * This indenter uses document variables to determine when to add/remove indents. + * + * It attempts to get the following variables from the document: + * - var-indent-indent-after: A rerular expression which will cause a line to + * be indented by one unit, if the first non-whitespace-only line above matches. + * - var-indent-indent: A regular expression, which will cause a matching line + * to be indented by one unit. + * - var-indent-unindent: A regular expression which will cause the line to be + * unindented by one unit if matching. + * - var-indent-triggerchars: a list of characters that should cause the + * indentiou to be recalculated immediately when typed. + * - var-indent-handle-couples: a list of paren sets to handle. Any combination + * of 'parens' 'braces' and 'brackets'. Each set type is handled + * the following way: If there are unmatched opening instances on the above line, + * one indent unit is added, if there are unmatched closing instances on the + * current line, one indent unit is removed. + * - var-indent-couple-attribute: When looking for unmatched couple openings/closings, + * only characters with this attribute is considered. The value must be the + * attribute name from the syntax xml file, for example "Symbol". If it's not + * specified, attribute 0 is used (usually 'Normal Text'). + * + * The idea is to provide a somewhat intelligent indentation for perl, php, + * bash, scheme and in general formats with humble indentation needs. + */ +class KateVarIndent : public KateNormalIndent +{ + Q_OBJECT + + public: + /** + * Purely for readability, couples we know and love + */ + enum pairs { + Parens=1, + Braces=2, + Brackets=4, + AngleBrackets=8 + }; + + KateVarIndent( KateDocument *doc ); + virtual ~KateVarIndent(); + + virtual void processNewline (KateDocCursor &cur, bool needContinue); + virtual void processChar (QChar c); + + virtual void processLine (KateDocCursor &line); + virtual void processSection (const KateDocCursor &begin, const KateDocCursor &end); + + virtual bool canProcessLine() const { return true; } + + virtual uint modeNumber () const { return KateDocumentConfig::imVarIndent; }; + + private slots: + void slotVariableChanged(const QString&, const QString&); + + private: + /** + * Check if coupled characters are in balance within one line. + * @param line the line to check + * @param open the opening character + * @param close the closing character + * @param attrib the attribute the characters must have, defaults to + * KateAutoIndent::symbolAttrib + */ + int coupleBalance( int line, const QChar &open, const QChar &close ) const; + + /** + * @return true if there is a matching opening with the correct attribute + * @param end a cursor pointing to the closing character + */ + bool hasRelevantOpening( const KateDocCursor &end ) const; + + class KateVarIndentPrivate *d; +}; + +class KateScriptIndent : public KateNormalIndent +{ + Q_OBJECT + + public: + KateScriptIndent( KateDocument *doc ); + ~KateScriptIndent(); + + virtual void processNewline( KateDocCursor &cur, bool needContinue ); + virtual void processChar( QChar c ); + + virtual void processLine (KateDocCursor &line); +// virtual void processSection (const KateDocCursor &begin, const KateDocCursor &end); + + virtual bool canProcessLine() const { return true; } + + virtual uint modeNumber () const { return KateDocumentConfig::imScriptIndent; }; + private: + KateIndentScript m_script; +}; + +class ScriptIndentConfigPage : public IndenterConfigPage +{ + Q_OBJECT + + public: + ScriptIndentConfigPage ( QWidget *parent=0, const char *name=0 ); + virtual ~ScriptIndentConfigPage (); + + public slots: + /** + * Apply changes. + */ + virtual void apply (); +}; + +#endif + +// kate: space-indent on; indent-width 2; replace-tabs on; |