Compare commits
70 Commits
f6cd13b587
...
presentati
Author | SHA1 | Date | |
---|---|---|---|
1fdd75cec6
|
|||
a03f31e237
|
|||
65dce1b060
|
|||
5b2683b3a4
|
|||
43de32edd2
|
|||
263e1c5f20
|
|||
f1eba8b28a
|
|||
b9c070b6c8
|
|||
957c8e2ed1
|
|||
1eed4d7ca3
|
|||
ee6946373c
|
|||
30b1ce923f
|
|||
886221e821
|
|||
665efa6b77
|
|||
9806dbd95b
|
|||
19dcc79a98
|
|||
6e08f67ea4
|
|||
87a2de2a07
|
|||
5f07ecae00
|
|||
1f2d9a9b3d
|
|||
2f1f346735
|
|||
34f2980123
|
|||
5ba13f48b7
|
|||
4da2ad6e6e
|
|||
6f0881d984
|
|||
330a3d6b4e
|
|||
110c31099a
|
|||
5364463d1f
|
|||
57e445a02d
|
|||
0eec47dc72
|
|||
f3eade6ef6
|
|||
198c798f2c
|
|||
85c5fcf3a2
|
|||
b35823a0a3
|
|||
9aa3e1cb4d
|
|||
c68e027c01
|
|||
59fe511c25
|
|||
7f1d2b274e
|
|||
ddb749e247
|
|||
8fc7b7346f
|
|||
b13c2c7ff3
|
|||
2bd00b4b46 | |||
120df63984 | |||
9d086e6436 | |||
39a90c8245 | |||
eb653d1196 | |||
62d90435c3 | |||
492165db60 | |||
ac87a6080d | |||
fa03ca647c | |||
bbf3f8163a | |||
80a277b062 | |||
04f8994933 | |||
6a2670c94d | |||
7e05fb1432 | |||
3912a2a74c | |||
1aff1e7336 | |||
ecd50343a4 | |||
d79c9e9d47 | |||
6cf9edd955 | |||
d9e2205553 | |||
41b4bba16b | |||
03987fea67 | |||
2e703e3785 | |||
d8c06e9f49 | |||
480e6a38e2 | |||
6505b22d90 | |||
d2c5efb43a | |||
efa6fd31c5 | |||
9dd21a7b40 |
3
.gitignore
vendored
@ -1,5 +1,4 @@
|
||||
output
|
||||
__pycache__
|
||||
Makefile
|
||||
*.pid
|
||||
plugins
|
||||
cache
|
||||
|
8
.gitmodules
vendored
@ -1,3 +1,9 @@
|
||||
[submodule "themes/clean-blog"]
|
||||
path = themes/clean-blog
|
||||
url = ssh://gitea@git.epheme.re:2222/fmouhart/pelican-clean-blog.git
|
||||
url = https://git.epheme.re/fmouhart/pelican-clean-blog.git
|
||||
[submodule "plugins/autopages"]
|
||||
path = plugins/autopages
|
||||
url = https://git.epheme.re/fmouhart/pelican-autopages.git
|
||||
[submodule "plugins/i18n_subsites"]
|
||||
path = plugins/i18n_subsites
|
||||
url = https://git.epheme.re/fmouhart/pelican-i18n_subsites.git
|
||||
|
21
Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
all: build
|
||||
|
||||
build:
|
||||
uv run pelican -s publishconf.py
|
||||
|
||||
dev:
|
||||
uv run invoke livereload
|
||||
|
||||
publish:
|
||||
uv run invoke publish
|
||||
|
||||
clean:
|
||||
uv run invoke clean
|
||||
|
||||
%.mo: %.po
|
||||
msgfmt "$^" -o "$@"
|
||||
|
||||
init: themes/clean-blog/translations/fr/LC_MESSAGES/messages.mo
|
||||
uv sync
|
||||
|
||||
.PHONY: clean build publish dev init
|
@ -4,7 +4,7 @@ Date: 2019-04-22 17:00
|
||||
Modified: 2023-05-14 20:00+02:00
|
||||
Author: Fabrice
|
||||
Category: antisèches
|
||||
Tags: git, termtosvg
|
||||
Tags: git, termtosvg, cli
|
||||
Slug: git-tricks
|
||||
Header_Cover: ../images/covers/water.jpg
|
||||
Summary: Une compilation de commandes git que j’utilise ponctuellement
|
||||
|
@ -4,7 +4,7 @@ Date: 2019-04-22 17:00
|
||||
Modified: 2023-05-14 20:00+2:00
|
||||
Author: Fabrice
|
||||
Category: cheat sheets
|
||||
Tags: git, termtosvg
|
||||
Tags: git, termtosvg, cli
|
||||
Slug: git-tricks
|
||||
Header_Cover: images/covers/water.jpg
|
||||
Summary: A compilation of some `git` tricks I keep forgetting.
|
||||
|
@ -2,8 +2,8 @@
|
||||
Title: wget/curl
|
||||
Date: 2022-07-25 13:45 CEST
|
||||
Author: Fabrice
|
||||
Category: cheat sheets
|
||||
Tags: wget, curl
|
||||
Category: antisèches
|
||||
Tags: wget, curl, cli
|
||||
Slug: wget-curl
|
||||
Header_Cover: ../images/covers/speedboat.jpg
|
||||
Summary: Quelques commandes wget et curl utiles dans la vie de tous les jours.
|
||||
|
@ -3,7 +3,7 @@ Title: wget/curl
|
||||
Date: 2022-07-25 13:45 CEST
|
||||
Author: Fabrice
|
||||
Category: cheat sheets
|
||||
Tags: wget, curl
|
||||
Tags: wget, curl, cli
|
||||
Slug: wget-curl
|
||||
Header_Cover: images/covers/speedboat.jpg
|
||||
Summary: Some useful wget and curl commands, such as downloading a repository.
|
||||
|
BIN
content/examples/revealjs-speakerview.png
Normal file
After Width: | Height: | Size: 381 KiB |
147
content/examples/tikz-graph.svg
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
content/examples/typst-example.pdf
Normal file
BIN
content/images/covers/aix-en-provence.jpg
Normal file
After Width: | Height: | Size: 548 KiB |
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 227 KiB After Width: | Height: | Size: 224 KiB |
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 220 KiB |
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 199 KiB |
BIN
content/images/covers/fern-forest.jpg
Normal file
After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 319 KiB After Width: | Height: | Size: 309 KiB |
BIN
content/images/covers/garamond.jpg
Normal file
After Width: | Height: | Size: 481 KiB |
Before Width: | Height: | Size: 469 KiB After Width: | Height: | Size: 465 KiB |
Before Width: | Height: | Size: 291 KiB After Width: | Height: | Size: 281 KiB |
Before Width: | Height: | Size: 473 KiB After Width: | Height: | Size: 451 KiB |
BIN
content/images/covers/orgue.jpg
Normal file
After Width: | Height: | Size: 487 KiB |
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 280 KiB After Width: | Height: | Size: 267 KiB |
BIN
content/images/covers/printing-press.jpg
Normal file
After Width: | Height: | Size: 470 KiB |
BIN
content/images/covers/pts24-talk.jpg
Normal file
After Width: | Height: | Size: 113 KiB |
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 213 KiB |
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 182 KiB |
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 308 KiB |
BIN
content/images/nvim-which-keys.png
Normal file
After Width: | Height: | Size: 38 KiB |
@ -1,7 +1,8 @@
|
||||
---
|
||||
title: Bienvenue
|
||||
pagetitle: le blog de fmouhart: bienvenue
|
||||
date: 2019-04-22
|
||||
Date: 2019-04-22
|
||||
Modified: 2019-04-22
|
||||
author: Fabrice Mouhartem
|
||||
Header_Cover: ../images/covers/home.jpg
|
||||
slug: home
|
||||
@ -9,7 +10,7 @@ save_as: ./index.html
|
||||
URL:
|
||||
og_image: ../images/miniature.png
|
||||
article_list: true
|
||||
Lang: fr
|
||||
lang: fr
|
||||
---
|
||||
|
||||
Bienvenue sur mon *blog*, je suis Fabrice Mouhartem.
|
||||
@ -23,3 +24,7 @@ Si vous cherchez une version anglophone de ce blog, c'est [par là]({filename}in
|
||||
|
||||
Pour toutes remarques ou commentaires, n’hésitez pas à me contacter par e-mail à l’adresse suivante : <img style="height:2em" src="/images/mel.png" alt="courriel"/>.
|
||||
|
||||
Si vous voulez être mis au courant des nouveaux articles (en anglais et en français), des flux de syndication sont disponibles:
|
||||
|
||||
* [Atom](/feeds/all.atom.xml)
|
||||
* [RSS](/feeds/all.rss.xml)
|
||||
|
@ -1,7 +1,8 @@
|
||||
---
|
||||
title: Welcome
|
||||
pagetitle: fmouhart's blog: welcome!
|
||||
date: 2019-04-22
|
||||
Date: 2019-04-22
|
||||
Modified: 2023-12-25
|
||||
author: Fabrice Mouhartem
|
||||
Header_Cover: images/covers/home.jpg
|
||||
slug: home
|
||||
@ -13,9 +14,14 @@ Lang: en
|
||||
---
|
||||
|
||||
I'm Fabrice Mouhartem, and I welcome you to this _blog_, which aims at relieving my brain from the hard task of remembering all sorts of weird stuffs (thus, don't expect me to provide you some fresh original contents). I hope it'll help some of you as well.
|
||||
Those stuffs will be mainly about my everyday use of _linux_ but not only.
|
||||
Those stuffs will be mainly about my everyday use of _Linux_ but not only.
|
||||
|
||||
If you are lost and are looking for my professional page, it's available [**here**](https://fmouhart.epheme.re) where you can find a list of my [annex activities](https://fmouhart.epheme.re/pages/etc.html) as well as a list of [free and open source software I everyday use](https://fmouhart.epheme.re/pages/etc.html#free-and-open-source-software).
|
||||
If you are lost and are looking for my professional page, it's available [**here**](https://fmouhart.epheme.re) where you can find a list of my [annex activities](https://fmouhart.epheme.re/pages/etc.html) as well as a list of [free and open source software I use every day](https://fmouhart.epheme.re/pages/etc.html#free-and-open-source-software).
|
||||
If you are looking for a French version of this blog, you take a look over [there]({filename}index-fr.md).
|
||||
|
||||
If you want to send me any questions or comments about this blog, feel free to do so at <img style="height:2em" src="/images/mel.png" alt="courriel"/>.
|
||||
|
||||
For those interested to follow the blog, there are the following feeds:
|
||||
|
||||
- [Atom](/feeds/all-en.atom.xml) and [Atom (fr + en)](/feeds/all.atom.xml)
|
||||
- [RSS](/feeds/all-en.rss.xml) and [RSS (fr+en)](/feeds/all.rss.xml)
|
||||
|
329
content/software/nvim-configure.md
Normal file
@ -0,0 +1,329 @@
|
||||
---
|
||||
Title: Setup Neovim with kickstart.nvim
|
||||
Date: 2023-12-25 17:15
|
||||
Modified: 2025-02-12 13:00
|
||||
Lang: en
|
||||
Author: Fabrice
|
||||
Category: software
|
||||
Tags: vim, neovim, setup
|
||||
Slug: nvim-kickstart
|
||||
table-of-contents: true
|
||||
Header_Cover: ../images/covers/antennae.jpg
|
||||
Summary: How to create a sane Neovim configuration with kickstart.nvim as a
|
||||
starting point.
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
## How I managed my configuration
|
||||
|
||||
When I started using Vim, I started editing my `.vimrc` bit by bit and
|
||||
incrementally before it starts getting too big for me to find anything inside
|
||||
it and not using even half of the plugins I installed. That goes without saying,
|
||||
there were quite a bit on conflicting keymaps as well as I'm using
|
||||
[bépo](http://bepo.fr/) as my keyboard layout with [partial remaps
|
||||
(fr)](https://cdn.bepo.fr/images/Vim-bepo-066.png).
|
||||
|
||||
Obviously, it slowly became quite a mess. To address this issue, I decided to
|
||||
reorganise my `$HOME/.config/vim` directory using the [vim directory
|
||||
structure](https://www.panozzaj.com/blog/2011/09/09/vim-directory-structure/)
|
||||
and did some cleanup at this point of time. I think it was also around this
|
||||
period that I discovered that Vim8 added a native package manager that I started
|
||||
to use. Thus, at this point, I started organising my configuration with semantic
|
||||
files, such as `$VIMHOME/plugin/spelling.vim` to manage my spelling
|
||||
configuration for instance. This approach makes debugging easier, and also
|
||||
checking custom keyboard shortcuts easier, as I just have to check
|
||||
`$VIMHOME/plugin/omnicomplete.vim` for instance to know which shortcuts I set up
|
||||
when I'm still getting the habits of using them.
|
||||
|
||||
At some point of time, I moved to Neovim, and simply moved my configuration from
|
||||
Vim to Neovim. All the while continuing adding more and more plugins on top of
|
||||
each other depending on my hype, especially because the world of Neovim plugins
|
||||
opened up to me. Needless to say that less than half of these plugins were put
|
||||
into good use. Which leads to my first configuration big cleanup.
|
||||
|
||||
Six months ago, I wiped my _frankenconfig_, and started back from scratch in
|
||||
[lua](https://lua.org/about.html), with the same structural approach as
|
||||
previously, but now wondering if the plugin would be useful or not. Since my
|
||||
first time using Vim, there were some big changes in the vim ecosystem,
|
||||
especially in language management with
|
||||
[tree-sitter](https://tree-sitter.github.io/tree-sitter/) and
|
||||
[lsp](https://en.wikipedia.org/wiki/Language_Server_Protocol). These two bring
|
||||
into the environment a unified way to manage languages without depending on
|
||||
language-specific plugins. Henceforth, I didn't need specific plugins to have
|
||||
nice syntax coloration for obscure languages anymore, or get frustrated with
|
||||
[omnicomplete](https://vim.fandom.com/wiki/Omni_completion) which decided not to
|
||||
work only for some languages… While it's not an absolute rule (for instance, I'm
|
||||
using [vimtex]({filename}./nvim-latex.md) for latex, which includes a more
|
||||
accurate syntax coloring than tree-sitter). I also moved from the native vim way
|
||||
of managing plugins to use [`Lazy`](https://github.com/folke/lazy.nvim) as a
|
||||
proper plugin manager, which helped me synchronize my configuration between my
|
||||
different computers. It was working nice and well, with some weird bugs (see
|
||||
below) on first install, but as it was punctual… I just ignored it.
|
||||
|
||||
```plain
|
||||
E5113: Error while calling lua chunk:
|
||||
$VIMHOME/nvim/init.lua:13: E21: Cannot make changes, 'modifiable' is off
|
||||
```
|
||||
|
||||
However, I was unhappy with some of my configurations, and if I managed to have
|
||||
something functional, there were many details that annoy me that stemmed for
|
||||
some configuration I wrote some times ago and of course didn't document. This
|
||||
leads us to today, where I just decided to use
|
||||
[`kickstart.nvim`](https://github.com/nvim-lua/kickstart.nvim). It is a well
|
||||
documented vim starting configuration (it's not a distribution, it still
|
||||
requires your inputs to obtain something that fits your needs), which was
|
||||
exactly what I needed to start anew… but not fully from scratch.
|
||||
|
||||
## The migration
|
||||
|
||||
To move my configuration from `kickstart.nvim`, I wanted to get the best of both
|
||||
world. For instance, I didn't want to have an
|
||||
[`init.lua`](https://github.com/nvim-lua/kickstart.nvim/blob/master/init.lua)
|
||||
that is over 600 lines long. I thus decided to split it into short files that
|
||||
manages a specific part of the configuration: completion, lsps, treesitter,
|
||||
mappings after reading the different configuration default from nvim-kickstart
|
||||
and changing what I disliked. To do that, I started with using the
|
||||
[`NVIM_APPNAME`](https://practical.li/neovim/configuration/) environment option
|
||||
in order to make the move in a non-destructive way.
|
||||
After installing the bare minimum to make it usable for me (as a bépo user), I
|
||||
exported the `NVIM_APPNAME` variable to start using my configuration to help me
|
||||
debug it on the fly.
|
||||
I also decided to write this blog post to remember the process and maybe helped
|
||||
some people who want to configure their text editor.
|
||||
|
||||
Note that in the following, we will assume that the reader is already familiar
|
||||
with Neovim and lua.
|
||||
|
||||
# Configuring Neovim
|
||||
|
||||
My (in use) configuration for Neovim is available [here](https://git.epheme.re/fmouhart/nvim-config-kickstart).
|
||||
|
||||
I started using git from the start in order to remember what I did by using its
|
||||
[history](https://git.epheme.re/fmouhart/nvim-config-kickstart/commits/branch/master).
|
||||
As it's not the easier thing to read however, here follows my rationals, and
|
||||
thought during this process in a chronological order.
|
||||
|
||||
## kickstart.nvim
|
||||
|
||||
`kickstart.nvim` is a starting Neovim configuration file which was created by
|
||||
[TJ DeVries](https://github.com/tjdevries), a core developer of Neovim, author
|
||||
of [telescope.nvim](https://github.com/nvim-lua/telescope.nvim) and content
|
||||
creator about Neovim. You can see a quick presentation on his YouTube channel
|
||||
[[here]](https://www.youtube.com/watch?v=stqUbv-5u2s).
|
||||
|
||||
To summarise, it is a starting configuration including a minimal set of plugins
|
||||
that helps to have a modern editor, that has a working and customizable LSP
|
||||
configuration with [Mason](https://github.com/williamboman/mason.nvim) to help
|
||||
install LSP servers, git helpers, completion, telescope, and a choice of
|
||||
shortcuts that are quite natural to learn (unlike what I used previously because
|
||||
I was simply adding shortcuts one after another without thinking of the
|
||||
compatibility between them).
|
||||
|
||||
Note that it is made for educational purpose, and thus is not modularised as is
|
||||
(hence the single self-contained `init.lua` file). Which leads us to our first
|
||||
step after simply pasting the content of `init.lua` into the `$VIMHOME/init.lua`
|
||||
file.
|
||||
|
||||
## Modular configuration
|
||||
|
||||
When in doubt about some shortcuts, I'm under the habit of going to read the
|
||||
corresponding configuration file in my `$VIMHOME/plugin` directory.
|
||||
`kickstart.nvim` includes `which-key`, that is a plugin that pops a helper when
|
||||
waiting for a command as shown hereunder.
|
||||
|
||||
[](../images/nvim-which-keys.png)
|
||||
|
||||
Thanks to that, I start getting rid of this habit. However, having a modular
|
||||
configuration helps debugging it. Usually, when an error spawns, the filename
|
||||
and location of what has triggered it appears in the stack trace, and it's
|
||||
easier to search in a short file than a thousand-line long one.
|
||||
|
||||
After a first read of the configuration file, I decided to split it into smaller
|
||||
files. Note that if you want to start directly from there a project that does
|
||||
exactly that exists:
|
||||
|
||||
* [kickstart-modular.nvim](https://github.com/dam9000/kickstart-modular.nvim)
|
||||
|
||||
However, I find it easier for educational purpose to have everything in one
|
||||
place to linearly read it first.
|
||||
|
||||
The process was quite simple, as the file was already divided logically into
|
||||
components that make sense, I just had to take the content of those sections and
|
||||
move them into the `$VIMHOME/lua` folder before including them in `init.lua`. I
|
||||
hesitated to continue using the `$VIMHOME/plugin` directory for that, but I then
|
||||
realised that having it inside init.lua allows having a structure that allows
|
||||
using `init.lua` as an index, and I can start
|
||||
[jumping](https://vimhelp.org/motion.txt.html) from there to access my
|
||||
specific configurations.
|
||||
|
||||
To illustrate it, let's take the example of completion. In `kickstart.nvim`,
|
||||
there is a section called "Configure nvim-cmp", that deleted and pasted into a
|
||||
file `$VIMHOME/lua/complete.lua` before adding the line `require('complete')` to
|
||||
load it. You can see the result in this
|
||||
[commit](https://git.epheme.re/fmouhart/nvim-config-kickstart/commit/7ce423fade9d6877b2e9174dd9b9dea36254ac19).
|
||||
|
||||
## Survival
|
||||
|
||||
Now that it's done, I need my basic keymaps for using Vim/Neovim in bépo. I
|
||||
added the file `$VIMHOME/lua/bepo.lua` and simply load it with a line
|
||||
`require('bepo')` in my `$VIMHOME/init.lua` file.
|
||||
|
||||
I also merged my personal remap inside the `$VIMHOME/lua/mappings.lua` file
|
||||
which already contained the ones imported from `kickstart.nvim` from the
|
||||
previous step. These mappings are convenient ones such as the following one to
|
||||
easily open folds to a given level.
|
||||
|
||||
```lua
|
||||
local keymap = vim.keymap.set
|
||||
|
||||
-- z0…z9 to open folds to a certain level
|
||||
for i=0,9 do
|
||||
keymap('n', 'z' .. i , ':set fdl=' .. i .. '<CR>', {noremap = true, silent = false})
|
||||
end
|
||||
```
|
||||
|
||||
I also merged and cleaned redundant general options in the
|
||||
`$VIMHOME/lua/general-options.lua` file. For instance to ignore folded content
|
||||
when jumping between paragraphs for instance, there is the following line in the
|
||||
aforementioned file:
|
||||
|
||||
```lua
|
||||
-- folds
|
||||
vim.g.ip_skipfold=true
|
||||
```
|
||||
|
||||
Once all of that is done, at this point of time, I started moving to use the
|
||||
configuration by exporting `NVIM_APPNAME=new_nvim` inside my `.zshrc`.
|
||||
The idea is that now I bootstrapped my Neovim config to proficiently edit the
|
||||
configuration, which in lua also uses LSP and many of `kickstart.nvim` features.
|
||||
During this process I notice what I liked and disliked to know how to edit the
|
||||
configuration while editing the configuration.
|
||||
|
||||
## Importing my former configuration
|
||||
|
||||
After having the minimal setup top edit a configuration, I now need to make
|
||||
things work for other things as well.
|
||||
|
||||
That is dependent of your workflow. For reference, I personally use Neovim to:
|
||||
|
||||
* Write text in [markdown](https://daringfireball.net/projects/markdown/) (such as what I'm currently doing)
|
||||
for different purposes;
|
||||
* blog post, emails or more generally text blocks that will be exported in
|
||||
html.
|
||||
* Read text written in Markdown;
|
||||
* Try to organise my life using [neorg](https://github.com/nvim-neorg/neorg);
|
||||
* [LaTeX](https://en.wikipedia.org/wiki/LaTeX) documents and slideshows;
|
||||
* Write code in a variety of languages.
|
||||
|
||||
To do that I went to my previous configuration (which fortunately was already
|
||||
using [`Lazy`](https://github.com/folke/lazy.nvim) as a plugin manager). To do
|
||||
that, I picked my specific plugins, for instance `Neorg`, to import the
|
||||
configuration. For the example of `Neorg` it has multiple steps as I had a
|
||||
`$VIMHOME/plugin/neorg.lua` that contained my general configuration and
|
||||
`$VIMHOME/ftplugin/norg.lua` which has specific configuration when editing a
|
||||
note in `Neorg`.
|
||||
|
||||
After asking `Lazy` to install `Neorg`, I first imported the general
|
||||
configuration from my previous `plugin` folder in my new `lua` folder, as
|
||||
depicted by this
|
||||
[commit](https://git.epheme.re/fmouhart/nvim-config-kickstart/commit/0e8587b461b67082c1e34ef9cb07180ccfee9f8b).
|
||||
|
||||
After wondering if I should create a `ftplugin` directory, I finally decided to
|
||||
move to autocommands to manage different filetypes. The reason behind that was
|
||||
that I had a limited amount of lines in total in my former `ftplugin` directory,
|
||||
and the subdivision with `augroup` and `autocmd` in Vim makes it reasonably
|
||||
readable. Which brought me to this
|
||||
[commit](https://git.epheme.re/fmouhart/nvim-config-kickstart/commit/c506a7ea7868ba80dc053a59cbb66c5efa666e2c).
|
||||
|
||||
Then some sanity and cleanup have been made. For example, adding a description
|
||||
field to my key maps so that `which-key` nicely prints them. See this
|
||||
[commit](https://git.epheme.re/fmouhart/nvim-config-kickstart/commit/689bb2024d97fdc9e5e656517f00e446e95ae198).
|
||||
|
||||
Now, rinse and repeat for each plugin/specific configuration set: `vimtex`,
|
||||
`vim-pandoc-syntax` (which I mainly use for the
|
||||
[concealer](https://vimhelp.org/syntax.txt.html#conceal)), spelling
|
||||
configuration, etc.
|
||||
|
||||
All the while keeping a critical eye on what I'm moving. For instance, I have a
|
||||
mapping on the following command to fix typo on a misspelled word under the
|
||||
cursor when writing text: <code>mz[s1z=\`z</code>. However, the key was bound at
|
||||
anytime, even when spelling was not enabled. To fix that, we changed the way the
|
||||
binding was called: instead of being called everytime, we embedded it inside an
|
||||
[`autocmd`](https://vimhelp.org/autocmd.txt.html#autocommands) which [triggers
|
||||
when the option](https://vimhelp.org/autocmd.txt.html#OptionSet) `spell` is set.
|
||||
To see the resulting configuration, see these two files:
|
||||
[`autocommands.lua`](https://git.epheme.re/fmouhart/nvim-config-kickstart/src/commit/d0afa1066cabab3d2b0aa7e2e84a267ce0532c61/lua/autocommands.lua#L32-L37)
|
||||
for the autocommand setting, and
|
||||
[`spelling.lua`](https://git.epheme.re/fmouhart/nvim-config-kickstart/src/commit/d0afa1066cabab3d2b0aa7e2e84a267ce0532c61/lua/spelling.lua)
|
||||
for the utils module.
|
||||
|
||||
Just for the record, this is what it does:
|
||||
|
||||
1. Store the current cursor location: `mz` [sets a
|
||||
mark](https://vimhelp.org/motion.txt.html#mark) z on current position;
|
||||
2. [Go to the previous spelling error](https://vimhelp.org/spell.txt.html#%5Bs): `[s`;
|
||||
3. [Pick the first spelling suggestion](https://vimhelp.org/spell.txt.html#z%3D): `1z=`;
|
||||
4. Go back to the stored location: <code>\`z</code> [jumps to
|
||||
mark](https://vimhelp.org/motion.txt.html#%60) z at the right column.
|
||||
|
||||
## Adjusting the configuration
|
||||
|
||||
While testing the default behaviour of `kickstart.nvim`, which changes quite a
|
||||
few things for me, I realised that some of them were quite smart, such as
|
||||
<Space> as the leader key, which was on `,` before because of its accessibility
|
||||
in bépo, disabling quite a [useful motion
|
||||
binding](https://vimhelp.org/motion.txt.html#%2C), some are more personal
|
||||
tastes, such as the default register to be the system one or not.
|
||||
|
||||
I thus tried some of these options and decided while editing the configuration
|
||||
and writing this blog post which one where working nicely for me (with the help
|
||||
of `which-key` to help me during this whole process), and which one were not
|
||||
quite working (`unnamedplus` as default clipboard, I really use both separately,
|
||||
and I don't want to have my system clipboard polluted)
|
||||
|
||||
Moreover, `:healthcheck which-keys` was really helpful to debug some colliding
|
||||
key bindings, especially because of bépo, which has been incrementally fixed
|
||||
while editing the configuration. I already wrote a blog post about how I handle
|
||||
those in [vimtex]({filename}./nvim-latex.md).
|
||||
|
||||
My former configuration also featured LSP, but Mason was not used, which made me
|
||||
install my LSP server from my system package manager. However, I still prefer
|
||||
using the system one for some languages that features some changes between
|
||||
versions, which I [also
|
||||
configured](https://git.epheme.re/fmouhart/nvim-config-kickstart/src/commit/d0afa1066cabab3d2b0aa7e2e84a267ce0532c61/lua/lsp.lua#L120-L149)
|
||||
in the `$VIMHOME/lua/lsp-configure.lua` file.
|
||||
|
||||
# Final thoughts
|
||||
|
||||
To conclude, I would like to say thanks to the French
|
||||
[tuppervim](https://tuppervim.org) community, which regularly organises meetings
|
||||
where we can show our latest configuration file, or just exchange nice tips. I
|
||||
discovered both [TJ DeVries](https://www.youtube.com/c/TJDeVries) and
|
||||
[`kickstart.nvim`](https://github.com/nvim-lua/kickstart.nvim) there.
|
||||
|
||||
I still have to get rid of some habits (such as the comma as a leader key) and
|
||||
get used to it, but I'm happy with the change so far, beside knowing exactly
|
||||
what is in my configuration, it also helped me fix some weird key conflicts
|
||||
while editing markdown, making writing this blog post quite pleasant.
|
||||
|
||||
While trying the Git-related key bindings utilities bundled with
|
||||
`kickstart.nvim`, while being quite minimal, it still filled my needs
|
||||
(especially adding a hunk from visual selection, which is helpful to split
|
||||
commits into sub-blocks when `git add -p` would have been quite tedious to use).
|
||||
|
||||
The [status bar](https://github.com/nvim-lualine/lualine.nvim) was also a
|
||||
pleasant surprise for me. It is exactly the kind of things I find useful but a
|
||||
pain to configure. I may tweak it a bit in the future, but so far it's fine as
|
||||
it is.
|
||||
|
||||
The configuration will continue to evolve from this point, as my use of computer
|
||||
and Neovim will change as well. And to finish, I think what TJ Devries said in
|
||||
[this video](https://www.youtube.com/watch?v=QMVIJhC9Veg) about text editor is
|
||||
quite on point: you don't have to spend time in your configuration if it is not
|
||||
fun for you, just take something that works for you. I actually took the time to
|
||||
do it because I find it interesting and fun 🙂
|
||||
|
||||
If you also find it fun, and want to try it, I strongly encourage you to take a
|
||||
cup of hot cocoa, put on some relaxing music, and just dive head first!
|
579
content/software/nvim-latex.md
Normal file
@ -0,0 +1,579 @@
|
||||
---
|
||||
Title: Neovim as a LaTex Development Environment
|
||||
Date: 2023-10-14 12:00:00+0200
|
||||
Modified: 2023-10-14 17:00:00+0200
|
||||
Lang: en
|
||||
Author: Fabrice
|
||||
Category: software
|
||||
Tags: vim, neovim, latex, zathura
|
||||
Slug: nvim-latex
|
||||
table-of-contents: true
|
||||
Header_Cover: ../images/covers/fern-forest.jpg
|
||||
Summary: How to turn Neovim into a full-fledged latex development environment
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
[LaTeX](https://en.wikipedia.org/wiki/LaTeX) is a typesetting software for
|
||||
producing typographically sound printable documents that is mostly used by the
|
||||
scientific community (but [not
|
||||
only](https://www.ctan.org/pkg/latex-sciences-humaines)) as it allows writing
|
||||
mathematics formulae in a somewhat *not-that-much painful* way, is shipped with
|
||||
[bibliography engines](https://www.ctan.org/pkg/biblatex), enables easy
|
||||
cross-referencing and automatically generates table of contents.
|
||||
|
||||
It is based on a markup language that allows writers to focus on the content of
|
||||
the document and leaves the typesetting to the software (at least most of the
|
||||
time).
|
||||
It moreover enjoys [many](https://ctan.org/) libraries that span from enabling
|
||||
[new features](https://ctan.org/pkg/algorithm2e) to [simpler
|
||||
version](https://www.ctan.org/pkg/a4wide) of more [complete
|
||||
tools](https://ctan.org/pkg/geometry).
|
||||
|
||||
In this blog post we will see how to setup [Neovim](https://neovim.io/) to
|
||||
manipulate LaTeX document while enabling modern features such as
|
||||
[language server
|
||||
protocol](https://en.wikipedia.org/wiki/Language_Server_Protocol) and what you
|
||||
want from any LaTeX IDEs: forward and backward
|
||||
searches (respectively going from the source code to the resulting document and
|
||||
vice-versa, thanks to
|
||||
[synctex](https://tug.org/tugboat/tb29-3/tb93laurens.pdf)).
|
||||
|
||||
As a PDF reader, we will use [zathura](https://pwmt.org/projects/zathura/) to
|
||||
show how to setup backward search (search from the document toward the source).
|
||||
It is a highly configurable, lightweight document viewer which natively enjoys
|
||||
vim-like shortcuts.
|
||||
|
||||
# Ingredients
|
||||
|
||||
Before starting we will need several components to achieve this lofty goal of
|
||||
painlessly writing LaTeX documents with the best text editor. Let us start by
|
||||
listing them; we will shortly see the installation and configuration procedure:
|
||||
|
||||
* A configurable text editor to be able to write the document:
|
||||
[Neovim](https://neovim.io). For that we will also need some plugins to
|
||||
unleash its full capability:
|
||||
* [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig): a plugin to
|
||||
facilitate the configuration
|
||||
[LSP](https://en.wikipedia.org/wiki/Language_Server_Protocol) for `Neovim`.
|
||||
* [nvim-cmp](https://github.com/hrsh7th/nvim-cmp): a completion engine for
|
||||
`Neovim`.
|
||||
* [vimtex](https://github.com/lervag/vimtex): a language specific plugin for
|
||||
LaTeX files that supports many features such as accurate syntactic
|
||||
coloration, support of multi-files, add LaTeX-specific [text
|
||||
objects](https://vimhelp.org/motion.txt.html#text-objects), improved
|
||||
foldings and so on.
|
||||
* [texlab](https://github.com/latex-lsp/texlab): to enable LSP features, you
|
||||
also a LSP server for vim to communicate with, which is exactly what
|
||||
`texlab` is.
|
||||
* [zathura](https://pwmt.org/projects/zathura/): finally a PDF viewer, we will
|
||||
use `zathura` here, but `vimtex` supports many others with predefined setups.
|
||||
However you will have to look for the specific documentation of your pdf
|
||||
reader to enable reverse search if it is possible.
|
||||
|
||||
# Setting Neovim up
|
||||
|
||||
Now that we have prepared everything, we need to setup `Neovim`.
|
||||
We will assume a blank configuration and start from scratch.
|
||||
I got inspired by a [blogpost about snippets in
|
||||
Neovim](https://pcoves.gitlab.io/en/blog/nvim-snippets/#installation) and used
|
||||
`NVIM_APPNAME` environment variables for testing this configuration. Please let
|
||||
me know if anything is not working as intended.
|
||||
|
||||
## Being Lazy
|
||||
|
||||
Anyhow, we first need to install the different plugins that we need. For this
|
||||
purpose, I used the [lazy](https://github.com/folke/lazy.nvim) plugin manager,
|
||||
but you can use whichever you see fit for the task.
|
||||
|
||||
```lua
|
||||
-- Lazy Package Manager
|
||||
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
|
||||
if not vim.loop.fs_stat(lazypath) then
|
||||
vim.fn.system({
|
||||
"git",
|
||||
"clone",
|
||||
"--filter=blob:none",
|
||||
"https://github.com/folke/lazy.nvim.git",
|
||||
"--branch=stable", -- latest stable release
|
||||
lazypath,
|
||||
})
|
||||
end
|
||||
vim.opt.rtp:prepend(lazypath)
|
||||
|
||||
-- Packages
|
||||
require("lazy").setup({
|
||||
"lervag/vimtex",
|
||||
"neovim/nvim-lspconfig",
|
||||
"hrsh7th/cmp-nvim-lsp",
|
||||
"hrsh7th/nvim-cmp",
|
||||
})
|
||||
```
|
||||
|
||||
In the code block above —in `$NVIM_CONFIG/init.lua`— the first part is to bootstrap lazy (so it can install
|
||||
itself if not already there) and the last block describe the installation of the
|
||||
following plugins : `vimtex`, `nvim-lspconfig`, `nvim-cmp` and finally
|
||||
`cmp-nvim-lsp` to glue the completion engine and `lspconfig`.
|
||||
|
||||
Now it is all good and done, but nothing is configured yet, and if you open a
|
||||
LaTeX file in this state, you will only enjoy the benefits of an unconfigured
|
||||
`vimtex`, which is already nice as is it, but not enough to achieve our goal.
|
||||
And it's a bit sad to have installed three other plugins for nothing.
|
||||
|
||||
# vimtex
|
||||
|
||||
It will be a bit anti-climatic after the previous teasing, but we will use
|
||||
`vimtex` as vanilla as possible…
|
||||
We still need to tell it to use `zathura` as a pdf viewer:
|
||||
```lua
|
||||
vim.g.vimtex_view_method = "zathura"
|
||||
```
|
||||
|
||||
This will allow `vimtex` to automatically open `zathura` upon compilation,
|
||||
which is bound to `<LocalLeader>ll` by default. Meaning that we have to define
|
||||
[`<LocalLeader>`](https://neovim.io/doc/user/map.html#%3CLocalLeader%3E), which
|
||||
I usually set to be a comma: “`,`”:
|
||||
```lua
|
||||
vim.g.maplocalleader = ","
|
||||
```
|
||||
|
||||
Now, you can use `,lv` to view the current line in `zathura`, and `,ll` to
|
||||
compile your document. Yay!
|
||||
|
||||
More can be then done, such as using vimtex folds, which are disabled by
|
||||
default (contrary to what [vim-latex](https://github.com/vim-latex/vim-latex)
|
||||
was doing, which is the former plugin I used):
|
||||
|
||||
```lua
|
||||
-- From: https://github.com/lervag/vimtex/blob/master/doc/vimtex.txt#L4671-L4713
|
||||
vim.o.foldmethod = "expr"
|
||||
vim.o.foldexpr="vimtex#fold#level(v:lnum)"
|
||||
vim.o.foldtext="vimtex#fold#text()"
|
||||
-- I like to see at least the content of the sections upon opening
|
||||
vim.o.foldlevel=2
|
||||
```
|
||||
|
||||
Now the sky is your limit, but to start with, here follows a quick list of what
|
||||
is possible now:
|
||||
|
||||
- Compile the document: `,ll`
|
||||
- This also automatically generates a [quickfix
|
||||
buffer](https://vimhelp.org/quickfix.txt.html) which is quite complete… even
|
||||
a tad bit too much sometimes.
|
||||
I used it as is to hunt for over/underfull hboxes, but you can filter them
|
||||
out by setting the
|
||||
[`vim.g.vimtex_quickfix_ignore_filters`](https://github.com/lervag/vimtex/blob/master/doc/vimtex.txt#L2365-L2378)
|
||||
variable.
|
||||
- View the current location in the document: `,lv`.
|
||||
- Show table of content navigation: `,lt`.
|
||||
* Using latex-specific text objects such as `$` for math or `e` for environment
|
||||
(defined by `\begin{…}` and `\end{…}`).
|
||||
- Insert command/environment : `<F6>/<F7>` (in normal and visual mode; these are
|
||||
not very accessible, but can be remapped).
|
||||
- Support for [TeX
|
||||
directives](https://github.com/lervag/vimtex/blob/master/doc/vimtex.txt#L481-L504)
|
||||
(which are common with others LaTeX' IDEs), such as
|
||||
`%! TeX program = xelatex` to specify a latex compiler.
|
||||
* For machine-aided proofreading, you can also enable [grammar checking
|
||||
tools](https://github.com/lervag/vimtex/blob/master/doc/vimtex.txt#L5577-L5610),
|
||||
such as [languagetool](https://languagetool.org/). I didn't check for
|
||||
[grammalecte](https://grammalecte.net/) support for French yet, but it may
|
||||
prove to be an [interesting
|
||||
endeavour](https://upload.wikimedia.org/wikipedia/commons/9/9f/Rabbit_Hole.jpg).
|
||||
|
||||
**Remark.** vimtex
|
||||
[claims](https://github.com/lervag/vimtex/blob/master/doc/vimtex.txt#L6549-L6624)
|
||||
that their coloration is more accurate than what
|
||||
[tree-sitter](https://tree-sitter.github.io/tree-sitter/), then if you are using
|
||||
[nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter), you may
|
||||
want to disable it for vimtex (it raises a warning otherwise):
|
||||
|
||||
```lua
|
||||
require("nvim-treesitter.configs").setup({
|
||||
highlight = {
|
||||
enable = true,
|
||||
disable = { "latex", },
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Okay, that's all and good, but to quote [wikipedia](https://en.wikipedia.org):
|
||||
|
||||
> The goal of the [language server] protocol is to allow programming language
|
||||
> support to be implemented and distributed independently of any given editor or
|
||||
> IDE. In the early 2020s LSP quickly became a "norm" for language intelligence
|
||||
> tools providers.
|
||||
|
||||
Source: <https://en.wikipedia.org/wiki/Language_Server_Protocol>
|
||||
|
||||
We are not early 2020s-ready for LaTeX yet, and even if we can send our current
|
||||
location to `zathura`, the contrary is not possible yet.
|
||||
Let us now address these two issues.
|
||||
|
||||
# Language Server Protocol
|
||||
|
||||
Setting up language server protocol with Vim is a big morsel, and have been the
|
||||
topic of [some tuppervim's
|
||||
sessions](https://tuppervim.org/archives/pads/grenoble-2212.txt) at some point.
|
||||
|
||||
Here follows a minimal configuration that should work with `texlab`:
|
||||
|
||||
```lua
|
||||
-- Minimal lsp config
|
||||
local lspconfig = require("lspconfig")
|
||||
lspconfig.texlab.setup {}
|
||||
```
|
||||
|
||||
Easy, innit? Well, that's well and good, we can now see errors and warnings
|
||||
decorating the file like a Christmas tree, but we can not use any of the LSP
|
||||
tools such as obtaining information on a bibliography key, or rename a macro.
|
||||
|
||||
However, let us just remark that texlab is a pretty minimal LSP server, and
|
||||
does not implement the myriads of possible functionalities.
|
||||
Henceforth, I simply copy-pasted the default example from the [nvim-lspconfig
|
||||
Readme](https://github.com/neovim/nvim-lspconfig), tried the shortcuts one by
|
||||
one, and removed those which raised an error for “not implemented
|
||||
functionality” 🤡:
|
||||
|
||||
```lua
|
||||
-- Use LspAttach autocommand to only map the following keys
|
||||
-- after the language server attaches to the current buffer
|
||||
vim.api.nvim_create_autocmd("LspAttach", {
|
||||
group = vim.api.nvim_create_augroup("UserLspConfig", {}),
|
||||
callback = function(ev)
|
||||
-- Enable completion triggered by <c-x><c-o>
|
||||
vim.bo[ev.buf].omnifunc = "v:lua.vim.lsp.omnifunc"
|
||||
|
||||
-- Buffer local mappings.
|
||||
-- See `:help vim.lsp.*` for documentation on any of the below functions
|
||||
local opts = { buffer = ev.buf }
|
||||
vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
|
||||
vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
|
||||
vim.keymap.set("n", "gR", vim.lsp.buf.rename, opts)
|
||||
vim.keymap.set("n", "gr", vim.lsp.buf.references, opts)
|
||||
end,
|
||||
})
|
||||
```
|
||||
|
||||
Which thus enables:
|
||||
|
||||
* Omnicompletion using LSP (I won't elaborate on this point, either you use it
|
||||
or not, but if you're using it, it may be useful to leave. I personally
|
||||
don't).
|
||||
* Go to a definition, with `gd`, which can be a macro, a reference, or even a
|
||||
bibliography reference.
|
||||
* Show the information about the element under the cursor using `K`, it can be
|
||||
useful to quickly check a reference. Note that pressing `K` twice jumps into
|
||||
the floating window. That can prove useful to copy an article title to search
|
||||
for it somewhere else for instance.
|
||||
* Rename a macro/variable among **all** files in the current working document
|
||||
using `gR`.
|
||||
It's a lifesaver when renaming macros as it avoids writing [regular
|
||||
expressions](https://xkcd.com/1171/).
|
||||
* Show each place where a reference appears with `gr` in a
|
||||
[quickfix](https://vimhelp.org/quickfix.txt.html) window.
|
||||
It allows checking where a formula is referenced or verifying if you cited
|
||||
yourself enough.
|
||||
I personally use
|
||||
[telescope.nvim](https://github.com/nvim-telescope/telescope.nvim) for that
|
||||
purpose as it is more readable, but it goes beyond the scope of this blogpost.
|
||||
|
||||
And that is about it.
|
||||
We now follow the same steps as before: enable the completion engine by fetching
|
||||
the configuration from the [nvim-cmp](https://github.com/hrsh7th/nvim-cmp)
|
||||
readme file and the [vimtex
|
||||
documentation](https://github.com/lervag/vimtex/blob/master/doc/vimtex.txt#L4586-L4625),
|
||||
then prune it.
|
||||
|
||||
```lua
|
||||
-- nvim-cmp
|
||||
local cmp = require("cmp")
|
||||
cmp.setup({
|
||||
sources = cmp.config.sources({
|
||||
{ name = "nvim_lsp" },
|
||||
{ name = "buffer" },
|
||||
}),
|
||||
mapping = cmp.mapping.preset.insert({
|
||||
["<C-Space>"] = cmp.mapping.complete(),
|
||||
["<C-u>"] = cmp.mapping.scroll_docs(-4),
|
||||
["<C-d>"] = cmp.mapping.scroll_docs(4),
|
||||
["<C-l>"] = cmp.mapping.confirm({ select = true }),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
And we're all good from Neovim's side. You can of course start fine-tuning it
|
||||
but it's not the purpose of this blogpost.
|
||||
|
||||
# Plug it into zathura
|
||||
|
||||
Now that you tweaked your Neovim configuration so much that it now consumes 10GB
|
||||
of memory and takes 12s to launch using all your 24 CPU cores, we can move onto
|
||||
configuring zathura.
|
||||
|
||||
One of the reasons I moved from
|
||||
[vim-latex](https://github.com/vim-latex/vim-latex) to
|
||||
[vimtex](https://github.com/lervag/vimtex) is reverse search: to enable it with
|
||||
`vim-latex`, I was using [nvim-remote](https://github.com/mhinz/neovim-remote)
|
||||
which is a wrapper for `nvim --listen` with a lot of constraints, while the most
|
||||
annoying one is that if I used reverse search from a detached[^1] zathura window
|
||||
without starting `nvr` first… then it spawns the process which I cannot recover.
|
||||
Which usually happens when I'm in a rush to fix something quickly.
|
||||
|
||||
Fortunately, this is a thing of the past as it is possible to directly send a
|
||||
directive to `vimtex` upon which it will look for the corresponding buffer and
|
||||
open the file at the corresponding location while following its state
|
||||
(which can be viewed with `,li`).
|
||||
To do so, the
|
||||
[documentation](https://github.com/lervag/vimtex/blob/master/doc/vimtex.txt#L5985-L6033)
|
||||
states that you have to launch the following command, where `%l` is the line in
|
||||
the file and `%f` is the name of the file:
|
||||
|
||||
```bash
|
||||
nvim --headless -c "VimtexInverseSearch %l '%f'"
|
||||
```
|
||||
|
||||
That's all and good, we just have to tell Zathura which command to launch when
|
||||
doing backward search, which by default is done with `Ctrl` + `left mouse
|
||||
button` on the portion of the text you want to view in the code.
|
||||
To do that, the following configuration that you can put in
|
||||
`$HOME/.config/zathura/zathurarc` should do the trick:
|
||||
|
||||
```
|
||||
set synctex true
|
||||
set synctex-editor-command "nvim --headless -c \"VimtexInverseSearch %{line} '%{input}'\""
|
||||
```
|
||||
|
||||
And… that's it! You can now go to the location you want in your source file,
|
||||
compile it on the fly and scrutinise the warnings to look for overfull hboxes!
|
||||
|
||||
[^1]: Meaning that it is not owned by any terminal I have opened, I
|
||||
can otherwise still recover it somehow.
|
||||
|
||||
# Conclusion
|
||||
|
||||
In this blogpost, we saw how to minimally set up Neovim to work with latex using
|
||||
modern toolchains. You can use it as a base to then improve your workflow and
|
||||
write your documents in a breeze with neovim.
|
||||
|
||||
To summarise the configuration we used, it can be done in an `init.lua` file in
|
||||
your vim configuration directory:
|
||||
|
||||
```lua
|
||||
-- Lazy Package Manager
|
||||
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
|
||||
if not vim.loop.fs_stat(lazypath) then
|
||||
vim.fn.system({
|
||||
"git",
|
||||
"clone",
|
||||
"--filter=blob:none",
|
||||
"https://github.com/folke/lazy.nvim.git",
|
||||
"--branch=stable", -- latest stable release
|
||||
lazypath,
|
||||
})
|
||||
end
|
||||
vim.opt.rtp:prepend(lazypath)
|
||||
|
||||
require("lazy").setup({
|
||||
"lervag/vimtex",
|
||||
"neovim/nvim-lspconfig",
|
||||
"hrsh7th/cmp-nvim-lsp",
|
||||
"hrsh7th/nvim-cmp",
|
||||
})
|
||||
|
||||
-- vimtex
|
||||
vim.g.vimtex_view_method = "zathura"
|
||||
vim.g.maplocalleader = ","
|
||||
|
||||
vim.o.foldmethod = "expr"
|
||||
vim.o.foldexpr="vimtex#fold#level(v:lnum)"
|
||||
vim.o.foldtext="vimtex#fold#text()"
|
||||
vim.o.foldlevel=2
|
||||
|
||||
-- Minimal lsp config
|
||||
local lspconfig = require("lspconfig")
|
||||
lspconfig.texlab.setup {}
|
||||
|
||||
-- Use LspAttach autocommand to only map the following keys
|
||||
-- after the language server attaches to the current buffer
|
||||
vim.api.nvim_create_autocmd("LspAttach", {
|
||||
group = vim.api.nvim_create_augroup("UserLspConfig", {}),
|
||||
callback = function(ev)
|
||||
-- Enable completion triggered by <c-x><c-o>
|
||||
vim.bo[ev.buf].omnifunc = "v:lua.vim.lsp.omnifunc"
|
||||
|
||||
-- Buffer local mappings.
|
||||
-- See `:help vim.lsp.*` for documentation on any of the below functions
|
||||
local opts = { buffer = ev.buf }
|
||||
vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
|
||||
vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
|
||||
vim.keymap.set("n", "gR", vim.lsp.buf.rename, opts)
|
||||
vim.keymap.set("n", "gr", vim.lsp.buf.references, opts)
|
||||
end,
|
||||
})
|
||||
|
||||
-- nvim-cmp
|
||||
local cmp = require("cmp")
|
||||
cmp.setup({
|
||||
sources = cmp.config.sources({
|
||||
{ name = "buffer" },
|
||||
{ name = "nvim_lsp" },
|
||||
}),
|
||||
mapping = cmp.mapping.preset.insert({
|
||||
["<C-Space>"] = cmp.mapping.complete(),
|
||||
["<C-u>"] = cmp.mapping.scroll_docs(-4),
|
||||
["<C-d>"] = cmp.mapping.scroll_docs(4),
|
||||
["<C-l>"] = cmp.mapping.confirm({ select = true }),
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
and the following in your `zathurarc` file:
|
||||
|
||||
```
|
||||
set synctex true
|
||||
set synctex-editor-command "nvim --headless -c \"VimtexInverseSearch %{line} '%{input}'\""
|
||||
```
|
||||
|
||||
Note that due to some technical limitations, it's not fully perfect.
|
||||
For instance, synctex is not fully accurate with beamer slides, and just select
|
||||
the whole slide instead of the selected text. It is still better than nothing
|
||||
in my opinion, and it's a drawback that every LaTeX IDE is subject to.
|
||||
|
||||
Now that everything is set up, you can skim the [vimtex
|
||||
documentation](https://github.com/lervag/vimtex/blob/master/doc/vimtex.txt) to
|
||||
look for things you want to activate and learn more about its features.
|
||||
Keep in mind though that you should not be too greedy, just pick some habits one
|
||||
at a time in order to ingrain them into your workflow.
|
||||
You can also expand directly `Neovim` with
|
||||
[snippets](https://github.com/L3MON4D3/LuaSnip) support for instance to automate
|
||||
some tasks as LaTeX can be quite verbose from time to time.
|
||||
I leave you now with some further reading about the topic.
|
||||
|
||||
## See Also
|
||||
|
||||
* jdhao. [A Complete Guide on Writing LaTeX with Vimtex in
|
||||
Neovim](https://jdhao.github.io/2019/03/26/nvim_latex_write_preview/). June 2019.
|
||||
A blogpost that serves the same purpose as this one, eventhough it's not fully
|
||||
up to date, for instance regarding backward search.
|
||||
* Gilles Castel. [How I'm able to take notes in mathematics lectures using LaTeX
|
||||
and Vim](https://castel.dev/post/lecture-notes-1/).
|
||||
An example of how to streamline writing maths with Neovim, vimtex and
|
||||
snippets. The goal may not be for everyone (as writing new maths and following
|
||||
a lecture are not one and the same), but it's still an interesting read. For
|
||||
instance it presents the `concealment` feature of [vim](https://www.vim.org/)
|
||||
that makes previewing the result easier.
|
||||
I also recommend the rest of the blog, as it contains information about
|
||||
[inkscape](https://inkscape.org/) and how to integrate it with LaTeX.
|
||||
|
||||
# Bonus: Key bindings for bépo users
|
||||
|
||||
As a [bépo](https://fr.wikipedia.org/wiki/B%C3%A9po) user, I have some remapping
|
||||
done in Neovim, and especially [direction
|
||||
keys](https://vimhelp.org/usr_02.txt.html#02.3):
|
||||
|
||||
```lua
|
||||
-- Some shortcuts
|
||||
local keymap = vim.keymap.set
|
||||
local opts = {noremap = true, silent = true}
|
||||
|
||||
-- [HJKL] <-> {CTSR}
|
||||
local map_list = {
|
||||
['c'] = 'h', ['r'] = 'l', ['t'] = 'j', ['s'] = 'k', ['C'] = 'H', ['R'] = 'L', ['T'] = 'J', ['S'] = 'K', -- [HJKL] -> [CTSR]
|
||||
['j'] = 't', ['J'] = 'T', ['l'] = 'c', ['L'] = 'C', ['h'] = 'r', ['H'] = 'R', ['k'] = 's', ['K'] = 'S', -- [CTSR] -> [HJKL]: J = until, L = change, h = replace, k = substitute
|
||||
}
|
||||
for key, binding in pairs(map_list) do
|
||||
keymap({'n', 'x'}, key, binding, opts)
|
||||
end
|
||||
```
|
||||
|
||||
That's nice and all but… it conflicts with the [vimtex default
|
||||
mappings](https://github.com/lervag/vimtex/blob/master/doc/vimtex.txt#L800-L912)
|
||||
such as `cse` to rename an environment which can be useful to replace an `align`
|
||||
with `align*` for instance. Meaning that going back one character would trigger
|
||||
vim to wait for the next key input, which is kind of annoying.
|
||||
|
||||
Hence the need to remap the vimtex default shortcuts starting with `c`, `t`, `s`
|
||||
or `r`.
|
||||
Fortunately, it's only the case for `c` and `t`. I first just add the remapping
|
||||
to `$NVIMDIR/after/ftplugin/tex.lua`, however I soon noticed that it's not
|
||||
sufficient as vimtex is also used for `.tikz`, `.cls` and `.bib` files,[^2] thus we
|
||||
will use
|
||||
[autocommand](https://neovim.io/doc/user/lua-guide.html#lua-guide-autocommands)
|
||||
for that:
|
||||
|
||||
```lua
|
||||
-- Some BÉPO mappings for vimtex
|
||||
vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
|
||||
pattern = {"*.tex", "*.bib", "*.cls", "*.tikz",},
|
||||
group = vim.api.nvim_create_augroup("latex", { clear = true }),
|
||||
callback = function()
|
||||
local vimtex_remaps = {
|
||||
-- c <-> t
|
||||
{ mode = "n", source = "csd", target = "tsd", command = "<Plug>(vimtex-delim-change-math)"},
|
||||
{ mode = "n", source = "csc", target = "lsc", command = "<Plug>(vimtex-cmd-change)"},
|
||||
{ mode = "n", source = "cse", target = "lse", command = "<Plug>(vimtex-env-change)"},
|
||||
{ mode = "n", source = "cs$", target = "ls$", command = "<Plug>(vimtex-env-change-math))"},
|
||||
-- t <-> j
|
||||
{ mode = {"x", "n"}, source = "tsD", target = "jsD", command = "<Plug>(vimtex-delim-toggle-modifier-reverse)"},
|
||||
{ mode = {"x", "n"}, source = "tsd", target = "jsd", command = "<Plug>(vimtex-delim-toggle-modifier)"},
|
||||
{ mode = {"x", "n"}, source = "tsf", target = "jsf", command = "<Plug>(vimtex-cmd-toggle-frac)"},
|
||||
{ mode = "n", source = "tsc", target = "jsc", command = "<Plug>(vimtex-cmd-toggle-star)"},
|
||||
{ mode = "n", source = "ts$", target = "js$", command = "<Plug>(vimtex-env-toggle-math)"},
|
||||
{ mode = "n", source = "tse", target = "jse", command = "<Plug>(vimtex-env-toggle-star)"},
|
||||
}
|
||||
|
||||
for _,remap in pairs(vimtex_remaps) do
|
||||
if vim.fn.maparg(remap.source) ~= "" then
|
||||
vim.keymap.del(remap.mode, remap.source, { buffer = true })
|
||||
vim.keymap.set(remap.mode, remap.target, remap.command, { silent = true, noremap = true, buffer = true})
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
```
|
||||
|
||||
The sanity check with
|
||||
[`maparg(·)`](https://vimhelp.org/builtin.txt.html#maparg%28%29) is done to
|
||||
avoid unmapping a mapping that already doesn't exist, which will raise an error
|
||||
(as I have the (bad?) habit to type `:e` to reload the current file when
|
||||
thinking, that what triggered this behaviour in my case).
|
||||
|
||||
**Remark.** Please also note that it is not fully remapped yet, for instance in the table of
|
||||
content navigation there are still collisions, as `t` for instance toggles
|
||||
showing TODOs or `s` toggles the section numbering.
|
||||
|
||||
To finish and for the sake of completeness, here follows the bépo-bindings for
|
||||
zathura, to put in your `zathurarc` file:
|
||||
|
||||
```text
|
||||
## BEPO
|
||||
# hjkl → ctsr
|
||||
map t scroll down
|
||||
map s scroll up
|
||||
map c scroll left
|
||||
map r scroll right
|
||||
|
||||
# JK → TS
|
||||
map T navigate next
|
||||
map S navigate previous
|
||||
|
||||
# r → p
|
||||
map p rotate rotate-cw
|
||||
|
||||
# R → u
|
||||
map u reload
|
||||
|
||||
# Mode Index
|
||||
map [index] t navigate_index down
|
||||
map [index] s navigate_index up
|
||||
map [index] r navigate_index expand
|
||||
map [index] c navigate_index collapse
|
||||
|
||||
map [index] R navigate_index expand-all
|
||||
map [index] C navigate_index collapse-all
|
||||
```
|
||||
|
||||
[^2]: Actually `.cls` and `.tikz` are detected as tex files, so the `ftplugin`
|
||||
approach works but `.bib` is detected as a bibtex file and enjoys its own
|
||||
filetype.
|
@ -1,11 +1,11 @@
|
||||
---
|
||||
Title: Gérer vos mots de passe avec pass
|
||||
Date: 2019-04-22 19:00
|
||||
Modified: 2019-04-24 11:12
|
||||
Modified: 2024-02-24 18:00
|
||||
Lang: fr
|
||||
Author: Fabrice
|
||||
Category: programmes
|
||||
Tags: pass, git
|
||||
Tags: pass, git, cli
|
||||
Slug: password-store
|
||||
Header_Cover: ../images/covers/clovers.jpg
|
||||
Summary: Un gestionnaire de mots de passe simple qui repose sur gpg, et synchronisé via git.
|
||||
@ -14,9 +14,9 @@ Summary: Un gestionnaire de mots de passe simple qui repose sur gpg, et synchron
|
||||
Comme nous vivons dans un monde dangereux où les failles de sécurité sont découvertes tous les jours et où les fuites de données sont devenues monnaies courantes, il est recommandé d’utiliser un mot de passe différent pour chacune de nos identités numériques.
|
||||
Cependant, cela devient vite une horreur à maintenir manuellement, j’avais essayé d’utiliser un bloc note en 2003 que j’ai perdu au bout d’un mois (et les mots de passe avec).
|
||||
|
||||
Heureusement, les gestionnaires de mots de passes ont fleurit depuis, et plusieurs proposent des fonctionnalités de base similaires : multiplateforme (en particulier sur les téléphones intelligents), génération de mots de passe « sécurisés », intégration navigateur…
|
||||
Heureusement, les gestionnaires de mots de passes ont fleuri depuis, et plusieurs proposent des fonctionnalités de base similaires : mufti plateforme (en particulier sur les téléphones intelligents), génération de mots de passe « sécurisés », intégration navigateur…
|
||||
|
||||
Je ne vais pas pour faire une comparaison détaillée, mais si vous souhaitez jeter un coup d’œil, [wikipedia](https://en.wikipedia.org) propose une table de comparaison détaillée [**par ici** (en)](https://en.wikipedia.org/wiki/List_of_password_managers).
|
||||
Je ne vais pas pour faire une comparaison détaillée, mais si vous souhaitez jeter un coup d’œil, [Wikipédia](https://en.wikipedia.org) propose une table de comparaison détaillée [**par ici** (en)](https://en.wikipedia.org/wiki/List_of_password_managers).
|
||||
|
||||
Dans cette recherche, grâce à [moviuro](https://try.popho.be), mon choix s’est porté sur [pass](https://www.passwordstore.org/) avec [pass-otp](https://github.com/tadfisher/pass-otp#readme) (et [passmenu](https://git.zx2c4.com/password-store/tree/contrib/dmenu)).
|
||||
Je n’ai pas non plus la prétention de faire un guide détaillé sur pass, comme ceux-ci sont déjà faciles à trouver sur internet, par exemple [**par ici** (en)](https://medium.com/@chasinglogic/the-definitive-guide-to-password-store-c337a8f023a1).
|
||||
@ -32,6 +32,34 @@ Pour **re**générer un mot de passe, l’option `-i` ici est **importante** pui
|
||||
Cela évite donc de devoir utiliser du [git sale]({filename}/cheat-sheets/git-fr.md) pour retirer l’erreur de l’arbre des commits vu que `pass <cmd>` fait automatiquement un commit atomique à la fin de la commande.
|
||||
Je l’oublie parfois, c’est pourquoi je laisse ça ici en guise de rappel.
|
||||
|
||||
Sur certains services, il arrive que l’on ait besoin de spécifier un ensemble de caractères admissibles pour les mots de passe.
|
||||
Cela peut être fait via la variable d’environnement `PASSWORD_STORE_CHARACTER_SET`.
|
||||
Le contenu de cette variable est transmis à la [commande `tr`](https://fr.wikipedia.org/wiki/Tr_(Unix)).
|
||||
Ainsi, pour créer un code PIN, on peut spécifier la valeur suivante : `PASSWORD_STORE_CHARACTER_SET='[:digit:]'` et indiquer la longueur désirée du mot de passe en dernier argument de la commande.
|
||||
|
||||
Par exemple, pour générer un code PIN de 6 chiffres :
|
||||
|
||||
```sh
|
||||
PASSWORD_STORE_CHARACTER_SET='[:digit:]' pass generate <pass-name> 6
|
||||
```
|
||||
|
||||
Je n’ai en revanche pas trouvé comment forcer la présence de caractères spéciaux… je lance donc la commande plusieurs fois dans ces cas avec l’option `-i` pour écrire en place après la première tentative.
|
||||
Ce n’est pas la meilleure solution, qui en plus pollue l’historique git mais bon… ça fonctionne.
|
||||
|
||||
Par exemple, pour générer un mot de passe sur un service _fictif_ qui supporterait les caractères spéciaux suivants: `-_@$<>` pour des mots de passe d’au plus 20 caractères, on peut utiliser la commande suivante :
|
||||
|
||||
```sh
|
||||
PASSWORD_STORE_CHARACTER_SET='[:alnum:]-_@$<>' pass generate <pass-name> 20
|
||||
```
|
||||
|
||||
Si on souhaite faire de la rotation de clefs ou simplement mettre à jour ses identités, il est possible de relancer la commande `pass init`, où on peut y spécifier l’identifiant de la nouvelle clef… ou plusieurs identifiants.
|
||||
Cela peut être utile pour avoir plusieurs clefs sur des périphériques différents pour mieux contrôler les risques de fuite de clef.
|
||||
On peut également avoir des sous dossiers de son dossier `$HOME/.password-store/` chiffrés sous des clefs spécifiques (cela se contrôle avec l’option `-p/--path=` de `pass init`).
|
||||
Une application possible étant de séparer les clefs personnelles des clefs professionnelles (qui peuvent alors être chiffré sous une clef partagée entre les personnes ayant accès au jeu de mots-de-passe).
|
||||
On pourrait imaginer coupler ça avec les [sous-modules git](https://git-scm.com/book/en/v2/Git-Tools-Submodules), mais je ne m’y suis pas aventuré…
|
||||
|
||||
Pour finir :
|
||||
|
||||
```sh
|
||||
pass git <ce que vous voulez>
|
||||
```
|
||||
|
@ -1,10 +1,10 @@
|
||||
---
|
||||
Title: Manage your passwords with pass
|
||||
Date: 2019-04-22 19:00
|
||||
Modified: 2019-04-23 14:24
|
||||
Modified: 2024-02-24 18:00
|
||||
Author: Fabrice
|
||||
Category: software
|
||||
Tags: pass, git
|
||||
Tags: pass, git, cli
|
||||
Slug: password-store
|
||||
Header_Cover: images/covers/clovers.jpg
|
||||
Summary: A simple password manager that relies on gpg, and synchronized with git.
|
||||
@ -14,9 +14,9 @@ Lang: en
|
||||
As security breaches are discovered regularly, and so leakage happens, it is recommended to have a different password on each account.
|
||||
However, this task is obviously a pain to maintain by hand. I did use a notebook back in 2003, which I lost within a month, given that I'm a very organized person.
|
||||
|
||||
Hopefully, many password managers exist, with similar features: cross-platform (especially smartphone support), password generation,browser integration…
|
||||
Hopefully, many password managers exist, with similar features: cross-platform (especially smartphone support), password generation, browser integration…
|
||||
|
||||
I'm not here to compare them, if you want to give a look, [wikipedia](https://en.wikipedia.org) provides a nice comparison table [**there**](https://en.wikipedia.org/wiki/List_of_password_managers).
|
||||
I'm not here to compare them, if you want to give a look, [Wikipedia](https://en.wikipedia.org) provides a nice comparison table [**there**](https://en.wikipedia.org/wiki/List_of_password_managers).
|
||||
|
||||
However, thanks to [moviuro](https://try.popho.be), my choice is [pass](https://www.passwordstore.org/) along with [pass-otp](https://github.com/tadfisher/pass-otp#readme) (and [passmenu](https://git.zx2c4.com/password-store/tree/contrib/dmenu)).
|
||||
I don't intend either to make a comprehensive guide, as those already populate the internet, for example [**here**](https://medium.com/@chasinglogic/the-definitive-guide-to-password-store-c337a8f023a1).
|
||||
@ -28,7 +28,32 @@ Here are just some commands I often use.
|
||||
```sh
|
||||
pass generate -i <pass-name>
|
||||
```
|
||||
To regenerate a password, the `-i` is important to avoid overwritting the whole file and having to rely on [dirty git]({filename}/cheat-sheets/git.md) to withdraw your mistake (`pass <cmd>` will automatically commit your change)… I sometimes forget it, so let's put it here as a reminder.
|
||||
To regenerate a password, the `-i` is important to avoid overwriting the whole file and having to rely on [dirty git]({filename}/cheat-sheets/git.md) to withdraw your mistake (`pass <cmd>` will automatically commit your change)… I sometimes forget it, so let's put it here as a reminder.
|
||||
|
||||
Sometimes it can be useful to specify the accepted special chars, this can be done using the `PASSWORD_STORE_CHARACTER_SET` environment variable.
|
||||
This value is interpreted by the [`tr` command](https://en.wikipedia.org/wiki/Tr_(Unix)),
|
||||
hence to create a PIN, you can use the following value: `PASSWORD_STORE_CHARACTER_SET='[:digit:]'`, then specify the length with the last argument.
|
||||
|
||||
For instance, to generate a 6 digit PIN:
|
||||
|
||||
```sh
|
||||
PASSWORD_STORE_CHARACTER_SET='[:digit:]' pass generate <pass-name> 6
|
||||
```
|
||||
|
||||
I didn’t manage to specify how to have at least one of them, so I run the command multiple times (with the `-i` option to change the file in place after the first one)…
|
||||
It pollutes a bit the git history but, well… it works.
|
||||
|
||||
For instance, for a service supporting only the following characters: `-_@$<>` of at most 20 char long (fictive example), you can use the following command:
|
||||
|
||||
```sh
|
||||
PASSWORD_STORE_CHARACTER_SET='[:alnum:]-_@$<>' pass generate <pass-name> 20
|
||||
```
|
||||
|
||||
If for some reasons you want to rotate your keys, you can rerun the `pass init` command by indicating the new gpg ID (or multiple keys to have it available under multiple devices that don’t share the same key to limit the risks of key leakage).
|
||||
Note that you can also have a subfolder encrypted under a specific key (it can be specified using the `-p/--path=` option for `pass init`) if you want to share it to some other devices, or to separate work from personal passwords.
|
||||
It should be possible to use [`git submodule`](https://git-scm.com/book/en/v2/Git-Tools-Submodules) as well, but I didn’t try.
|
||||
|
||||
To finish:
|
||||
|
||||
```sh
|
||||
pass git <whatever you want>
|
||||
|
@ -1,6 +1,7 @@
|
||||
---
|
||||
Title: Use termtosvg to screencast your terminal
|
||||
Date: 2019-04-24 17:01+5:30
|
||||
Modified: 2023-07-10 12:00
|
||||
Author: Fabrice
|
||||
Category: software
|
||||
Tags: termtosvg
|
||||
@ -15,7 +16,7 @@ Therefore, it is common to just paste those term information when it comes to sh
|
||||
|
||||
However, once the Pandora box of terminals is opened, yet another world reveals itself: [ncurse](https://www.gnu.org/software/ncurses/).
|
||||
It is common to represent static elements with it using a screenshot, however as I already complained about it in [another post]({filename}/tips/latex-adblock.md).
|
||||
It is not a fully satisfactory solution as we also loose all the text information, and it is thus impossible to copy a part of the screen content without typing it again (or [OCR](https://www.gnu.org/software/ncurses/)ise the screenshot?).
|
||||
It is not a fully satisfactory solution as we also loose all the text information, and it is thus impossible to copy a part of the screen content without typing it again (or [OCR](https://en.wikipedia.org/wiki/Optical_character_recognition)ise the screenshot?).
|
||||
|
||||
[Nicolas Bedos](https://github.com/nbedos) comes with a solution for this named [termtosvg](https://nbedos.github.io/termtosvg/).
|
||||
This small python program is available on `pip` as well as [github](https://nbedos.github.io/termtosvg/).
|
||||
|
252
content/software/typst.md
Normal file
@ -0,0 +1,252 @@
|
||||
---
|
||||
Title: Typesetting with Typst
|
||||
Date: 2024-10-19 18:00
|
||||
Modified: 2025-02-14 12:45
|
||||
Lang: en
|
||||
Author: Fabrice
|
||||
Category: software
|
||||
Tags: vim, neovim, typst
|
||||
Slug: typst-intro
|
||||
table-of-contents: true
|
||||
Summary: An overview of Typst for simple usage.
|
||||
Header_Cover: ../images/covers/printing-press.jpg
|
||||
---
|
||||
|
||||
For about ten years now, I’ve been using _LaTeX_ to typeset any document which
|
||||
aims to be printed. The main reason is that I’m quite familiar with the syntax
|
||||
to adjust the page setting to what I imagine. Other solutions exist to ease this
|
||||
workflow, such as [Pandoc](https://pandoc.org/) to convert easier to write syntax to
|
||||
other formats. However, this solution was not palatable to me as the universal
|
||||
aspect of Pandoc, makes it a pain to specify pagination properties. And, to
|
||||
produce a PDF in the end, Pandoc calls _LaTeX_, and for the sake of simplicity I
|
||||
prefer to directly write in _LaTeX_ (see the conclusion for clarification).
|
||||
|
||||
However, for some kind of documents that I don’t write very often, such as
|
||||
letters, it’s sometimes a pain to find the syntax of the [LaTeX class for
|
||||
letters](https://texlive.mycozy.space/macros/latex/contrib/lettre/lettre.pdf)<sup>(fr)</sup>
|
||||
I use. Recently, I had to write small documents (approx 3 pages), with a
|
||||
bibliography, and that just needed to have a nice and neat presentation. Before
|
||||
going farther, I decided to give a try to [typst](https://typst.app/). It is an
|
||||
open-source typesetting engine that is written in
|
||||
[rust](https://rust-lang.org/), that promotes modern features such as
|
||||
_incremental compilation_, and a scripting language that is actually readable by
|
||||
humans. Moreover, the markup language is clean, and as in
|
||||
[markdown] or [asciidoc], it can be read from the source (without a
|
||||
[concealer](https://alok.github.io/2018/04/26/using-vim-s-conceal-to-make-languages-more-tolerable/))
|
||||
to have an idea of the typeset text before compiling it.
|
||||
|
||||
|
||||
The project is still in development and some features may break before the first
|
||||
major version is out. However, to quickly generate a document, it can be a good
|
||||
idea to consider. Also, please note that there is no native output from Typst to
|
||||
HTML. However, Pandoc can read and write `.typ` files, so it’s an alternative
|
||||
worth considering given that native LaTeX is **not** easy to write for that
|
||||
purpose.
|
||||
|
||||
In the following, it will be a quick overview of the features that I find nice
|
||||
in Typst. Please don’t expect an in-depth review, I only used it for a couple of
|
||||
opportunities.
|
||||
|
||||
# Syntax
|
||||
|
||||
To illustrate Typst, here follows a simple document, with its corresponding [compiled
|
||||
version]({static}/examples/typst-example.pdf).
|
||||
|
||||
```typst
|
||||
/* Set some variables for the authors and the title */
|
||||
#let title = [How to type in Typst]
|
||||
#let authors = ("Fabrice Mouhartem", )
|
||||
|
||||
/* Set some document properties:
|
||||
* - Numbering of sections (default: none)
|
||||
* - PDF properties (it does not print anything) */
|
||||
#set heading(numbering: "I.")
|
||||
#set document(title: title, author: authors)
|
||||
|
||||
/* Now we can print the title and the authors */
|
||||
#align(center, text(size: 17pt, strong(title)))
|
||||
#for author in authors { // TODO: would be better in a grid
|
||||
align(center, text(author))
|
||||
}
|
||||
|
||||
/* Table of contents */
|
||||
#outline()
|
||||
|
||||
/* To define a section */
|
||||
= Introduction
|
||||
/* And to write the content: */
|
||||
To _type_ in Typst, you just have to… *type*.
|
||||
|
||||
= Conclusion
|
||||
See, it was #strike[hard] easy.
|
||||
```
|
||||
|
||||
Besides the programmatic part at the start, we can see that the syntax is close
|
||||
to what we may know in other simple markup languages such as [markdown] or
|
||||
[asciidoc]. However, it is its own and Typst [doesn’t
|
||||
plan](https://github.com/typst/typst/discussions/2498) to converge toward
|
||||
another markup language, especially knowing that the markdown syntax is
|
||||
[ambiguous](https://roopc.net/posts/2014/markdown-cfg/).
|
||||
|
||||
For the preamble of the file, it can be deferred to another file to accentuate
|
||||
the separation between content and typesetting. We won’t go into details, but it
|
||||
was mostly there to illustrate some parts of the language, such as variable
|
||||
declaration (`#let …`) or loops over arrays (`#for … in …`). We also set some
|
||||
values about the document using either static values (for the numbering) or the
|
||||
defined variables (authors and title options).
|
||||
|
||||
Let us now check that these options are indeed well set:
|
||||
```bash
|
||||
❯ pdfinfo "typst-example.pdf" | head -n 3
|
||||
Title: How to type in Typst
|
||||
Author: Fabrice Mouhartem
|
||||
Creator: Typst 0.12.0
|
||||
```
|
||||
|
||||
The generated document is a bit bare, but we can easily change it, and as easily
|
||||
create a template to automate this work for us.
|
||||
|
||||
# Example: a letter (the French way)
|
||||
|
||||
For a simple example, I’ll take the letter one, for which I wrote a simple
|
||||
template to generate them. The template is available in [this
|
||||
repository](https://git.epheme.re/fmouhart/typst-lettre). The main issue I had
|
||||
is that the French way of doing letters revert the order of the addresses of the
|
||||
sender and recipient are… reverted compared to the English style.
|
||||
|
||||
Let us dig in what it does by looking at the example file.
|
||||
|
||||
First thing first, the file is loading the template from `lettre.typ`. This file
|
||||
defines the typesetting and the paginations properties, and provide an
|
||||
initialisation function to define the different headers, which you can look into
|
||||
if you feel curious. If you find it a bit unbearable, you can create a new file
|
||||
`preamble.typ` to hide everything, and include it with `#include "preamble.typ"`
|
||||
at the outset of the file.
|
||||
|
||||
```typst
|
||||
#import "lettre.typ": *
|
||||
|
||||
#show: doc => lettre.with(
|
||||
de: [
|
||||
Sender\
|
||||
Address
|
||||
],
|
||||
pour: [
|
||||
Recipient\
|
||||
Address
|
||||
],
|
||||
objet: "subject of the letter", // optional
|
||||
date: "date of sending", // optional
|
||||
lieu: "location",
|
||||
introduction: "opening",
|
||||
cloture: "closing",
|
||||
signature: "signature",
|
||||
post: [
|
||||
post-letter (e.g., post-scriptum)
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
This will generate the template with the elements where they should be, in a
|
||||
very simple fashion. Now, we just have to write the content of the letter and
|
||||
have a `pdf` file pretty easily with `typst compile` without all the files that
|
||||
_LaTeX_ generates for us. As a bonus, it also set some PDFs metadata from the
|
||||
input variables.
|
||||
|
||||
# Bibliography
|
||||
|
||||
Another nice feature is that Typst embeds a bibliography engine, that is
|
||||
compatible with the bibtex format. Meaning that I don’t have to change the way I
|
||||
manage my bibliography or directly use [community-managed
|
||||
bibliography](https://cryptobib.di.ens.fr/).
|
||||
|
||||
For that you simply have to call the bibliography function where you want it to be generated:
|
||||
|
||||
```typst
|
||||
#bibliography("bibliography.bib", title: "References", style: "springer-basic")
|
||||
```
|
||||
|
||||
And cite the references you want with the `@bibkey` syntax (note that it’s the
|
||||
same syntax for cross-referencing) or the `#cite` function. Note that if you
|
||||
have a `+` in your bibliography key, the label won’t be recognized. It is my
|
||||
case as my bibkeys are in the _alpha_ style with the initials of the authors +
|
||||
year up to 3 names, and a `+` afterward… To be able to cite the reference
|
||||
anyway, just do `#cite(label("bib+key"))`.
|
||||
|
||||
The full list of natively available style is given in the [Typst
|
||||
documentation](https://typst.app/docs/reference/model/bibliography/#parameters-style),
|
||||
however you can define your own in the [Citation Style
|
||||
Language](https://citationstyles.org/). Meaning that you can pick the best one
|
||||
for your usage in the [CSL
|
||||
repository](https://github.com/citation-style-language/styles).
|
||||
|
||||
To put multiple citations (as in `\cite{ref1, ref2}` in _LaTeX_), you just have
|
||||
to concatenate them, like `@ref1 @ref2`. If the citation style supports it, it would automatically
|
||||
merge them under the same bracket (however, it’s not the case for all citation
|
||||
styles).
|
||||
|
||||
# Tooling
|
||||
|
||||
Unlike my [blogpost about using nvim for LaTeX]({filename}./nvim-latex.md),
|
||||
it’s pretty much easier here.
|
||||
|
||||
I just added the [`typst.vim`](https://github.com/kaarmu/typst.vim) plugin to
|
||||
_neovim_, added a binding for the `:TypstWatch` command and that’s basically
|
||||
all. It is possible to set the `g:typst_pdf_viewer` (`vim.g.typst_pdf_viewer` in
|
||||
Lua) global variable as well if you want to have a different default PDF viewer
|
||||
for your system and for edition.
|
||||
|
||||
Now, each time I save, the document is incrementally compiled (I think) and
|
||||
updated in my PDF viewer.
|
||||
|
||||
I tried using typst language servers as well, but they don’t seem mature enough
|
||||
yet. In the end, the `typst.vim` plugin suffices to my needs without being too
|
||||
nosy.
|
||||
|
||||
Hopefully, the tooling will get better with time.
|
||||
|
||||
# Conclusion
|
||||
|
||||
For simple document typesetting, even with features such as bibliography,
|
||||
cross-referencing, and table of contents, Typst seems to be a good choice.
|
||||
However, for long-term support documents, such as documentation, I would wait to
|
||||
see it being more stable. Even while writing this blog post, the _lettre_
|
||||
template I made was done in Typst 0.11, and preparing it in a repository raised
|
||||
some warnings about [breaking changes from
|
||||
0.12](https://typst.app/docs/changelog/0.12.0/) which has been published…
|
||||
[yesterday](https://typst.app/blog/2024/typst-0.12/) (at the time of writing):
|
||||
|
||||
> Added
|
||||
> [`par.spacing`](https://typst.app/docs/reference/model/par/#parameters-spacing
|
||||
> "Typst Documentation: paragraph spacing") property for configuring paragraph
|
||||
> spacing. This should now be used instead of `show par: set block(spacing: ..)`
|
||||
> **(Breaking change)**
|
||||
|
||||
Which also leads me to say that one other advantage of Typst is… the readability of
|
||||
error messages. They are way much cleaner than the ones from _LaTeX_. Leading to
|
||||
easier debugging as well. I, however, can’t say for sure as I didn’t typeset big
|
||||
documents using Typst yet (which is unlikely to happen given my stance so far,
|
||||
but who knows…).
|
||||
|
||||
Finally, to complete the note about compiling in _LaTeX_ from Pandoc in the
|
||||
introduction of this blogpost… I’m apparently not up to date. For the sake of
|
||||
transparency, it is possible to use different PDF engines with Pandoc according
|
||||
to the [documentation](https://pandoc.org/MANUAL.html#option--pdf-engine). I
|
||||
didn’t try them yet, so I can’t provide feedbacks about them. Note that Typst is
|
||||
part of the PDF generators, as well as other nice typesetting projects such as
|
||||
[pagedjs](https://pagedjs.org/) that aims at paginating HTML sources to have
|
||||
great web page and print-ready PDFs. However, the argument about avoiding
|
||||
intermediate steps if possible still holds (moreover when the syntax of Typst is
|
||||
already clean enough).
|
||||
|
||||
## See Also
|
||||
|
||||
- [Awesome Typst](https://github.com/qjcg/awesome-typst): a repository listing
|
||||
useful links for typst users.
|
||||
- [Typst for _LaTeX_ users](https://typst.app/docs/guides/guide-for-latex-users/
|
||||
"Typst documentation: guide for LaTeX users"): a comprehensive guide for typst
|
||||
for _LaTeX_ users.
|
||||
|
||||
[markdown]: https://daringfireball.net/projects/markdown/
|
||||
[asciidoc]: https://asciidoc.org/
|
||||
|
97
content/software/xidel.md
Normal file
@ -0,0 +1,97 @@
|
||||
---
|
||||
Title: Manipulate XML/HTML with Xidel
|
||||
Date: 2023-10-29 22:00
|
||||
Lang: en
|
||||
Author: Fabrice
|
||||
Category: software
|
||||
Tags: xidel, html, xml, cli
|
||||
Slug: xidel
|
||||
table-of-contents: false
|
||||
Header_Cover: ../images/covers/aix-en-provence.jpg
|
||||
Summary: An example-based approach on how to easily parse XML/HTML files and stubs with Xidel.
|
||||
---
|
||||
|
||||
You may know [jq](https://jqlang.github.io/jq/) process
|
||||
[json](https://www.json.org/json-en.html) files in command line. At some point I
|
||||
was looking for the simplicity of such a swiss-knife tool for
|
||||
[XML](https://www.w3.org/XML/)/[HTML](https://html.spec.whatwg.org/multipage/),
|
||||
mostly for simple usages that don't require me to resort to a full-fledged
|
||||
scripting language such as [python](https://python.org) or dabbing in [regular
|
||||
expressions](https://en.wikipedia.org/wiki/Regular_expression) that will never
|
||||
work because of a carriage return at an unexpected place, and guess what? It exists!
|
||||
|
||||
This tool is [Xidel](https://www.videlibri.de/xidel.html). It is a bit more than
|
||||
that as it also allows downloading files, which enables extra features such as
|
||||
navigating a site following specific links. You can find more about it in the
|
||||
[list of examples](https://www.videlibri.de/xidel.html#examples) given in the
|
||||
project website, which is a nice introduction to the possibilities of the tool.
|
||||
|
||||
However, I mainly use it for simple cases, where I mix-and-match the best of
|
||||
both worlds: a graphical client (such as
|
||||
[firefox](https://www.mozilla.org/en-US/firefox/new/)), and a CLI tool, which in
|
||||
this case is Xidel.
|
||||
|
||||
To do this, we will see a simple use case, where filtering by hand can be a bit
|
||||
tedious. Let us assume that we want to obtain the URL list of pdf versions of
|
||||
Victor Hugo's novels in French from Wikisource if available.
|
||||
|
||||
We start from this page: <https://fr.wikisource.org/wiki/Auteur:Victor_Hugo>,
|
||||
that lists which is available on <https://fr.wikisource.org>.
|
||||
|
||||
Now, we can simply select the “Romans” section as it is and copy it. Normally
|
||||
you can check that you indeed have the html in your clipboard by typing
|
||||
`wl-paste -t text/html` on wayland or `xclip -selection clipboard -o -t
|
||||
text/html` on X11 if you have xclip installed. In the following we will assume a
|
||||
Wayland environment with
|
||||
[wl-clipboard](https://github.com/bugaevc/wl-clipboard), but it should also work
|
||||
with `xclip` (not tested, please let me know how it behaves).
|
||||
|
||||
Now that's good, but we now need to filter and parse it, we can start with a
|
||||
simple test:
|
||||
|
||||
```bash
|
||||
wl-paste -t text/html | xidel -e '//a/@href'
|
||||
```
|
||||
|
||||
Which will show us the target of each links in our selection. To explain the
|
||||
syntax, the option `-e` tells `xidel` to extract the content that is passed as
|
||||
input, which is either a
|
||||
[template](https://benibela.de/documentation/internettools/extendedhtmlparser.THtmlTemplateParser.html)
|
||||
or following the [XPath](https://en.wikipedia.org/wiki/XPath) syntax to parse
|
||||
the [DOM](https://en.wikipedia.org/wiki/Document_Object_Model) tree. In the
|
||||
above example we used the latter, to obtain every anchors (`//a`) and then their
|
||||
`href` attribute with `@href`.
|
||||
From there we can see that pdf versions contains the string… “pdf”.
|
||||
Now, we can see another nice part of XPath, is that we can filter using
|
||||
functions:
|
||||
|
||||
```bash
|
||||
wl-paste -t text/html | xidel -e '//a/@href[contains(., "pdf")]'
|
||||
```
|
||||
|
||||
The last magical part here, is the dot notation, which refers to the current
|
||||
item “value”. I’m not the most familiar with the subtleties here, and you can
|
||||
refer to this stackoverflow [short answer](https://stackoverflow.com/a/38240971)
|
||||
or long answer just above for more details.
|
||||
|
||||
You can also edit the way the filtering is done, for instance if the anchors you
|
||||
are targeting are named “Download”, you can obtain the links with:
|
||||
```bash
|
||||
wl-paste -t text/html | xidel -e '//a[contains(., "Download")]/@href'
|
||||
```
|
||||
|
||||
If you want strict equality because there are “Download PDF” and “Download epub”
|
||||
links for instance:
|
||||
|
||||
```bash
|
||||
wl-paste -t text/html | xidel -e '//a[text()="Download PDF"]/@href'
|
||||
```
|
||||
|
||||
To go further, you can also pass HTTP headers and cookies to `xidel` via the
|
||||
`--header/-H` and `--load-cookies` options respectively. It is also possible to
|
||||
use the `--follow/-f` command to hop in the pages that matches (using the same
|
||||
syntax as above) to obtain a link from it… or event directly download it with
|
||||
the `--download` option and so on.
|
||||
|
||||
In this blogpost we only look at a local version of pre-filtered content using
|
||||
you web browser, but the possibilities are endless!
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
Title: Écrire son courriel en markdown avec vim
|
||||
Date: 2019-04-22 19:00
|
||||
Modified: 2019-04-24 09:35
|
||||
Modified: 2023-10-14 19:00
|
||||
Author: Fabrice
|
||||
Category: astuces
|
||||
Tags: emails, pandoc, Vim
|
||||
@ -24,7 +24,11 @@ pandoc -t html5 -s <fichier> | xclip -selection clipboard
|
||||
|
||||
Ainsi, en ajoutant ce raccourci dans votre fichier de configuration pour les markdown dans vim (pour ma part il est dans `ftplugin/pandoc.vim`):
|
||||
```vim
|
||||
map <raccourcis> :w !pandoc -t html5 -s \| xclip -selection clipboard<cr>
|
||||
map <raccourci> :w !pandoc -t html5 -s \| xclip -selection clipboard<cr>
|
||||
```
|
||||
ou en version plus moderne (lua + wayland):
|
||||
```lua
|
||||
vim.keymap.set('n', <raccourci>, ':w !pandoc -t html5 -s | wl-copy<CR><CR>', { noremap = true, silent = true })
|
||||
```
|
||||
on peut alors directement coller le contenu du *buffer* courant formatée par [pandoc](https://pandoc.org/) dans thunderbird.
|
||||
Bien entendu, vous pouvez décorer cette commande à l’aide de vos options favorites.
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
Title: Write your emails in markdown with vim
|
||||
Date: 2019-04-22 19:00
|
||||
Modified: 2019-04-24 09:35
|
||||
Modified: 2023-10-14 19:00
|
||||
Author: Fabrice
|
||||
Category: tips
|
||||
Tags: emails, pandoc, Vim
|
||||
@ -26,6 +26,10 @@ Therefore, adding:
|
||||
```vim
|
||||
map <your map> :w !pandoc -t html5 -s \| xclip -selection clipboard<cr>
|
||||
```
|
||||
or a more modern version using `lua` and `wayland`:
|
||||
```lua
|
||||
vim.keymap.set('n', <your map>, ':w !pandoc -t html5 -s | wl-copy<CR><CR>', { noremap = true, silent = true })
|
||||
```
|
||||
in your vim `ftplugin/pandoc.vim` configuration file allows you to copy directly the output of [pandoc](https://pandoc.org/) on you opened buffer into your clipboard and thus past it directly into thunderbird.
|
||||
Of course, you can customize this command line as you want. For instance my base-header-level is 4, as I think that first-level titles are a bit too much for emails.
|
||||
You can even use some simple [css rules](https://perfectmotherfuckingwebsite.com/) in a separated style sheet along with the `--self-contained` option of pandoc to be able to do basic general formating (for a newsletter for instance).
|
||||
|
218
content/tips/presenting.md
Normal file
@ -0,0 +1,218 @@
|
||||
---
|
||||
Title: Tools for making and giving presentations
|
||||
Date: 2024-11-03
|
||||
Author: Fabrice
|
||||
Category: Tips
|
||||
Tags: presentation, vim, latex
|
||||
Slug: presenting
|
||||
Header_Cover: ../images/covers/pts24-talk.jpg
|
||||
Summary: Some of the tools I use for making and giving presentations.
|
||||
lang: en
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Over the past year, I have to give quite a few presentations in different
|
||||
contexts: internal to the company, for open-source conferences, for business
|
||||
conferences…
|
||||
|
||||
I used these different opportunities to refine a bit my presentation tools, and
|
||||
I just summarize them here for curious people. Please note that this blog post
|
||||
will only cover the tooling needed to produce slides, not what to put inside.
|
||||
|
||||
This page may be updated, for instance if I start using yet another tool for
|
||||
slide making that I think is worth mentioning. If you have subscribed to this
|
||||
blog’s [RSS feed], you will be notified of future updates.
|
||||
|
||||
# Making Slides
|
||||
|
||||
For slide making, I prefer using tools that separate the content from the actual
|
||||
design. I’m thus not using fancy WYSIWYG tools for that. If you are not
|
||||
interested in that, you can already skip to the [presenting slides] section.
|
||||
|
||||
## LaTeX Beamer
|
||||
|
||||
As explained in the [typst article], I’m mostly using [LaTeX] to produce/typeset
|
||||
documents, and presentations are not an exception. For this purpose I’m using
|
||||
[beamer].
|
||||
|
||||
For this purpose, my [vim setup for LaTeX] proved to be pretty useful,
|
||||
especially with the “compilation on save” feature. It allows me to have an
|
||||
already set up text editor for LaTeX without having to fiddle and twiddle with
|
||||
multiple setups. However, the backward search is not very accurate with beamer
|
||||
slides.
|
||||
|
||||
### Overlays and Graphics
|
||||
|
||||
The main advantage, besides my familiarity with [LaTeX], lays in the [overlay]
|
||||
system in beamer, that is quite powerful and provides a very precise way to
|
||||
display elements. This overlay mechanism also compounds well with [TikZ] to
|
||||
design animated graphics.
|
||||
|
||||
For instance in the example below, I can show the top part of the graph
|
||||
initially, then the bottom, and change the name of the last node for the second
|
||||
slide. That can be easily adjusted to have more steps in the process.
|
||||
|
||||
```latex
|
||||
…
|
||||
\usetikzlibrary{positioning}
|
||||
…
|
||||
\begin{tikzpicture}
|
||||
\tikzstyle{node} = [draw, rectangle, fill=blue!40, minimum height=2em]
|
||||
\tikzstyle{arrow} = [->, >=stealth, very thick]
|
||||
\node[node] (start) {Data};
|
||||
\node[node, right=1cm of start] (a1) {Enc($\cdot$)};
|
||||
\node<2->[node, below=5mm of a1] (a2) {Sig($\cdot$)};
|
||||
\node<1>[node, right=1cm of a1] (stop) {Encrypted Data};
|
||||
\node<2->[node, right=1cm of a1] (stop) {Encrypted and Signed Data};
|
||||
|
||||
\draw[arrow] (start) -- (a1);
|
||||
\draw<2->[arrow] (start) -- (a2);
|
||||
\draw[arrow] (a1) -- (stop);
|
||||
\draw<2->[arrow] (a2) -- (stop);
|
||||
\end{tikzpicture}
|
||||
```
|
||||
|
||||
Resulting in:
|
||||
|
||||
{width=66%}
|
||||
|
||||
Moreover, you have access to the whole latex ecosystem, especially those for
|
||||
neat illustrations such as [tikzpingus].
|
||||
|
||||
**Note:** I feel compelled to say that the above technique is unsafe under fairly
|
||||
reasonable assumptions. Long story short you should sign first *then* encrypt
|
||||
and not do both in parallel. Please see [this paper](https://ia.cr/2001/045)
|
||||
from the Crypto 2001 conference if you want a more detailed explanation.
|
||||
|
||||
### Customisation
|
||||
|
||||
It is also quite easy to customise slides with beamer. For instance, with
|
||||
[metropolis], from its
|
||||
[documentation](https://ctan.tetaneutral.net/macros/latex/contrib/beamer-contrib/themes/metropolis/doc/metropolistheme.pdf),
|
||||
section 8 describes where to find specific colours. As for the fonts, if you are
|
||||
using xelatex/lualatex, a simple `\setmainfont` suffices to redefine it.
|
||||
|
||||
For instance, if I want to have the alert text in orange:
|
||||
|
||||
```latex
|
||||
\setbeamercolor[alerted text]{fg=orange}
|
||||
```
|
||||
|
||||
### Drawbacks
|
||||
|
||||
However, LaTeX starts to slow down quickly, especially with a lot of [TikZ]
|
||||
drawings… On documents, it’s not really an issue as it is possible to cache the
|
||||
drawings with the `externalize` tikz library. However, when mixing overlays and
|
||||
TikZ, it starts to [need some
|
||||
tweaks](https://tex.stackexchange.com/questions/78955/use-tikz-external-feature-with-beamer-only).
|
||||
I never included them in my workflow as they make TikZ drawings more complicated
|
||||
than they are.
|
||||
|
||||
## Typst Touying
|
||||
|
||||
## Pandoc and reveal.js
|
||||
|
||||
[reveal.js] is a javascript framework to produce clean and dynamic slides. My
|
||||
settings to generate them are liberally inspired by [Pablo
|
||||
Coves](https://pcoves.gitlab.io/blog/pandoc-markdown-revealjs/).
|
||||
|
||||
[Pandoc] on the other hand is a document converter tool that supports a very
|
||||
extensive spectrum of formats and syntaxes. My most use case is to convert
|
||||
markdown to some other reflowable format (usually HTML, and sometimes EPUB).
|
||||
|
||||
Using both in conjunction allows for quick and dynamic presentations which don’t
|
||||
require _accuracy_ in placements. That may be the case for lightning talks for
|
||||
instance. The main advantage compared to the two above solutions is that
|
||||
[reveal.js] takes advantage of web browser capabilities to produce dynamic
|
||||
transitions. Those are otherwise hard to get from PDFs (some people made custom
|
||||
PDF reader for that).
|
||||
|
||||
I know that it’s also possible to use [pandoc] to produce directly [beamer] slides
|
||||
for instance, thus benefiting from the simpler [Markdown] syntax while having
|
||||
[LaTeX] as an engine. I however find this approach too rigid. It is indeed easy
|
||||
to feed some LaTeX‑specific commands via the YAML header, e.g., for styling.
|
||||
Unfortunately, when the need arises to do some specific positioning on a slide
|
||||
for example, then we end up with some markdown-TeX mix that I found deeply
|
||||
inelegant. That’s why I usually stick to LaTeX (or more recently [typst]) to
|
||||
produce PDFs, as these tools are designed with an awareness of the page layout
|
||||
(which blends well into the language). This property is not the case with
|
||||
[Markdown], which is a markup language for text formatting (not typesetting).
|
||||
|
||||
### Ease of use
|
||||
|
||||
One nice thing about [pandoc] + [reveal.js] slide making is that, for simple
|
||||
intends and purpose, there are very little structural codes (contrary to
|
||||
[beamer] for instance where you have to define several variables before
|
||||
starting).
|
||||
|
||||
From the following code, you can start making a presentation:
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Example Presentation
|
||||
subtitle: It’s all about presenting
|
||||
author: Fabrice Mouhartem
|
||||
date: 2025-01-29
|
||||
theme: solarized
|
||||
---
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```sh
|
||||
pandoc --standalone -t revealjs -o output.html input.md
|
||||
```
|
||||
|
||||
And that’s all… well, it’s just a title slide and an empty slide, but it’s the
|
||||
beginning of a **wonderful** presentation.
|
||||
|
||||
Then, similarly to [typst] + [touying], a level 1 heading creates a title slide,
|
||||
and a level 2 heading spawns a new content slide. You can also spawn a new slide
|
||||
with three hyphens (`---`).
|
||||
|
||||
### Speaker view
|
||||
|
||||
One of the advantage of [reveal.js] is the built-in [speaker view]. It spans a
|
||||
pop-up with useful pieces of information for the speaker: a chronometer, a preview of the
|
||||
upcoming slide and notes if there are any.
|
||||
|
||||
Its behaviour is similar to what you can have with `pdfpc` that I’ll show later
|
||||
for PDF slides.
|
||||
|
||||

|
||||
|
||||
### Customisation
|
||||
|
||||
- List of default [reveal.js styles]
|
||||
- Simple customisation with CSS:
|
||||
<https://gist.github.com/jsoma/629b9564af5b1e7fa62d0a3a0a47c296#styling> see
|
||||
<https://github.com/hakimel/reveal.js/blob/master/css/theme/template/exposer.scss>
|
||||
as well for exposed variables.
|
||||
- However, in standalone mode, changing the font does not work well…
|
||||
- Create custom theme: <https://github.com/hakimel/reveal.js/blob/master/css/theme/README.md>
|
||||
- <https://github.com/Chouhartem/reveal.js/tree/cryptpad-theme>
|
||||
|
||||
# Presenting Slides {#presenting-slides}
|
||||
|
||||
## wl-mirror
|
||||
|
||||
## pdfpc
|
||||
|
||||
[RSS feed]: /feeds/all.rss.xml
|
||||
[typst]: https://typst.app/
|
||||
[touying]: https://touying-typ.github.io/
|
||||
[typst article]: {filename}../software/typst.md
|
||||
[presenting slides]: #presenting-slides
|
||||
[LaTeX]: https://www.latex-project.org/
|
||||
[beamer]: https://ctan.org/pkg/beamer
|
||||
[vim setup for LaTeX]: {filename}../software/nvim-latex.md
|
||||
[overlay]: https://www.overleaf.com/learn/latex/Beamer_Presentations%3A_A_Tutorial_for_Beginners_(Part_4)%E2%80%94Overlay_Specifications
|
||||
[TikZ]: https://www.ctan.org/pkg/pgf
|
||||
[tikzpingus]: https://github.com/EagleoutIce/tikzpingus
|
||||
[reveal.js]: https://revealjs.com/
|
||||
[reveal.js styles]: https://revealjs.com/themes/
|
||||
[pandoc]: https://pandoc.org/
|
||||
[metropolis]: https://github.com/matze/mtheme
|
||||
[markdown]: https://en.wikipedia.org/wiki/Markdown
|
||||
[speaker view]: https://revealjs.com/speaker-view/
|
@ -45,10 +45,16 @@ Tessen interprète ensuite la réponse de ces outils pour les intégrer avec
|
||||
Après avoir essayé _fuzzel_, je me suis rendu compte que leur algorithme de
|
||||
recherche approximative ne me convenait pas, n'étant pas
|
||||
[fzf](https://github.com/junegunn/fzf) qui est intégré dans pas mal de mes
|
||||
programmes et dont j'ai pris mes habitudes quant à la recherche.
|
||||
programmes et dont j'ai pris mes habitudes quant à la recherche (par exemple
|
||||
pour la complétion dans mon `shell`), ainsi que certains raccourcis assez
|
||||
universels comme `Ctrl-u` pour effacer la ligne en cours.
|
||||
|
||||
J'ai donc décidé d'utiliser `rofi` qui avait l'air de bien fonctionner… mis à
|
||||
part les raccourcis claviers. Mais un aperçu de la page de manuel indique que cela est possible:
|
||||
J'ai donc décidé d'utiliser `rofi` qui avait l'air de bien fonctionner bien
|
||||
qu'il ne se lance via `xwayland` qui n'est pas considéré comme assez pur par
|
||||
certaines personnes.
|
||||
Sauf que les raccourcis claviers spécifiques à `rofi-pass` ne fonctionnent pas
|
||||
par défaut.
|
||||
Cependant un aperçu de la page de manuel indique que cela est possible:
|
||||
|
||||
> If the dmenu program of your choice supports custom keybindings with exit
|
||||
> codes greater than or equal to 10, tessen can execute custom operations on a
|
||||
@ -65,7 +71,7 @@ tombe bien, dans la configuration de rofi, il y a les options
|
||||
[`kb-custom-<n>`](https://github.com/davatorium/rofi/blob/next/doc/rofi-keys.5.markdown#kb-custom-1)
|
||||
qui permettent d’associer la touche ou combinaison de touches à un code d’erreur
|
||||
valant “_9+n_”, `kb-custom-1` correspondant donc à 10 et `kb-custom-9`
|
||||
correspondant à 20 (je précise parce qu'au début j'avais associé un raccourcis à
|
||||
correspondant à 20. Je précise parce qu'au début j'avais associé un raccourcis à
|
||||
`kb-custom-10` en me disant que ça serait associé au code de sortie 10, et donc
|
||||
interprété par tessen comme `auto type username and password ` d'après le
|
||||
manuel… or il n'en était rien. Heureusement que je suis tombé sur un [message sur
|
||||
@ -93,7 +99,9 @@ J'ai d'abord essayé de le rajouter dans la configuration par défaut
|
||||
avec [rofimoji](https://github.com/fdw/rofimoji) qui ne s'est pas gêné pour me
|
||||
le dire.
|
||||
|
||||
Maintenant il ne reste plus qu'à l'intégrer à tessen, ce qui est possible à l'aide du fichier de configuration `$HOME/.config/tessen/config` à l'aide des lignes :
|
||||
Maintenant il ne reste plus qu'à l'intégrer à tessen, ce qui est possible à
|
||||
l'aide du fichier de configuration `$HOME/.config/tessen/config` à l'aide des
|
||||
lignes :
|
||||
|
||||
```sh
|
||||
dmenu_backend="rofi"
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
Title: Rofi's keyboard shortcut for passwordstore on Wayland
|
||||
Date: 2023-07-09 15:00
|
||||
Date: 2023-07-10 12:00
|
||||
Author: Fabrice
|
||||
Category: Tips
|
||||
Tags: pass, rofi, tessen
|
||||
|
@ -32,7 +32,7 @@ TIMEZONE = 'Europe/Paris'
|
||||
|
||||
#LANG
|
||||
DEFAULT_LANG = 'en'
|
||||
LOCALE = 'en_GB.UTF-8'
|
||||
LOCALE = 'en_GB.utf8'
|
||||
DEFAULT_DATE_FORMAT = '%A, %B %d, %Y'
|
||||
I18N_SUBSITES = {
|
||||
'fr': {
|
||||
@ -59,5 +59,5 @@ CATEGORY_SAVE_AS = '{slug}/index.html'
|
||||
CATEGORY_PAGE_PATH= 'categories'
|
||||
|
||||
# Uncomment following line if you want document-relative URLs when developing
|
||||
#RELATIVE_URLS = True
|
||||
# RELATIVE_URLS = True
|
||||
|
||||
|
1
plugins/autopages
Submodule
1
plugins/i18n_subsites
Submodule
@ -15,9 +15,12 @@ RELATIVE_URLS = False
|
||||
|
||||
DELETE_OUTPUT_DIRECTORY = True
|
||||
|
||||
FEED_ALL_ATOM = None
|
||||
FEED_DOMAIN = SITEURL
|
||||
FEED_ALL_ATOM = 'feeds/all.atom.xml'
|
||||
FEED_ALL_RSS = 'feeds/all.rss.xml'
|
||||
CATEGORY_FEED_ATOM = None
|
||||
TRANSLATION_FEED_ATOM = None
|
||||
TRANSLATION_FEED_ATOM = 'feeds/all-{lang}.atom.xml'
|
||||
TRANSLATION_FEED_RSS = 'feeds/all-{lang}.rss.xml'
|
||||
AUTHOR_FEED_ATOM = None
|
||||
AUTHOR_FEED_RSS = None
|
||||
|
||||
|
16
pyproject.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[project]
|
||||
authors = [
|
||||
{name = "Fabrice Mouhartem", email = "chouhartem@epheme.re"},
|
||||
]
|
||||
license = {text = "CC-by-SA"}
|
||||
requires-python = "<4.0,>=3.12"
|
||||
dependencies = [
|
||||
"pelican<5.0.0,>=4.10.1",
|
||||
"markdown<4.0,>=3.7",
|
||||
"invoke<3.0.0,>=2.2.0",
|
||||
"livereload<3.0.0,>=2.7.0",
|
||||
]
|
||||
name = "blog"
|
||||
version = "0.1.0"
|
||||
description = "Personal blog (blog.epheme.re)"
|
||||
readme = "README.md"
|
51
readme.md
@ -1 +1,52 @@
|
||||
This repository contains the sources necessary to build the blog at:
|
||||
<https://blog.epheme.re>
|
||||
|
||||
# Dependencies
|
||||
|
||||
To use this repository as intended, you need, to build the blog, the following
|
||||
software:
|
||||
|
||||
- `git`
|
||||
- `make`
|
||||
- `uv`
|
||||
- `gettext`
|
||||
|
||||
To synchronise the blog remotely with its intended target, the synchronisation
|
||||
is done using `rsync` over `ssh`.
|
||||
|
||||
# Install
|
||||
|
||||
To install a local copy to work on this blog, you also need other components,
|
||||
such as the [theme](https://git.epheme.re/fmouhart/pelican-clean-blog) and
|
||||
[some](https://git.epheme.re/fmouhart/pelican-autopages)
|
||||
[plugins](https://git.epheme.re/fmouhart/pelican-clean-blog). Those are embedded
|
||||
in the repository as a git submodule. You can thus simply run git clone with the
|
||||
`--recurse-submodule` option:
|
||||
|
||||
```sh
|
||||
git clone --recurse-submodule https://git.epheme.re/fmouhart/blog.git fmouhart-blog
|
||||
```
|
||||
|
||||
This blog relies on [pelican](https://getpelican.com) as a static site
|
||||
generator. To manage the different python dependencies of this project, we are
|
||||
using [`uv`](https://github.com/astral-sh/uv) as a python project manager.
|
||||
|
||||
Moreover, translations are managed with python `gettext` which requires
|
||||
compiling the translation file.
|
||||
|
||||
Those two steps are performed with the following command:
|
||||
|
||||
```sh
|
||||
make init
|
||||
```
|
||||
|
||||
# Development
|
||||
|
||||
When writing an article, you can run the blog with `livereload` enabled with the
|
||||
command:
|
||||
|
||||
```sh
|
||||
make dev
|
||||
```
|
||||
|
||||
It’ll span a local development server on port `8000`: <http://localhost:8000>
|
||||
|
150
tasks.py
Normal file
@ -0,0 +1,150 @@
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from invoke import task
|
||||
from invoke.main import program
|
||||
from pelican import main as pelican_main
|
||||
from pelican.server import ComplexHTTPRequestHandler, RootedHTTPServer
|
||||
from pelican.settings import DEFAULT_CONFIG, get_settings_from_file
|
||||
|
||||
OPEN_BROWSER_ON_SERVE = False
|
||||
SETTINGS_FILE_BASE = "pelicanconf.py"
|
||||
SETTINGS = {}
|
||||
SETTINGS.update(DEFAULT_CONFIG)
|
||||
LOCAL_SETTINGS = get_settings_from_file(SETTINGS_FILE_BASE)
|
||||
SETTINGS.update(LOCAL_SETTINGS)
|
||||
|
||||
CONFIG = {
|
||||
"settings_base": SETTINGS_FILE_BASE,
|
||||
"settings_publish": "publishconf.py",
|
||||
# Output path. Can be absolute or relative to tasks.py. Default: 'output'
|
||||
"deploy_path": SETTINGS["OUTPUT_PATH"],
|
||||
# Host and port for `serve`
|
||||
"host": "localhost",
|
||||
"port": 8000,
|
||||
# for publication
|
||||
"ssh_user": "fmouhart",
|
||||
"ssh_host": "blog.epheme.re",
|
||||
"ssh_port": 22,
|
||||
"ssh_path": "/srv/http/blog",
|
||||
}
|
||||
|
||||
|
||||
@task
|
||||
def clean(c):
|
||||
"""Remove generated files"""
|
||||
if os.path.isdir(CONFIG["deploy_path"]):
|
||||
shutil.rmtree(CONFIG["deploy_path"])
|
||||
os.makedirs(CONFIG["deploy_path"])
|
||||
|
||||
|
||||
@task
|
||||
def build(c):
|
||||
"""Build local version of site"""
|
||||
pelican_run("-s {settings_base}".format(**CONFIG))
|
||||
|
||||
|
||||
@task
|
||||
def rebuild(c):
|
||||
"""`build` with the delete switch"""
|
||||
pelican_run("-d -s {settings_base}".format(**CONFIG))
|
||||
|
||||
|
||||
@task
|
||||
def regenerate(c):
|
||||
"""Automatically regenerate site upon file modification"""
|
||||
pelican_run("-r -s {settings_base}".format(**CONFIG))
|
||||
|
||||
|
||||
@task
|
||||
def serve(c):
|
||||
"""Serve site at http://$HOST:$PORT/ (default is localhost:8000)"""
|
||||
|
||||
class AddressReuseTCPServer(RootedHTTPServer):
|
||||
allow_reuse_address = True
|
||||
|
||||
server = AddressReuseTCPServer(
|
||||
CONFIG["deploy_path"],
|
||||
(CONFIG["host"], CONFIG["port"]),
|
||||
ComplexHTTPRequestHandler,
|
||||
)
|
||||
|
||||
if OPEN_BROWSER_ON_SERVE:
|
||||
# Open site in default browser
|
||||
import webbrowser
|
||||
|
||||
webbrowser.open("http://{host}:{port}".format(**CONFIG))
|
||||
|
||||
sys.stderr.write("Serving at {host}:{port} ...\n".format(**CONFIG))
|
||||
server.serve_forever()
|
||||
|
||||
|
||||
@task
|
||||
def reserve(c):
|
||||
"""`build`, then `serve`"""
|
||||
build(c)
|
||||
serve(c)
|
||||
|
||||
|
||||
@task
|
||||
def preview(c):
|
||||
"""Build production version of site"""
|
||||
pelican_run("-s {settings_publish}".format(**CONFIG))
|
||||
|
||||
@task
|
||||
def livereload(c):
|
||||
"""Automatically reload browser tab upon file modification."""
|
||||
from livereload import Server
|
||||
|
||||
def cached_build():
|
||||
cmd = "-s {settings_base} -e CACHE_CONTENT=true LOAD_CONTENT_CACHE=true"
|
||||
pelican_run(cmd.format(**CONFIG))
|
||||
|
||||
cached_build()
|
||||
server = Server()
|
||||
theme_path = SETTINGS["THEME"]
|
||||
watched_globs = [
|
||||
CONFIG["settings_base"],
|
||||
f"{theme_path}/templates/**/*.html",
|
||||
]
|
||||
|
||||
content_file_extensions = [".md", ".rst"]
|
||||
for extension in content_file_extensions:
|
||||
content_glob = "{}/**/*{}".format(SETTINGS["PATH"], extension)
|
||||
watched_globs.append(content_glob)
|
||||
|
||||
static_file_extensions = [".css", ".js"]
|
||||
for extension in static_file_extensions:
|
||||
static_file_glob = f"{theme_path}/static/**/*{extension}"
|
||||
watched_globs.append(static_file_glob)
|
||||
|
||||
for glob in watched_globs:
|
||||
server.watch(glob, cached_build)
|
||||
|
||||
if OPEN_BROWSER_ON_SERVE:
|
||||
# Open site in default browser
|
||||
import webbrowser
|
||||
|
||||
webbrowser.open("http://{host}:{port}".format(**CONFIG))
|
||||
|
||||
server.serve(host=CONFIG["host"], port=CONFIG["port"], root=CONFIG["deploy_path"])
|
||||
|
||||
|
||||
@task
|
||||
def publish(c):
|
||||
"""Publish to production via rsync"""
|
||||
pelican_run("-s {settings_publish}".format(**CONFIG))
|
||||
c.run(
|
||||
'rsync --delete --exclude ".DS_Store" -rv -c '
|
||||
'-e "ssh -p {ssh_port}" '
|
||||
"{} {ssh_user}@{ssh_host}:{ssh_path}".format(
|
||||
CONFIG["deploy_path"].rstrip("/") + "/", **CONFIG
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def pelican_run(cmd):
|
||||
cmd += " " + program.core.remainder # allows to pass-through args to pelican
|
||||
pelican_main(shlex.split(cmd))
|
348
uv.lock
generated
Normal file
@ -0,0 +1,348 @@
|
||||
version = 1
|
||||
requires-python = ">=3.12, <4.0"
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.8.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blinker"
|
||||
version = "1.9.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blog"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "invoke" },
|
||||
{ name = "livereload" },
|
||||
{ name = "markdown" },
|
||||
{ name = "pelican" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "invoke", specifier = ">=2.2.0,<3.0.0" },
|
||||
{ name = "livereload", specifier = ">=2.7.0,<3.0.0" },
|
||||
{ name = "markdown", specifier = ">=3.7,<4.0" },
|
||||
{ name = "pelican", specifier = ">=4.10.1,<5.0.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "docutils"
|
||||
version = "0.21.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "feedgenerator"
|
||||
version = "2.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pytz" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5e/4e/0efde53652edbae3f86c0ec67260bb53287edc67033ac8d00fe08cd02557/feedgenerator-2.1.0.tar.gz", hash = "sha256:f075f23f28fd227f097c36b212161c6cf012e1c6caaf7ff53d5d6bb02cd42b9d", size = 20682 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/a1/b7b1711d9bf43c3795366431633ab6ba6942744243aad809272ebfa59b39/feedgenerator-2.1.0-py3-none-any.whl", hash = "sha256:93b7ce1c5a86195cafd6a8e9baf6a2a863ebd6d9905e840ce5778f73efd9a8d5", size = 21796 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "invoke"
|
||||
version = "2.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f9/42/127e6d792884ab860defc3f4d80a8f9812e48ace584ffc5a346de58cdc6c/invoke-2.2.0.tar.gz", hash = "sha256:ee6cbb101af1a859c7fe84f2a264c059020b0cb7fe3535f9424300ab568f6bd5", size = 299835 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/66/7f8c48009c72d73bc6bbe6eb87ac838d6a526146f7dab14af671121eb379/invoke-2.2.0-py3-none-any.whl", hash = "sha256:6ea924cc53d4f78e3d98bc436b08069a03077e6f85ad1ddaa8a116d7dad15820", size = 160274 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jinja2"
|
||||
version = "3.1.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markupsafe" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "livereload"
|
||||
version = "2.7.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "tornado" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/43/6e/f2748665839812a9bbe5c75d3f983edbf3ab05fa5cd2f7c2f36fffdf65bd/livereload-2.7.1.tar.gz", hash = "sha256:3d9bf7c05673df06e32bea23b494b8d36ca6d10f7d5c3c8a6989608c09c986a9", size = 22255 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e4/3e/de54dc7f199e85e6ca37e2e5dae2ec3bce2151e9e28f8eb9076d71e83d56/livereload-2.7.1-py3-none-any.whl", hash = "sha256:5201740078c1b9433f4b2ba22cd2729a39b9d0ec0a2cc6b4d3df257df5ad0564", size = 22657 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown"
|
||||
version = "3.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/54/28/3af612670f82f4c056911fbbbb42760255801b3068c48de792d354ff4472/markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2", size = 357086 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "3.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mdurl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markupsafe"
|
||||
version = "3.0.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 },
|
||||
{ url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 },
|
||||
{ url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 },
|
||||
{ url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 },
|
||||
{ url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 },
|
||||
{ url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-set"
|
||||
version = "4.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4c/ca/bfac8bc689799bcca4157e0e0ced07e70ce125193fc2e166d2e685b7e2fe/ordered-set-4.1.0.tar.gz", hash = "sha256:694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8", size = 12826 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/33/55/af02708f230eb77084a299d7b08175cff006dea4f2721074b92cdb0296c0/ordered_set-4.1.0-py3-none-any.whl", hash = "sha256:046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562", size = 7634 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pelican"
|
||||
version = "4.11.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "blinker" },
|
||||
{ name = "docutils" },
|
||||
{ name = "feedgenerator" },
|
||||
{ name = "jinja2" },
|
||||
{ name = "ordered-set" },
|
||||
{ name = "pygments" },
|
||||
{ name = "python-dateutil" },
|
||||
{ name = "rich" },
|
||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||
{ name = "unidecode" },
|
||||
{ name = "watchfiles" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/27/42/c06c1a7a3136729ece5a1f98544ede83edd593b3cd9110c9ad61bcc7f4dd/pelican-4.11.0.tar.gz", hash = "sha256:b90234487b818d391733acc1306b785934009749b1fc112b879df9bd89478bd8", size = 24148058 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/79/32/01df483f255438e792771b11ebe804af15957739e88673ca95c89289c0f4/pelican-4.11.0-py3-none-any.whl", hash = "sha256:aca6993f6b8a03a20f6828471089cb0504a4dca71e0d30b341fa80ab65668fa4", size = 24127868 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.18.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.9.0.post0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "six" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2024.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3a/31/3c70bf7603cc2dca0f19bdc53b4537a797747a58875b552c8c413d963a3f/pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", size = 319692 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/11/c3/005fcca25ce078d2cc29fd559379817424e94885510568bc1bc53d7d5846/pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725", size = 508002 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.9.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.17.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tornado"
|
||||
version = "6.4.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/59/45/a0daf161f7d6f36c3ea5fc0c2de619746cc3dd4c76402e9db545bd920f63/tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b", size = 501135 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/26/7e/71f604d8cea1b58f82ba3590290b66da1e72d840aeb37e0d5f7291bd30db/tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1", size = 436299 },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/44/87543a3b99016d0bf54fdaab30d24bf0af2e848f1d13d34a3a5380aabe16/tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803", size = 434253 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/fb/fdf679b4ce51bcb7210801ef4f11fdac96e9885daa402861751353beea6e/tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec", size = 437602 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/3b/e31aeffffc22b475a64dbeb273026a21b5b566f74dee48742817626c47dc/tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946", size = 436972 },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/55/b78a464de78051a30599ceb6983b01d8f732e6f69bf37b4ed07f642ac0fc/tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf", size = 437173 },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/5e/be4fb0d1684eb822c9a62fb18a3e44a06188f78aa466b2ad991d2ee31104/tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634", size = 437892 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f5/33/4f91fdd94ea36e1d796147003b490fe60a0215ac5737b6f9c65e160d4fe0/tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73", size = 437334 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/ae/c1b22d4524b0e10da2f29a176fb2890386f7bd1f63aacf186444873a88a0/tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c", size = 437261 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b5/25/36dbd49ab6d179bcfc4c6c093a51795a4f3bed380543a8242ac3517a1751/tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482", size = 438463 },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/cc/58b1adeb1bb46228442081e746fcdbc4540905c87e8add7c277540934edb/tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", size = 438907 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.12.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2025.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/43/0f/fa4723f22942480be4ca9527bbde8d43f6c3f2fe8412f00e7f5f6746bc8b/tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", size = 194950 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/dd/84f10e23edd882c6f968c21c2434fe67bd4a528967067515feca9e611e5e/tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639", size = 346762 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unidecode"
|
||||
version = "1.3.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "watchfiles"
|
||||
version = "1.0.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f5/26/c705fc77d0a9ecdb9b66f1e2976d95b81df3cae518967431e7dbf9b5e219/watchfiles-1.0.4.tar.gz", hash = "sha256:6ba473efd11062d73e4f00c2b730255f9c1bdd73cd5f9fe5b5da8dbd4a717205", size = 94625 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5b/1a/8f4d9a1461709756ace48c98f07772bc6d4519b1e48b5fa24a4061216256/watchfiles-1.0.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:229e6ec880eca20e0ba2f7e2249c85bae1999d330161f45c78d160832e026ee2", size = 391345 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/d2/6750b7b3527b1cdaa33731438432e7238a6c6c40a9924049e4cebfa40805/watchfiles-1.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5717021b199e8353782dce03bd8a8f64438832b84e2885c4a645f9723bf656d9", size = 381515 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4e/17/80500e42363deef1e4b4818729ed939aaddc56f82f4e72b2508729dd3c6b/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0799ae68dfa95136dde7c472525700bd48777875a4abb2ee454e3ab18e9fc712", size = 449767 },
|
||||
{ url = "https://files.pythonhosted.org/packages/10/37/1427fa4cfa09adbe04b1e97bced19a29a3462cc64c78630787b613a23f18/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43b168bba889886b62edb0397cab5b6490ffb656ee2fcb22dec8bfeb371a9e12", size = 455677 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c5/7a/39e9397f3a19cb549a7d380412fd9e507d4854eddc0700bfad10ef6d4dba/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb2c46e275fbb9f0c92e7654b231543c7bbfa1df07cdc4b99fa73bedfde5c844", size = 482219 },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/2d/7113931a77e2ea4436cad0c1690c09a40a7f31d366f79c6f0a5bc7a4f6d5/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:857f5fc3aa027ff5e57047da93f96e908a35fe602d24f5e5d8ce64bf1f2fc733", size = 518830 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/1b/50733b1980fa81ef3c70388a546481ae5fa4c2080040100cd7bf3bf7b321/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55ccfd27c497b228581e2838d4386301227fc0cb47f5a12923ec2fe4f97b95af", size = 497997 },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/b4/9396cc61b948ef18943e7c85ecfa64cf940c88977d882da57147f62b34b1/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c11ea22304d17d4385067588123658e9f23159225a27b983f343fcffc3e796a", size = 452249 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/69/0c65a5a29e057ad0dc691c2fa6c23b2983c7dabaa190ba553b29ac84c3cc/watchfiles-1.0.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:74cb3ca19a740be4caa18f238298b9d472c850f7b2ed89f396c00a4c97e2d9ff", size = 614412 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/b9/319fcba6eba5fad34327d7ce16a6b163b39741016b1996f4a3c96b8dd0e1/watchfiles-1.0.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7cce76c138a91e720d1df54014a047e680b652336e1b73b8e3ff3158e05061e", size = 611982 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/47/143c92418e30cb9348a4387bfa149c8e0e404a7c5b0585d46d2f7031b4b9/watchfiles-1.0.4-cp312-cp312-win32.whl", hash = "sha256:b045c800d55bc7e2cadd47f45a97c7b29f70f08a7c2fa13241905010a5493f94", size = 271822 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/94/b0165481bff99a64b29e46e07ac2e0df9f7a957ef13bec4ceab8515f44e3/watchfiles-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:c2acfa49dd0ad0bf2a9c0bb9a985af02e89345a7189be1efc6baa085e0f72d7c", size = 285441 },
|
||||
{ url = "https://files.pythonhosted.org/packages/11/de/09fe56317d582742d7ca8c2ca7b52a85927ebb50678d9b0fa8194658f536/watchfiles-1.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:22bb55a7c9e564e763ea06c7acea24fc5d2ee5dfc5dafc5cfbedfe58505e9f90", size = 277141 },
|
||||
{ url = "https://files.pythonhosted.org/packages/08/98/f03efabec64b5b1fa58c0daab25c68ef815b0f320e54adcacd0d6847c339/watchfiles-1.0.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:8012bd820c380c3d3db8435e8cf7592260257b378b649154a7948a663b5f84e9", size = 390954 },
|
||||
{ url = "https://files.pythonhosted.org/packages/16/09/4dd49ba0a32a45813debe5fb3897955541351ee8142f586303b271a02b40/watchfiles-1.0.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa216f87594f951c17511efe5912808dfcc4befa464ab17c98d387830ce07b60", size = 381133 },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/59/5aa6fc93553cd8d8ee75c6247763d77c02631aed21551a97d94998bf1dae/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c9953cf85529c05b24705639ffa390f78c26449e15ec34d5339e8108c7c407", size = 449516 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/aa/df4b6fe14b6317290b91335b23c96b488d365d65549587434817e06895ea/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cf684aa9bba4cd95ecb62c822a56de54e3ae0598c1a7f2065d51e24637a3c5d", size = 454820 },
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/71/185f8672f1094ce48af33252c73e39b48be93b761273872d9312087245f6/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f44a39aee3cbb9b825285ff979ab887a25c5d336e5ec3574f1506a4671556a8d", size = 481550 },
|
||||
{ url = "https://files.pythonhosted.org/packages/85/d7/50ebba2c426ef1a5cb17f02158222911a2e005d401caf5d911bfca58f4c4/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38320582736922be8c865d46520c043bff350956dfc9fbaee3b2df4e1740a4b", size = 518647 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/7a/4c009342e393c545d68987e8010b937f72f47937731225b2b29b7231428f/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39f4914548b818540ef21fd22447a63e7be6e24b43a70f7642d21f1e73371590", size = 497547 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/7c/1cf50b35412d5c72d63b2bf9a4fffee2e1549a245924960dd087eb6a6de4/watchfiles-1.0.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f12969a3765909cf5dc1e50b2436eb2c0e676a3c75773ab8cc3aa6175c16e902", size = 452179 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/a9/3db1410e1c1413735a9a472380e4f431ad9a9e81711cda2aaf02b7f62693/watchfiles-1.0.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0986902677a1a5e6212d0c49b319aad9cc48da4bd967f86a11bde96ad9676ca1", size = 614125 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/e1/0025d365cf6248c4d1ee4c3d2e3d373bdd3f6aff78ba4298f97b4fad2740/watchfiles-1.0.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:308ac265c56f936636e3b0e3f59e059a40003c655228c131e1ad439957592303", size = 611911 },
|
||||
{ url = "https://files.pythonhosted.org/packages/55/55/035838277d8c98fc8c917ac9beeb0cd6c59d675dc2421df5f9fcf44a0070/watchfiles-1.0.4-cp313-cp313-win32.whl", hash = "sha256:aee397456a29b492c20fda2d8961e1ffb266223625346ace14e4b6d861ba9c80", size = 271152 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f0/e5/96b8e55271685ddbadc50ce8bc53aa2dff278fb7ac4c2e473df890def2dc/watchfiles-1.0.4-cp313-cp313-win_amd64.whl", hash = "sha256:d6097538b0ae5c1b88c3b55afa245a66793a8fec7ada6755322e465fb1a0e8cc", size = 285216 },
|
||||
]
|