• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • applications API Reference
  • KDE Home
  • Contact Us
 

Kate

  • kde-4.14
  • applications
  • kate
  • part
  • script
katescriptmanager.cpp
Go to the documentation of this file.
1 // This file is part of the KDE libraries
2 // Copyright (C) 2005 Christoph Cullmann <cullmann@kde.org>
3 // Copyright (C) 2005 Joseph Wenninger <jowenn@kde.org>
4 // Copyright (C) 2006, 2009 Dominik Haumann <dhaumann kde org>
5 // Copyright (C) 2008 Paul Giannaros <paul@giannaros.org>
6 // Copyright (C) 2010 Joseph Wenninger <jowenn@kde.org>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License version 2 as published by the Free Software Foundation.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Library General Public License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public License
18 // along with this library; see the file COPYING.LIB. If not, write to
19 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 // Boston, MA 02110-1301, USA.
21 
22 #include "katescriptmanager.h"
23 
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 
28 #include <QFile>
29 #include <QFileInfo>
30 #include <QStringList>
31 #include <QMap>
32 #include <QUuid>
33 
34 #include <kconfig.h>
35 #include <kconfiggroup.h>
36 #include <kstandarddirs.h>
37 #include <kde_file.h>
38 
39 #include "kateglobal.h"
40 #include "katecmd.h"
41 
42 KateScriptManager* KateScriptManager::m_instance = 0;
43 
44 KateScriptManager::KateScriptManager() : QObject(), KTextEditor::Command()
45 {
46  KateCmd::self()->registerCommand (this);
47 
48  // use cached info
49  collect();
50 }
51 
52 KateScriptManager::~KateScriptManager()
53 {
54  KateCmd::self()->unregisterCommand (this);
55  qDeleteAll(m_indentationScripts);
56  qDeleteAll(m_commandLineScripts);
57  m_instance = 0;
58 }
59 
60 KateIndentScript *KateScriptManager::indenter(const QString &language)
61 {
62  KateIndentScript *highestPriorityIndenter = 0;
63  foreach(KateIndentScript *indenter, m_languageToIndenters.value(language.toLower())) {
64  // don't overwrite if there is already a result with a higher priority
65  if(highestPriorityIndenter && indenter->indentHeader().priority() < highestPriorityIndenter->indentHeader().priority()) {
66 #ifdef DEBUG_SCRIPTMANAGER
67  kDebug(13050) << "Not overwriting indenter for"
68  << language << "as the priority isn't big enough (" <<
69  indenter->indentHeader().priority() << '<'
70  << highestPriorityIndenter->indentHeader().priority() << ')';
71 #endif
72  }
73  else {
74  highestPriorityIndenter = indenter;
75  }
76  }
77 
78 #ifdef DEBUG_SCRIPTMANAGER
79  if(highestPriorityIndenter) {
80  kDebug(13050) << "Found indenter" << highestPriorityIndenter->url() << "for" << language;
81  } else {
82  kDebug(13050) << "No indenter for" << language;
83  }
84 #endif
85 
86  return highestPriorityIndenter;
87 }
88 
89 void KateScriptManager::collect(bool force)
90 {
91  // local information cache
92  KConfig cfgFile("katescriptingrc", KConfig::NoGlobals);
93 
94  // we might need to enforce reload!
95  {
96  KConfigGroup config(&cfgFile, "General");
97  // If KatePart version does not match, better force a true reload
98  if(KateGlobal::katePartVersion() != config.readEntry("kate-version", QString("0.0"))) {
99  config.writeEntry("kate-version", KateGlobal::katePartVersion());
100  force = true;
101  }
102  }
103 
104  // clear out the old scripts and reserve enough space
105  qDeleteAll(m_indentationScripts);
106  qDeleteAll(m_commandLineScripts);
107  m_indentationScripts.clear();
108  m_commandLineScripts.clear();
109 
110  m_languageToIndenters.clear();
111  m_indentationScriptMap.clear();
112 
116  foreach (const QString &type, QStringList () << "indentation" << "commands") {
117  // get a list of all .js files for the current type
118  const QStringList list = KGlobal::dirs()->findAllResources("data", "katepart/script/" + type + "/*.js", KStandardDirs::NoDuplicates);
119 
120  // iterate through the files and read info out of cache or file
121  foreach(const QString &fileName, list) {
122  // get abs filename....
123  QFileInfo fi(fileName);
124  const QString absPath = fi.absoluteFilePath();
125  const QString baseName = fi.baseName ();
126 
127  // each file has a group
128  const QString group = "Cache "+ fileName;
129  KConfigGroup config(&cfgFile, group);
130 
131  // stat the file to get the last-modified-time
132  KDE_struct_stat sbuf;
133  memset(&sbuf, 0, sizeof(sbuf));
134  KDE::stat(fileName, &sbuf);
135 
136  // check whether file is already cached
137  bool useCache = false;
138  if(!force && cfgFile.hasGroup(group)) {
139  useCache = (sbuf.st_mtime == config.readEntry("last-modified", 0));
140  }
141 
142  // read key/value pairs from the cached file if possible
143  // otherwise, parse it and then save the needed information to the cache.
144  QHash<QString, QString> pairs;
145  if(useCache) {
146  const QMap<QString, QString> entries = config.entryMap();
147  for(QMap<QString, QString>::ConstIterator entry = entries.constBegin();
148  entry != entries.constEnd();
149  ++entry)
150  pairs[entry.key()] = entry.value();
151  }
152  else if(parseMetaInformation(fileName, pairs)) {
153  config.writeEntry("last-modified", int(sbuf.st_mtime));
154  // iterate keys and save cache
155  for(QHash<QString, QString>::ConstIterator item = pairs.constBegin();
156  item != pairs.constEnd();
157  ++item)
158  config.writeEntry(item.key(), item.value());
159  }
160  else {
161  // parseMetaInformation will have informed the user of the problem
162  continue;
163  }
164 
168  KateScriptHeader generalHeader;
169  if(type == "indentation") {
170  generalHeader.setScriptType(Kate::IndentationScript);
171  } else if (type == "commands") {
172  generalHeader.setScriptType(Kate::CommandLineScript);
173  } else {
174  // should never happen, we dictate type by directory
175  Q_ASSERT (false);
176  }
177 
178  generalHeader.setLicense(pairs.take("license"));
179  generalHeader.setAuthor(pairs.take("author"));
180  generalHeader.setRevision(pairs.take("revision").toInt());
181  generalHeader.setKateVersion(pairs.take("kate-version"));
182  generalHeader.setCatalog(pairs.take("i18n-catalog"));
183 
184  // now, cast accordingly based on type
185  switch(generalHeader.scriptType()) {
186  case Kate::IndentationScript: {
187  KateIndentScriptHeader indentHeader;
188  indentHeader.setName(pairs.take("name"));
189  indentHeader.setBaseName(baseName);
190  if (indentHeader.name().isNull()) {
191  kDebug( 13050 ) << "Script value error: No name specified in script meta data: "
192  << qPrintable(fileName) << '\n' << "-> skipping indenter" << '\n';
193  continue;
194  }
195 
196  // required style?
197  indentHeader.setRequiredStyle(pairs.take("required-syntax-style"));
198  // which languages does this support?
199  QString indentLanguages = pairs.take("indent-languages");
200  if(!indentLanguages.isNull()) {
201  indentHeader.setIndentLanguages(indentLanguages.split(','));
202  }
203  else {
204  indentHeader.setIndentLanguages(QStringList() << indentHeader.name());
205 
206  #ifdef DEBUG_SCRIPTMANAGER
207  kDebug( 13050 ) << "Script value warning: No indent-languages specified for indent "
208  << "script " << qPrintable(fileName) << ". Using the name ("
209  << qPrintable(indentHeader.name()) << ")\n";
210  #endif
211  }
212  // priority?
213  bool convertedToInt;
214  int priority = pairs.take("priority").toInt(&convertedToInt);
215 
216  #ifdef DEBUG_SCRIPTMANAGER
217  if(!convertedToInt) {
218  kDebug( 13050 ) << "Script value warning: Unexpected or no priority value "
219  << "in: " << qPrintable(fileName) << ". Setting priority to 0\n";
220  }
221  #endif
222 
223  indentHeader.setPriority(convertedToInt ? priority : 0);
224  KateIndentScript *script = new KateIndentScript(fileName, indentHeader);
225  script->setGeneralHeader(generalHeader);
226  foreach(const QString &language, indentHeader.indentLanguages()) {
227  m_languageToIndenters[language.toLower()].push_back(script);
228  }
229 
230  m_indentationScriptMap.insert(indentHeader.baseName(), script);
231  m_indentationScripts.append(script);
232  break;
233  }
234  case Kate::CommandLineScript: {
235  KateCommandLineScriptHeader commandHeader;
236  commandHeader.setFunctions(pairs.take("functions").split(QRegExp("\\s*,\\s*"), QString::SkipEmptyParts));
237  if (commandHeader.functions().isEmpty()) {
238  kDebug(13050) << "Script value error: No functions specified in script meta data: "
239  << qPrintable(fileName) << '\n' << "-> skipping script" << '\n';
240  continue;
241  }
242  KateCommandLineScript* script = new KateCommandLineScript(fileName, commandHeader);
243  script->setGeneralHeader(generalHeader);
244  m_commandLineScripts.push_back(script);
245  break;
246  }
247  case Kate::UnknownScript:
248  default:
249  kDebug( 13050 ) << "Script value warning: Unknown type ('" << qPrintable(type) << "'): "
250  << qPrintable(fileName) << '\n';
251  }
252  }
253  }
254 
255 
256 
257 #ifdef DEBUG_SCRIPTMANAGER
258  // XX Test
259  if(indenter("Python")) {
260  kDebug( 13050 ) << "Python: " << indenter("Python")->global("triggerCharacters").isValid() << "\n";
261  kDebug( 13050 ) << "Python: " << indenter("Python")->function("triggerCharacters").isValid() << "\n";
262  kDebug( 13050 ) << "Python: " << indenter("Python")->global("blafldsjfklas").isValid() << "\n";
263  kDebug( 13050 ) << "Python: " << indenter("Python")->function("indent").isValid() << "\n";
264  }
265  if(indenter("C"))
266  kDebug( 13050 ) << "C: " << qPrintable(indenter("C")->url()) << "\n";
267  if(indenter("lisp"))
268  kDebug( 13050 ) << "LISP: " << qPrintable(indenter("Lisp")->url()) << "\n";
269 #endif
270 
271  cfgFile.sync();
272 }
273 
274 
275 bool KateScriptManager::parseMetaInformation(const QString& url,
276  QHash<QString, QString> &pairs)
277 {
278  // a valid script file -must- have the following format:
279  // The first line must contain the string 'kate-script'.
280  // All following lines have to have the format 'key : value'. So the value
281  // is separated by a colon. Leading non-letter characters are ignored, that
282  // include C and C++ comments for example.
283  // Parsing the header stops at the first line with no ':'.
284 
285  QFile file(url);
286  if(!file.open(QIODevice::ReadOnly)) {
287  kDebug( 13050 ) << "Script parse error: Cannot open file " << qPrintable(url) << '\n';
288  return false;
289  }
290 
291  kDebug(13050) << "Update script: " << url;
292  QTextStream ts(&file);
293  ts.setCodec("UTF-8");
294  if(!ts.readLine().contains("kate-script")) {
295  kDebug( 13050 ) << "Script parse error: No header found in " << qPrintable(url) << '\n';
296  file.close();
297  return false;
298  }
299 
300  QString line;
301  while(!(line = ts.readLine()).isNull()) {
302  int colon = line.indexOf(':');
303  if(colon <= 0)
304  break; // no colon -> end of header found
305 
306  // if -1 then 0. if >= 0, move after star.
307  int start = 0; // start points to first letter. idea: skip '*' and '//'
308  while(start < line.length() && !line.at(start).isLetter())
309  ++start;
310 
311  QString key = line.mid(start, colon - start).trimmed();
312  QString value = line.right(line.length() - (colon + 1)).trimmed();
313  pairs[key] = value;
314 
315 #ifdef DEBUG_SCRIPTMANAGER
316  kDebug(13050) << "KateScriptManager::parseMetaInformation: found pair: "
317  << "(" << key << " | " << value << ")";
318 #endif
319  }
320 
321  file.close();
322  return true;
323 }
324 
325 void KateScriptManager::reload()
326 {
327  collect(true);
328  emit reloaded();
329 }
330 
332 
333 bool KateScriptManager::exec(KTextEditor::View *view, const QString &_cmd, QString &errorMsg)
334 {
335  QStringList args(_cmd.split(QRegExp("\\s+"), QString::SkipEmptyParts));
336  QString cmd(args.first());
337  args.removeFirst();
338 
339  if(!view) {
340  errorMsg = i18n("Could not access view");
341  return false;
342  }
343 
344  if (cmd == "reload-scripts") {
345  reload();
346  return true;
347  } else {
348  errorMsg = i18n("Command not found: %1", cmd);
349  return false;
350  }
351 }
352 
353 bool KateScriptManager::help(KTextEditor::View *view, const QString &cmd, QString &msg)
354 {
355  Q_UNUSED(view)
356 
357  if (cmd == "reload-scripts") {
358  msg = i18n("Reload all JavaScript files (indenters, command line scripts, etc).");
359  return true;
360  } else {
361  msg = i18n("Command not found: %1", cmd);
362  return false;
363  }
364 }
365 
366 const QStringList &KateScriptManager::cmds()
367 {
368  static QStringList l;
369 
370  l.clear();
371  l << "reload-scripts";
372 
373  return l;
374 }
375 
376 
377 
378 KTextEditor::TemplateScript* KateScriptManager::registerTemplateScript (QObject* owner, const QString& script)
379 {
380  KateTemplateScript* kts = new KateTemplateScript(script);
381  m_templateScripts.append(kts);
382 
383  connect(owner, SIGNAL(destroyed(QObject*)),
384  this, SLOT(slotTemplateScriptOwnerDestroyed(QObject*)));
385  m_ownerScript.insertMulti(owner, kts);
386  return kts;
387 }
388 
389 void KateScriptManager::unregisterTemplateScript(KTextEditor::TemplateScript* templateScript)
390 {
391  int index = m_templateScripts.indexOf(templateScript);
392  if (index != -1) {
393  QObject* k = m_ownerScript.key(templateScript);
394  m_ownerScript.remove(k, templateScript);
395  m_templateScripts.removeAt(index);
396  delete templateScript;
397  }
398 }
399 
400 void KateScriptManager::slotTemplateScriptOwnerDestroyed(QObject* owner)
401 {
402  while (m_ownerScript.contains(owner)) {
403  KTextEditor::TemplateScript* templateScript = m_ownerScript.take(owner);
404  kDebug() << "Destroying template script" << templateScript;
405  m_templateScripts.removeAll(templateScript);
406  delete templateScript;
407  }
408 }
409 
410 KateTemplateScript* KateScriptManager::templateScript(KTextEditor::TemplateScript* templateScript)
411 {
412  if (m_templateScripts.contains(templateScript)) {
413  return static_cast<KateTemplateScript*>(templateScript);
414  }
415 
416  return 0;
417 }
418 
419 // kate: space-indent on; indent-width 2; replace-tabs on;
QTextStream::setCodec
void setCodec(QTextCodec *codec)
QList::clear
void clear()
KateScriptManager
Manage the scripts on disks – find them and query them.
Definition: katescriptmanager.h:43
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
KateScriptManager::help
bool help(KTextEditor::View *view, const QString &cmd, QString &msg)
get help for a command
Definition: katescriptmanager.cpp:353
Kate::Script::i18n
QScriptValue i18n(QScriptContext *context, QScriptEngine *engine)
i18n("text", arguments [optional])
Definition: katescripthelpers.cpp:186
KateCmd::unregisterCommand
bool unregisterCommand(KTextEditor::Command *cmd)
Definition: katecmd.cpp:59
KateIndentScriptHeader::priority
int priority() const
Definition: kateindentscript.h:53
KateScriptManager::parseMetaInformation
static bool parseMetaInformation(const QString &url, QHash< QString, QString > &pairs)
Extract the meta data from the script at url and put in pairs.
Definition: katescriptmanager.cpp:275
QTextStream::readLine
QString readLine(qint64 maxlen)
KateCommandLineScriptHeader::setFunctions
void setFunctions(const QStringList &functions)
Definition: katecommandlinescript.h:38
KateScriptHeader::setLicense
void setLicense(const QString &license)
Definition: katescript.h:61
KateScriptManager::exec
bool exec(KTextEditor::View *view, const QString &cmd, QString &errorMsg)
execute command
Definition: katescriptmanager.cpp:333
KateCommandLineScriptHeader
Definition: katecommandlinescript.h:32
KateIndentScriptHeader::setRequiredStyle
void setRequiredStyle(const QString &requiredStyle)
Definition: kateindentscript.h:41
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
KateCmd::self
static KateCmd * self()
Definition: katecmd.cpp:112
QMap::constBegin
const_iterator constBegin() const
QMap< QString, QString >
KateScriptHeader::setScriptType
void setScriptType(Kate::ScriptType scriptType)
Definition: katescript.h:86
KateScriptHeader::setAuthor
void setAuthor(const QString &author)
Definition: katescript.h:66
KateScriptHeader::setKateVersion
void setKateVersion(const QString &kateVersion)
Definition: katescript.h:76
KateScriptHeader
Definition: katescript.h:53
QFile
QTextStream
KateCommandLineScript
A specialized class for scripts that are of type KateScriptInformation::IndentationScript.
Definition: katecommandlinescript.h:80
QString::isNull
bool isNull() const
QChar::isLetter
bool isLetter() const
KateIndentScriptHeader::name
const QString & name() const
Definition: kateindentscript.h:38
QRegExp
KateCommandLineScriptHeader::functions
const QStringList & functions() const
Definition: katecommandlinescript.h:40
QHash::constEnd
const_iterator constEnd() const
QHash< QString, QString >
KateGlobal::katePartVersion
static QString katePartVersion()
Returns the current version of Kate Part: KDE X.Y.Z contains Kate Part X-1.Y.
Definition: kateglobal.cpp:60
QObject
kateglobal.h
QList::isEmpty
bool isEmpty() const
QFileInfo::absoluteFilePath
QString absoluteFilePath() const
QString::trimmed
QString trimmed() const
QMap::constEnd
const_iterator constEnd() const
KateScriptManager::reload
void reload()
explicitly reload all scripts
Definition: katescriptmanager.cpp:325
katecmd.h
QString
KateScript::url
const QString & url()
The script's URL.
Definition: katescript.h:123
KateScript::setGeneralHeader
void setGeneralHeader(const KateScriptHeader &generalHeader)
set the general header after construction of the script
Definition: katescript.cpp:229
KateScriptHeader::setCatalog
void setCatalog(const QString &catalog)
Definition: katescript.h:81
QFile::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
KateIndentScript
A specialized class for scripts that are of type KateScriptInformation::IndentationScript.
Definition: kateindentscript.h:94
Kate::UnknownScript
Don't know what kind of script this is.
Definition: katescript.h:47
QStringList
QString::right
QString right(int n) const
KateScriptManager::collect
void collect(bool force=false)
Find all of the scripts matching the wildcard directory.
Definition: katescriptmanager.cpp:89
QFileInfo
QString::toLower
QString toLower() const
QHash::value
const T value(const Key &key) const
KateScriptManager::~KateScriptManager
virtual ~KateScriptManager()
Definition: katescriptmanager.cpp:52
KateIndentScriptHeader::baseName
const QString & baseName() const
Definition: kateindentscript.h:58
KateIndentScriptHeader::setBaseName
void setBaseName(const QString &baseName)
Definition: kateindentscript.h:56
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
KateScriptManager::unregisterTemplateScript
void unregisterTemplateScript(KTextEditor::TemplateScript *templateScript)
unregister a given script
Definition: katescriptmanager.cpp:389
QFile::close
virtual void close()
KateScriptManager::cmds
const QStringList & cmds()
supported commands as prefixes
Definition: katescriptmanager.cpp:366
QHash::constBegin
const_iterator constBegin() const
KateScriptManager::registerTemplateScript
KTextEditor::TemplateScript * registerTemplateScript(QObject *owner, const QString &script)
managing of scripts for the template handler.
Definition: katescriptmanager.cpp:378
QString::mid
QString mid(int position, int n) const
QHash::take
T take(const Key &key)
KateIndentScriptHeader::setPriority
void setPriority(int priority)
Definition: kateindentscript.h:51
QString::at
const QChar at(int position) const
QString::length
int length() const
KateCmd::registerCommand
bool registerCommand(KTextEditor::Command *cmd)
Definition: katecmd.cpp:38
katescriptmanager.h
Kate::IndentationScript
The script is an indenter.
Definition: katescript.h:43
KateIndentScriptHeader
Definition: kateindentscript.h:30
KateIndentScriptHeader::setName
void setName(const QString &name)
Definition: kateindentscript.h:36
KateTemplateScript
Definition: katetemplatescript.h:28
KateScriptManager::slotTemplateScriptOwnerDestroyed
void slotTemplateScriptOwnerDestroyed(QObject *owner)
Definition: katescriptmanager.cpp:400
KateScriptHeader::setRevision
void setRevision(int revision)
Definition: katescript.h:71
KateIndentScriptHeader::indentLanguages
const QStringList & indentLanguages() const
Definition: kateindentscript.h:48
QFileInfo::baseName
QString baseName() const
KateScriptManager::indenter
KateIndentScript * indenter(const QString &language)
Get an indentation script for the given language – if there is more than one result, this will return the script with the highest priority.
Definition: katescriptmanager.cpp:60
KateIndentScript::indentHeader
const KateIndentScriptHeader & indentHeader() const
Definition: kateindentscript.cpp:35
KateScriptManager::templateScript
KateTemplateScript * templateScript(KTextEditor::TemplateScript *templateScript)
Definition: katescriptmanager.cpp:410
Kate::CommandLineScript
The script contains command line commands.
Definition: katescript.h:45
KateScriptHeader::scriptType
Kate::ScriptType scriptType() const
Definition: katescript.h:88
KateIndentScriptHeader::setIndentLanguages
void setIndentLanguages(const QStringList &indentLanguages)
Definition: kateindentscript.h:46
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat May 9 2020 03:56:58 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

applications API Reference

Skip menu "applications API Reference"
  •   kate
  •       kate
  •   KTextEditor
  •   Kate
  • Konsole

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal