Compare commits
1 commit
main
...
ieeeeqnarr
Author | SHA1 | Date | |
---|---|---|---|
5d87d32087 |
31 changed files with 324 additions and 127 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,4 +4,3 @@ scripts/test.py
|
||||||
scripts/.idea
|
scripts/.idea
|
||||||
scripts/credentials.json
|
scripts/credentials.json
|
||||||
scripts/token.pickle
|
scripts/token.pickle
|
||||||
__pycache__
|
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -23,7 +23,7 @@ SOFTWARE.
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021,2022 Maximilian Keßler
|
Copyright (c) 2021 Maximilian Keßler
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
16
Makefile
16
Makefile
|
@ -1,16 +0,0 @@
|
||||||
PKGNAME=university-setup
|
|
||||||
PREFIX=mkessler
|
|
||||||
|
|
||||||
install:
|
|
||||||
mkdir -p $(DESTDIR)/opt/$(PREFIX)/${PKGNAME}
|
|
||||||
mkdir -p $(DESTDIR)/etc/opt/$(PREFIX)/${PKGNAME}
|
|
||||||
|
|
||||||
cp src/* $(DESTDIR)/opt/$(PREFIX)/${PKGNAME}
|
|
||||||
cp config/* $(DESTDIR)/etc/opt/$(PREFIX)/${PKGNAME}
|
|
||||||
|
|
||||||
install -Dm644 "LICENSE" $(DESTDIR)/usr/share/licenses/$(PREFIX)/${PKGNAME}/LICENSE
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
rm -rf $(DESTDIR)/opt/$(PREFIX)/${PKGNAME}
|
|
||||||
rm -rf $(DESTDIR)/etc/opt/$(PREFIX)/${PKGNAME}
|
|
||||||
rm -rf $(DESTDIR)/usr/share//licenses/$(PREFIX)/${PKGNAME}
|
|
15
README.md
15
README.md
|
@ -1,16 +1,9 @@
|
||||||
# Fork
|
# Fork
|
||||||
|
|
||||||
This fork of [gillescastell/university-setup][setup] contains my personal customatizations to the setup Gilles uses. The main point is that the `info.yaml` file now contains options for specifying the subfolders for the notes, as well as subfolders for the lectures. This helps me re-use the `current_course` directory for other data as well (e.g. my exercise sheets) while having a single dedicated folder for my lecture notes. It is implemented with an additional `Notes` class that handles this. Possibly, one can extend this to e.g. an `Exercises` class that one can add to each course etc.
|
This fork contains my personal customatizations to the setup Gilles uses. The main point is that the `info.yaml` file now contains options for specifying the subfolders for the notes, as well as subfolders for the lectures. This helps me re-use the `current_course` directory for other data as well (e.g. my exercise sheets) while having a single dedicated folder for my lecture notes. It is implemented with an additional `Notes` class that handles this. Possibly, one can extend this to e.g. an `Exercises` class that one can add to each course etc.
|
||||||
|
|
||||||
Additionally, this version features a `.courseignore` file you can place in the `ROOT` folder to ignore some directories for the courses.
|
Additionally, this version features a `.courseignore` file you can place in the `ROOT` folder to ignore some directories for the courses.
|
||||||
|
|
||||||
|
|
||||||
##
|
|
||||||
If you want to install this, run `make install` on your favourite unix operating system.
|
|
||||||
This installs into `/opt/mkessler/university-setup`.
|
|
||||||
|
|
||||||
There is also a [PKGBUILD][pkgbuild] for Arch linux available.
|
|
||||||
|
|
||||||
# Managing LaTeX lecture notes
|
# Managing LaTeX lecture notes
|
||||||
|
|
||||||
This repository complements my [third blog post about my note taking setup](https://castel.dev/post/lecture-notes-3).
|
This repository complements my [third blog post about my note taking setup](https://castel.dev/post/lecture-notes-3).
|
||||||
|
@ -21,7 +14,7 @@ This repository complements my [third blog post about my note taking setup](http
|
||||||
ROOT
|
ROOT
|
||||||
├── riemann-surfaces
|
├── riemann-surfaces
|
||||||
│ ├── info.yaml
|
│ ├── info.yaml
|
||||||
│ ├── master.texvllt sollte ich
|
│ ├── master.tex
|
||||||
│ ├── lec_01.tex
|
│ ├── lec_01.tex
|
||||||
│ ├── ...
|
│ ├── ...
|
||||||
│ ├── lec_13.tex
|
│ ├── lec_13.tex
|
||||||
|
@ -159,7 +152,3 @@ Some utility functions
|
||||||
#### `compile-all-masters.py`
|
#### `compile-all-masters.py`
|
||||||
|
|
||||||
This script updates the `master.tex` files to include all lectures and compiles them. I use when syncing my notes to the cloud. This way I always have access to my compiles notes on my phone.
|
This script updates the `master.tex` files to include all lectures and compiles them. I use when syncing my notes to the cloud. This way I always have access to my compiles notes on my phone.
|
||||||
|
|
||||||
|
|
||||||
[setup]: https://github.com/gillescastel/university-setup
|
|
||||||
[pkgbuild]: https://git.abstractnonsen.se/arch/university-setup-git
|
|
||||||
|
|
265
preamble.tex
Normal file
265
preamble.tex
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
% Some basic packages
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
\usepackage{textcomp}
|
||||||
|
\usepackage[dutch]{babel}
|
||||||
|
\usepackage{url}
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{float}
|
||||||
|
\usepackage{booktabs}
|
||||||
|
\usepackage{enumitem}
|
||||||
|
|
||||||
|
\pdfminorversion=7
|
||||||
|
|
||||||
|
% Don't indent paragraphs, leave some space between them
|
||||||
|
\usepackage{parskip}
|
||||||
|
|
||||||
|
% Hide page number when page is empty
|
||||||
|
\usepackage{emptypage}
|
||||||
|
\usepackage{subcaption}
|
||||||
|
\usepackage{multicol}
|
||||||
|
\usepackage{xcolor}
|
||||||
|
|
||||||
|
% Other font I sometimes use.
|
||||||
|
% \usepackage{cmbright}
|
||||||
|
|
||||||
|
% Math stuff
|
||||||
|
\usepackage{amsmath, amsfonts, mathtools, amsthm, amssymb}
|
||||||
|
% Fancy script capitals
|
||||||
|
\usepackage{mathrsfs}
|
||||||
|
\usepackage{cancel}
|
||||||
|
% Bold math
|
||||||
|
\usepackage{bm}
|
||||||
|
% Some shortcuts
|
||||||
|
\newcommand\N{\ensuremath{\mathbb{N}}}
|
||||||
|
\newcommand\R{\ensuremath{\mathbb{R}}}
|
||||||
|
\newcommand\Z{\ensuremath{\mathbb{Z}}}
|
||||||
|
\renewcommand\O{\ensuremath{\emptyset}}
|
||||||
|
\newcommand\Q{\ensuremath{\mathbb{Q}}}
|
||||||
|
\newcommand\C{\ensuremath{\mathbb{C}}}
|
||||||
|
|
||||||
|
% Easily typeset systems of equations (French package)
|
||||||
|
\usepackage{systeme}
|
||||||
|
|
||||||
|
% Put x \to \infty below \lim
|
||||||
|
\let\svlim\lim\def\lim{\svlim\limits}
|
||||||
|
|
||||||
|
%Make implies and impliedby shorter
|
||||||
|
\let\implies\Rightarrow
|
||||||
|
\let\impliedby\Leftarrow
|
||||||
|
\let\iff\Leftrightarrow
|
||||||
|
\let\epsilon\varepsilon
|
||||||
|
|
||||||
|
% Add \contra symbol to denote contradiction
|
||||||
|
\usepackage{stmaryrd} % for \lightning
|
||||||
|
\newcommand\contra{\scalebox{1.5}{$\lightning$}}
|
||||||
|
|
||||||
|
% \let\phi\varphi
|
||||||
|
|
||||||
|
% Command for short corrections
|
||||||
|
% Usage: 1+1=\correct{3}{2}
|
||||||
|
|
||||||
|
\definecolor{correct}{HTML}{009900}
|
||||||
|
\newcommand\correct[2]{\ensuremath{\:}{\color{red}{#1}}\ensuremath{\to }{\color{correct}{#2}}\ensuremath{\:}}
|
||||||
|
\newcommand\green[1]{{\color{correct}{#1}}}
|
||||||
|
|
||||||
|
% horizontal rule
|
||||||
|
\newcommand\hr{
|
||||||
|
\noindent\rule[0.5ex]{\linewidth}{0.5pt}
|
||||||
|
}
|
||||||
|
|
||||||
|
% hide parts
|
||||||
|
\newcommand\hide[1]{}
|
||||||
|
|
||||||
|
% si unitx
|
||||||
|
\usepackage{siunitx}
|
||||||
|
\sisetup{locale = FR}
|
||||||
|
|
||||||
|
% Environments
|
||||||
|
\makeatother
|
||||||
|
% For box around Definition, Theorem, \ldots
|
||||||
|
\usepackage{mdframed}
|
||||||
|
\mdfsetup{skipabove=1em,skipbelow=0em}
|
||||||
|
\theoremstyle{definition}
|
||||||
|
\newmdtheoremenv[nobreak=true]{definitie}{Definitie}
|
||||||
|
\newmdtheoremenv[nobreak=true]{eigenschap}{Eigenschap}
|
||||||
|
\newmdtheoremenv[nobreak=true]{gevolg}{Gevolg}
|
||||||
|
\newmdtheoremenv[nobreak=true]{lemma}{Lemma}
|
||||||
|
\newmdtheoremenv[nobreak=true]{propositie}{Propositie}
|
||||||
|
\newmdtheoremenv[nobreak=true]{stelling}{Stelling}
|
||||||
|
\newmdtheoremenv[nobreak=true]{wet}{Wet}
|
||||||
|
\newmdtheoremenv[nobreak=true]{postulaat}{Postulaat}
|
||||||
|
\newmdtheoremenv{conclusie}{Conclusie}
|
||||||
|
\newmdtheoremenv{toemaatje}{Toemaatje}
|
||||||
|
\newmdtheoremenv{vermoeden}{Vermoeden}
|
||||||
|
\newtheorem*{herhaling}{Herhaling}
|
||||||
|
\newtheorem*{intermezzo}{Intermezzo}
|
||||||
|
\newtheorem*{notatie}{Notatie}
|
||||||
|
\newtheorem*{observatie}{Observatie}
|
||||||
|
\newtheorem*{oef}{Oefening}
|
||||||
|
\newtheorem*{opmerking}{Opmerking}
|
||||||
|
\newtheorem*{praktisch}{Praktisch}
|
||||||
|
\newtheorem*{probleem}{Probleem}
|
||||||
|
\newtheorem*{terminologie}{Terminologie}
|
||||||
|
\newtheorem*{toepassing}{Toepassing}
|
||||||
|
\newtheorem*{uovt}{UOVT}
|
||||||
|
\newtheorem*{vb}{Voorbeeld}
|
||||||
|
\newtheorem*{vraag}{Vraag}
|
||||||
|
|
||||||
|
\newmdtheoremenv[nobreak=true]{definition}{Definition}
|
||||||
|
\newtheorem*{eg}{Example}
|
||||||
|
\newtheorem*{notation}{Notation}
|
||||||
|
\newtheorem*{previouslyseen}{As previously seen}
|
||||||
|
\newtheorem*{remark}{Remark}
|
||||||
|
\newtheorem*{note}{Note}
|
||||||
|
\newtheorem*{problem}{Problem}
|
||||||
|
\newtheorem*{observe}{Observe}
|
||||||
|
\newtheorem*{property}{Property}
|
||||||
|
\newtheorem*{intuition}{Intuition}
|
||||||
|
\newmdtheoremenv[nobreak=true]{prop}{Proposition}
|
||||||
|
\newmdtheoremenv[nobreak=true]{theorem}{Theorem}
|
||||||
|
\newmdtheoremenv[nobreak=true]{corollary}{Corollary}
|
||||||
|
|
||||||
|
% End example and intermezzo environments with a small diamond (just like proof
|
||||||
|
% environments end with a small square)
|
||||||
|
\usepackage{etoolbox}
|
||||||
|
\AtEndEnvironment{vb}{\null\hfill$\diamond$}%
|
||||||
|
\AtEndEnvironment{intermezzo}{\null\hfill$\diamond$}%
|
||||||
|
% \AtEndEnvironment{opmerking}{\null\hfill$\diamond$}%
|
||||||
|
|
||||||
|
% Fix some spacing
|
||||||
|
% http://tex.stackexchange.com/questions/22119/how-can-i-change-the-spacing-before-theorems-with-amsthm
|
||||||
|
\makeatletter
|
||||||
|
\def\thm@space@setup{%
|
||||||
|
\thm@preskip=\parskip \thm@postskip=0pt
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
% Exercise
|
||||||
|
% Usage:
|
||||||
|
% \oefening{5}
|
||||||
|
% \suboefening{1}
|
||||||
|
% \suboefening{2}
|
||||||
|
% \suboefening{3}
|
||||||
|
% gives
|
||||||
|
% Oefening 5
|
||||||
|
% Oefening 5.1
|
||||||
|
% Oefening 5.2
|
||||||
|
% Oefening 5.3
|
||||||
|
\newcommand{\oefening}[1]{%
|
||||||
|
\def\@oefening{#1}%
|
||||||
|
\subsection*{Oefening #1}
|
||||||
|
}
|
||||||
|
|
||||||
|
\newcommand{\suboefening}[1]{%
|
||||||
|
\subsubsection*{Oefening \@oefening.#1}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
% \lecture starts a new lecture (les in dutch)
|
||||||
|
%
|
||||||
|
% Usage:
|
||||||
|
% \lecture{1}{di 12 feb 2019 16:00}{Inleiding}
|
||||||
|
%
|
||||||
|
% This adds a section heading with the number / title of the lecture and a
|
||||||
|
% margin paragraph with the date.
|
||||||
|
|
||||||
|
% I use \dateparts here to hide the year (2019). This way, I can easily parse
|
||||||
|
% the date of each lecture unambiguously while still having a human-friendly
|
||||||
|
% short format printed to the pdf.
|
||||||
|
|
||||||
|
\usepackage{xifthen}
|
||||||
|
\def\testdateparts#1{\dateparts#1\relax}
|
||||||
|
\def\dateparts#1 #2 #3 #4 #5\relax{
|
||||||
|
\marginpar{\small\textsf{\mbox{#1 #2 #3 #5}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
\def\@lecture{}%
|
||||||
|
\newcommand{\lecture}[3]{
|
||||||
|
\ifthenelse{\isempty{#3}}{%
|
||||||
|
\def\@lecture{Lecture #1}%
|
||||||
|
}{%
|
||||||
|
\def\@lecture{Lecture #1: #3}%
|
||||||
|
}%
|
||||||
|
\subsection*{\@lecture}
|
||||||
|
\marginpar{\small\textsf{\mbox{#2}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% These are the fancy headers
|
||||||
|
\usepackage{fancyhdr}
|
||||||
|
\pagestyle{fancy}
|
||||||
|
|
||||||
|
% LE: left even
|
||||||
|
% RO: right odd
|
||||||
|
% CE, CO: center even, center odd
|
||||||
|
% My name for when I print my lecture notes to use for an open book exam.
|
||||||
|
% \fancyhead[LE,RO]{Gilles Castel}
|
||||||
|
|
||||||
|
\fancyhead[RO,LE]{\@lecture} % Right odd, Left even
|
||||||
|
\fancyhead[RE,LO]{} % Right even, Left odd
|
||||||
|
|
||||||
|
\fancyfoot[RO,LE]{\thepage} % Right odd, Left even
|
||||||
|
\fancyfoot[RE,LO]{} % Right even, Left odd
|
||||||
|
\fancyfoot[C]{\leftmark} % Center
|
||||||
|
|
||||||
|
\makeatother
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% Todonotes and inline notes in fancy boxes
|
||||||
|
\usepackage{todonotes}
|
||||||
|
\usepackage{tcolorbox}
|
||||||
|
|
||||||
|
% Make boxes breakable
|
||||||
|
\tcbuselibrary{breakable}
|
||||||
|
|
||||||
|
% Verbetering is correction in Dutch
|
||||||
|
% Usage:
|
||||||
|
% \begin{verbetering}
|
||||||
|
% Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
|
||||||
|
% tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
|
||||||
|
% vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
|
||||||
|
% no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
||||||
|
% \end{verbetering}
|
||||||
|
\newenvironment{verbetering}{\begin{tcolorbox}[
|
||||||
|
arc=0mm,
|
||||||
|
colback=white,
|
||||||
|
colframe=green!60!black,
|
||||||
|
title=Opmerking,
|
||||||
|
fonttitle=\sffamily,
|
||||||
|
breakable
|
||||||
|
]}{\end{tcolorbox}}
|
||||||
|
|
||||||
|
% Noot is note in Dutch. Same as 'verbetering' but color of box is different
|
||||||
|
\newenvironment{noot}[1]{\begin{tcolorbox}[
|
||||||
|
arc=0mm,
|
||||||
|
colback=white,
|
||||||
|
colframe=white!60!black,
|
||||||
|
title=#1,
|
||||||
|
fonttitle=\sffamily,
|
||||||
|
breakable
|
||||||
|
]}{\end{tcolorbox}}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% Figure support as explained in my blog post.
|
||||||
|
\usepackage{import}
|
||||||
|
\usepackage{xifthen}
|
||||||
|
\usepackage{pdfpages}
|
||||||
|
\usepackage{transparent}
|
||||||
|
\newcommand{\incfig}[1]{%
|
||||||
|
\def\svgwidth{\columnwidth}
|
||||||
|
\import{./figures/}{#1.pdf_tex}
|
||||||
|
}
|
||||||
|
|
||||||
|
% Fix some stuff
|
||||||
|
% %http://tex.stackexchange.com/questions/76273/multiple-pdfs-with-page-group-included-in-a-single-page-warning
|
||||||
|
\pdfsuppresswarningpagegroup=1
|
||||||
|
|
||||||
|
|
||||||
|
% My name
|
||||||
|
\author{Gilles Castel}
|
|
@ -1,5 +0,0 @@
|
||||||
google-api-python-client
|
|
||||||
google-auth-oauthlib
|
|
||||||
python-dateutil
|
|
||||||
pytz
|
|
||||||
PyYAML
|
|
|
@ -1,6 +1,5 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
# default is 'primary', if you are using a separate calendar for your course schedule,
|
# default is 'primary', if you are using a separate calendar for your course schedule,
|
||||||
# your calendarId (which you can find by going to your Google Calendar settings, selecting
|
# your calendarId (which you can find by going to your Google Calendar settings, selecting
|
||||||
# the relevant calendar and scrolling down to Calendar ID) probably looks like
|
# the relevant calendar and scrolling down to Calendar ID) probably looks like
|
||||||
|
@ -11,7 +10,7 @@ USERCALENDARID = 'primary'
|
||||||
CURRENT_COURSE_SYMLINK = Path('~/current_course').expanduser()
|
CURRENT_COURSE_SYMLINK = Path('~/current_course').expanduser()
|
||||||
CURRENT_COURSE_ROOT = CURRENT_COURSE_SYMLINK.resolve()
|
CURRENT_COURSE_ROOT = CURRENT_COURSE_SYMLINK.resolve()
|
||||||
CURRENT_COURSE_WATCH_FILE = Path('/tmp/current_course').resolve()
|
CURRENT_COURSE_WATCH_FILE = Path('/tmp/current_course').resolve()
|
||||||
ROOT = Path('~/uni/semester-6').expanduser()
|
ROOT = Path('~/Uni/semester-5').expanduser()
|
||||||
DATE_FORMAT = '%a %d %b %Y'
|
DATE_FORMAT = '%a %d %b %Y'
|
||||||
LOCALE = "de_DE.utf8"
|
LOCALE = "de_DE.utf8"
|
||||||
COURSE_IGNORE_FILE = '.courseignore'
|
COURSE_IGNORE_FILE = '.courseignore'
|
||||||
|
@ -23,11 +22,10 @@ DEFAULT_NEW_LECTURE_HEADER = r'\lecture[]{{{date}}}{{{title}}}'
|
||||||
DEFAULT_NEW_LECTURE_TITLE = 'Untitled'
|
DEFAULT_NEW_LECTURE_TITLE = 'Untitled'
|
||||||
DEFAULT_LECTURE_SEARCH_REGEX = r'lecture.*({\d*})?{(.*?)}{(.*)}'
|
DEFAULT_LECTURE_SEARCH_REGEX = r'lecture.*({\d*})?{(.*?)}{(.*)}'
|
||||||
DEFAULT_IMPORT_INDENTATION = 4
|
DEFAULT_IMPORT_INDENTATION = 4
|
||||||
|
FALLBACK_COURSE_INFO_FILE = Path(__file__).parent.resolve() / 'fallback.yaml'
|
||||||
TIMEZONE = pytz.timezone('CET')
|
TIMEZONE = pytz.timezone('CET')
|
||||||
SCHEDULER_DELAY = 60
|
SCHEDULER_DELAY = 60
|
||||||
DEFAULT_LATEX_COUNTER_AUX_FILE_EXTENSION = '.cnt'
|
DEFAULT_LATEX_COUNTER_AUX_FILE_EXTENSION = '.cnt'
|
||||||
TERMINAL = 'i3-sensible-terminal'
|
|
||||||
EDITOR = 'vim'
|
|
||||||
|
|
||||||
NEW_EXERCISE_SHEET_HEADER = '\n'.join([
|
NEW_EXERCISE_SHEET_HEADER = '\n'.join([
|
||||||
r"%! TEX root = ./*.tex",
|
r"%! TEX root = ./*.tex",
|
|
@ -20,7 +20,7 @@ from google_auth_oauthlib.flow import InstalledAppFlow
|
||||||
from google.auth.transport.requests import Request
|
from google.auth.transport.requests import Request
|
||||||
|
|
||||||
from courses import Courses
|
from courses import Courses
|
||||||
from config_loader import USERCALENDARID, TIMEZONE, SCHEDULER_DELAY
|
from config import USERCALENDARID, TIMEZONE, SCHEDULER_DELAY
|
||||||
|
|
||||||
courses = Courses()
|
courses = Courses()
|
||||||
|
|
|
@ -4,7 +4,7 @@ import warnings
|
||||||
import yaml
|
import yaml
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from config_loader import ROOT, CURRENT_COURSE_ROOT, CURRENT_COURSE_SYMLINK, CURRENT_COURSE_WATCH_FILE, COURSE_IGNORE_FILE, \
|
from config import ROOT, CURRENT_COURSE_ROOT, CURRENT_COURSE_SYMLINK, CURRENT_COURSE_WATCH_FILE, COURSE_IGNORE_FILE, \
|
||||||
COURSE_INFO_FILE_NAME, FALLBACK_COURSE_INFO_FILE
|
COURSE_INFO_FILE_NAME, FALLBACK_COURSE_INFO_FILE
|
||||||
from notes import Notes
|
from notes import Notes
|
||||||
from links import Links
|
from links import Links
|
||||||
|
@ -23,7 +23,13 @@ class Course:
|
||||||
f"file in the directory or add the directory to the course ignore file named"
|
f"file in the directory or add the directory to the course ignore file named"
|
||||||
f" '{COURSE_IGNORE_FILE}' in your root directory ({ROOT})")
|
f" '{COURSE_IGNORE_FILE}' in your root directory ({ROOT})")
|
||||||
self.info = {'title': str(path.stem) + ' (unnamed course)'}
|
self.info = {'title': str(path.stem) + ' (unnamed course)'}
|
||||||
fallback_file = yaml.safe_load(FALLBACK_COURSE_INFO_FILE.open())
|
if FALLBACK_COURSE_INFO_FILE.is_file():
|
||||||
|
fallback_file = yaml.safe_load(FALLBACK_COURSE_INFO_FILE.open())
|
||||||
|
else:
|
||||||
|
warnings.warn(f"No fallback course info file found. Program might crash if your provided info files do not"
|
||||||
|
f"have the correct file format or are missing specified values. Provide the fallback course"
|
||||||
|
f"file at {FALLBACK_COURSE_INFO_FILE}.")
|
||||||
|
fallback_file = {}
|
||||||
self.info = merge_dictionaries(self.info, fallback_file)
|
self.info = merge_dictionaries(self.info, fallback_file)
|
||||||
self._notes = None
|
self._notes = None
|
||||||
self._links = None
|
self._links = None
|
|
@ -2,20 +2,15 @@ from file_list import Files, FileHandle, FileType
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from utils import normalize
|
from utils import normalize
|
||||||
from config_loader import NEW_EXERCISE_SHEET_HEADER
|
from config import NEW_EXERCISE_SHEET_HEADER
|
||||||
|
|
||||||
|
|
||||||
class ExerciseWriteUp(FileHandle):
|
class ExerciseWriteUp(FileHandle):
|
||||||
def __init__(self, root_dir: Path, course):
|
def __init__(self, root_dir: Path, course):
|
||||||
self.root_dir = root_dir
|
self.root_dir = root_dir
|
||||||
self.course = course
|
self.course = course
|
||||||
try:
|
FileHandle.__init__(self, next(self.root_dir.rglob('*.tex')), FileType.tex)
|
||||||
tex_file = next(self.root_dir.rglob('*.tex'))
|
|
||||||
except StopIteration:
|
|
||||||
print("No valid '.tex' file found in directory {}, can't instantiate write up here".format(root_dir))
|
|
||||||
# TODO: raise proper error
|
|
||||||
exit(1)
|
|
||||||
FileHandle.__init__(self, tex_file, FileType.tex)
|
|
||||||
|
|
||||||
class Exercise:
|
class Exercise:
|
||||||
def __init__(self, course, number: int):
|
def __init__(self, course, number: int):
|
||||||
|
@ -57,6 +52,7 @@ class Exercises(list):
|
||||||
self._solutions = None
|
self._solutions = None
|
||||||
self._writeups = None
|
self._writeups = None
|
||||||
self._sheets = Files(self.sheet_root)
|
self._sheets = Files(self.sheet_root)
|
||||||
|
self.ignored_folders = [self.sheet_root, self.solutions_root]
|
||||||
list.__init__(self, (Exercise(self.course, num) for num in map(lambda s: s.number, self._sheets)))
|
list.__init__(self, (Exercise(self.course, num) for num in map(lambda s: s.number, self._sheets)))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -72,7 +68,7 @@ class Exercises(list):
|
||||||
@property
|
@property
|
||||||
def writeups(self):
|
def writeups(self):
|
||||||
if not self._writeups:
|
if not self._writeups:
|
||||||
dirs = [d for d in self.root.glob('ub*') if d.is_dir()]
|
dirs = list(d for d in self.root.iterdir() if d.is_dir() and d not in self.ignored_folders)
|
||||||
self._writeups = sorted((ExerciseWriteUp(d, self.course) for d in dirs), key=lambda e: e.number)
|
self._writeups = sorted((ExerciseWriteUp(d, self.course) for d in dirs), key=lambda e: e.number)
|
||||||
return self._writeups
|
return self._writeups
|
||||||
|
|
|
@ -17,7 +17,6 @@ literature:
|
||||||
notes:
|
notes:
|
||||||
path: '.'
|
path: '.'
|
||||||
texinputs: '.'
|
texinputs: '.'
|
||||||
build_dir: '.'
|
|
||||||
master_file: 'master.tex'
|
master_file: 'master.tex'
|
||||||
full_file: 'full.tex'
|
full_file: 'full.tex'
|
||||||
lectures:
|
lectures:
|
29
scripts/ieeeeqnarray.py
Normal file
29
scripts/ieeeeqnarray.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# A python script designed to parse the contents of an \[ \] in latex (given in the arguments), and make a nice IEEEeqnarray* with correct indent and columns from it.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
indent=len(sys.argv[1])-4 # Indent got by the indent of the leading \[ of equation
|
||||||
|
topline = sys.argv[2].strip() # Get the content of the first line of the equation
|
||||||
|
level = 0 # Counts the 'level' of stacked braces
|
||||||
|
position = 0 # Will save the position of the found = in the top line
|
||||||
|
parsed_line = '' # Parsed top line
|
||||||
|
|
||||||
|
for x in topline:
|
||||||
|
if x in ['(','[','{']:
|
||||||
|
level+=1
|
||||||
|
parsed_line+=x
|
||||||
|
elif x in [')',']','}']:
|
||||||
|
level-=1
|
||||||
|
parsed_line+=x
|
||||||
|
elif level == 0 and x == '=':
|
||||||
|
position = len(parsed_line)
|
||||||
|
parsed_line+='& = &'
|
||||||
|
else:
|
||||||
|
parsed_line+=x
|
||||||
|
|
||||||
|
# Set correct indent and newline to the parsed line
|
||||||
|
parsed_line = ' '*(indent+4) + parsed_line[0:-1].strip() + ' \\\\\n'
|
||||||
|
|
||||||
|
# Print the output, adding \begin{}, the top line, a new line with '& = &' and \end{}
|
||||||
|
print(" "*indent +"\\begin{IEEEeqnarray*}{rCl}\n" + parsed_line + ' '*(position+indent+4) + "& = & \n" + " "*indent + "\\end{IEEEeqnarray*}")
|
||||||
|
|
|
@ -46,7 +46,7 @@ def main(args):
|
||||||
arglist = []
|
arglist = []
|
||||||
if len(args) > 1:
|
if len(args) > 1:
|
||||||
path = Path(args[1])
|
path = Path(args[1])
|
||||||
arglist = list(path.glob('*.aux')) + list(path.glob('build/*.aux'))
|
arglist = list(path.glob('*.aux'))
|
||||||
else:
|
else:
|
||||||
arglist = ['/home/maximilian/current_course/full.aux']
|
arglist = ['/home/maximilian/current_course/full.aux']
|
||||||
|
|
||||||
|
@ -61,7 +61,6 @@ def main(args):
|
||||||
else:
|
else:
|
||||||
command = selected
|
command = selected
|
||||||
return command.strip()
|
return command.strip()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
0
src/new-writeup.py → scripts/new-writeup.py
Executable file → Normal file
0
src/new-writeup.py → scripts/new-writeup.py
Executable file → Normal file
|
@ -4,7 +4,7 @@ import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from config_loader import LECTURE_START_MARKER, LECTURE_END_MARKER, DEFAULT_IMPORT_INDENTATION, \
|
from config import LECTURE_START_MARKER, LECTURE_END_MARKER, DEFAULT_IMPORT_INDENTATION, \
|
||||||
DEFAULT_LATEX_COUNTER_AUX_FILE_EXTENSION
|
DEFAULT_LATEX_COUNTER_AUX_FILE_EXTENSION
|
||||||
from window_subprocess import edit
|
from window_subprocess import edit
|
||||||
from lectures import Lectures, number2filename
|
from lectures import Lectures, number2filename
|
||||||
|
@ -21,7 +21,6 @@ class Notes:
|
||||||
self.full_file: Path = self.root / self.info['full_file']
|
self.full_file: Path = self.root / self.info['full_file']
|
||||||
self.texinputs: Path = self.root / self.info['texinputs']
|
self.texinputs: Path = self.root / self.info['texinputs']
|
||||||
self._lectures = None
|
self._lectures = None
|
||||||
self.build_dir: Path = self.root / self.info['build_dir']
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_header_footer(filepath):
|
def get_header_footer(filepath):
|
||||||
|
@ -64,11 +63,8 @@ class Notes:
|
||||||
if not setcounters:
|
if not setcounters:
|
||||||
return ''
|
return ''
|
||||||
if lec - 1 not in lecture_list and self.full_file:
|
if lec - 1 not in lecture_list and self.full_file:
|
||||||
cnt_file = self.full_file.with_suffix(DEFAULT_LATEX_COUNTER_AUX_FILE_EXTENSION)
|
|
||||||
if not cnt_file.exists():
|
|
||||||
cnt_file = self.full_file.parent / 'build' / cnt_file.name
|
|
||||||
return dict2setcounters(parse_counters(
|
return dict2setcounters(parse_counters(
|
||||||
cnt_file,
|
self.full_file.with_suffix(DEFAULT_LATEX_COUNTER_AUX_FILE_EXTENSION),
|
||||||
{'lecture': lec}
|
{'lecture': lec}
|
||||||
))
|
))
|
||||||
return ''
|
return ''
|
||||||
|
@ -102,7 +98,7 @@ class Notes:
|
||||||
|
|
||||||
def open_full(self):
|
def open_full(self):
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
['zathura', str(self.build_dir / self.full_file.with_suffix('.pdf').name)],
|
['zathura', str(self.full_file.with_suffix('.pdf'))],
|
||||||
stdout=subprocess.DEVNULL,
|
stdout=subprocess.DEVNULL,
|
||||||
stderr=subprocess.DEVNULL
|
stderr=subprocess.DEVNULL
|
||||||
)
|
)
|
||||||
|
@ -110,7 +106,7 @@ class Notes:
|
||||||
|
|
||||||
def open_terminal(self):
|
def open_terminal(self):
|
||||||
result = subprocess.Popen(
|
result = subprocess.Popen(
|
||||||
['i3-sensible-terminal'], env=self.environment(), cwd=self.root
|
['termite'], env=self.environment(), cwd=self.root
|
||||||
)
|
)
|
||||||
|
|
||||||
def compile_master(self):
|
def compile_master(self):
|
0
src/open.py → scripts/open.py
Executable file → Normal file
0
src/open.py → scripts/open.py
Executable file → Normal file
|
@ -2,7 +2,7 @@
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from config_loader import DEFAULT_IMPORT_INDENTATION
|
from config import DEFAULT_IMPORT_INDENTATION
|
||||||
|
|
||||||
|
|
||||||
def parse_counters(filepath: Path, break_point: Dict) -> Dict:
|
def parse_counters(filepath: Path, break_point: Dict) -> Dict:
|
|
@ -2,6 +2,7 @@
|
||||||
from courses import Courses
|
from courses import Courses
|
||||||
from exercises import Exercises
|
from exercises import Exercises
|
||||||
from rofi import rofi
|
from rofi import rofi
|
||||||
|
from config import MAX_LEN
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
from courses import Courses
|
from courses import Courses
|
||||||
from rofi import rofi
|
from rofi import rofi
|
||||||
from utils import generate_short_title
|
from utils import generate_short_title
|
||||||
from config_loader import MAX_LEN
|
from config import MAX_LEN
|
||||||
|
|
||||||
notes = Courses().current.notes
|
notes = Courses().current.notes
|
||||||
lectures = notes.lectures
|
lectures = notes.lectures
|
|
@ -3,7 +3,7 @@ from datetime import datetime
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from config_loader import MAX_LEN
|
from config import MAX_LEN
|
||||||
|
|
||||||
|
|
||||||
def beautify(string):
|
def beautify(string):
|
|
@ -4,20 +4,14 @@ import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from config_loader import TERMINAL, EDITOR
|
|
||||||
|
|
||||||
|
|
||||||
def edit(filepath: Path, rootpath: Path = None, env=os.environ, servername='tex lecture'):
|
def edit(filepath: Path, rootpath: Path = None, env=os.environ, servername='tex lecture'):
|
||||||
if not rootpath:
|
if not rootpath:
|
||||||
rootpath = filepath.root
|
rootpath = filepath.root
|
||||||
subprocess.Popen([
|
subprocess.Popen([
|
||||||
TERMINAL,
|
"termite",
|
||||||
"-e",
|
"-e",
|
||||||
EDITOR,
|
f"vim --servername {servername} --remote-silent {str(filepath)}"
|
||||||
f"--servername",
|
|
||||||
f"{servername}",
|
|
||||||
f"--remote-silent",
|
|
||||||
f"{str(filepath)}"
|
|
||||||
], env=env, cwd=str(rootpath))
|
], env=env, cwd=str(rootpath))
|
||||||
|
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
import shutil
|
|
||||||
from pathlib import Path
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# We read a configuration file for university setup that is located
|
|
||||||
# in $XDG_CONFIG_HOME/university-setup/config.cfg
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_file(name: str) -> Path:
|
|
||||||
# System installation
|
|
||||||
f1 = Path('/etc/opt/mkessler/university-setup') / name
|
|
||||||
# no installation, try relative path
|
|
||||||
f2 = Path(__file__).parent.parent / 'config' / name
|
|
||||||
if f1.exists():
|
|
||||||
return f1
|
|
||||||
if f2.exists():
|
|
||||||
return f2
|
|
||||||
raise FileNotFoundError(f'Default file {name} not found, bad installation.')
|
|
||||||
|
|
||||||
|
|
||||||
# Ensure that config.py and fallback.yaml are present
|
|
||||||
# in the config directory and returns this directory
|
|
||||||
def get_config_dir() -> Path:
|
|
||||||
if 'XDG_CONFIG_HOME' in os.environ.keys():
|
|
||||||
xdg_config_home = Path(os.environ['XDG_CONFIG_HOME']).resolve()
|
|
||||||
else:
|
|
||||||
xdg_config_home = Path('~/.config').expanduser().resolve()
|
|
||||||
config_file = xdg_config_home / 'university-setup' / 'config.py'
|
|
||||||
fallback_file = xdg_config_home / 'university-setup' / 'fallback.yaml'
|
|
||||||
config_file.parent.mkdir(exist_ok=True, parents=True)
|
|
||||||
|
|
||||||
# Copy defaults if not present already
|
|
||||||
if not config_file.exists():
|
|
||||||
shutil.copy(get_default_file('config.py'), config_file)
|
|
||||||
print(f'Initialized default config file at {str(config_file)}.')
|
|
||||||
if not fallback_file.exists():
|
|
||||||
shutil.copy(get_default_file('fallback.yaml'), fallback_file)
|
|
||||||
print(f'Initialized default fallback file at {str(fallback_file)}.')
|
|
||||||
|
|
||||||
return config_file.parent.absolute()
|
|
||||||
|
|
||||||
|
|
||||||
FALLBACK_COURSE_INFO_FILE = get_config_dir() / 'fallback.yaml'
|
|
||||||
|
|
||||||
sys.path.append(str(get_config_dir()))
|
|
||||||
|
|
||||||
# Note that IDEs will probably complain about this, since they cannot find the module right now
|
|
||||||
# they might also flag this as an unused import, but the imported config values
|
|
||||||
# are in turn imported by all the oder scripts
|
|
||||||
from config import *
|
|
||||||
|
|
||||||
# future: potentially check that config in fact defines all symbols that we need
|
|
Loading…
Reference in a new issue