Git commit 3466f6dc98583254ea87c341a3289daf007ccca5 by Thomas Friedrichsmeier. Committed on 10/06/2025 at 12:37. Pushed by tfry into branch 'master'.
Update documentation for script type snippets M +11 -35 addons/snippets/editsnippet.cpp M +3 -5 addons/snippets/snippet.cpp M +65 -39 doc/kate/plugins.docbook M +8 -0 doc/katepart/development.docbook https://invent.kde.org/utilities/kate/-/commit/3466f6dc98583254ea87c341a3289daf007ccca5 diff --git a/addons/snippets/editsnippet.cpp b/addons/snippets/editsnippet.cpp index e42e6e261e..cc48a71774 100644 --- a/addons/snippets/editsnippet.cpp +++ b/addons/snippets/editsnippet.cpp @@ -72,28 +72,20 @@ EditSnippet::EditSnippet(SnippetRepository *repository, Snippet *snippet, QWidge connect(m_ui->modeComboBox, &QComboBox::currentIndexChanged, this, [this]() { if (m_ui->modeComboBox->currentData().toInt() == Snippet::TextTemplate) { m_ui->snippetLabel->setText( - i18n("The text your snippet will insert into the document. " - "<a href=\"A template snippet can contain editable fields. They can be " - "cycled by pressing Tab. The following expressions can be used " - "in the template text to create fields: <br><tt>${field_name}</tt> " - "creates a simple, editable field. All subsequent occurrences of the " - "same field_name will mirror the contents of the first " - "during editing.<br><tt>${field_name=default}</tt> can be used to " - "specify a default value for the field, where <tt>default</tt> can be any " - "JavaScript expression (use quotatio marks to specify " - "a fixed string as default value).<br><tt>${func(other_field1, " - "other_field2, ...)</tt> evaluates a JavaScript function defined in the " - "'Scripts Library' tab on each edit, and is replaced by the value returned " - "by that function.<br><tt>${cursor}</tt> " - "can be used to mark the end position of the cursor after everything " - "else was filled in.\">More...</a>")); - m_snippetView->document()->setMode(QStringLiteral("None")); // TODO + i18n("Text to insert into the document (see " + "<a href=\"help:/kate/kate-application-plugin-snippets.html\">handbook</a> " + "for special fields).")); + m_snippetView->document()->setMode(QStringLiteral("Normal")); } else { // TODO - m_ui->snippetLabel->setText(i18n("Explanation for script. Individual portion vs Script Library")); + m_ui->snippetLabel->setText( + i18n("Javascript code to evaluate (see " + "<a href=\"help:/kate/kate-application-plugin-snippets.html\">handbook</a> " + "for details).")); m_snippetView->document()->setMode(QStringLiteral("JavaScript")); } }); + m_ui->snippetLabel->setOpenExternalLinks(true); m_ui->modeComboBox->addItem(i18n("Text template"), QVariant(Snippet::TextTemplate)); m_ui->modeComboBox->addItem(i18n("Script"), QVariant(Snippet::Script)); @@ -102,19 +94,9 @@ EditSnippet::EditSnippet(SnippetRepository *repository, Snippet *snippet, QWidge m_scriptsView->document()->setText(m_repo->script()); m_scriptsView->document()->setModified(false); - // TODO: link to handbook m_ui->scriptLabel->setText( - i18n("Write down JavaScript helper functions to use in your snippets here. " - "<a href=\"Editable template fields are accessible as local variables. " - "For example in a template snippet containing <tt>${field}</tt>, a " - "variable called <tt>field</tt> will be present which contains the " - "up-to-date contents of the template field. Those variables can either " - "be used in the function statically or passed as arguments, by using the " - "<tt>${func(field)}</tt> or <tt>${field2=func(field)}</tt> syntax in the " - "snippet string.<br>You can use the kate scripting API to get the " - "selected text, full text, file name and more by using the appropriate " - "methods of the <tt>document</tt> and <tt>view</tt> objects. Refer to " - "the scripting API documentation for more information.\">More...</a>")); + i18n("JavaScript functions shared between all snippets in this repository (see " + "<a href=\"help:/kate/kate-application-plugin-snippets.html\">handbook</a>).")); m_ui->descriptionLabel->setText(i18n("(Optional) description to show in tooltips. May contain HTML formatting.")); m_descriptionView = createView(m_ui->descriptionTab); @@ -134,12 +116,6 @@ EditSnippet::EditSnippet(SnippetRepository *repository, Snippet *snippet, QWidge connect(m_ui->snippetShortcut, &KKeySequenceWidget::keySequenceChanged, this, &EditSnippet::topBoxModified); connect(m_snippetView->document(), &KTextEditor::Document::textChanged, this, &EditSnippet::validate); - auto showHelp = [](const QString &text) { - QWhatsThis::showText(QCursor::pos(), text); - }; - connect(m_ui->snippetLabel, &QLabel::linkActivated, showHelp); - connect(m_ui->scriptLabel, &QLabel::linkActivated, showHelp); - // if we edit a snippet, add all existing data if (m_snippet) { setWindowTitle(i18n("Edit Snippet %1 in %2", m_snippet->text(), m_repo->text())); diff --git a/addons/snippets/snippet.cpp b/addons/snippets/snippet.cpp index 51d0ba135b..422f502c96 100644 --- a/addons/snippets/snippet.cpp +++ b/addons/snippets/snippet.cpp @@ -98,11 +98,9 @@ void Snippet::apply(KTextEditor::View *view, const QString &repoScript) const view->insertTemplate(view->cursorPosition(), snippet(), repoScript); } else { QVariant res; - auto ok = view->evaluateScript(repoScript + u'\n' + snippet(), &res); - if (!ok) { - // show error message, by simply inserting it - view->document()->insertText(view->cursorPosition(), res.toString()); - } + view->evaluateScript(repoScript + u'\n' + snippet(), &res); + // for convenience, insert result (or error message) at cursor position + view->document()->insertText(view->cursorPosition(), res.toString()); } } diff --git a/doc/kate/plugins.docbook b/doc/kate/plugins.docbook index d673beab72..a61fdf50a6 100644 --- a/doc/kate/plugins.docbook +++ b/doc/kate/plugins.docbook @@ -3355,7 +3355,7 @@ that are for the currently opened file type.</para></listitem> </menuchoice></term> <listitem> <para>Create a new snippet, which is a reusable chunk of text you -may insert in any part of any document.</para> +may insert in any part of any document, or a small script.</para> </listitem> </varlistentry> @@ -3463,16 +3463,24 @@ than one file type pressing the &Shift; while adding types.</para></listitem> <varlistentry> <term><guilabel>Name</guilabel></term> -<listitem><para>The name will be shown in the completion list.</para></listitem> +<listitem><para>The name as shown in the list of snippets, and in the completion list (required).</para></listitem> +</varlistentry> + +<varlistentry> +<term><guilabel>Type</guilabel></term> +<listitem><para>Snippets may either be defined as text templates or scripts. Both types allow to use &javascript; functions +(see below, for details), and can thus be used to similar effect. However, as a rule of thumb, text templates will be more +suiteable, if you mostly want to <emphasis>insert</emphasis> text, while scripts are often an easier solution, if you want to +<emphasis>modify</emphasis> text).</para></listitem> </varlistentry> <varlistentry> <term>Shortcut</term> -<listitem><para>Pressing this shortcut will insert the snippet into the document.</para></listitem> +<listitem><para>Pressing this shortcut will insert (or run) the snippet into the current document.</para></listitem> </varlistentry> <varlistentry> -<term><guilabel>Snippets</guilabel></term> +<term><guilabel>Snippet</guilabel> (type <userinput>Text Template</userinput>)</term> <listitem><para>The text your snippet will insert into the document.</para> <para>A snippet can contain editable fields. They can be cycled by pressing 	. The following expressions can be used in the template @@ -3484,64 +3492,81 @@ of the first during editing.</para> <para><userinput>${<replaceable>field_name=default</replaceable>}</userinput> can be used to specify a default value for the field. <replaceable>default</replaceable> can be any &javascript; expression.</para> -<para>Use <userinput>${<replaceable>field_name</replaceable>=<replaceable>text</replaceable>}</userinput> +<para>Use quotes (<userinput>${<replaceable>field_name</replaceable>=<replaceable>"text"</replaceable>}</userinput>) to specify a fixed string as default value.</para> <para><userinput>${func(<replaceable>other_field1</replaceable>, <replaceable>other_field2</replaceable>, ...)}</userinput> can be used to create a -field which evaluates a &javascript; function on each edit and contains its -contents. See the <guilabel>Scripts</guilabel> tab for more information.</para> +field which evaluates a &javascript; function on each edit and is replaced by that +function's return value. See the <guilabel>Script Library</guilabel> tab for more information.</para> <para><userinput>${cursor}</userinput> can be used to mark the end position of the cursor after everything else was filled in.</para> </listitem> </varlistentry> <varlistentry> -<term><guilabel>Scripts</guilabel></term> -<listitem><para>&javascript; helper functions to use in your snippets.</para> -<para>All &javascript; functions should return the contents you want to place in a -template field as a string.</para> -<para>Functions are called in a scope which contains the contents of all -editable template fields as local variables. For example in a snippet +<term><guilabel>Snippet</guilabel> (type <userinput>Script</userinput>)</term> +<listitem><para>The &javascript; code to evaluate for this snippet</para> +<para>If this code contains a <userinput>return</userinput>, the returned string will be inserted at the current +cursor position, but you can also use the <ulink url="help:/katepart/dev-scripting.html#dev-scripting-api">&kate; +scripting API</ulink> to modify the document, directly.</para> +<para>Additionally, your code may use functions defined in the <guilabel>Script Library</guilabel> tab, which +are shared between all snippets in a repository.</para> +</listitem> +</varlistentry> + +<varlistentry> +<term><guilabel>Script Library</guilabel></term> +<listitem><para>&javascript; helper functions to use in your snippets. These functions are shared between all snippets in a repository.</para> +<para>You can use the <ulink url="help:/katepart/dev-scripting.html#dev-scripting-api">&kate; scripting API</ulink> +to get the selected text, full text, file name and more by using the appropriate methods of the <userinput>document</userinput> +and <userinput>view</userinput> objects. Refer to the scripting API +documentation for more information.</para> + +<para>When scripting in conjuction with <userinput>Text Template</userinput> snippets, you should keep the +following details/hints in mind:</para> +<itemizedlist> +<listitem><para>Remember that only the <emphasis>return value</emphasis> of a function is inserted in a field.</para></listitem> +<listitem><para>The contents of all editable template fields are available as variables in this scope. For example in a snippet containing <userinput>${<replaceable>field</replaceable>}</userinput>, a variable called <userinput>field</userinput> will be present which contains the up-to-date contents of the template field. Those variables can either be used in the function statically or passed as arguments, by using the <userinput>${func(field)}</userinput> or <userinput>${<replaceable>field2=func(field)</replaceable>}</userinput> -syntax in the snippet string.</para> -<para>You can use -the <ulink url="help:/katepart/dev-scripting.html#dev-scripting-api">&kate; scripting API</ulink> -to get the selected text, full text, file name and -more by using the appropriate methods of the <userinput>document</userinput> -and <userinput>view</userinput> objects. Refer to the scripting API -documentation for more information.</para> -<para>For more complex scripts it may be important to understand that +syntax in the snippet string.</para></listitem> +<listitem><para>For more complex scripts it may be important to understand that <emphasis>first</emphasis>, the raw snippet is inserted into the document, and <emphasis>then</emphasis> functions are being evaluated. E.g., if a function retrieves the text on the line where the snippet is being inserted, that text will also contain -<userinput>${functionCall()}</userinput>.</para> -<para>As an example of working with selections using the scripting API, a simple way -to wrap selected text inside tags is this snippet: -<userinput><strong>${view.selectedText()}</strong></userinput> -</para> -<para>The following example invokes a script that inserts a default text in case -there is no selection. Snippet:</para> +<userinput>${functionCall()}</userinput>. Where this causes complications, consider using a +<userinput>Script</userinput>-type snippet, instead.</para></listitem> +<listitem><para>To simply wrap the currently selected text into tags, use: <userinput><strong>${view.selectedText()}</strong></userinput></para></listitem> +</itemizedlist> +</listitem> +</varlistentry> + +<varlistentry> +<term><guilabel>Description</guilabel></term> +<listitem><para>An optional description of what this snippet does. This will be shown in tooltips. The description +may contain basic HTML formatting.</para></listitem> +</varlistentry> + +<varlistentry> +<term>Usage example</term> +<listitem><para>The following example invokes a script that wraps the selected text, or - if +there is no selection - a default text, into tags (Snippet type <userinput>Script</userinput>):</para> <para> -<userinput>${rangeCommand("<strong>%%1</strong>", "Bold")}</userinput></para> -<para>Script: <programlisting> -function rangeCommand(command, def) { - if (view.selectedText().length > 0) { - return command.replace("%%1", view.selectedText()); - } else { - return command.replace("%%1", def); - } -} +let range = view.hasSelection() ? view.selection() : new Range(view.cursorPosition(), view.cursorPosition()); +let innertext = range.isEmpty() ? "Bold" : document.text(range); +document.removeText(range); +document.insertText(range.start, "<strong>" + innertext + "</strong>"); </programlisting> </para> </listitem> </varlistentry> </variablelist> + </sect3> </sect2> @@ -3557,10 +3582,11 @@ function rangeCommand(command, def) { </mediaobject> </screenshot> -<para>You can call snippets in two ways:</para> +<para>You can call snippets in several ways:</para> <itemizedlist> -<listitem><para>By choosing the snippet from the tool view.</para></listitem> +<listitem><para>By clicking on the snippet from the tool view.</para></listitem> +<listitem><para>Using a keyboard shortcut, if you have assigned one.</para></listitem> <listitem><para>While writing, you can press <keycombo action="simul">&Ctrl; &Space;</keycombo>, which will display all the snippets in a convenient window from which you can choose. This key combination provides diff --git a/doc/katepart/development.docbook b/doc/katepart/development.docbook index a9bc121605..86fbd50148 100644 --- a/doc/katepart/development.docbook +++ b/doc/katepart/development.docbook @@ -2584,6 +2584,8 @@ a theme.</para> The &kappname; editor component is easily extensible by writing scripts. The scripting language is ECMAScript (widely known as &javascript;). &kappname; supports two kinds of scripts: indentation and command line scripts. +A functionality similar to command line scripts is also provided in the +<ulink url="help:/kate/kate-application-plugin-snippets.html">snippets plugin</ulink> </para> <sect2 id="dev-scripting-indentation"> @@ -2742,6 +2744,12 @@ by <ulink url="mailto:[email protected]">contacting the mailing list</ulink>. <sect2 id="dev-scripting-command-line"> <title>Command Line Scripts</title> +<note> +<para>A functionality similar the command line scripts, detailed here, is also provided in the +<ulink url="help:/kate/kate-application-plugin-snippets.html">snippets plugin</ulink>. +This plugin may provide an easier starting point, especially for small custom scripts.</para> +</note> + <para> As it is hard to satisfy everyone's needs, &kappname; supports little helper tools for quick text manipulation through the
