Skip to content

Scripts

Christoph Matthies edited this page Aug 4, 2018 · 26 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.

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

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 scripts allows to set the linewrapping 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 scipt 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 achived 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)

Simultaneouly toggle Structure, Log and PDF

This was a request by a user who wished to simultaneouly 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

Mark 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 = documents.length;
    if (Debug) { alert('NumOfDocs='+NumOfDocs) };
    for (var i = 0; i < NumOfDocs; i++) {
        SaveDocument(i, documents[i]);
    };
};

function SaveDocument(i, Document) {
    var CurEditor = Document.editorView.editor;
    var CurFileName = CurEditor.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, CurEditor.text()); };
};

Tested with: TXS 2.7

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 behind the structure command (e.g. \chapter{Foo bar}). 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];
// sanetize 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();
// 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 likings.

Tested with: TXS 2.9.4

Finding local line numbers in a verbatim environment

Question: I want to find the local line number within a verbatim environment, because I want to reference it in the surrounding text.

Solution: 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. 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 intend as an auto-completion when hitting Return. To achive 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 keyborad layouts, backslash is tedious to type. Hence other symbols maybe either to use as a starter to insert latex commands.

Trigger: §

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

Tested with: TXS 2.12.8

Clone this wiki locally