A way to integrate LaTeX, VSCode, and Inkscape in macOS
Also available: My website
- Document Inkscape shortcut manager for macOS implemented in #1
- VSCode-LaTeX-Inkscape
I use LaTeX heavily in the past two years for both academic work and professional work, and I think I'm quite proficient in terms of typing things out in LaTeX. But when I see this blog post from Gilles Castel-How I'm able to take notes in mathematics lectures using LaTeX and Vim and also How I draw figures for my mathematical lecture notes using Inkscape, I realize that I'm still too naive.
I took quite a few math courses, hence after finding out this workflow, I decided to adapt the whole setup from Linux-Vim to macOS-VSCode. So, if you're interested in this and in the same situation as me, namely if you don't want to jump into Linux and Vim, follow me!
If you still don't know what to expect, please check out my Notes taken in this setup. Deciding to adopt this workflow probably is the best choice I did throughout my education!
Please look through the two blog posts above by Gilles Castel! They are incredible and worth spending your time to understand how all things work, and what's the motivation behind all these. I'm only mimicking his workflow, with a little patience to set up the whole thing in my environment. Show respect to the original author!
First thing first, please set up your VSCode with LaTeX properly with LaTeX Workshop, there are lots of tutorials online, just check them out and set them up properly.
Now, we go through things one by one following Gilles Castel's blog post.
This is probably the only thing I don't like that much in Gilles Castel's setup. I'm quite comfortable looking at LaTeX source code for formula, and I don't think they look that nice. But if you want to set them up in VSCode, there is an extension here, I have no experience with this particular setup, feel free to try them out though.
A snippet is a short reusable piece of text that can be triggered by some other text. For example, when I type dm
, the word dm
will be expanded to a math environment:
If you are a math guy, you may need to type some inline math like \(\)
, which is kind of painful. But with snippet, you can have
See? You just type fm
, and then your snippet not only automatically type \(\)
for you, but it also sends your cursor between \(\)
! With this, you can type something really fast:
Note that in the above demo, I use a very common snippet, qs
for ^{2}
.
As you can imagine, this can be quite complex. For example, you can even have something like this:
or this:
Too fast to keep track of? For the first snippet, I type table2 5
, and then it generates a table with 2 rows and 5 columns. For the second one, I type pmat
for matrix, and then type 2 5
to indicate that I want a 2 by 5 matrix, then boom! My snippets do that for me in an instant!
Feeling it? Let's try to set up this step by step. And maybe you can create your snippets also! Here is some useful snippets for you.
If you look around in the VSCode extension marketplace to find UltiSnips' equivalence, you probably will find Vsnips. But I'm not sure why this is the case, I can't figure out how to set it up properly. Hence, I find another alternative, which is HyperSnips. Please first download HyperSnips. Now, just follow the instruction, copy latex.hsnips into $HOME/Library/Application Support/Code/User/hsnips/
, and you're good to go!
To modify this file, you can either go to this file in your finder or use VSCode built-in command function. For command function,
- Press
shift+cmd+space
to type in some command to VSCode. - Type
>HyperSnips: Open Snippet File
- Choose
latex.hsnips
For a further and detailed explanation for snippets, please go to check out the original blog post!
Unlike Gilles Castel's approach, there is an available extension out there for you to simplify your math calculation already! Please go to checkout Latex SYMPY Calculator. It's works like follows:
Magic right? Let's set it up! First, please look at the installation document provided by Latex Sympy Calculator. After your installation is done, you can then set up the keybinding for calculating the math expression. I use shift+e
, where e
stands for evaluating, to calculate in the way that it will append an equal sign and the answer right after your formula, just like above. And if you don't want to show the intermediate steps of your calculation, you can use shift+r
, where r
stands for replacing, to directly replace the whole formula and give me the answer only. See the demo below:
You can find my keybinding setup in this repo. But stay tuned, there is more to come! Let's go to the last thing covered in Gilles Castel's post, correcting spelling mistakes.
Although my typing speed is quite high, I have typos all the time. So this is a must for me. And surprisingly, this is the hardest thing until now for me to set it upright. Let's see how we can configure this functionality in VSCode!
Firstly, you need to download multi-command to perform this. And this is a very powerful extension, which allows you to do a sequence of actions in one shortcut. We will use this later on also, and that's the place it shines.
And then, after searching for some time, I find out that there is a popular spelling checker out there which meets our needs, Code Spell Checker. Just download it, it's useful.
If you are bad at grammar like me, you definitely want to install LTeX to check some simple grammar mistakes for you. Although it's not powerful like Grammarly, not even comparable, it's still a good reference for you to keep your eyes on some simple mistakes you may overlook.
Now, it's time to configure all these. Open your Keyboard Shortcuts page in VSCode, which is in the bottom left
And then go into its JSON
file, which is at the upper right:
Now, paste the following code in keybindings.json
:
{
"key": "cmd+l",
"command": "extension.multiCommand.execute",
"args": {
"sequence": [
"cSpell.goToPreviousSpellingIssue",
{
"command": "editor.action.codeAction",
"args": {
"kind": "quickfix",
"apply": "first"
}
},
"cursorUndo",
]
}
},
Make sure that the curly braces above have a trailing comma, otherwise, VSCode will complain about it.
Now, as long as you see there is a spelling error, you just type cmd+l
, the keybinding will do the following things:
- Use one of the default function from cSpell's:
goToPreviousSpellingIssue
, which jump your cursor on that spelling error word - Triggered a default editor action, with the argument being
quickfix
to open a quick fix drop-down list, and choose thefirst
suggestion - Move your cursor back by
cursorUndo
Here is a quick demo for how it works when typing:
Additionally, if you also want to correct your grammar error, I use the shortcut cmd+k
to trigger a quick-fix for a general error. The setting looks like this:
{
"key": "cmd+k",
"command": "extension.multiCommand.execute",
"args": {
"sequence": [
"editor.action.marker.prev",
{
"command": "editor.action.codeAction",
"args": {
"kind": "quickfix",
"apply": "first"
}
},
"cursorUndo",
]
}
},
There is an unofficial API for Grammarly, but the functionality is not that useful if one wants to use auto-correction. Hence, I'll leave it as a TODO for now.
Now, the first part is over. Let's go to the next truly beautiful, elegant, and exciting world, drawing with Inkscape.
Before we go to any setup detail, let's first look at some figures I draw right after I have set this up:
This is quite eye-pleasing, right? Those are some drawings I made when taking Linear programming lectures. But this is just my naive drawing, compare to Gilles Castel's examples, this is nothing. Check it out for the original blog. Or for more figures I draw, you can check out Note.
One last thing is that I'll assume you have already installed VSCode Vim. While this is not required, if you don't want to use it, then you'll need to assign different keybinding. Anyway, you'll see what I mean until then!
A big question is, why Inkscape? In Gilles Castel's blog, he had already explained it. One reason is that although
However, by using Inkscape, you only need to type (Ok, not quite, you don't need to type them out manually as you'll see) the following:
\begin{figure}[H]
\centering
\incfig{figure's name}
\caption{Your caption}
\label{fig:label}
\end{figure}
And then you're done! And also, the compilation time for this is shorter than you can ever expect. Let's get started then!
First thing first, include the following in your header
\usepackage{import}
\usepackage{xifthen}
\usepackage{pdfpages}
\usepackage{transparent}
\newcommand{\incfig}[1]{%
\def\svgwidth{\columnwidth}
\import{https://github.com/sleepymalc/VSCode-LaTeX-Inkscape/blob/main/demo/figures/}{#1.pdf_tex}
}
This assumes that your LaTeX project's home directory looks like this:
LaTeX_project
│
├── LaTex.tex
│
├── LaTex.pdf
│
├── Figures
│ ├── fig1
│ ├── fig2
│ .
│ .
.
.
Now, let's get into the fun part. Let's set up the shortcut for this.
You need to install Inkscape first. I recommend you install this in a terminal. I assume that you have your homebrew
installed. Then, just type the following into your terminal:
brew install --cask inkscape
This is a figure manager developed by Gilles Castel, and here is the repo. I recommend you to follow the installation instruction there. Here is just some guideline for you
-
You need to download choose first, for later usage.
-
Type this in your terminal
pip3 install inkscape-figures
-
type
inkscape-figure
in your terminal to make sure you have corrected install it.
If you're using Linux and Vim, then you are done already. But since you're using macOS and VSCode, please follow me, there is some more thing for you to configure.
Firstly, please type the following command in your terminal
where inkscape-figures
to find out where the inkscape-figures
is installed. In my environment, I use Anaconda quite a lot, so mine is /Users/pbb/opt/anaconda3/bin/inkscape-figures
.
Now, go to a relative directory, in my case, it's in /Users/pbb/opt/anaconda3/lib/python3.8/site-packages/inkscapefigures
. Open this directory by VSCode, there is something for you to modify.
Ok, I know you probably don't have that much patience now, so I have a modified version available here. If you don't want to know the detail, you can just copy this main.py
and replace the current one. If you're interesting, lets me explain it to you.
Notice that there is one thing for you need to modify in the source code in main.py
in Inkscape figure manager. Since Gilles Castel originally use figures/
as his subfolder name to store figures, you need to change every figures/
in the source code into Figures/
if you're modifying the source code on your own rather than copy mine.
In Gilles Castel's approach, he uses the shortcut ctrl-f
to trigger this script, which will copy the whole line's content depending on the cursor's position, and the script will send the snippets by the function
def latex_template(name, title):
return '\n'.join((r"\begin{figure}[ht]",
r" This is a custom LaTeX template!",
r" \centering",
rf" \incfig[1]{{{name}}}",
rf" \caption{{{title}}}",
rf" \label{{fig:{name}}}",
r"\end{figure}"))
to stdout
, and then create a figure by the name
, which is the content of the line.
But this in VSCode is impossible, hence we don't need this, we'll use another approach, namely, we'll accomplish the task by command line. And if we leave this function as it was, then it will send all these snippets into our terminal, which is quite annoying. So the modified version just removes this snippet completely.
Now, the only thing you need to do is to copy the keybindings.json and settings.json into your own keybindings.json
and settings.json
and then you're done. But let me explain it to you, in case you want to modify it to meet your need later on. First thing first, we see that in the given code in keybindings.json and settings.json, we're using Command Runner, so let me tell you how to set this up first.
The last thing you need to install is Command Runner. This will allow you to send commands into a terminal with the shortcut. The configuration is in setting.json
. Please copy the content into your own setting.json
.
We're now prepared to see a detailed explanation about commands provided in Inkscape figure manager. There are three different commands in theInkscape figure manager. We break it down one by one.
Since Inkscape in default does not save the file in pdf+latex
, hence we need Inkscape figure manager to help us. We need to first open the file watcher to watch the file for any changes. If there is any, then the file watcher will tell Inkscape to save the file in pdf+latex
format.
To open the file watcher, you can type inkscape-figures watch
in the terminal. In my case, I set up a short for this. In keybindings.json, we have
{
"key": "ctrl+f",
"command": "command-runner.run",
"args": {
"command": "inkscapeStart",
"terminal": {
"name": "runCommand",
"shellArgs": [],
"autoClear": true,
"autoFocus": false
}
},
"when": "editorTextFocus && vim.active && vim.use<C-f> && !inDebugRepl && vim.mode == 'Visual'"
}
for starting the Inkscape figure manager. And the command is defined in settings.json:
"command-runner.commands": {
"inkscapeStart": "inkscape-figures watch"
}
In detail, we just use command runner
to run the command we defined in settings.json, in this case, I explicitly tell the keybinding ctrl+f
will trigger inkscapeStart
when I'm in Visual
mode in Vim, which is just inkscape-figures watcher
as defined above.
Notice that we set the autoFocus=false
for the terminal command runner
use since we don't want a pop-up terminal to distract us. If you want to see whether the command is triggered correctly every time, you can set it to true
.
Same as above, we also use ctrl+f
to trigger inkscape-figures create
command. But in this case, we do a little bit more than that. We set up our keybindings.json as
{
"key": "ctrl+f",
"command": "extension.multiCommand.execute",
"args": {
"sequence": [
"editor.action.clipboardCopyAction",
"editor.action.insertLineAfter",
"cursorUp",
"editor.action.deleteLines",
{
"command": "editor.action.insertSnippet",
"args": {
"name": "incfig"
}
},
{
"command": "command-runner.run",
"args": {
"command": "inkscapeCreate",
},
"terminal": {
"name": "runCommand",
"shellArgs": [],
"autoClear": true,
"autoFocus": false
}
},
]
},
"when": "editorTextFocus && vim.active && vim.use<C-f> && !inDebugRepl && vim.mode == 'Insert'"
},
and also in settings.json:
"command-runner.commands": {
"inkscapeCreate": "inkscape-figures create ${selectedText} ${workspaceFolder}/Figures/"
}
We break down what ctrl+f
do in Insert
mode exactly step by step. We see that when we press ctrl+f
in Insert
mode, we trigger multiCommand.execute
to execute a sequence of instructions, which are
- Copy the content into your clipboard of the line your cursor at
- We insert a bland line after since we need to insert a snippet, and that's will delete an additional line. You can try to delete this and the next instruction, and see what happens.
- After inserting a new line, we move back our cursor.
- We delete that copied content by removing this line.
- We insert a snippet defined in
latex.json
. Notice that this is the default snippet functionality built-in VSCode, not what we have used above. I'll explain where to copy this file in a minute. - Lastly, we send a command in a terminal by
command runner
, with the commandinkscapeCreate
we defined in settings.json. Then we're done!
In the fifth instruction, we need to use the snippet like
{
"incfig": {
"prefix": "incfig",
"body": [
"\\begin{figure}[H]",
"\t\\centering",
"\t\\incfig{${1:$CLIPBOARD}}",
"\t\\caption{${2:title}}",
"\t\\label{fig:${1:$CLIPBOARD}}",
"\\end{figure}",
],
"description": "Inserts mathematical diagram"
}
}
which is just the snippet we remove from Inkscape figure manager's source code! It's back again, in a different approach! You can paste this into your configuration by the following steps:
- Press
shift+cmd+p
to open the VSCode command - Type
snippets
, and choosePreferences: Configure User Snippets
. - Choose
New Global Snippets file...
- Enter
latex
to create a new file. - Paste the above snippets into that file.
Don't know what happen? Let me break it down for you. Firstly, I change into insert
mode in VSCode Vim and type my new figure's name figure-test
. And then, I press ctrl+f
to trigger a keybinding. Then it will automatically create an Inkscape figure named figure-test
for me and open it.
Now, let's see the last thing I have to share with you.
Again, we also use ctrl+f
to trigger inkscape-figures edit
command. We set up our keybindings.json as
{
"key": "ctrl+f",
"command": "command-runner.run",
"args": {
"command": "inkscapeEdit",
"terminal": {
"name": "runCommand",
"shellArgs": [],
"autoClear": true,
"autoFocus": false
}
},
"when": "editorTextFocus && vim.active && vim.use<C-f> && !inDebugRepl && vim.mode == 'Normal'"
},
and also in settings.json:
"command-runner.commands": {
"inkscapeEdit": "inkscape-figures edit ${workspaceFolder}/Figures/"
}
This is what's you should expect when you want to edit a particular figure:
This is where choose comes into play. When you press ctrl+f
in Normal
mode, you'll trigger the inkscape-figures edit
command, and it'll look into your Figures/
subfolder to see what figures you have and pop out a window for you to choose. After you press enter
, it will open that file for you to edit. In my demo, I create another figure named figure-test2
, then modify it a little, and compile it again.
This is the most complicated part of the whole setup, I would say. Leave as a TODO.
This is the whole setup I have, and let's wrap this up since I know this may be quite overwhelming.
- Before you start your project, please go to
Visual
mode by enteringv
inNormal
mode. And then pressctrl+f
. This will set up the file watcher. - When you want to create a new figure, go into a new line, type the name of your figure in
Insert
mode, then pressctrl+f
. This will create a new figure with the name you typed, and open it in Inkscape for you. - When you have drawn your figure, as long as you press
cmd+s
, it will automatically save the figure inpdf+latex
for you, then you can close Inkscape. - When you want to edit one of your figures, you press
ctrl+f
inNormal
mode, it will pop out a window for you to choose the figure you want to edit. And the rest is the same as 3.
After some research, although there is a way to let the original script in inkscape-shortcut-manager run correctly since it depends on xlib
, which is no longer used by macOS for almost every application(including Inkscape, as expected), hence the only thing I can do now is to give up. In a perceivable future, if I have time to find an alternative way to interrupt the window activity in macOS, I'll try to configure it for macOS.
I have been working on Category Theory for a while, and I find out that quiver is quite appealing, hence I integrate it into my workflow. You can also pull it to your local environment and configure the Vscode Task and combined it with a hotkey to use it locally. Specifically, I add the following code into my keybindings.json
:
{
"key": "ctrl+c",
"command": "command-runner.run",
"args": {
"command": "quiver",
"terminal": {
"name": "runCommand",
"shellArgs": [],
"autoClear": true,
"autoFocus": false
}
},
"when": "editorTextFocus"
},
and also, define the command quiver
as
"command-runner.commands": {
"quiver": "open -na 'Google Chrome' --args --new-window <path-to-quiver>/quiver/src/index.html"
},
Notice that you'll need to build it first if you want to use it offline! Please follow the tutorial here. Otherwise, it's totally fine to use "quiver": "open -na 'Google Chrome' --args --new-window https://q.uiver.app/"
as your command.
This is how the workflow looks like.
Now, instead using HyperSnips for Math, we're now using HyperSnips, namely the original one! Since I just find out that we can trigger the snippets only in math mode by using the special keyword called context
, hence I just migrate to the original one. To migrate, you just need to uninstall HyperSnips for Math, install HyperSnips with the updated latex.hsnips I prepared for you, and then enjoy!
Again, thanks to Gilles Castel, this workflow fits my style. Although it originally works in Linux+Vim only, the idea is the most important thing. Without his wonderful post, I can't even imagine this is possible. But now it is! Go to his original post to show him some love.
- Academic_Template (A general LaTeX template for making PPT by beamer and Academic Report)
- Notes (All notes taken in this setup)
- gillescastel/inkscape-figures
- gillescastel/inkscape-shortcut-manager
- chipsenkbeil/choose
- varkor/quiver