Skip to content

Scripts

sunderme edited this page Sep 16, 2025 · 30 revisions

This page will become a collection of user scripts which provides additional features that are too special to be implemented in the binary itself.

A description of the scripting language can be found in the User Manual. Notice that the available Javascript functions may change in later TeXstudio releases.

Txs has been expanded to download scripts/macros directly from texstudio-macro. The most convenient way for developers is to clone that repository, add macros and hand them in as pull-requests. Alternatively enhancement requests with attached macro files are welcome. Scripts on this wiki are less likely to be taken up in the repository.

Feel free to add your own scripts.

User Scripts

Trivial eval example

This example shows how you can write a simple script that executes the current editor text as another script. It can also be used when writing new scripts, because it is faster than opening the user macro dialog for every change.

%SCRIPT eval(editor.text()); 

Tested with: TMX 1.9.9 or later

Copy filename to clipboard

%SCRIPT app.clipboard = editor.fileName(); 

Tested with: TXS 2.3

Remove all empty lines

%SCRIPT var tl = editor.document().textLines(); for (var i=tl.length-1;i>=0;i--) if (tl[i]=="") tl.splice(i, 1); editor.setText(tl.join("\n")); 

Tested with: TXS 2.3

Remove all duplicated lines

%SCRIPT var tl = editor.document().textLines(); for (var i=tl.length-1;i>=0;i--) { var found = false; if (tl[i] != "") for (var j=i-1;j>=0;j--) if (tl[i] == tl[j]) { found = true; break; } if (found) tl.splice(i, 1); } editor.setText(tl.join("\n")); 

Tested with: TXS 2.3

Remove whitespace at the end of all lines

%SCRIPT var tl = editor.document().textLines(); for (var i=tl.length-1;i>=0;i--) tl[i] = tl[i].replace(/\s+$/, ''); editor.setText(tl.join("\n")); 

Tested with: TXS 2.8.0

Decode hex dumps

%SCRIPT editor.replace(/[0-9A-Fa-f]{2}/, "g", function(c){ return String.fromCharCode(1*("0x"+c.selectedText())); }) 

Tested with: TXS 2.3

Calculator

This is a calculator evaluates a mathematical expression on the current line, like %sin(3.1415)=

%SCRIPT currentLine=editor.text(cursor.lineNumber()); from=currentLine.lastIndexOf("%")+1; to=currentLine.lastIndexOf("="); if (from>=0 && to > from) { toEvaluate = currentLine.substring(from, to); with (Math) { value = eval(toEvaluate);} cursor.eraseLine(); cursor.insertText(currentLine.substring(0, from)+toEvaluate+"="+value); cursor.insertLine(); cursor.movePosition(1,cursorEnums.Left ); } 

Tested with: TMX 1.9.9 or later

Macro virus

Copy it at the beginning of a tex file and it will copy itself.

% !TeX TXS-SCRIPT = macrovirus % //Trigger: ?load-file | ?new-file | ?new-from-template %var self; %if (hasGlobal("macrovirus")) self = getGlobal("macrovirus"); %else { % var l1, l2 = -1; % editor.search(/% *!TeX *TXS-SCRIPT *= *macrovirus/, function(c){l1 = c.lineNumber();}); % editor.search(/% *TXS-SCRIPT-END/, function(c){if (l2 != -1 || l1 > c.lineNumber()) return; l2 = c.lineNumber();}); % self = ""; % for (var l=l1;l<=l2;l++) % self = self + editor.text(l) + "\n"; % setGlobal("macrovirus", self); %} % %for (var i=0;i<documents.length;i++) %if (documents[i].editorView.editor.search( /% *!TeX *TXS-SCRIPT *= *macrovirus/ ) == 0) { %documents[i].cursor(0).insertText(self); %} % TXS-SCRIPT-END 

(tikz) Coordinate pair mover

This script adds to all coordinate pairs in the currently selected text the offset of the first pair, which translates all pairs in a given direction. E.g. if you have (1 + 1, 2 - 1.5) (3, 4) it will be changed to (2, 0.5) (4, 2.5).

