summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquentin@aristote.fr <quentin@aristote.fr>2023-08-21 11:36:24 +0200
committerquentin@aristote.fr <quentin@aristote.fr>2023-08-21 17:44:49 +0200
commit731a43a83e2e2b61d11c5ac33fe96f92cef41bb5 (patch)
treeea32a6c6ae5c036cab7b390543f9cb71e9444095
initial commit
-rw-r--r--.gitignore317
-rw-r--r--default.nix33
-rw-r--r--flake.lock82
-rw-r--r--flake.nix49
-rw-r--r--lib/default.nix5
-rw-r--r--lib/latex.nix133
-rw-r--r--src/default.nix22
-rw-r--r--src/education/default.nix21
-rw-r--r--src/experience/default.nix22
-rw-r--r--src/header.tex10
-rw-r--r--src/languages/default.nix22
-rw-r--r--src/publications/default.nix19
-rw-r--r--src/sections.nix15
13 files changed, 750 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b08f2b0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,317 @@
+# Created by https://www.toptal.com/developers/gitignore/api/latex
+# Edit at https://www.toptal.com/developers/gitignore?templates=latex
+
+### LaTeX ###
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+.*.lb
+
+## Intermediate documents:
+*.dvi
+*.xdv
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+# *.eps
+*.pdf
+
+## Generated if empty string is given at "Please type another file name for output:"
+.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex(busy)
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Build tool directories for auxiliary files
+# latexrun
+latex.out/
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.pre
+*.snm
+*.vrb
+
+# changes
+*.soc
+
+# comment
+*.cut
+
+# cprotect
+*.cpt
+
+# elsarticle (documentclass of Elsevier journals)
+*.spl
+
+# endnotes
+*.ent
+
+# fixme
+*.lox
+
+# feynmf/feynmp
+*.mf
+*.mp
+*.t[1-9]
+*.t[1-9][0-9]
+*.tfm
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+*.lzo
+*.lzs
+*.slg
+*.slo
+*.sls
+
+# uncomment this for glossaries-extra (will ignore makeindex's style files!)
+# *.ist
+
+# gnuplot
+*.gnuplot
+*.table
+
+# gnuplottex
+*-gnuplottex-*
+
+# gregoriotex
+*.gaux
+*.glog
+*.gtex
+
+# htlatex
+*.4ct
+*.4tc
+*.idv
+*.lg
+*.trc
+*.xref
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
+# *.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# luatexja-ruby
+*.ltjruby
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc[0-9]*
+*.slf[0-9]*
+*.slt[0-9]*
+*.stc[0-9]*
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# newpax
+*.newpax
+
+# nomencl
+*.nlg
+*.nlo
+*.nls
+
+# pax
+*.pax
+
+# pdfpcnotes
+*.pdfpc
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# scrwfile
+*.wrt
+
+# svg
+svg-inkscape/
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# tcolorbox
+*.listing
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# titletoc
+*.ptc
+
+# todonotes
+*.tdo
+
+# vhistory
+*.hst
+*.ver
+
+# easy-todo
+*.lod
+
+# xcolor
+*.xcp
+
+# xmpincl
+*.xmpi
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices and outlines
+*.xyc
+*.xyd
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# LyX
+*.lyx~
+
+# Kile
+*.backup
+
+# gummi
+.*.swp
+
+# KBibTeX
+*~[0-9]*
+
+# TeXnicCenter
+*.tps
+
+# auto folder when using emacs and auctex
+./auto/*
+*.el
+
+# expex forward references with \gathertags
+*-tags.tex
+
+# standalone packages
+*.sta
+
+# Makeindex log files
+*.lpz
+
+# xwatermark package
+*.xwm
+
+# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
+# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
+# Uncomment the next line to have this generated file ignored.
+#*Notes.bib
+
+### LaTeX Patch ###
+# LIPIcs / OASIcs
+*.vtc
+
+# glossaries
+*.glstex
+
+# End of https://www.toptal.com/developers/gitignore/api/latex
+
+### Nix ###
+result* \ No newline at end of file
diff --git a/default.nix b/default.nix
new file mode 100644
index 0000000..6385c9d
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,33 @@
+{ pkgs, latex, data }:
+
+let
+ commonArgs = {
+ inherit data latex make;
+ inherit (pkgs) lib;
+ };
+ make = path: overrides:
+ let f = import path;
+ in f ((builtins.intersectAttrs (builtins.functionArgs f) commonArgs)
+ // overrides);
+
+ cvTEX = builtins.toFile "cv.tex" (make ./src { });
+ source = pkgs.callPackage ({ noto-fonts-emoji,
+ # Source files
+ cv-tex ? cvTEX, files ? data.files }:
+ pkgs.runCommand "cv-src" { } ''
+ mkdir -p "$out" && cd $_
+ ln -sT ${cv-tex} cv.tex
+ ln -sT ${files} files
+ ln -sT ${noto-fonts-emoji}/share/fonts/noto fonts
+ '') { };
+in {
+ src = source;
+ pdf = pkgs.callPackage ({ cv-src ? source, texlive }:
+ pkgs.runCommand "cv.pdf" {
+ buildInputs = [ texlive.combined.moderncv ];
+ } ''
+ export HOME=$(pwd)
+ latexmk -pdflua -cd "${cv-src}"/cv.tex --output-directory=$(pwd)
+ mv cv.pdf "$out"
+ '') { };
+}
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..6e87763
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,82 @@
+{
+ "nodes": {
+ "data": {
+ "inputs": {
+ "flake-utils": [
+ "flake-utils"
+ ],
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1692544293,
+ "narHash": "sha256-H/uRnMyKwoqI+KBFy40HFn5vnJXKD2bjYSeIICeS23Y=",
+ "owner": "qaristote",
+ "repo": "info",
+ "rev": "1b58988cc70068e43c479809f3b3fa34bc5ff11d",
+ "type": "github"
+ },
+ "original": {
+ "owner": "qaristote",
+ "repo": "info",
+ "type": "github"
+ }
+ },
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1689068808,
+ "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
+ "type": "github"
+ },
+ "original": {
+ "id": "flake-utils",
+ "type": "indirect"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1692494774,
+ "narHash": "sha256-noGVoOTyZ2Kr5OFglzKYOX48cx3hggdCPbXrYMG2FDw=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "3476a10478587dec90acb14ec6bde0966c545cc0",
+ "type": "github"
+ },
+ "original": {
+ "id": "nixpkgs",
+ "type": "indirect"
+ }
+ },
+ "root": {
+ "inputs": {
+ "data": "data",
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..9d25023
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,49 @@
+{
+ description = "Quentin Aristote's CV.";
+
+ inputs = {
+ data = {
+ # url = "github:qaristote/info";
+ url = "github:qaristote/info";
+ inputs = {
+ nixpkgs.follows = "/nixpkgs";
+ flake-utils.follows = "/flake-utils";
+ };
+ };
+ };
+
+ outputs = { self, nixpkgs, flake-utils, data }:
+ {
+ lib = import ./lib { inherit (nixpkgs) lib; };
+ } // flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = import nixpkgs {
+ inherit system;
+ overlays = [
+ (self: super: {
+ texlive = super.lib.recursiveUpdate super.texlive {
+ combined.moderncv = super.texlive.combine {
+ inherit (super.texlive)
+ scheme-basic biber biblatex latexmk luatex luatexbase
+ moderncv fontspec fontawesome5 academicons pgf multirow
+ arydshln emoji;
+ };
+ };
+ })
+ ];
+ };
+ in {
+ packages = {
+ texlive.combined.moderncv = pkgs.texlive.combined.moderncv;
+ cv = import ./default.nix {
+ inherit pkgs;
+ inherit (self.lib.pp) latex;
+ data = data.formatWith."${system}" self.lib.pp.latex;
+ };
+ };
+ defaultPackage = self.packages."${system}".cv.pdf;
+ devShell = pkgs.mkShell {
+ packages = with pkgs; [ nixfmt texlive.combined.moderncv ];
+ };
+ });
+}
diff --git a/lib/default.nix b/lib/default.nix
new file mode 100644
index 0000000..57653ad
--- /dev/null
+++ b/lib/default.nix
@@ -0,0 +1,5 @@
+{ lib }:
+
+{
+ pp.latex = import ./latex.nix { inherit lib; };
+}
diff --git a/lib/latex.nix b/lib/latex.nix
new file mode 100644
index 0000000..99cd783
--- /dev/null
+++ b/lib/latex.nix
@@ -0,0 +1,133 @@
+{ lib, ... }:
+
+let
+ lines = content:
+ if lib.isList content then
+ (if content == [ ] then
+ ""
+ else
+ lines (builtins.head content) + "\n" + lines (builtins.tail content))
+ else
+ content;
+ sortByFun = cmp: f: lib.sort (x: y: cmp (f x) (f y));
+ sortByPath = cmp: keys: sortByFun cmp (lib.getAttrFromPath keys);
+ sortByKey = cmp: key: sortByPath cmp [ key ];
+ for = iterable: f:
+ if lib.isList iterable then
+ builtins.map f iterable
+ else
+ lib.mapAttrsToList f iterable;
+
+ tryOverride = f: arg:
+ if lib.isAttrs arg then
+ tryOverride (attrs: content: f (arg // attrs) content)
+ else
+ f { } arg;
+
+ setOptionalArg = name: value: "${name}=${value}";
+ expandArgsPrefixed = numArgs: prefix:
+ if numArgs <= 0 then
+ prefix
+ else
+ arg:
+ let
+ appendToPrefix = if lib.isAttrs arg then
+ "[" + lib.concatStringsSep "," (lib.mapAttrsToList setOptionalArg arg)
+ + "]"
+ else
+ "{${arg}}";
+ newNumArgs = if lib.isAttrs arg then numArgs else numArgs - 1;
+ in expandArgsPrefixed newNumArgs (prefix + appendToPrefix);
+ macroWithOpts = name: numArgs: expandArgsPrefixed numArgs "\\${name}";
+ macro = name: content:
+ let
+ contentExpanded = if lib.isList content then
+ lib.concatStringsSep "}{" content
+ else
+ content;
+ in "\\${name}{${contentExpanded}}";
+ sectionMacro = type: name: content: ''
+ \${type}{${name}}
+
+ ${lines content}
+ '';
+ environment = name: content: ''
+ \begin{${name}}
+ ${lines content}
+ \end{${name}}
+ '';
+
+ latex = {
+ inherit macro environment;
+
+ comment = content: "% ${content}";
+ document = environment "document";
+ section = sectionMacro "section";
+
+ title = macroWithOpts "title" 1;
+
+ url = macroWithOpts "url" 1;
+ href = macroWithOpts "href" 2;
+ bold = macroWithOpts "textbf" 1;
+
+ cite = macroWithOpts "cite" 1;
+ moderncv = {
+ name = macroWithOpts "name" 2;
+ email = macroWithOpts "email" 1;
+ extrainfo = macroWithOpts "extrainfo" 1;
+ photo = macroWithOpts "photo" 1;
+ makecvtitle = macro "makecvtitle" [ ];
+ cventry = macroWithOpts "cventry" 6;
+ cvlistitem = macroWithOpts "cvlistitem" 1;
+ cvline = macroWithOpts "cvline" 2;
+ cvitemwithcomment = macroWithOpts "cvitemwithcomment" 3;
+ cvdoubleitem = macroWithOpts "cvdoubleitem" 4;
+ };
+ };
+
+ file = path: "files/${path}";
+ href = latex.href;
+ timerange = startdate: enddate:
+ let
+ print = builtins.mapAttrs (name: x: builtins.toString x);
+ # let str = builtins.toString x;
+ # in if name == "year" then
+ # builtins.substring 2 4 str
+ # else
+ # (if name == "month" && x < 10 then "0${str}" else str));
+ start = print startdate;
+ end = print enddate;
+ months = {
+ "1" = "jan";
+ "2" = "feb";
+ "3" = "mar";
+ "4" = "apr";
+ "5" = "may";
+ "6" = "jun";
+ "7" = "jul";
+ "8" = "aug";
+ "9" = "sep";
+ "10" = "oct";
+ "11" = "nov";
+ "12" = "dec";
+ };
+ in "${months."${start.month}"}."
+ + lib.optionalString (start.year != end.year) " ${start.year}"
+ + " -- ${months."${end.month}"}. ${end.year}";
+in latex // {
+ inherit for file href lines timerange;
+ code = x: x;
+ sort = let
+ lt = x: y: x < y;
+ gt = x: y: x > y;
+ in {
+ byKey = sortByKey lt;
+ byPath = sortByPath lt;
+ byFun = sortByFun lt;
+ reverse = {
+ byKey = sortByKey gt;
+ byPath = sortByPath gt;
+ byFun = sortByFun gt;
+ };
+ };
+}
diff --git a/src/default.nix b/src/default.nix
new file mode 100644
index 0000000..421367b
--- /dev/null
+++ b/src/default.nix
@@ -0,0 +1,22 @@
+{ latex, data, make, ... }:
+
+with latex;
+let sections = sort.byKey "priority" (make ./sections.nix { });
+in with data.basics;
+lines [
+ (builtins.readFile ./header.tex)
+ (comment "-------------------- EXTRA --------------------")
+ (for sections (section: section.extraHeader))
+ (comment "-------------------- DATA --------------------")
+ (moderncv.name name.first name.last)
+ (moderncv.email email.personal)
+ (moderncv.extrainfo (latex.url url))
+ (moderncv.photo { "" = "128pt"; } avatar)
+ ""
+ (document [
+ (title institution.position)
+ moderncv.makecvtitle
+ description
+ (for sections (section: section.content))
+ ])
+]
diff --git a/src/education/default.nix b/src/education/default.nix
new file mode 100644
index 0000000..5b79323
--- /dev/null
+++ b/src/education/default.nix
@@ -0,0 +1,21 @@
+{ latex, data, lib, ... }:
+
+let
+ education = data.education;
+ sortByStartDate = latex.sort.reverse.byFun
+ (x: with x.date.start; day + 100 * month + 10000 * year);
+in {
+ title = "Education";
+ priority = 10;
+ content = with latex;
+ for (sortByStartDate education) (item:
+ with item;
+ [
+ (moderncv.cventry (latex.timerange date.start date.end) studyType
+ (with institution; href url name) institution.location "" description)
+ ] ++ lib.optional (item ? "years") (for (sortByStartDate years) (year:
+ with year;
+ moderncv.cvlistitem "${with program; bold (href url acronym)} (${
+ timerange date.start date.end
+ }). ${program.studyType}. {\\small ${description}}")));
+}
diff --git a/src/experience/default.nix b/src/experience/default.nix
new file mode 100644
index 0000000..500fd9e
--- /dev/null
+++ b/src/experience/default.nix
@@ -0,0 +1,22 @@
+{ latex, data, lib, ... }:
+
+let experience = data.experience;
+in {
+ title = "Experience";
+ priority = 0;
+ content = with latex;
+ for
+ (sort.reverse.byFun (x: with x.date.start; day + 100 * month + 10000 * year)
+ experience) (item:
+ with item;
+ moderncv.cventry (latex.timerange date.start date.end)
+ institution.position (with institution; href url name)
+ institution.location (if item ? supervisors then
+ "supervised by " + lib.concatStringsSep " \\& "
+ (for supervisors (supervisor: with supervisor; href url name))
+ else
+ "") (description + lib.optionalString (item ? assets) (" " + cite
+ (lib.concatStringsSep ","
+ (for (lib.filter (asset: asset.type == "Publications") assets)
+ (lib.getAttr "id"))))));
+}
diff --git a/src/header.tex b/src/header.tex
new file mode 100644
index 0000000..487888d
--- /dev/null
+++ b/src/header.tex
@@ -0,0 +1,10 @@
+\documentclass[11pt, a4paper, sans, colorlinks = True, citecolor = blue,
+urlcolor = blue]{moderncv}
+
+% --------------------- STYLE --------------------
+\moderncvstyle{casual}
+\moderncvcolor{green}
+\nopagenumbers{}
+
+% -------------------- MARGINS --------------------
+\usepackage[scale=0.75]{geometry}
diff --git a/src/languages/default.nix b/src/languages/default.nix
new file mode 100644
index 0000000..d030818
--- /dev/null
+++ b/src/languages/default.nix
@@ -0,0 +1,22 @@
+{ latex, data, lib, ... }:
+
+let
+ languages = data.languages;
+ sortByProficiency = lib.sort (lang1: lang2:
+ let
+ prof1 = lang1.proficiency;
+ prof2 = lang2.proficiency;
+ in (prof2 == "basic") || (prof1 == "native")
+ || (prof2 == "intermediate" && prof1 == "fluent"));
+in {
+ title = "Languages";
+ priority = 20;
+ extraHeader = ''
+ \usepackage{emoji}
+ \setemojifont{NotoColorEmoji.ttf}[Path=./fonts/]
+ '';
+ content = with latex;
+ for (sortByProficiency languages) (lang:
+ with lang;
+ moderncv.cvline "${name} \\emoji{${icon.shortcode}}" proficiency);
+}
diff --git a/src/publications/default.nix b/src/publications/default.nix
new file mode 100644
index 0000000..1d6232e
--- /dev/null
+++ b/src/publications/default.nix
@@ -0,0 +1,19 @@
+{ latex, data, lib, ... }:
+
+let
+ publications = data.publications;
+ publicationsBIB = builtins.toFile "publications.bib" (latex.lines
+ (builtins.map (entry: entry.cite.biblatex)
+ (latex.sort.reverse.byPath [ "issued" "date-parts" ] publications)));
+in {
+ title = "Publications";
+ priority = 30;
+ extraHeader = ''
+ \usepackage[sorting=ydnt]{biblatex}
+ \addbibresource{${publicationsBIB}}
+ '';
+ content = ''
+ \nocite{*}
+ \printbibliography[heading=none]
+ '';
+}
diff --git a/src/sections.nix b/src/sections.nix
new file mode 100644
index 0000000..faed484
--- /dev/null
+++ b/src/sections.nix
@@ -0,0 +1,15 @@
+{ latex, make, ... }:
+
+let
+ sectionTemplate = section: {
+ inherit (section) title priority;
+ extraHeader = if section ? extraHeader then section.extraHeader else "";
+ content = latex.section section.title section.content;
+ };
+ makeSection = path: sectionTemplate (make path { });
+in builtins.map makeSection [
+ ./experience
+ ./education
+ ./languages
+ ./publications
+]