%SCRIPT var doit = function(){ var mytext=cursor.selectedText(); var regExNumberPre = " *[0-9]+([.][0-9]*)? *"; var regExDigit = /[0-9]/; var regExSpace = / /g; var regExPairPre = " *(-?"+regExNumberPre+")"; var regExPair = new RegExp("()[(]"+regExPairPre+","+regExPairPre+"[)]"); ; //read first coordinate pair var regExFirstPairPre = regExPairPre + " *([+-]"+regExNumberPre+")?"; var regExFirstPair = new RegExp("()[(]"+regExFirstPairPre+","+regExFirstPairPre+"[)]"); //extract offsets (start regex search from first digit, to allow -x - y) var matches = regExFirstPair.exec(mytext); if (matches == null) throw "missing"; //throw matches; var offsetXPre = matches[4]; var offsetYPre = matches[8]; if (offsetXPre == "" && offsetYPre == "") throw "abc"; var offsetX = offsetXPre == ""?0.0:offsetXPre.replace(regExSpace, "")*1.0; var offsetY = offsetYPre == ""?0.0:offsetYPre.replace(regExSpace, "")*1.0; //move first pair var matchpos = mytext.search(regExFirstPair); editor.write(mytext.slice(0,matchpos)); editor.write("("+(matches[2].replace(regExSpace, "")*1.0+offsetX)); editor.write(", "+(matches[6].replace(regExSpace, "")*1.0+offsetY)+")"); //move other pairs var remaining = mytext.slice(matchpos+matches[0].length); while (remaining != ""){ matches = regExPair.exec(remaining); if (matches == null) break; matchpos = remaining.search(regExPair); editor.write(remaining.slice(0,matchpos)); remaining = remaining.slice(matchpos+matches[0].length); editor.write("(" + ((matches[2].replace(regExSpace, "")*1.0)+offsetX) + ", "+ ((matches[4].replace(regExSpace, "")*1.0)+offsetY) + ")"); } editor.write(remaining); } doit(); 

Tested with: TMX 1.9.9

Frequency counter

Count how often every letter in the selection/document is used.

%SCRIPT var s = cursor.hasSelection()?cursor.selectedText():editor.text(); var hash = {}; for (var i=0; i < s.length; i++ ) hash[s[i]] = (hash[s[i]]==null?0:hash[s[i]]) + 1; cursor.movePosition(cursorEnums.End); for (var k in hash) cursor.insertText(k+": "+hash[k]+"\n"); 

Tested with: TMX 2.1

Sorting

Sorts all lines in the document

%SCRIPT var a = new Array(); for (var i=0; i<editor.document().lineCount(); i++) { a.push(editor.text(i)); } a.sort(); var t = ""; for (var l in a) { t+= a[l]+"\n"; } editor.setText(t); 

Tested with: TMX 2.1

Pseudo-LaTeX generator

This script creates a random text with LaTeX-commands. This is not much useful for itself, but it can be used to find bugs/crashes of TeXstudio. Notice that it is quite slow (~1 min) and that the generated text does not actually compile.

%SCRIPT var characters=" ,.,.,,.,.;:;.+_^-.;/()[]{}[],aabcdeeeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzzABCDEFGHIJKLMNOPQRSTUVWXYZäöüÄÖÜÖÄÖÄÜ1234567890"; var charactersSafe=" ,.,.,,.,.;:;.+-.;/()[][],aabcdeeeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzzABCDEFGHIJKLMNOPQRSTUVWXYZäöüÄÖÜÖÄÖÄÜ1234567890"; var cid1 = "aB"; var cid2 = "abcdefghij"; function randUntil(i) { return Math.floor(Math.random()*i); } function insertRandomString(cs){ for (var j=randUntil(100);j>0;j--) editor.insertText(cs[Math.floor(Math.random()*cs.length)]); } function insertRandomId(){ switch (randUntil(2)) { case 0: for (var i=4+randUntil(5);i>0;i--) editor.insertText(cid1[randUntil(cid1.length)]); break; case 1: for (var i=2;i>0;i--) editor.insertText(cid2[randUntil(cid2.length)]); break; } } totalLoopCutOff = 1500; function insertRandomLaTeX(deep){ for (var i=50+deep*10;i>0;i--) { totalLoopCutOff--; if (totalLoopCutOff<0) return; switch (Math.floor(Math.random()*16)) { case 0: editor.insertText(Math.random()); break; case 1: case 2: insertRandomString(characters); break; case 3: editor.insertText("$"); if (deep>0) insertRandomLaTeX(deep-1); editor.insertText("$"); break; case 4: editor.insertText("\\chapter{");insertRandomString(charactersSafe); editor.insertText("}"); break; case 5: editor.insertText("\\section{");insertRandomString(charactersSafe); editor.insertText("}"); break; case 6: editor.insertText("\\");editor.insertText("sectio");editor.insertText("n");editor.insertText("{");insertRandomString(charactersSafe); editor.insertText("}"); break; case 7: case 8: case 9: editor.insertText("\n"); break; case 10: editor.insertText("\\label{"); insertRandomId(); editor.insertText("}"); break; case 11: editor.insertText("\\ref{"); insertRandomId(); editor.insertText("}"); break; case 12: editor.insertText("\\cite{"); insertRandomId(); editor.insertText("}"); break; case 13: editor.insertText("\\include{"); insertRandomId(); editor.insertText("}"); break; case 14: if (Math.random() < 0.5) editor.insertText("%TODO"); insertRandomString(characters); break; case 15: editor.insertText("\\begin{block}"); if (deep>0) insertRandomLaTeX(deep-2); editor.insertText("\\end{block}"); break; } } } editor.insertText("\\documentclass[12pt,letterpaper]{report}\n"); editor.insertText("\\begin{document}\n"); insertRandomLaTeX(4); editor.insertText("\\end{document}\n"); //alert("insert complete"); cursor.movePosition(1, cursorEnums.End); var lineCount = cursor.lineNumber(); for (var i=1; i<10000;i++){ cursor.setLineNumber(randUntil(lineCount)); cursor.movePosition(1, cursorEnums.EndOfLine); var lineLength = cursor.columnNumber()+1; cursor.setColumnNumber(randUntil(lineLength)); if (Math.random()<0.75) cursor.insertText(characters[randUntil(characters.length)]); else cursor.deleteChar(); } 

Tested with: TMX 2.0

Change search panels to be case sensitive

%SCRIPT //Set the search panel of the editor editor.searchPanel.findChild("cbCase").checked = true; //Set the search panel of the pdf viewer pdfs[0].search.findChild("cbCase").checked = true; 

Tested with: TXS 2.4

Convert selected text to uppercase

Note: From version 2.7 on, there is native support for changing case at Edit -> Text Operations. You won't need this script anymore. However we'll leave it here as example code.

%SCRIPT // Converts selected text to uppercase cursor.replaceSelectedText(cursor.selectedText().toUpperCase()) 

Tested with: TXS 2.5

Generate environment after typing trigger code

When typing !mabc (ends with space), the following is generated:

\begin{multicols}{abc} \end{multicols}" 

Trigger: !m(\S+)\s

%SCRIPT env = triggerMatches[1] txt = "\\begin{multicols}{"+env+"}\n" txt = txt+"\n" txt = txt+"\\end{multicols}\n" cursor.insertText(txt) cursor.movePosition(2, cursorEnums.Up) cursor.movePosition(1, cursorEnums.StartOfLine) 

Auto-correct multiple capital letters

Auto-correct multiple capital letters at the start of a word while typing. All characters except the first are converted to lowercase. Words consisting only of capital letters are not affected by the auto-correction.

Trigger: [a-z]

%SCRIPT typedChar = triggerMatches[0] cursor.movePosition(1, cursorEnums.StartOfWord, cursorEnums.KeepAnchor) lastWord = cursor.selectedText() re = /^[A-Z]{2,}/g if (lastWord.match(re)) { cursor.movePosition(1, cursorEnums.NextCharacter, cursorEnums.KeepAnchor) cursor.replaceSelectedText(cursor.selectedText().toLowerCase()) } cursor.movePosition(1, cursorEnums.EndOfWord) cursor.clearSelection() cursor.insertText(typedChar) 

Tested with: TXS 2.9.4

Paste as LaTeX table

When you copy multiple rows and/or columns from a spreadsheet application, columns are usually separated by tabs and rows by newline characters. This script takes the text from the clipboard and converts it into the LaTeX table format. The example creates a simple tabular with left-aligned columns. You are free to adapt it to your needs.

%SCRIPT text = app.clipboard numCols = text.split('\n')[0].split('\t').length colspec = Array(numCols+1).join("l") text = text.replace(/\t/g, " & ") text = text.replace(/\n/g, " \\\\\n") text = "\\begin{tabular}{" + colspec + "}\n" + text + "\\end{tabular}\n" cursor.insertText(text) 

Tested with: TXS 2.11.2

Word Completion

Note: Since TeXstudio natively provides word completion, this script mainly serves for demonstration. To use the built-in word completion, simply type the start of the word (at least 3 letters) and then hit Ctrl+Space.

Having to type long words can be annoying, particularly with technical terms which may appear quite frequently in a text. The below script checks if the already typed characters match with the start of a word from a fixed word list. If so, the word is inserted. It is convenient to assign a handy shortcut such as Shift+Enter to the script.

%SCRIPT // simple script for automatic word completion var words = ["trans-impedance-amplifier", "Dzyaloshinskii-Moriya interaction"] cursor.movePosition(1, cursorEnums.WordLeft, cursorEnums.KeepAnchor) txt = cursor.selectedText() for (var i=0; i<words.length; i++) { if (words[i].indexOf(txt) == 0) { cursor.removeSelectedText() editor.write(words[i]) break } } if (cursor.hasSelection()) { cursor.moveTo(cursor.anchorLineNumber(), cursor.anchorColumnNumber()) } 

Tested with: TXS 2.5

Introspection

The following script lists all properties of the editor object. Of course, you can adapt it to inspect other objects.

%SCRIPT var pn = Object.getOwnPropertyNames(editor) editor.write(pn.join("\n")) 

Tested with: TXS 2.5

Controlling Wrapping

The following script allows you to set the line wrapping of the editor. Note: This only controls the editor. Changes are not reflected in the settings dialog. After accessing the settings dialog, the original value from the settings take over again. See the next example for a way to adjust the settings as well.

%SCRIPT // Set the wrap style of the editor // ***** configuration ***** /* possible wrap styles are 0: None 1: Soft wrap at window edge 2: Soft wrap after lineWidth chars 3: Hard wrap after lineWidth chars */ wrapStyle = 3 /* only relevant for styles 2 and 3 */ lineWidth = 60 // number of chars averageCharWidth = 8 // depends on the actual font being used // ***** code ***** editor.setLineWrapping(wrapStyle > 0); editor.setSoftLimitedLineWrapping(wrapStyle == 2); editor.setHardLineWrapping(wrapStyle > 2); if (wrapStyle > 1) { if (lineWidth < 20) lineWidth = 20; lineWidthInPixels = lineWidth * averageCharWidth editor.setWrapLineWidth(lineWidthInPixels); } else { editor.setWrapLineWidth(0); } 

Tested with: TXS 2.5.2

Switching between no wrapping and soft wrapping at the window edge

This example shows how to toggle between two ways of wrapping (no wrapping and soft wrapping at the window edge). Settings are updated accordingly.

%SCRIPT if (getPersistent("Editor/WordWrapMode") == "1"){ editor.setLineWrapping(false); setPersistent("Editor/WordWrapMode","0") } else { editor.setLineWrapping(true); setPersistent("Editor/WordWrapMode","1") } editor.setSoftLimitedLineWrapping(false); editor.setHardLineWrapping(false); 

Teseted with: TXS 2.10.4

Underlining with ulem-package

If you are using the ulem package and want to use the command \ulem{} instead of \underline{}, this little script detects if the package is loaded and inserts the correct command automatically.

%SCRIPT packages = editor.document().containedPackages(); usingUlem = false; for (i=0; i<packages.length; i++) { if (packages[i] == "ulem") { usingUlem = true; break; } } if (usingUlem) { editor.document().editorView.insertMacro('\\uline{%|}'); } else { editor.document().editorView.insertMacro('\\underline{%|}'); } 

Replace characters by their LaTeX equivalent while typing

For languages with accented chars it is convenient to type the chars on the keyboard and have them translated to LaTeX code on the fly. This can be achieved by the following script.

Additionally, you have to set the trigger of the script to a regular expression matching all required chars. If there are only a few special chars, a simple or-list is ok: ä|ö|ü. In case of many replacements the more generic \w may be used as trigger.

Trigger: ä|ö|u

or

Trigger: \w

%SCRIPT replacements = { "ä": "\\'a", "ö": "\\'o", "ü": "\\'u", } c = triggerMatches if (c in replacements) { c = replacements[c] } editor.write(c) 

Simultaneously toggle Structure, Log and PDF

This was a request by a user who wished to simultaneously hide Structure, Log and PDF to have maximal space for editing. Moreover they should be restored afterwards easily.

For convenience, you may assign a shortcut to the macro via Options -> Configure TeXstudio -> Shortcuts.

%SCRIPT visible = app.getManagedAction("main/view/show/outputview").checked app.getManagedAction("main/view/show/outputview").trigger(!visible) app.getManagedAction("main/view/show/structureview").trigger(!visible) if (visible) { if (pdfs.length > 0) pdfs[0].close(); } else { app.getManagedAction("main/tools/view").trigger() } 

Advanced Comment Toggle

Note: As of TXS 2.11.2 there is a built-in function will be a builtin function Idefix -> Toggle Comment. Therefore this script is obsolete. However it may still serve as an example for similar tasks.

This script toggles the comments on the selected lines. It is a block-wise operation, i.e. all lines are commented/uncommented depending on the first selected line. This allows to properly comment/uncomment larger blocks which already contain comments. The block-operation gracefully handles uncommenting also for lines that do not contain a comment. Additionally, a space is inserted (and removed) after the comment char for better readability.

%SCRIPT startLine = cursor.anchorLineNumber() endLine = cursor.lineNumber() if (endLine < startLine) { tmp = startLine startLine = endLine endLine = tmp } nextChar = function() {return String.fromCharCode(cursor.nextChar())} cursor.beginEditBlock() cursor.moveTo(startLine, 0) line = editor.text(cursor.lineNumber()); hasComment = line.match(/^\s*%/) if (hasComment) { // uncomment for (l=startLine; l<=endLine; l++) { cursor.moveTo(l, 0) while (nextChar() in [' ', '\t']) cursor.movePosition(1, cursorEnums.NextCharacter); if (nextChar() == '%') cursor.deleteChar(); if (nextChar() == ' ') { cursor.movePosition(1, cursorEnums.NextCharacter); if (nextChar() != ' ') { // not an indentation cursor.deletePreviousChar(); } } } } else { // comment for (l=startLine; l<=endLine; l++) { cursor.moveTo(l, 0) cursor.insertText('% ') } } cursor.endEditBlock() 

Time tracker

Takes a list of times (e.g. 13:14-15:16 or 52m, each on a separate line) and calculates the total time.

%SCRIPT //alert(editor.document().lineCount()); var r = /^ *([0-9]+):([0-9]+) *- *([0-9]+)+:([0-9]+)/; var r2 = /([0-9]+) *m *$/; var nt = ""; var totald = 0; for (var i=0; i<editor.document().lineCount(); i++) { var e = r.exec(editor.text(i)); if (e) { var fh = e[1] * 1; var fm = e[2] * 1; var th = e[3] * 1; var tm = e[4] * 1; var d = 0; if (fh == th) d += tm - fm + 1; else if (fh < th) { d += 60 - fm + tm + 60 * (th - fh - 1) + 1; } else alert("daybreak!"); nt += e[0]+" => "+d+"m"; totald += d; } else { nt += editor.text(i); e = r2.exec(editor.text(i)); if (e) { totald += e[1] * 1; } } nt += "\n"; } nt += "\n\n ==> "+ totald + " = " + Math.floor(totald / 60) +":"+ (totald % 60); alert(nt); 

Tested with: TXS 2.6.6

WakaTime Plugin

This example shows how you can time track using WakaTime. https://github.com/wakatime/texstudio-wakatime

Tested with: TMX 2.6.6 or later

Mark Indexentry

This script marks the word "under the cursor" as an indexentry with \index{foo}foo. Use it with a Hotkey like Shift+F1 for a faster running.

%SCRIPT cursor.select(cursorEnums.WordUnderCursor) idx = cursor.selectedText() cursor.movePosition(0,cursorEnums.StartOfWord) editor.setCursor(cursor) editor.write("\\index{"+idx+"}") cursor.movePosition(0,cursorEnums.EndOfWord) editor.setCursor(cursor) cursor.clearSelection() 

Tested with: TXS 2.8.0

Git Commit and Push

Simple Git commit and push support. Use it maybe with the ?save-file trigger. Needs privileged write mode to run! It will ask for it.

%SCRIPT choisedialog = UniversalInputDialog(["Commit","Commit with Push"],"Git","choiseGIT") choisedialog.setWindowTitle("Git") choise = choisedialog.get("comment") if (choisedialog.exec() != null) { if (choisedialog.get("choiseGIT") == "Commit") { dialog = new UniversalInputDialog() dialog.setWindowTitle("Git commit / push") dialog.add("Committed by TeXstudio", "Comment", "comment") dialog.add(true, "Commit all Files","allfiles") if (dialog.exec() != null) { comment = dialog.get("comment") if ((dialog.get("allfiles")) == true){ buildManager.runCommand("git commit -a -m \"" + comment + "\"", editor.fileName()) }else{ buildManager.runCommand("git commit " + editor.fileName() + " -m \"" + comment + "\"", editor.fileName()) } } } else if (choisedialog.get("choiseGIT") == "Commit with Push") { dialog = new UniversalInputDialog() dialog.setWindowTitle("Git commit / push") dialog.add("Committed by TeXstudio", "Comment", "comment") dialog.add("master", "Branch", "branch") dialog.add(true, "Commit all Files","allfiles") if (dialog.exec() != null) { comment = dialog.get("comment") branch = dialog.get("branch") if ((dialog.get("allfiles")) == true){ buildManager.runCommand("git commit -a -m \"" + comment + "\"", editor.fileName()) }else{ buildManager.runCommand("git commit " + editor.fileName() + " -m \"" + comment + "\"", editor.fileName()) } buildManager.runCommand("git push origin \"" + branch +"\"", editor.fileName()) } } } 

Tested with: TXS 2.6.6

Move cursor to the beginning of the text in the line

Simply pressing the Home key moves the cursor to the start of the line. There is no native functionality to go to the start of the text (i.e. after the indentation). This can be accomplished with the following script. Pressing Home again, move it to the default beginning of the line.

%SCRIPT pos = cursor.columnNumber(); cursor.movePosition(1, cursorEnums.StartOfLine); i = 0; while (cursor.nextChar()==' '.charCodeAt(0) || cursor.nextChar()=='\t'.charCodeAt(0)) { cursor.movePosition(1, cursorEnums.NextCharacter); i++; } if (pos == i) { cursor.movePosition(1, cursorEnums.StartOfLine); } 

As a second step, go to Options -> Configure... -> Shortcuts and assign Home to that new script.

Tested with: TXS 2.9.4

Periodic auto-save all documents under a new name

This script periodically saves all open documents under a new name (uses the _bak suffix). Use the ?txs-start trigger to activate the script upon TXS launch.

%SCRIPT var Debug = false; //default = false var DoSave = true; //default = true var Interval = 60000;// set the time in milliseconds. 60000=1mins registerAsBackgroundScript("auto_save"); setTimeout(TimedFunction,Interval); function TimedFunction() { if (Debug) { alert('timer expired') }; SaveAllDocuments(); setTimeout(TimedFunction,Interval); //rearm the timed function } function SaveAllDocuments(){ if (Debug) { alert('SaveAllDocuments called') }; var NumOfDocs = documentsManager.documents.length; if (Debug) { alert('NumOfDocs='+NumOfDocs) }; for (var i = 0; i < NumOfDocs; i++) { SaveDocument(i, documentsManager.documents[i]); }; }; function SaveDocument(i, Document) { var CurFileName = Document.fileName; if (Debug) { alert('i='+i+' FileName='+CurFileName) }; var newName = CurFileName.replace(/.tex$/, '_bak.tex'); if (Debug) { alert('i='+i+' newName='+newName) }; if (DoSave) { writeFile(newName, Document.text()); }; }; 

Tested with: TXS 4.0.2

Protecting Capitalization of BibTeX Titles

BibTeX automatically changes the capitalization of titles according to the settings in the BibTeX style. Sometimes it is necessary to protect capital letters to prevent BibTeX changing their case; e.g.

title = "Pascal, {C}, {Java}: were they all conceived in {ETH}?" 

The following script capitalizes and protects the first letter of the word under the cursor:

%SCRIPT c = cursor; c.movePosition(1, cursorEnums.StartOfWord); c.insertText('{'); c.movePosition(1, cursorEnums.NextCharacter, cursorEnums.KeepAnchor); c.replaceSelectedText(c.selectedText().toUpperCase()); c.clearSelection(); c.insertText('}'); 

Tested with: TXS 2.7.0

Key Replacement: Automatically insert <space> before comment

If you always want to have a space between your text and a comment, you may let TXS automatically insert a space if you type a comment sign (%) right behind a non-space. To do so, you can use a positive lookbehind regular expression as a trigger:

Trigger: (?language:latex)(?<=\\S)%
Type: normal
Text: Note: the first character is a space. The % is doubled for escaping.

 %% 

Automatic label creation by pressing space after a structure command

If you want a label created for any section, subsection, chapter, etc. that you add, this script auto-generates a label after pressing <space> behind the structure command (e.g. \chapter{Foo bar}<space>). The label is preceded by a corresponding prefix and the title is sanitized (e.g. \chapter{Foo bar}\label{ch:foo-bar}). TXS provides label generation through the right-click menu in the structure view, but this is IMHO quicker and provides different prefixes for different types of structures.

How to use it:

Create a macro and use the following as trigger: (?<=\\((sub)*section|chapter|part|paragraph)\{([^}]*)\})[ ]

As LaTeX content use:

%SCRIPT // all matches matches = triggerMatches; // the structure title title = matches[matches.length-1]; // shorten to three words title = title.match(/^([^ ]+ ){0,2}([^ ]+)?/i)[0]; // sanitize title title = title.replace(/[äàáâã]/gi,"a"); title = title.replace(/[ëèéêẽ]/gi,"e"); title = title.replace(/[ïìíîĩ]/gi,"i"); title = title.replace(/[öòóôõ]/gi,"o"); title = title.replace(/[üùúûũ]/gi,"u"); title = title.replace(/[ç]/gi,"c"); title = title.replace(/\W/gi,"-").toLowerCase(); // remove ending dash title = title.replace(/-$/, ''); // get long type type = matches[2]; prefixes = { "subsubsection": "sec", "subsection": "sec", "section": "sec", "chapter": "ch", "part": "part", "paragraph": "pg" } // replace type by short type if (type in prefixes) { type = prefixes[type]; } // output editor.write("\\label{"+type+":"+title+"}"); 

Adjust the prefixes to your liking.

Tested with: TXS 2.9.4

Finding local line numbers in a verbatim environment

This script finds the local line number within a verbatim environment (e.g., useful if you want to reference it in the surrounding text).

To use: Place the cursor at the desired line and run the following script (it's convenient to assign a shortcut for running the script):

%SCRIPT lines = editor.document().textLines(); for (var i=cursor.lineNumber(); i>=0; i--) { l = lines[i]; if (l.indexOf("\\begin{verbatim}") >= 0) { ln = cursor.lineNumber() - i; app.setClipboardText(ln) alert('Local line number in itemize:\n' + ln + '\n(Copied to clipboard)'); } } 

This can easily adapted for other environments like minted or listings.

Tested with: TXS 2.9.4

Finding the next sectioning command

This script moves the cursor to the next sectioning command. More information can be found in this tex.stackexchange post. It's just a demonstration and easily adaptable for other commands.

%SCRIPT commands = ["\\part", "\\chapter", "\\section", "\\subsection", "\\subsubsection", "\\paragraph"]; while (!cursor.atEnd()) { cursor.movePosition(1, cursorEnums.NextWord) if (cursor.nextChar() != '\\'.charCodeAt(0)) { continue; } cursor.movePosition(1, cursorEnums.NextCharacter, cursorEnums.KeepAnchor); cursor.movePosition(1, cursorEnums.EndOfWord, cursorEnums.KeepAnchor); if (commands.indexOf(cursor.selectedText()) >= 0) { cursor.setColumnNumber(cursor.anchorColumnNumber()) editor.scrollToFirstLine(cursor.lineNumber()) break; } } 

Tested with: TXS 2.11.2

Insert citation and open completion menu

This simple script fills in the LaTeX citation command and opens the completion menu so that you can choose the correct reference. You can replace \\autocite{} with other LaTeX commands, i.e. \\cite{}.

%SCRIPT editor.write("\\autocite{}"); cursor.shift(-1); app.normalCompletion() 

Tested with: TXS 2.10.6

Insert a \end{env} when hitting Return and the cursor is behind \begin{env}

This script is somewhat similar to Idefix -> Complete -> Close latest open environment. However it's specifically intended as an auto-completion when hitting Return. To achieve this, bind the Return key to the macro using Options -> Shortcuts.

%SCRIPT previousChar = function() {return String.fromCharCode(cursor.previousChar())} nextChar = function() {return String.fromCharCode(cursor.nextChar())} String.prototype.startsWith = function(searchString, position) { position = position || 0; return this.indexOf(searchString, position) === position; }; getClosingEnvironment = function() { // returns \end{env} if the cursor is at the end of \begin{env} // returns undefined otherwise if (previousChar() == '}') { cursor.movePosition(1, cursorEnums.Left, cursorEnums.KeepAnchor); } while (nextChar() != '{') { if (cursor.atLineStart()) break; cursor.movePosition(1, cursorEnums.Left, cursorEnums.KeepAnchor); } cursor.movePosition(1, cursorEnums.Left, cursorEnums.KeepAnchor); cursor.movePosition(1, cursorEnums.StartOfWordOrCommand, cursorEnums.KeepAnchor); var result; if (cursor.selectedText().startsWith("\\begin")) { result = cursor.selectedText().replace("\\begin", "\\end"); } cursor.flipSelection(); cursor.clearSelection(); return result; } var env = getClosingEnvironment(); cursor.insertLine(); if (env !== undefined) { cursor.insertLine(); cursor.insertText(env); cursor.movePosition(1, cursorEnums.PreviousLine); } 

Tested with: TXS 2.11.0

Quoting a selection

Assume that you would like to put double quotes around a word or a group of words. This script simplifies the process: Simply select the group of words and type a double quote. The trigger defined here is for single quotes, double quotes and $, but it can be adapted to other chars as well.

Trigger: "|'|\$

%SCRIPT c = triggerMatches; if (editor.cutBuffer.length) { editor.insertText(c + editor.cutBuffer + c); } else { editor.insertText(c); } 

Tested with: TXS 2.12.6

Insert backslash and start completion with "§"

On some keyboard layouts, backslash is tedious to type. Hence, other symbols maybe easier to use as a starter to insert LaTeX commands.

Trigger: §

%SCRIPT cursor.insertText("\\") app.normalCompletion(); 

Tested with: TXS 2.12.8

Selecting a string beginning with $ and ending with $

This script assumes the mouse cursor is somewhere in between two $ symbols on the same line, i.e., $...$, and highlights/selects everything in between. This functionality is similar to that of the Ctrl+D keyboard shortcut, which selects the single word that the cursor is on.

Note that the script does not check whether the content between the $s are in a math environment. That is, if you have There are $x$ apples| and $y$ oranges. where | is the cursor, then apples and will become selected.

%SCRIPT // grab the line the cursor is on var ln = cursor.lineNumber(); var tl = editor.text(ln); // get text before and after cursor var beforeText = tl.substr(0, cursor.columnNumber()); var afterText = tl.substr(cursor.columnNumber(), tl.length); // search for last $ before cursor, and first $ after cursor var op = beforeText.lastIndexOf('\$'); var cl = afterText.indexOf('\$'); if (op>=0 && cl>=0){ // match found, select everything between the $$ cursor.selectColumns(op+1, cl+cursor.columnNumber()) } 

Tested with: TXS 2.12.11

Repeat last citation

This script finds the last usage of a "/cite" command and creates a new citation to the same reference.

%SCRIPT var lineNo = cursor.lineNumber() while (lineNo > 0) {	splits = editor.text(lineNo).split("\\cite")	//loop to find last line with a citation:	if (splits.length > 1) {	// identify last citation	endingString = splits[splits.length - 1]	patt = /\{([^\}]*)\}/	var reference = endingString.match(patt)[1]	editor.write("\\citep{"+reference+"}")	lineNo = 0	}	lineNo = lineNo - 1 } 

Tested with: TXS 2.12.22

Select the current section

Highlight the subsection you are currently in. Add with shortcut Ctrl+M, Ctrl+S. Repeat call to select higher order (containing section, chapter, part, etc).

%SCRIPT commands = ["\\part", "\\chapter", "\\section", "\\subsection", "\\subsubsection", "\\paragraph"]; maxIndex=commands.length startL=0 startN=0 sectionName="\\part" if (cursor.selectedText().match(/^\\[a-z]{1,}/)) {	starter=cursor.selectedText().match(/^\\[a-z]{1,}/)[0]	if (commands.indexOf(starter) >= 0) {	maxIndex=commands.indexOf(starter)	} } while (!cursor.atStart()) { cursor.movePosition(1, cursorEnums.PreviousWord) if (cursor.nextChar() != '\\'.charCodeAt(0)) { continue; } cursor.movePosition(1, cursorEnums.NextCharacter, cursorEnums.KeepAnchor); cursor.movePosition(1, cursorEnums.EndOfWord, cursorEnums.KeepAnchor); if (commands.indexOf(cursor.selectedText()) >= 0) { if (commands.indexOf(cursor.selectedText()) < maxIndex) { sectionName=cursor.selectedText() cursor.movePosition(1, cursorEnums.PreviousWord) startN=cursor.columnNumber()//anchorColumnNumber startL=cursor.lineNumber() break; }} cursor.movePosition(1, cursorEnums.PreviousWord) } cursor.movePosition(1, cursorEnums.NextWord, cursorEnums.KeepAnchor) // now select forwards for the end of section while (!cursor.atEnd()) {	cursor.movePosition(1, cursorEnums.NextWord, cursorEnums.KeepAnchor)	if (!cursor.selectedText().match(/\\[a-z]{1,}$/)) {	continue;	}	endTerm=cursor.selectedText().match(/\\[a-z]{1,}$/)[0]	if (commands.indexOf(endTerm) >= 0) {	if (commands.indexOf(endTerm) <= commands.indexOf(sectionName)) {	cursor.movePosition(1, cursorEnums.PreviousWord, cursorEnums.KeepAnchor)	endN=cursor.columnNumber()//anchorColumnNumber	endL=cursor.lineNumber()	break;	}} } editor.scrollToFirstLine(startL) 

Tested with: TXS 2.12.22

Toggle Wrap/Fill Paragraph To Maximum Line Length

See #1483

%SCRIPT // Script: Toggle-Wrap-Paragraph // // Wraps paragraphs at word boundaries to lines of no more than given length. // If a selection is active, wraps the selection. Otherwise, wraps the text block // at the current cursor position. // // Repeated activation will toggle between wrapping/unwrapping the paragarph // // This functionality is usually bound to Alt+q. // // NOTE: TXS supports this out of the box via the menu item "Idefix/Hard Line Break...". You can // customize this script to tweak the behavior, and to invoke it immediately without clicking // through a dialog as when using the built-in version. var MAX_LINE_WIDTH = 80; var MAX_PAR_LINES = 100; // avoid infinite loop function wrap_paragraph(s, line_width) {	// split into words var words=s.split(/\s+/); var lines = [];	// form words into lines as strings var length = 0; var i = 0; for (; i < words.length; i++) { if( i> 0 && length + (i) + words[i].length >= line_width ) { lines.push(words.slice(0,i).join(" ")); words = words.slice(i); i = -1; length = 0; continue; } length += words[i].length; }	// ... and don't forget any partial last line if ( length > 0) { lines.push(words.slice(0,i).join(" ")); }	// form the resulting wrapped string var result=lines.join("\n");	// To maintain whitespace to next block, restore any trailing newlines.	var match_crlf_suffix = /[\r\n]+$/.exec(s);	if (match_crlf_suffix !== null) {	result += match_crlf_suffix[0];	}	return result; } function SelectParagraph() {	/* cursorEnums.StartOfBlock misbehaves when text contains math environments. So we implement this functionality explicitly.	*/	cursor.movePosition(1,cursorEnums.StartOfLine);	for (var i =0; i < MAX_PAR_LINES && ! cursor.atStart() ; i++) {	if( editor.text(cursor.lineNumber()) === "") {	break;	}	cursor.movePosition(1,cursorEnums.PreviousLine);	cursor.movePosition(1,cursorEnums.StartOfLine)	}	cursor.movePosition(1, cursorEnums.NextLine);	var start_line = cursor.lineNumber();	for (var i =0; i < MAX_PAR_LINES ; i++) {	if( "" === editor.text(cursor.lineNumber())) {	break;	}	cursor.movePosition(1,cursorEnums.NextLine);	}	cursor.movePosition(1, cursorEnums.PreviousLine);	var end_line = cursor.lineNumber();	cursor.moveTo(start_line, 0);	cursor.movePosition(end_line-start_line, cursorEnums.NextLine,cursorEnums.KeepAnchor);	cursor.movePosition(1, cursorEnums.EndOfLine,cursorEnums.KeepAnchor); } // if no selection is active, select the current text block if (!cursor.hasSelection()) {	SelectParagraph(); } // Do it var original_text = cursor.selectedText(); var wrapped = wrap_paragraph(cursor.selectedText(), MAX_LINE_WIDTH); if (original_text == wrapped) {	editor.replaceSelectedText(wrapped.replace(/\n/g," ")); } else {	editor.replaceSelectedText(wrapped); } cursor.clearSelection(); 

Tested with TXS 3.1.0.

Collapse all tikzpicture elements

See #1729

%SCRIPT envname = "tikzpicture"; lines = editor.document().textLines(); for (var i=0; i<lines.length; i++) { l = lines[i]; if (l.indexOf("\\begin{" + envname + "}")>-1) {	editor.document().collapse(i); } } 

Tested with TXS 3.1.2 / 4.0.0

ChatGPT for TeXstudio

Github repo

Replace character with placeholders

This script converts every "•" character (or whatever you want modifying the script) in a placeholder. One can then write simple commands like x_{•} everywhere, launch the script and proceed to fill every subscript by just going from one to the other with Tab. See also issue 4064

options = "g" Line = cursor.lineNumber(); scope = new QDocumentCursor(editor.document(), Line - 10, 0, Line + 10) Num = editor.search("•", options, scope); for(let i = 0; i < Num; i++){ editor.find("•", true, false, false, false); cursor.deletePreviousChar(); editor.insertSnippet("%<1%>"); } app.simulateKeyPress("Esc"); 

Automatically show pdf when opening tex files

Trigger: ?load-file

buildManager.runCommand(\"txs:///view-pdf\",editor.fileInfo()) 

Tested with 4.8.9

Clone this wiki locally