├── .github ├── CODEOWNERS └── workflows │ ├── checks.yaml │ └── publish.yml ├── .gitignore ├── CNAME ├── README.org ├── content ├── community │ ├── chat-with-us.org │ ├── code-of-conduct.org │ ├── getting-involved.org │ └── znc-bouncer-servers.org ├── emacs │ ├── Counsel-insert-relative-file-path.org │ ├── LSP-Python-(pyright)-config-in-emacs-from-scratch.org │ ├── LaTeX-config-(AucteX)-in-Emacs-from-scratch.org │ ├── Org-roam-setup-from-scratch.org │ ├── exwm-hacking.org │ ├── help-cheatsheet.org │ ├── index.org │ ├── org-roam.org │ └── try-gccemacs.org ├── guix │ ├── browsers.org │ ├── faqs.org │ ├── general-recommendations.org │ ├── index.org │ ├── nonguix-installation-guide.org │ ├── nvidia.org │ └── wsl.org └── index.org ├── local-build.sh ├── ox-slimhtml.el └── publish.el /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # The Wiki Editors team must review all PRs! 2 | * @SystemCrafters/wiki-editors -------------------------------------------------------------------------------- /.github/workflows/checks.yaml: -------------------------------------------------------------------------------- 1 | name: Check 2 | on: [pull_request] 3 | jobs: 4 | Elisp-checks: 5 | runs-on: ubuntu-latest 6 | strategy: 7 | matrix: 8 | check: 9 | - load-file 10 | - checkdoc 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: purcell/setup-emacs@master 14 | with: 15 | version: 27.2 16 | - uses: leotaku/elisp-check@master 17 | with: 18 | check: ${{ matrix.check }} 19 | file: publish.el 20 | Check-publish: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v2 24 | - uses: purcell/setup-emacs@master 25 | with: 26 | version: 27.2 27 | - run: ./local-build.sh 28 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check out 13 | uses: actions/checkout@v1 14 | 15 | - name: Check out the style repo 16 | run: git clone --depth 1 https://git.sr.ht/~daviwil/daviwil.com daviwil.com 17 | 18 | - name: Install Emacs 19 | uses: purcell/setup-emacs@master 20 | with: 21 | version: 27.2 22 | 23 | - name: Build the site 24 | run: | 25 | cp -R daviwil.com/public . 26 | ./local-build.sh 27 | 28 | - name: Publish generated content to GitHub Pages 29 | uses: JamesIves/github-pages-deploy-action@4.1.4 30 | with: 31 | branch: gh-pages 32 | folder: public 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.org-cache/ 2 | /.packages/ 3 | /gemini/ 4 | /public/ 5 | /content/articles.org 6 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | wiki.systemcrafters.net 2 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | #+title: Welcome to the System Crafters Wiki! 2 | 3 | See [[content/index.org][this file]] for more information! 4 | -------------------------------------------------------------------------------- /content/community/chat-with-us.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Chatting with the Community 2 | 3 | The System Crafters community hangs out in a few places, YouTube comments (and live chat on streams), Discord, and IRC (also accessible with a Matrix bridge). 4 | 5 | * YouTube 6 | You can chat with us during [[https://www.youtube.com/channel/UCAiiOTio8Yu69c3XnR7nQBQ][System Crafters live streams]]! 7 | 8 | ** Connecting to Twitch via IRC 9 | During the live streams, David has both YouTube and Twitch comments up via 10 | [[https://restream.io/][Restream]], meaning you can comment from either service (as long as it's 11 | working!). This is great for those of us who want to use IRC for comments, as 12 | Twitch enables commenting via IRC. Here's how to set that up (directions from 13 | [[https://gist.github.com/hunterbridges/ab095066d40f2e1a243e][this gist]], but who knows how long Github keeps those up). Of course, you'll 14 | need a [[https://www.twitch.tv/][Twitch.tv account]]. 15 | 16 | 1. Ensure that your Twitch account has 2-Factor Auth enabled. I ran into 17 | troubles with setting things up before and this was the solution. 18 | 2. Get an OAuth token for your Twitch account by visiting [[https://twitchapps.com/tmi/][this website]]. 19 | 3. Add a server to your IRC configuration using your OAuth token as the 20 | password. For ERC, you'll run something like this: 21 | #+begin_src emacs-lisp 22 | (erc-tls :server "irc.twitch.tv" 23 | :port 6667 24 | :password "" 25 | :nick "") 26 | #+end_src 27 | 4. Once connected, you'll need to send an IRCv3 message to the server telling it 28 | your capabilities. I'm not sure how to do this programmatically with ERC, 29 | but you should be able to send a message like so: 30 | ~/quote CAP REQ :twitch.tv/membership~. 31 | 5. You should be able to join chatrooms using the regular IRC commands from 32 | there! For Systemcrafters, run ~/join #systemcrafters~. 33 | 34 | * IRC 35 | [[ircs://irc.libera.chat/systemcrafters][#systemcrafters]] channel is on the [[https://libera.chat][libera.chat]] irc server along with a lot of other FOSS software channels like [[ircs://irc.libera.chat/emacs][#emacs]], [[ircs://irc.libera.chat/guix][#guix]], etc. 36 | ** Join via ERC 37 | You can join the [[ircs://irc.libera.chat/systemcrafters][#systemcrafters]] channel from within Emacs. For a quick introduction, have a look at [[https://www.youtube.com/watch?v=qWHTZIYTA4s][Chat Like the 90's in Emacs with ERC]], but for the impatient, you can use the following sexp: 38 | 39 | #+begin_src emacs-lisp 40 | (erc-tls :server "irc.libera.chat" 41 | :port 6697 42 | :nick "YOUR-NICK" 43 | :full-name "YOUR-FULL-NAME") 44 | #+end_src 45 | 46 | After your initial connection, use =/join #systemcrafters= to join the systemcrafters channel. For more information, see the [[info:erc][ERC manual]] or the [[https://www.emacswiki.org/emacs/ERC][ERC page in the Emacs Wiki]]. 47 | 48 | It's also a good idea to cloak your user (so your IP address is hidden from a ~whois~ query). You can do that by ~/join #libera-cloak~ and then sending the message ~!cloakme~. You only need to do it once for your NickServ account and it will cloak all your nicks anytime you connect. 49 | 50 | IRC chatting is simple, stable, hackable, and craftable, but because it's an old protocol with roots all the way back to the beginnings of the world wide web it comes with some limitations. One such limitation is that you have to be online to read messages. To learn more about configuring and using a ZNC bouncer server to stay connected and up to date with messages, see [[../znc-bouncer-servers/][ZNC Bouncer Server Setup]]. 51 | -------------------------------------------------------------------------------- /content/community/code-of-conduct.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Code of Conduct 2 | 3 | The System Crafters wiki's purpose is to provide extra resources for 4 | tools such as GNU Emacs and GNU Guix that might otherwise be difficult 5 | to understand. This is a community driven effort to organise the 6 | project and write articles. 7 | 8 | It is expected that those who contribute do so to improve the 9 | experience for all, and not to harm others. This may include 10 | disrespect, advertising, spamming, and other actions that do not 11 | benefit the wiki. 12 | 13 | Please ensure that you think through what you are doing before 14 | following through with it. 15 | 16 | Use the [[community/chat-with-us][community communication]] to improve your contribution and to 17 | collaborate with others, as well as the Git repositories. 18 | -------------------------------------------------------------------------------- /content/community/getting-involved.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Getting Involved 2 | #+AUTHOR: Daniel Rose 3 | 4 | If you'd like to contribute to this site, just send a pull request to 5 | the GitHub repository! The wiki editors will review and merge any 6 | changes that you send. 7 | 8 | Here is the wiki repository: 9 | https://github.com/SystemCrafters/wiki-site 10 | -------------------------------------------------------------------------------- /content/community/znc-bouncer-servers.org: -------------------------------------------------------------------------------- 1 | #+TITLE: ZNC Bouncer Server Setup 2 | 3 | An IRC bouncer server stays connected to IRC at all times on your behalf so that when you connect to it you can read all the messages that were sent to your channels while you were offline. This allows you to disconnect your client from the IRC server without losing context for the conversation or missing potentially relevant messages. When you reconnect, the ZNC bouncer server provides a replay of the conversation you missed while you were gone. 4 | 5 | Several members of the System Crafters community are running their own ZNC servers. Below is a tutorial for setting up a TLS/SSL enabled bouncer server using ZNC, Let's Encrypt, and CentOS. There has been some discussion about providing a multi-user server that members of the System Crafters community can use. Please contact =#systemcrafters= IRC users daviwil or nackjicholson if you would be interested in using a community bouncer server. The features of ZNC enable clearer and more fluid communication. We enjoy using IRC and want to know if a community ZNC bouncer server would be well utilized and beneficial for our communication. 6 | 7 | * External Resources 8 | 9 | - [[https://wiki.znc.in/ZNC][ZNC Wiki]] 10 | - [[https://wiki.znc.in/Signed_SSL_certificate#LetsEncrypt][ZNC Wiki - Signed SSL Certificate with Let's Encrypt]] 11 | - [[https://sgfault.com/2018/07/28/irc-bouncer-setup.html][Blog: Setting Up an IRC Bouncer]] 12 | - [[https://www.vultr.com/docs/installing-and-configuring-znc-on-centos-7][Blog: Vultr - Installing and Configuring ZNC on CentOS 7]] 13 | - [[https://chromium.googlesource.com/chromium/src.git/+/refs/heads/master/net/base/port_util.cc][Google Chrome - List of blocked ports]] 14 | 15 | * Tutorial: ZNC with SSL/TLS on CentOS 16 | 17 | The following commands and configuration instructions will set up a secure ZNC server for personal use. You will need a CentOS 7 server or virtual machine, as well as a registered domain name. In the tutorial znc.example.org will be used as the target domain name, and the ZNC server will be configured to run on port 6697. 18 | 19 | ** Install 20 | 21 | #+begin_src sh :eval never 22 | $ sudo yum update 23 | $ sudo yum install certbot znc 24 | #+end_src 25 | 26 | ** Firewall 27 | 28 | Opening necessary ports for certbot and ZNC. 29 | 30 | #+begin_src sh :eval never 31 | $ sudo firewall-cmd --zone=public --permanent --add-service=http 32 | $ sudo firewall-cmd --zone=public --permanent --add-service=https 33 | $ sudo firewall-cmd --add-port=6697/tcp 34 | $ sudo firewall-cmd --runtime-to-permanent 35 | #+end_src 36 | 37 | *Note:* Some browsers, like Google Chrome block port =6697= (amongst others) by default because it's commonly used for IRC networks (and thus not HTTP). One can remedy that by either switching to another port (both in the firewall settings and the ZNC configuration) or by forcing Chrome to explicitly allow it: 38 | 39 | #+begin_src sh :eval never 40 | chromium --explicitly-allowed-ports=6697 41 | #+end_src 42 | 43 | ** Use a Let's Encrypt Certificate with ZNC 44 | 45 | Let's Encrypt is a service that enables people to use SSL encryption more easily on the internet. Signed and verified certificates can be acquired using a simple CLI tool called =certbot=. The certificates expire rather quickly, and this is why auto-renewal steps are also shown below. 46 | 47 | #+begin_src sh :eval never 48 | $ sudo certbot certonly --standalone --preferred-challenges http --http-01-port 80 -d znc.example.org 49 | #+end_src 50 | 51 | In order to work over SSL, ZNC expects a combined cert file =znc.pem= to be accessible to it in the znc home path =/var/lib/znc/.znc=. 52 | 53 | #+begin_src sh :eval never 54 | $ sudo cat /etc/letsencrypt/live/znc.example.org/{privkey,fullchain}.pem > znc.pem 55 | $ sudo mv znc.pem /var/lib/znc/.znc/ 56 | $ sudo chown znc:znc /var/lib/znc/.znc/znc.pem 57 | #+end_src 58 | 59 | Make a crontab and renewal script to automatically check Let's Encrypt for certificate updates, and trigger a change to =znc.pem= when certificates are renewed. 60 | 61 | #+begin_src sh :eval never 62 | $ sudo touch /etc/letsencrypt/renewal-hooks/deploy/update-znc.pem 63 | $ sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/update-znc.pem 64 | #+end_src 65 | 66 | Copy the following into the =update-znc.pem= file using a text editor i.e. =sudo vi /etc/letsencrypt/renewal-hooks/deploy/update-znc.pem=. 67 | 68 | #+begin_src bash :eval never 69 | #!/bin/bash 70 | YOURDOMAIN="znc.example.org" 71 | 72 | [[ $RENEWED_LINEAGE != "/etc/letsencrypt/live/$YOURDOMAIN" ]] && exit 0 73 | echo "Updating certs" 74 | cat /etc/letsencrypt/live/$YOURDOMAIN/{privkey,fullchain}.pem > /var/lib/znc/.znc/znc.pem 75 | #+end_src 76 | 77 | Add this to cron by running ~crontab -e~. This will attempt renewal everyday at 3:15 a.m. you can change this time to any time you like. 78 | 79 | #+begin_src 80 | 15 3 * * * /usr/bin/certbot renew --quiet 81 | #+end_src 82 | 83 | Running ZNC. 84 | 85 | #+begin_src sh :eval never 86 | $ sudo -u znc znc --makeconf 87 | #+end_src 88 | 89 | Fill in the subsequent prompts with details that make sense for yourself. 90 | 91 | #+begin_src 92 | [ ?? ] Username (alphanumeric): willvaughn 93 | [ ?? ] Enter password: 94 | [ ?? ] Confirm password: 95 | [ ?? ] Nick [willvaughn]: nackjicholson 96 | [ ?? ] Alternate nick [nackjicholson_]: 97 | [ ?? ] Ident [willvaughn]: nackjicholson 98 | [ ?? ] Real name (optional): William Vaughn 99 | [ ?? ] Bind host (optional): 100 | [ ** ] Enabled user modules [chansaver, controlpanel] 101 | [ ** ] 102 | [ ?? ] Set up a network? (yes/no) [yes]: 103 | [ ** ] 104 | [ ** ] -- Network settings -- 105 | [ ** ] 106 | [ ?? ] Name [freenode]: libera 107 | [ ?? ] Server host (host only): irc.libera.chat 108 | [ ?? ] Server uses SSL? (yes/no) [no]: yes 109 | [ ?? ] Server port (1 to 65535) [6697]: 6697 110 | [ ?? ] Server password (probably empty): 111 | [ ?? ] Initial channels: 112 | #+end_src 113 | 114 | Run the ZNC systemd service. 115 | 116 | #+begin_src sh :eval never 117 | $ sudo systemctl start znc 118 | $ sudo systemctl enable znc 119 | #+end_src 120 | 121 | You should now be able to visit znc.example.com:6697 to use the ZNC web frontend. You can also connect to ZNC using =erc-tls=. If your browser blocks the 6697 port, read up on configuring settings to work around that on the znc wiki [[https://wiki.znc.in/FAQ#How_can_I_access_webadmin_with_my_browser.3F][here]]. 122 | 123 | #+begin_src emacs-lisp :eval never 124 | (erc-tls :server "znc.example.org" :port 6697 :nick "nackjicholson" :password "willvaughn/libera:") 125 | #+end_src 126 | * Tips, Tricks, and Troubleshooting 127 | Please add your own timps and tricks by editing the wiki. 128 | 129 | ** Fixing your nick 130 | 131 | Occasionally, the ZNC server may log you in as your alternate name. Usually that will mean that your name will have a trailing =_= on it. If you get stuck like that and it's not because your main nick is also logged in on another client, there is a trick to switching back to the main nick. By typing ~/nick ~ in your client you can trigger the ZNC server to configure a different nickname for this session. Then quitting and reconnecting should use the changed nickname that is configured. 132 | -------------------------------------------------------------------------------- /content/emacs/Counsel-insert-relative-file-path.org: -------------------------------------------------------------------------------- 1 | * Insert relative file path in current buffer using counsel 2 | ** 3 | Useful while inserting figures path/name in ~latex~. Similar to ~C-x C-f~ in ~vim~. 4 | 5 | source: [[https://emacs.stackexchange.com/questions/39105/insert-file-path-via-counsel][stack answer]] 6 | 7 | #+begin_src emacs-lisp 8 | (defun try-counsel-insert-file-path () 9 | "Insert relative file path in current buffer using counsel in minibuffer" 10 | (interactive) 11 | (unless (featurep 'counsel) (require 'counsel)) 12 | (ivy-read "Insert filename: " 'read-file-name-internal 13 | :matcher #'counsel--find-file-matcher 14 | :action 15 | (lambda (x) 16 | (insert (file-relative-name x))))) 17 | #+end_src 18 | 19 | 20 | 21 | ** 22 | Recommended keybinding and counsel setting 23 | 24 | #+begin_src emacs-lisp 25 | (use-package general 26 | :config 27 | (general-evil-setup t) 28 | 29 | (general-create-definer try/ctrl-c-keys 30 | :prefix "C-c")) 31 | 32 | (try/ctrl-c-keys 33 | "i" '(try-counsel-insert-file-path :which-key "insert relative filepath") 34 | ) 35 | #+end_src 36 | 37 | #+begin_src emacs-lisp 38 | (use-package counsel 39 | :diminish ivy-mode 40 | :diminish counsel-mode 41 | :bind (("C-s" . swiper) 42 | :map ivy-minibuffer-map 43 | ("TAB" . ivy-alt-done)) 44 | :init 45 | (ivy-mode 1) 46 | (counsel-mode 1) 47 | :config 48 | (setq ivy-use-virtual-buffers t) 49 | (setq enable-recursive-minibuffers t)) 50 | #+end_src -------------------------------------------------------------------------------- /content/emacs/LSP-Python-(pyright)-config-in-emacs-from-scratch.org: -------------------------------------------------------------------------------- 1 | #+title: EMACS python configuration from scratch using lsp-pyright 2 | #+startup: overview 3 | * Installation of packages 4 | ** Straight 5 | We will use ~straight.el~ to install packages 6 | #+begin_src emacs-lisp 7 | (defvar bootstrap-version) 8 | (let ((bootstrap-file 9 | (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) 10 | (bootstrap-version 5)) 11 | (unless (file-exists-p bootstrap-file) 12 | (with-current-buffer 13 | (url-retrieve-synchronously 14 | "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 15 | 'silent 'inhibit-cookies) 16 | (goto-char (point-max)) 17 | (eval-print-last-sexp))) 18 | (load bootstrap-file nil 'nomessage)) 19 | 20 | (straight-use-package 'use-package) 21 | (setq straight-use-package-by-default t) 22 | #+end_src 23 | 24 | ** Performance 25 | These options improve performance for lsp in emacs. Use ~M-x~ ~lsp-doctor~ in lsp-mode to investigate performance of your config.\\ 26 | 27 | check lsp documentation at [[https://emacs-lsp.github.io/lsp-mode/page/performance/][lsp performace]] \\ 28 | 29 | #+begin_src emacs-lisp 30 | ;; The default is 800 kilobytes. Measured in bytes. 31 | (setq gc-cons-threshold (* 100 1024 1024)) ;; 100 MB 32 | (setq read-process-output-max (* 1 1024 1024)) ;; 1 MB 33 | #+end_src 34 | 35 | ** No littering 36 | Keep clean =~/.emacs.d= folder. 37 | 38 | Check ~lsp~ files in =~/.emacs.d/var/lsp/*=. 39 | 40 | You can delete/modify this folder to hard reset lsp configuration in emacs. 41 | 42 | [[https://github.com/daviwil/emacs-from-scratch/blob/master/Emacs.org#keep-folders-clean][taken from EFS]] \\ 43 | 44 | #+begin_src emacs-lisp 45 | (use-package no-littering) 46 | 47 | ;; no-littering doesn't set this by default so we must place 48 | ;; auto save files in the same path as it uses for sessions 49 | (setq auto-save-file-name-transforms 50 | `((".*" ,(no-littering-expand-var-file-name "auto-save/") t))) 51 | 52 | #+end_src 53 | 54 | * Evil 55 | evil mode [[https://evil.readthedocs.io/en/latest/overview.html#installation-via-package-el][source]] 56 | ** evil mode 57 | [[https://github.com/emacs-evil/evil][github repo]] 58 | #+begin_src emacs-lisp 59 | (use-package evil 60 | :init 61 | (setq evil-toggle-key "C-") 62 | (setq evil-shift-width 2) 63 | (setq evil-want-integration t) 64 | (setq evil-want-keybinding nil) 65 | :custom 66 | (evil-undo-system 'undo-tree) 67 | :config 68 | (evil-mode 1) 69 | 70 | (define-key evil-insert-state-map (kbd "C-g") 'evil-normal-state) 71 | (define-key evil-insert-state-map (kbd "C-h") 'evil-delete-backward-char-and-join) 72 | 73 | ;; Use visual line motions even outside of visual-line-mode buffers 74 | (evil-global-set-key 'motion "j" 'evil-next-visual-line) 75 | (evil-global-set-key 'motion "k" 'evil-previous-visual-line) 76 | 77 | (evil-set-initial-state 'help-mode 'emacs) 78 | (evil-set-initial-state 'inferior-python-mode 'emacs) 79 | (evil-set-initial-state 'messages-buffer-mode 'emacs) 80 | (evil-set-initial-state 'dashboard-mode 'emacs) 81 | (evil-set-initial-state 'special-mode 'emacs) 82 | (evil-set-initial-state 'view-mode 'emacs) 83 | ) 84 | #+end_src 85 | 86 | ** evil-nerd-commentor 87 | Use ~M-/~ for comment/uncomment. 88 | 89 | [[https://github.com/redguardtoo/evil-nerd-commenter][source]] 90 | #+begin_src emacs-lisp 91 | (use-package evil-nerd-commenter 92 | :bind ("M-/" . evilnc-comment-or-uncomment-lines)) 93 | #+end_src 94 | 95 | ** undo-tree 96 | #+begin_src emacs-lisp 97 | (use-package undo-tree 98 | :diminish undo-tree-mode 99 | :config 100 | (global-undo-tree-mode) 101 | ) 102 | 103 | #+end_src 104 | 105 | * Ivy, counsel 106 | ** counsel 107 | #+begin_src emacs-lisp 108 | (use-package counsel 109 | :diminish ivy-mode 110 | :diminish counsel-mode 111 | :bind (("C-s" . swiper) 112 | :map ivy-minibuffer-map 113 | ("TAB" . ivy-alt-done)) 114 | :init 115 | (ivy-mode 1) 116 | (counsel-mode 1) 117 | :config 118 | (setq ivy-use-virtual-buffers t) 119 | (setq enable-recursive-minibuffers t)) 120 | #+end_src 121 | 122 | ** ivy-misc 123 | [[https://github.com/Yevgnen/ivy-rich]] 124 | #+begin_src emacs-lisp 125 | (use-package ivy-xref 126 | :init 127 | ;; xref initialization is different in Emacs 27 - there are two different 128 | ;; variables which can be set rather than just one 129 | (when (>= emacs-major-version 27) 130 | (setq xref-show-definitions-function #'ivy-xref-show-defs)) 131 | ;; Necessary in Emacs <27. In Emacs 27 it will affect all xref-based 132 | ;; commands other than xref-find-definitions (e.g. project-find-regexp) 133 | ;; as well 134 | (setq xref-show-xrefs-function #'ivy-xref-show-xrefs)) 135 | 136 | (use-package ivy-rich 137 | :init 138 | (ivy-rich-mode 1)) 139 | 140 | #+end_src 141 | 142 | ** prescient 143 | #+begin_src emacs-lisp 144 | (use-package ivy-prescient 145 | :after counsel 146 | :init 147 | (ivy-prescient-mode) 148 | (prescient-persist-mode) 149 | ) 150 | (use-package prescient 151 | :diminish 152 | :config 153 | ) 154 | #+end_src 155 | 156 | * Treemacs 157 | #+begin_src emacs-lisp 158 | (use-package treemacs) 159 | #+end_src 160 | 161 | * Tools 162 | ** which-key 163 | #+begin_src emacs-lisp 164 | (use-package which-key 165 | :diminish which-key-mode 166 | :config 167 | (which-key-mode)) 168 | 169 | #+end_src 170 | 171 | ** magit 172 | [[https://magit.vc/][Magit]] is the best Git interface. Common Git operations are easy to execute quickly using Magit’s command panel system. 173 | #+begin_src emacs-lisp 174 | (use-package magit 175 | :defer t 176 | :bind ("C-x g" . magit-status)) 177 | #+end_src 178 | 179 | ** projectile 180 | [[https://docs.projectile.mx/projectile/index.html][Projectile]] is a project management library for Emacs which makes it a lot easier to navigate around code projects for various languages. Many packages integrate with Projectile so it’s a good idea to have it installed even if you don’t use its commands directly. 181 | 182 | #+begin_src emacs-lisp 183 | (use-package projectile 184 | :diminish projectile-mode 185 | :hook 186 | (after-init . projectile-mode) 187 | :bind-keymap 188 | ("C-c p" . projectile-command-map) 189 | :init 190 | ;; NOTE: Set this to the folder where you keep your Git repos! 191 | (setq projectile-project-search-path '("~/foo/projects" "~/foo/reports")) 192 | (setq projectile-switch-project-action #'projectile-dired) 193 | :custom 194 | (projectile-completion-system 'ivy) 195 | (projectile-dynamic-mode-line nil) 196 | (projectile-enable-caching t) 197 | (projectile-indexing-method 'hybrid) 198 | (projectile-track-known-projects-automatically nil)) 199 | 200 | (use-package counsel-projectile 201 | :config (counsel-projectile-mode)) 202 | 203 | #+end_src 204 | ** eldoc 205 | #+begin_src emacs-lisp 206 | (use-package eldoc 207 | :diminish eldoc-mode 208 | ) 209 | #+end_src 210 | 211 | * Company 212 | ** company-mode 213 | #+begin_src emacs-lisp 214 | (use-package company 215 | :diminish company-mode 216 | :bind (:map company-active-map 217 | ("" . nil) 218 | ("TAB" . nil) 219 | ("M-" . company-complete-common-or-cycle) 220 | ("M-" . company-complete-selection)) 221 | (:map lsp-mode-map 222 | ("M-" . company-indent-or-complete-common)) 223 | :custom 224 | (company-minimum-prefix-length 2) 225 | (company-idle-delay 0.01) 226 | :config 227 | ) 228 | #+end_src 229 | 230 | ** prescient 231 | #+begin_src emacs-lisp 232 | (use-package company-prescient 233 | :after company 234 | :config 235 | (company-prescient-mode 1) 236 | (prescient-persist-mode) 237 | ) 238 | #+end_src 239 | 240 | * Yasnippet 241 | #+begin_src emacs-lisp 242 | (use-package yasnippet-snippets) 243 | (use-package yasnippet 244 | :diminish yas-minor-mode 245 | :config 246 | (yas-reload-all) 247 | ) 248 | #+end_src 249 | 250 | * Flycheck 251 | #+begin_src emacs-lisp 252 | (use-package flycheck 253 | :diminish flycheck-mode 254 | :init 255 | (setq flycheck-check-syntax-automatically '(save new-line) 256 | flycheck-idle-change-delay 5.0 257 | flycheck-display-errors-delay 0.9 258 | flycheck-highlighting-mode 'symbols 259 | flycheck-indication-mode 'left-fringe 260 | flycheck-standard-error-navigation t 261 | flycheck-deferred-syntax-check nil) 262 | ) 263 | #+end_src 264 | 265 | * Lsp mode 266 | ** lsp-mode 267 | [[https://github.com/daviwil/dotfiles/blob/master/Emacs.org#language-server-support][EFS notes]] \\ 268 | 269 | Nice article about main features of emacs lsp-mode ([[https://emacs-lsp.github.io/lsp-mode/page/main-features/][source)]] \\ 270 | 271 | EFS video [[https://github.com/daviwil/emacs-from-scratch/blob/master/show-notes/Emacs-08.org][notes]]\\ 272 | 273 | java specific lsp [[https://github.com/neppramod/java_emacs/blob/master/emacs-configuration.org][setting]] to learn how to setup lsp in emacs\\ 274 | 275 | Nice article to switch on/off certain features of lsp ([[https://emacs-lsp.github.io/lsp-mode/tutorials/how-to-turn-off/][source)]] \\ 276 | 277 | #+begin_src emacs-lisp 278 | (use-package lsp-mode 279 | :commands (lsp lsp-deferred) 280 | :hook 281 | (lsp-mode . lsp-enable-which-key-integration) 282 | :custom 283 | (lsp-diagnostics-provider :capf) 284 | (lsp-headerline-breadcrumb-enable t) 285 | (lsp-headerline-breadcrumb-segments '(project file symbols)) 286 | (lsp-lens-enable nil) 287 | (lsp-disabled-clients '((python-mode . pyls))) 288 | :init 289 | (setq lsp-keymap-prefix "C-c l") ;; Or 'C-l', 's-l' 290 | :config 291 | ) 292 | #+end_src 293 | 294 | ** lsp-ivy 295 | [[https://github.com/emacs-lsp/lsp-ivy][source github]]\\ 296 | 297 | lsp-ivy integrates Ivy with lsp-mode to make it easy to search for things by name in your code. When you run these commands, a prompt will appear in the minibuffer allowing you to type part of the name of a symbol in your code. Results will be populated in the minibuffer so that you can find what you’re looking for and jump to that location in the code upon selecting the result.\\ 298 | 299 | Try these commands with ~M-x~:\\ 300 | 301 | ~lsp-ivy-workspace-symbol~ - Search for a symbol name in the current project workspace\\ 302 | 303 | ~lsp-ivy-global-workspace-symbol~ - Search for a symbol name in all active project workspaces\\ 304 | 305 | #+begin_src emacs-lisp 306 | (use-package lsp-ivy 307 | :after lsp-mode 308 | ) 309 | #+end_src 310 | 311 | ** lsp-ui 312 | Documentation: [[https://emacs-lsp.github.io/lsp-ui/]] 313 | 314 | - ~lsp-ui-doc-focus-frame~ to enter the documentation frame to navigate and search around 315 | 316 | - ~lsp-ui-doc-unfocus-frame~ to leave documentation frame 317 | 318 | #+begin_src emacs-lisp 319 | (use-package lsp-ui 320 | :hook (lsp-mode . lsp-ui-mode) 321 | :after lsp-mode 322 | :custom 323 | (lsp-ui-doc-show-with-cursor nil) 324 | :config 325 | (setq lsp-ui-doc-position 'bottom) 326 | ) 327 | #+end_src 328 | 329 | ** lsp-treemacs 330 | Provides an even nicer UI on top of lsp-mode using Treemacs\\ 331 | 332 | - ~lsp-treemacs-symbols~ - Show a tree view of the symbols in the current file 333 | 334 | - ~lsp-treemacs-references~ - Show a tree view for the references of the symbol under the cursor 335 | 336 | - ~lsp-treemacs-error-list~ - Show a tree view for the diagnostic messages in the project 337 | 338 | #+begin_src emacs-lisp 339 | (use-package lsp-treemacs 340 | :after (lsp-mode treemacs) 341 | ) 342 | #+end_src 343 | 344 | * Python configuration 345 | [[https://github.com/daviwil/emacs-from-scratch/blob/master/show-notes/Emacs-IDE-02.org][efs series notes]]\\ 346 | 347 | [[https://ddavis.io/posts/emacs-python-lsp]]\\ 348 | 349 | some options are 350 | 351 | - [[https://emacs-lsp.github.io/lsp-mode/page/lsp-pyls/][pyls]] Palantir 352 | 353 | - [[https://emacs-lsp.github.io/lsp-python-ms][microsoft]] now depreciated by MS 354 | 355 | - [[https://emacs-lsp.github.io/lsp-pyright][pyright]] also by Microsoft 356 | 357 | ** pyright 358 | [[https://emacs-lsp.github.io/lsp-pyright/#configuration][config]] \\ 359 | 360 | #+begin_src emacs-lisp 361 | (use-package lsp-pyright 362 | :hook 363 | (python-mode . (lambda () 364 | (require 'lsp-pyright) 365 | (lsp-deferred)))) 366 | #+end_src 367 | 368 | ** pyvenv 369 | Strongly recommend to use python virtualenv to python work properly in emacs.\\ 370 | 371 | Assuming venvs are installed here =~/.venvs=\\ 372 | 373 | Learn about setting python virtual env below\\ 374 | 375 | [[https://blog.fredrikmeyer.net/2020/08/26/emacs-python-venv.html]]\\ 376 | 377 | [[https://ddavis.io/posts/emacs-python-lsp]]\\ 378 | 379 | You can use ~M-x pyvenv-activate~ to activate specific venv \\ 380 | 381 | #+begin_src emacs-lisp 382 | (use-package pyvenv 383 | :ensure t 384 | :init 385 | (setenv "WORKON_HOME" "~/.venvs/") 386 | :config 387 | ;; (pyvenv-mode t) 388 | 389 | ;; Set correct Python interpreter 390 | (setq pyvenv-post-activate-hooks 391 | (list (lambda () 392 | (setq python-shell-interpreter (concat pyvenv-virtual-env "bin/python"))))) 393 | (setq pyvenv-post-deactivate-hooks 394 | (list (lambda () 395 | (setq python-shell-interpreter "python3"))))) 396 | 397 | #+end_src 398 | 399 | ** formatting 400 | #+begin_src emacs-lisp 401 | (use-package blacken 402 | :init 403 | (setq-default blacken-fast-unsafe t) 404 | (setq-default blacken-line-length 80) 405 | ) 406 | #+end_src 407 | 408 | ** python-mode 409 | #+begin_src emacs-lisp 410 | (use-package python-mode 411 | :hook 412 | (python-mode . pyvenv-mode) 413 | (python-mode . flycheck-mode) 414 | (python-mode . company-mode) 415 | (python-mode . blacken-mode) 416 | (python-mode . yas-minor-mode) 417 | :custom 418 | ;; NOTE: Set these if Python 3 is called "python3" on your system! 419 | (python-shell-interpreter "python3") 420 | :config 421 | ) 422 | #+end_src 423 | 424 | * Keybinding 425 | Have a look at [[https://www.masteringemacs.org/article/mastering-key-bindings-emacs][mastering emacs]] tips for emacs keybinding.\\ 426 | 427 | ~C-c ~ and ~F5-F9~ are meant for user bindings.\\ 428 | 429 | For package maintainers, ~C-c C-~ or ~C-c ~ or ~C-c [{};:<>]~ are reserved for the major mode. Any other are reserved for minor modes, e.g. ~C-c @~ in =outline-minor-mode=. \\ 430 | 431 | See ~(info "(elisp) Key Binding Conventions")~ for a more complete explanation for package maintainers. You, as a user, can of course use any key binding you like, but keep in mind that those bindings might conflict with the ones chosen by the package maintainer.\\ 432 | 433 | ** General setup 434 | we will use general package ([[https://github.com/noctuid/general.el][source]]) for keybindings. 435 | #+begin_src emacs-lisp 436 | (use-package general 437 | :config 438 | (general-evil-setup t) 439 | 440 | (general-create-definer my/ctrl-c-keys 441 | :prefix "C-c") 442 | ) 443 | #+end_src 444 | 445 | ** Global keys 446 | use ~C-c~ prefix for global keybinding defined below 447 | #+begin_src emacs-lisp 448 | 449 | (my/ctrl-c-keys 450 | "t" '(treemacs-select-window :which-key "treemacs-select") 451 | ) 452 | #+end_src 453 | 454 | ** Lsp keybinding 455 | use ~SPC~ prefix for ~lsp-mode~ keybinding defined below. These keybindings are for ~evil~ normal mode. 456 | #+begin_src emacs-lisp 457 | 458 | (general-define-key 459 | :states '(normal visual) 460 | :keymaps 'lsp-mode-map 461 | :prefix "SPC" 462 | "d" '(lsp-find-definition :which-key "find-definitions") 463 | "r" '(lsp-find-references :which-key "find-references") 464 | "h" '(lsp-describe-thing-at-point :which-key "help-detailed") 465 | "e" '(lsp-ui-flycheck-list :which-key "flycheck-list") 466 | "o" 'counsel-imenu 467 | "x" 'lsp-execute-code-action) 468 | #+end_src 469 | 470 | * Workflow 471 | We assume following file structure for your project 472 | #+begin_src 473 | fooproject 474 | |--- .git 475 | |--- src 476 | |--- foo.py 477 | |--- .dir-locals.el 478 | |--- pyrightconfig.json 479 | 480 | #+end_src 481 | 482 | We assume =~/.venvs/foo_env= is the virtual environment you want to use for this project\\ 483 | 484 | The =~/.venvs= folder is already set in ~pyvenv~ setting above.\\ 485 | 486 | So, ~foo_env~ will be set using ~pyvenv-workon~ variable using ~.dir-locals.el~ file 487 | 488 | *** .dir-locals.el 489 | #+begin_src emacs-lisp 490 | (python-mode . ((pyvenv-workon . "foo_env"))) 491 | #+end_src 492 | 493 | *** pyrightconfig.json (optional) 494 | You can using minimal expample as your pyrightconfig file 495 | 496 | Check following for more options ([[https://github.com/microsoft/pyright/blob/master/docs/configuration.md][source]]) 497 | 498 | #+begin_src 499 | { 500 | "include": [ 501 | "src" 502 | ], 503 | "executionEnvironments": [ 504 | { 505 | "root": "src" 506 | } 507 | ] 508 | } 509 | #+end_src 510 | 511 | * How to set python virtualenv 512 | Some useful commands to setup virtualenv\\ 513 | 514 | - installation 515 | 516 | #+begin_src 517 | $ pip3 install virtualenv 518 | $ pip3 list 519 | $ mkdir ~/.venvs 520 | $ cd ~/.venvs 521 | #+end_src 522 | 523 | - create virtual environment 524 | 525 | #+begin_src 526 | $ virtualenv foo_env 527 | $ source foo_env/bin/activate 528 | $ which python 529 | #+end_src 530 | 531 | - install packages in virtual env 532 | 533 | #+begin_src 534 | $ pip install numpy 535 | $ pip list 536 | $ pip freeze --local > requirement.txt 537 | #+end_src 538 | 539 | - deactivate virtualenv 540 | 541 | #+begin_src 542 | $ deactivate 543 | #+end_src 544 | 545 | - add pythonpath (~.pth~) to already existing virtulenv 546 | 547 | If you have external projects you want to include in the pythonpath of your virtualenv, checkout following,\\ 548 | 549 | [[https://stackoverflow.com/a/47184788/237059]] 550 | 551 | #+begin_src shell 552 | cd $(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") 553 | echo some/library/path > some-library.pth 554 | #+end_src 555 | 556 | -------------------------------------------------------------------------------- /content/emacs/LaTeX-config-(AucteX)-in-Emacs-from-scratch.org: -------------------------------------------------------------------------------- 1 | #+startup: overview 2 | ** Packages and config 3 | *** straight 4 | #+begin_src emacs-lisp 5 | (defvar bootstrap-version) 6 | (let ((bootstrap-file 7 | (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) 8 | (bootstrap-version 5)) 9 | (unless (file-exists-p bootstrap-file) 10 | (with-current-buffer 11 | (url-retrieve-synchronously 12 | "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 13 | 'silent 'inhibit-cookies) 14 | (goto-char (point-max)) 15 | (eval-print-last-sexp))) 16 | (load bootstrap-file nil 'nomessage)) 17 | 18 | (straight-use-package 'use-package) 19 | (setq straight-use-package-by-default t) 20 | #+end_src 21 | 22 | *** evil 23 | 24 | #+begin_src emacs-lisp 25 | (use-package evil 26 | :init 27 | (setq evil-toggle-key "C-") 28 | (setq evil-shift-width 2) 29 | (setq evil-want-integration t) 30 | (setq evil-want-keybinding nil) 31 | :config 32 | (evil-mode 1) 33 | 34 | ;; Use visual line motions even outside of visual-line-mode buffers 35 | (evil-global-set-key 'motion "j" 'evil-next-visual-line) 36 | (evil-global-set-key 'motion "k" 'evil-previous-visual-line) 37 | 38 | (evil-set-initial-state 'dired-mode 'emacs) 39 | (evil-set-initial-state 'pdf-view-mode 'emacs) 40 | (evil-set-initial-state 'messages-buffer-mode 'emacs) 41 | ) 42 | 43 | (use-package evil-nerd-commenter 44 | :bind ("M-/" . evilnc-comment-or-uncomment-lines)) 45 | 46 | #+end_src 47 | *** counsel, ivy setting 48 | #+begin_src emacs-lisp 49 | (use-package counsel 50 | :diminish ivy-mode 51 | :diminish counsel-mode 52 | :bind (("C-s" . swiper) 53 | :map ivy-minibuffer-map 54 | ("TAB" . ivy-alt-done)) 55 | :init 56 | (ivy-mode 1) 57 | (counsel-mode 1) 58 | :config 59 | (setq ivy-use-virtual-buffers t) 60 | (setq enable-recursive-minibuffers t)) 61 | 62 | (use-package prescient 63 | :diminish 64 | :config 65 | ;; (prescient-persist-mode) 66 | ) 67 | 68 | 69 | (use-package ivy-prescient 70 | :after counsel 71 | :init 72 | (ivy-prescient-mode) 73 | (prescient-persist-mode) 74 | ) 75 | #+end_src 76 | *** company 77 | 78 | #+begin_src emacs-lisp 79 | (use-package company 80 | :straight (company :files (:defaults "icons")) 81 | :diminish company-mode 82 | :bind (:map company-active-map 83 | ("" . nil) 84 | ("TAB" . nil)) 85 | :custom 86 | (company-minimum-prefix-length 2) 87 | (company-idle-delay 0.01) 88 | :config 89 | ) 90 | 91 | (use-package company-prescient 92 | :after company 93 | :config 94 | (company-prescient-mode 1) 95 | (prescient-persist-mode) 96 | ) 97 | #+end_src 98 | 99 | *** magit, which key 100 | #+begin_src emacs-lisp 101 | (use-package which-key 102 | ;; :ensure t 103 | :diminish which-key-mode 104 | :config 105 | (which-key-mode)) 106 | 107 | ; magit 108 | (use-package magit 109 | ;; :ensure t 110 | :defer t 111 | :bind ("C-x g" . magit-status)) 112 | #+end_src 113 | *** pdf-tools 114 | #+begin_src emacs-lisp 115 | (use-package pdf-tools 116 | :magic ("%PDF" . pdf-view-mode) 117 | :config 118 | (pdf-tools-install) 119 | (setq-default pdf-view-display-size 'fit-page) 120 | ) 121 | 122 | #+end_src 123 | 124 | *** Custom functions 125 | #+begin_src emacs-lisp 126 | 127 | (defun try/TeX-command-save-buffer-and-run-all () 128 | "Save the buffer and run TeX-command-run-all" 129 | (interactive) 130 | (let (TeX-save-query) (TeX-save-document (TeX-master-file))) 131 | (TeX-command-run-all nil)) 132 | 133 | ;; copied ivy-bibtex and modified it to cite action 134 | (defun try/ivy-bibtex-cite (&optional arg local-bib) 135 | "Search BibTeX entries using ivy. 136 | 137 | With a prefix ARG the cache is invalidated and the bibliography 138 | reread. 139 | 140 | If LOCAL-BIB is non-nil, display that the BibTeX entries are read 141 | from the local bibliography. This is set internally by 142 | `ivy-bibtex-with-local-bibliography'." 143 | (interactive "P") 144 | (when arg 145 | (bibtex-completion-clear-cache)) 146 | (bibtex-completion-init) 147 | (let* ((candidates (bibtex-completion-candidates)) 148 | (key (bibtex-completion-key-at-point)) 149 | (preselect (and key 150 | (cl-position-if (lambda (cand) 151 | (member (cons "=key=" key) 152 | (cdr cand))) 153 | candidates)))) 154 | (ivy-read (format "Insert citation %s: " (if local-bib " (local)" "")) 155 | candidates 156 | :preselect preselect 157 | :caller 'ivy-bibtex 158 | :history 'ivy-bibtex-history 159 | :action 'ivy-bibtex-insert-citation))) 160 | 161 | (defun try/latex-mode-setup () 162 | (require 'company-reftex) 163 | (turn-on-reftex) 164 | (require 'company-auctex) 165 | (require 'company-math) 166 | (setq-local company-backends 167 | 168 | (append '( 169 | (company-reftex-labels 170 | company-reftex-citations) 171 | (company-math-symbols-unicode company-math-symbols-latex company-latex-commands) 172 | (company-auctex-macros company-auctex-symbols company-auctex-environments) 173 | company-ispell 174 | ) 175 | company-backends))) 176 | 177 | 178 | (defun try/counsel-insert-file-path () 179 | "Insert relative file path using counsel minibuffer" 180 | (interactive) 181 | (unless (featurep 'counsel) (require 'counsel)) 182 | (ivy-read "Insert filename: " 'read-file-name-internal 183 | :matcher #'counsel--find-file-matcher 184 | :action 185 | (lambda (x) 186 | (insert (file-relative-name x))))) 187 | 188 | #+end_src 189 | 190 | *** Olivetti 191 | #+begin_src emacs-lisp 192 | (use-package olivetti 193 | :diminish 194 | :hook (text-mode . olivetti-mode) 195 | :config 196 | (setq olivetti-body-width 100) 197 | ) 198 | #+end_src 199 | 200 | *** latex 201 | **** folding/unfolding like org-mode 202 | Enable folding and unfolding sections just like org-mode (using ~TAB~) using [[https://github.com/alphapapa/outshine/issues/85][outshine]] 203 | 204 | Check ~outshine-cycle~ for more options. 205 | #+begin_src emacs-lisp 206 | (use-package outshine 207 | :config 208 | (setq LaTeX-section-list '( 209 | ("part" 0) 210 | ("chapter" 1) 211 | ("section" 2) 212 | ("subsection" 3) 213 | ("subsubsection" 4) 214 | ("paragraph" 5) 215 | ("subparagraph" 6) 216 | ("begin" 7) 217 | ) 218 | ) 219 | (add-hook 'LaTeX-mode-hook #'(lambda () 220 | (outshine-mode 1) 221 | (setq outline-level #'LaTeX-outline-level) 222 | (setq outline-regexp (LaTeX-outline-regexp t)) 223 | (setq outline-heading-alist 224 | (mapcar (lambda (x) 225 | (cons (concat "\\" (nth 0 x)) (nth 1 x))) 226 | LaTeX-section-list)))) 227 | 228 | ) 229 | 230 | (general-define-key 231 | :states '(normal visual) 232 | :keymaps 'LaTeX-mode-map 233 | "TAB" '(outshine-cycle :which-key "outshine-cycle") 234 | ) 235 | #+end_src 236 | **** auctex 237 | [[https://people.umass.edu/weikaichen/post/emacs-academic-tools/][source: blog]] 238 | #+begin_src emacs-lisp 239 | 240 | ;; latexmk 241 | (use-package auctex-latexmk) 242 | ;; company 243 | (use-package company-math) 244 | (use-package company-auctex) 245 | (use-package company-reftex) 246 | 247 | 248 | ;; use cdlatex 249 | (use-package cdlatex) 250 | 251 | ;; https://gist.github.com/saevarb/367d3266b3f302ecc896 252 | ;; https://piotr.is/2010/emacs-as-the-ultimate-latex-editor/ 253 | 254 | (use-package latex 255 | :straight auctex 256 | :defer t 257 | :custom 258 | (olivetti-body-width 100) 259 | (cdlatex-simplify-sub-super-scripts nil) 260 | (reftex-default-bibliography 261 | '("~/ref.bib")) 262 | (bibtex-dialect 'biblatex) 263 | :mode 264 | ("\\.tex\\'" . latex-mode) 265 | :bind (:map LaTeX-mode-map 266 | ("C-c C-e" . cdlatex-environment) 267 | ) 268 | :hook 269 | (LaTeX-mode . olivetti-mode) 270 | (LaTeX-mode . TeX-PDF-mode) 271 | (LaTeX-mode . company-mode) 272 | (LaTeX-mode . flyspell-mode) 273 | (LaTeX-mode . flycheck-mode) 274 | (LaTeX-mode . LaTeX-math-mode) 275 | (LaTeX-mode . turn-on-reftex) 276 | (LaTeX-mode . TeX-source-correlate-mode) 277 | (LaTeX-mode . try/latex-mode-setup) 278 | (LaTeX-mode . turn-on-cdlatex) 279 | 280 | :config 281 | (setq TeX-auto-save t) 282 | (setq TeX-parse-self t) 283 | (setq-default TeX-master nil) 284 | (setq TeX-save-query nil) 285 | 286 | (setq reftex-plug-into-AUCTeX t) 287 | 288 | ;; pdftools 289 | ;; https://emacs.stackexchange.com/questions/21755/use-pdfview-as-default-auctex-pdf-viewer#21764 290 | (setq TeX-view-program-selection '((output-pdf "PDF Tools")) 291 | TeX-view-program-list '(("PDF Tools" TeX-pdf-tools-sync-view)) 292 | TeX-source-correlate-start-server t) ;; not sure if last line is neccessary 293 | ;; to have the buffer refresh after compilation, 294 | ;; very important so that PDFView refesh itself after comilation 295 | (add-hook 'TeX-after-compilation-finished-functions 296 | #'TeX-revert-document-buffer) 297 | 298 | ;; latexmk 299 | (require 'auctex-latexmk) 300 | (auctex-latexmk-setup) 301 | (setq auctex-latexmk-inherit-TeX-PDF-mode t) 302 | ) 303 | #+end_src 304 | 305 | **** ivy-bibtex 306 | 307 | #+begin_src emacs-lisp 308 | 309 | (use-package ivy-bibtex 310 | :custom 311 | (bibtex-completion-bibliography 312 | '("~/ref.bib")) 313 | (bibtex-completion-library-path '("~/papers")) 314 | (bibtex-completion-cite-prompt-for-optional-arguments nil) 315 | (bibtex-completion-cite-default-as-initial-input t) 316 | ) 317 | 318 | #+end_src 319 | **** org-ref 320 | 321 | #+begin_src emacs-lisp 322 | (use-package org-ref 323 | :custom 324 | (org-ref-default-bibliography "~/ref.bib") 325 | (org-ref-pdf-directory "~/papers") 326 | (org-ref-completion-library 'org-ref-ivy-cite) 327 | :config 328 | (require 'org-ref-wos) 329 | (require 'doi-utils) 330 | ) 331 | #+end_src 332 | 333 | ** Keybinding 334 | Use ~SPC~ has leader key (in evil normal mode) for local latex mode keybindings 335 | #+begin_src emacs-lisp 336 | 337 | (use-package general 338 | :config 339 | (general-evil-setup t)) 340 | 341 | (general-define-key 342 | :states '(normal visual) 343 | :keymaps 'LaTeX-mode-map 344 | :prefix "SPC" 345 | "f" '(LaTeX-fill-region :which-key "latex-fill-region") 346 | "SPC" '(try/TeX-command-save-buffer-and-run-all :which-key "latex-save-run") 347 | "c" '(try/ivy-bibtex-cite :which-key "ivy-cite") 348 | "i" '(try/counsel-insert-file-path :which-key "insert-relative-filepath") 349 | "b" '(ivy-bibtex :which-key "ivy-bibtex") 350 | "t" '(tab-bar-switch-to-tab :which-key "tab-switch-name") 351 | "o" '(outshine-imenu :which-key "menu") 352 | "t" '(outshine-cycle-buffer :which-key "fold-buffer") 353 | ) 354 | #+end_src 355 | 356 | ** Workflow 357 | TODO 358 | -------------------------------------------------------------------------------- /content/emacs/Org-roam-setup-from-scratch.org: -------------------------------------------------------------------------------- 1 | * straight.el installation 2 | We will use [[https://github.com/raxod502/straight.el][straight.el]] package manager instead of default emacs package manager 3 | #+begin_src emacs-lisp 4 | (defvar bootstrap-version) 5 | (let ((bootstrap-file 6 | (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory)) 7 | (bootstrap-version 5)) 8 | (unless (file-exists-p bootstrap-file) 9 | (with-current-buffer 10 | (url-retrieve-synchronously 11 | "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el" 12 | 'silent 'inhibit-cookies) 13 | (goto-char (point-max)) 14 | (eval-print-last-sexp))) 15 | (load bootstrap-file nil 'nomessage)) 16 | 17 | (straight-use-package 'use-package) 18 | (setq straight-use-package-by-default t) 19 | #+end_src 20 | * evil package 21 | ** main [[https://github.com/emacs-evil/evil][evil]] package 22 | #+begin_src emacs-lisp 23 | (use-package evil 24 | :init 25 | (setq evil-toggle-key "C-") 26 | (setq evil-shift-width 2) 27 | (setq evil-want-integration t) 28 | (setq evil-want-keybinding nil) 29 | :config 30 | (evil-mode 1) 31 | 32 | ;; Use visual line motions even outside of visual-line-mode buffers 33 | (evil-global-set-key 'motion "j" 'evil-next-visual-line) 34 | (evil-global-set-key 'motion "k" 'evil-previous-visual-line) 35 | 36 | (evil-set-initial-state 'dired-mode 'emacs) 37 | (evil-set-initial-state 'pdf-view-mode 'emacs) 38 | (evil-set-initial-state 'messages-buffer-mode 'emacs) 39 | (evil-set-initial-state 'special-mode 'emacs) 40 | (evil-set-initial-state 'view-mode 'emacs) 41 | (evil-set-initial-state 'deft-mode 'emacs) 42 | ) 43 | 44 | 45 | #+end_src 46 | ** evil commentor 47 | [[https://github.com/redguardtoo/evil-nerd-commenter][This]] package is used for commenting lines in emacs 48 | #+begin_src emacs-lisp 49 | (use-package evil-nerd-commenter 50 | :bind ("M-/" . evilnc-comment-or-uncomment-lines)) 51 | #+end_src 52 | ** undo tree 53 | for proper working of evil keybindings 54 | #+begin_src emacs-lisp 55 | (use-package undo-tree 56 | :diminish undo-tree-mode 57 | :config 58 | (global-undo-tree-mode) 59 | ) 60 | #+end_src 61 | * counsel ivy setting 62 | ** main package 63 | [[https://github.com/abo-abo/swiper][ivy/counsel/swiper]] is used for minibuffer completitions and searching 64 | #+begin_src emacs-lisp 65 | (use-package counsel 66 | :diminish ivy-mode 67 | :diminish counsel-mode 68 | :bind (("C-s" . swiper) 69 | :map ivy-minibuffer-map 70 | ("TAB" . ivy-alt-done)) 71 | :init 72 | (ivy-mode 1) 73 | (counsel-mode 1) 74 | :config 75 | (setq ivy-use-virtual-buffers t) 76 | (setq enable-recursive-minibuffers t)) 77 | 78 | #+end_src 79 | 80 | ** prescient.el 81 | [[https://github.com/raxod502/prescient.el][this]] package give better completions in ivy minibuffer based on recent usage 82 | #+begin_src emacs-lisp 83 | 84 | (use-package prescient 85 | :diminish 86 | :config 87 | ) 88 | 89 | (use-package ivy-prescient 90 | :after counsel 91 | :init 92 | (ivy-prescient-mode) 93 | (prescient-persist-mode) 94 | ) 95 | #+end_src 96 | 97 | * other useful tools 98 | ** olivetti, whichkey, magit 99 | #+begin_src emacs-lisp 100 | (use-package olivetti 101 | :diminish 102 | :hook 103 | (text-mode . olivetti-mode) 104 | :config 105 | (setq olivetti-body-width 100) 106 | ) 107 | ;;which-key 108 | (use-package which-key 109 | ;; :ensure t 110 | :diminish which-key-mode 111 | :config 112 | (which-key-mode)) 113 | 114 | ;; magit 115 | (use-package magit 116 | ;; :ensure t 117 | :defer t 118 | :bind ("C-x g" . magit-status)) 119 | #+end_src 120 | * org-mode 121 | ** main 122 | #+begin_src emacs-lisp 123 | (defun my/org-mode-setup () 124 | (org-indent-mode) 125 | (setq evil-auto-indent nil 126 | ) 127 | ;; remove olivetti keybindings 128 | ;; https://emacs.stackexchange.com/questions/32389/how-do-you-disable-all-keybinding-for-a-package 129 | (eval-after-load "olivetti" 130 | '(assq-delete-all 'olivetti-mode minor-mode-map-alist)) 131 | ) 132 | 133 | (use-package org 134 | :straight org-plus-contrib 135 | :hook 136 | (org-mode . olivetti-mode) 137 | (org-mode . which-function-mode) 138 | (org-mode . my/org-mode-setup) 139 | :custom 140 | (olivetti-body-width 100) 141 | (org-imenu-depth 4) 142 | :config 143 | (setq org-ellipsis " ▾") 144 | ) 145 | #+end_src 146 | ** org roam 147 | Assumed =~/.org-roam= as ~org-roam-directory~ and ~index.org~ in it is the index file 148 | *** main 149 | #+begin_src emacs-lisp 150 | (use-package org-roam 151 | ;; :ensure t 152 | ;; :hook 153 | ;; (after-init . org-roam-mode) 154 | :custom 155 | (org-roam-directory "~/.org-roam") 156 | (org-roam-index-file "~/.org-roam/index.org") 157 | ) 158 | #+end_src 159 | *** [[https://github.com/glucas/deft][deft]] 160 | Useful package to quickly search in all org-roam notes and go to them 161 | #+begin_src emacs-lisp 162 | (use-package deft 163 | :bind ("" . deft) 164 | :commands (deft) 165 | :config (setq deft-directory "~/.org-roam" 166 | deft-extensions '("md" "org"))) 167 | #+end_src 168 | * Custom functions 169 | This function will give [[https://github.com/vimwiki/vimwiki][vimwiki]] like workflow in org-roam\\ 170 | this function will be further modified so that it can closely replicate ~vimwiki~ workflow (using ~RET~ for making as well following the link depending on the context) 171 | #+begin_src emacs-lisp 172 | (defun my/org-roam-link-word-at-point () 173 | (interactive) 174 | (when (word-at-point t) 175 | (re-search-backward "\\b") 176 | (mark-word) 177 | (call-interactively #'org-roam-insert-immediate))) 178 | 179 | (defun my/org-roam-open-or-link-at-point () 180 | (interactive) 181 | (let ((context (org-element-context))) 182 | (if (equal (car context) 'link) 183 | (org-open-at-point) 184 | (my/org-roam-link-word-at-point)))) 185 | #+end_src 186 | 187 | Following local org-roam-mode is defined so that org-roam keybinding is valid only in org-roam-directory 188 | #+begin_src emacs-lisp 189 | (define-minor-mode my/local-org-roam-mode 190 | "Local version of `org-roam-mode'. 191 | Does nothing, can be used for local keybindings." 192 | :init-value nil 193 | :global nil 194 | :lighter " OR local" 195 | :keymap (let ((map (make-sparse-keymap))) 196 | map) 197 | :group 'org-roam 198 | :require 'org-roam 199 | (when my/local-org-roam-mode 200 | (message "Local keybindings for Org Roam enabled"))) 201 | #+end_src 202 | 203 | * Keybinding 204 | [[https://www.masteringemacs.org/article/mastering-key-bindings-emacs][mastering emacs]] tips for setting emacs keybinding\\ 205 | We will use ~general.el~ package for our keybinding 206 | ** [[https://github.com/noctuid/general.el][General]] setup 207 | #+begin_src emacs-lisp 208 | (use-package general 209 | :config 210 | (general-evil-setup t) 211 | ) 212 | #+end_src 213 | 214 | ** Org keybinding 215 | #+begin_src emacs-lisp 216 | (general-define-key 217 | :states '(normal visual) 218 | :keymaps 'org-mode-map 219 | :prefix "SPC" 220 | "e" '(:ignore t :which-key "export") 221 | "el" 'org-latex-export-to-pdf 222 | "ep" 'org-publish-current-project 223 | "s" 'org-store-link 224 | "o" 'counsel-imenu 225 | ) 226 | #+end_src 227 | 228 | ** org-roam 229 | #+begin_src emacs-lisp 230 | (general-define-key 231 | :states '(normal visual) 232 | :keymaps 'my/local-org-roam-mode-map 233 | :prefix "SPC" 234 | "r" '(:ignore t :which-key "roam") 235 | "rr" 'rename-file 236 | "rd" 'delete-file 237 | "rh" 'org-roam-jump-to-index 238 | "rb" 'org-roam 239 | ) 240 | ;; rebind enter key in normal mode to my/org-roam-link-word-at-point 241 | (define-key my/local-org-roam-mode-map [remap evil-ret] 'my/org-roam-open-or-link-at-point) 242 | #+end_src 243 | 244 | * ~.dir-local.el~ for org-roam-directory 245 | Add following to the =~/.org-roam/.dir-local.el= file 246 | #+begin_src emacs-lisp 247 | ;; for exporting all org-roam notes as light html project 248 | ((nil . ((eval . 249 | (setq org-publish-project-alist 250 | '( 251 | ("org-notes" 252 | :base-directory "~/.org-roam/" 253 | :base-extension "org" 254 | :publishing-directory "~/.org-roam/public_html/" 255 | :recursive t 256 | :publishing-function org-html-publish-to-html 257 | :headline-levels 4 ; Just the default for this project. 258 | :auto-preamble t 259 | ) 260 | ("org-static" 261 | :base-directory "~/.org-roam/" 262 | :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf" 263 | :publishing-directory "~/.org-roam/public_html/" 264 | :recursive t 265 | :publishing-function org-publish-attachment 266 | ) 267 | ("org" :components ("org-notes" "org-static")) 268 | )) 269 | ))) 270 | ;; enable local org-roam-mode for files in this folder 271 | (nil 272 | (eval my/local-org-roam-mode +1)) 273 | ) 274 | #+end_src 275 | 276 | * Migration from vimwiki to org-roam 277 | 278 | | Vimwiki keybind | Vimwiki function description | corresponding org-roam/emacs function | optional keybinding in emacs | 279 | | ww | Open default wiki index file. | ~org-roam-jump-to-index~ | ~SPC r h~ | 280 | | wd | Delete wiki file you are in. | ~delete-file~ | ~SPC r d~ | 281 | | wr | Rename wiki file you are in. | ~rename-file~ | ~SPC r r~ | 282 | | | Follow/Create wiki link. | ~my/org-roam-open-or-link-at-point~ | ~RET~ | 283 | | | Split and follow/create wiki link. | window management can be done separately | NA | 284 | | | Vertical split and follow/create wiki link. | window management can be done separately | NA | 285 | | | Go back to parent(previous) wiki link. | use switch-buffer | ~C-x b~ | 286 | | | Find next wiki link. | Will update | | 287 | | | Find previous wiki link. | Will update | | 288 | | :VimwikiAll2HTML | Convert all your wiki links to HTML. | ~org-publish-current-project~ | ~SPC e p~ | 289 | 290 | To use Follow link feature of ~vimwiki~ in ~org-roam~, one can use ~C-c C-o~ (~org-open-at-point~) function.\\ 291 | TODO : The ~my/org-roam-open-or-link-at-point~ can be modified further so that ~RET~ can make link word out of region selected. Will soon update this function. 292 | 293 | * Workflow 294 | TODO 295 | -------------------------------------------------------------------------------- /content/emacs/exwm-hacking.org: -------------------------------------------------------------------------------- 1 | #+title: EXWM Hacking Notes 2 | 3 | This is a set of notes that are being compiled as a part of the [[https://youtube.com/playlist?list=PLEoMzSkcN8oOS1y2uMspTXr1nd5JxUSzB][Hack Sessions]] series of streams! 4 | 5 | * Tasks 6 | 7 | ** TODO Find a good EXWM bug to investigate for next time 8 | 9 | - https://github.com/ch11ng/exwm/issues/847 10 | 11 | * Repository Links 12 | 13 | Here are the official EXWM repo links: 14 | 15 | - https://github.com/ch11ng/exwm/ 16 | - https://github.com/ch11ng/xelb 17 | - FAQ (helpful for debugging): https://github.com/ch11ng/exwm/wiki#faq 18 | 19 | If you'd like to contribute to my fork, you can check it out here: 20 | 21 | https://github.com/daviwil/exwm 22 | 23 | * EXWM Overview 24 | 25 | The files: 26 | 27 | ** exwm.el 28 | 29 | =exwm-init= is the entrypoint for setting up EXWM and connecting to the X Window System server. 30 | 31 | Many update functions used internally 32 | 33 | Part of the initialization process is to initialize modules like ICCCM and EWMH via functions like =xcb:ewmh:init=, these seem to be focused around fetching the IDs for well-known Atoms. Once they've been fetched, those subsystems are considered to be initialized. 34 | 35 | ** Other files 36 | 37 | BUG_HUNT.org 38 | README.md 39 | exwm-cm.el 40 | exwm-config.el 41 | exwm-core.el 42 | exwm-floating.el 43 | exwm-input.el 44 | exwm-layout.el 45 | exwm-manage.el 46 | exwm-randr.el 47 | exwm-systemtray.el 48 | exwm-workspace.el 49 | exwm-xim.el 50 | xinitrc 51 | 52 | * XELB Overview 53 | 54 | Generates elisp libraries for the X11 protocol with the =el_client.el= file, driven by the =Makefile= 55 | 56 | A small portion of the files are generated but many are helper libraries for specific parts of the X11 protocol. 57 | 58 | #+begin_quote 59 | 60 | ;; Interfaces are mainly defined in 'xcb.el'. Please refer to that file on how 61 | ;; to use them. Most of other files are either X11 core / extension protocol 62 | ;; libraries (e.g. xcb-randr.el) or utility libraries (e.g. xcb-keysyms.el). 63 | ;; Please check the corresponding files for more details. 64 | 65 | #+end_quote 66 | 67 | 68 | * Definitions 69 | 70 | ** xcb 71 | 72 | https://xcb.freedesktop.org/ 73 | [[https://xcb.freedesktop.org/tutorial/][xcb tutorial]] 74 | [[https://xcb.freedesktop.org/XmlXcb/][XML-XCB format for describing the X Window System protocol]] 75 | 76 | ** X Window System 77 | 78 | This is the client/server system which handles drawing to the screen, mouse/keyboard input, etc. 79 | 80 | You communicate with it via an XML-based protocol. 81 | 82 | ** ICCCM 83 | 84 | This seems to be a set of conventions for commuication between clients in the X Window System 85 | 86 | Describes window manager interactions at a low level 87 | 88 | https://www.x.org/releases/current/doc/xorg-docs/icccm/icccm.html#Introduction 89 | 90 | ** EWMH 91 | 92 | Extended Window Manager Hints 93 | 94 | An extended set of conventions for modern desktop environments (see Non-ICCCM features section) 95 | 96 | https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html 97 | 98 | Assumption: the window manager is the "root window" and anything in this document that describes messages handled by the root window are actually handled by the window manager. 99 | 100 | * Testing with Xephyr 101 | 102 | Docs: https://cgit.freedesktop.org/xorg/xserver/tree/hw/kdrive/ephyr/README 103 | 104 | Here's a simple script that can help with testing: 105 | 106 | #+begin_src sh 107 | 108 | #!/bin/sh 109 | Xephyr :1 -ac -dpi 180 -screen 1920x1080 & 110 | DISPLAY=:1 emacs 111 | pkill Xephyr 112 | 113 | #+end_src 114 | 115 | I'm also using this Emacs configuration for testing purposes: 116 | 117 | #+begin_src emacs-lisp 118 | 119 | (add-to-list 'load-path (expand-file-name "/home/daviwil/Projects/Code/xelb")) 120 | (add-to-list 'load-path (expand-file-name "/home/daviwil/Projects/Code/exwm")) 121 | 122 | (load-theme 'deeper-blue t) 123 | 124 | (require 'exwm) 125 | 126 | ;; Allow C+lmb to move windows 127 | (setq exwm-input-move-event 'C-down-mouse-1) 128 | 129 | ;; Set some global keys 130 | (setq exwm-input-global-keys 131 | `(([?\C-c ?x ?r] . exwm-reset) 132 | ([?\C-c ?x ?i] . exwm-input-toggle-keyboard) 133 | ([?\C-c ?x ?f] . exwm-layout-toggle-fullscreen) 134 | ([?\C-c ?x ?l] . (lambda (command) 135 | (interactive (list (read-shell-command "$ "))) 136 | (start-process-shell-command command nil command))) 137 | ([?\C-c ?x ?k] . (lambda () (interactive) (kill-buffer))) 138 | ,@(mapcar (lambda (i) 139 | `(,(kbd (format "C-c x %d" i)) . 140 | (lambda () 141 | (interactive) 142 | (exwm-workspace-switch-create ,i)))) 143 | (number-sequence 0 9)))) 144 | 145 | ;; Initialize EXWM 146 | (exwm-init) 147 | 148 | ;; Turn EXWM and XELB logging (check *XELB-DEBUG* buffer) 149 | (exwm-debug) 150 | 151 | ;; Enter the debugger when an error is encountered 152 | (toggle-debug-on-error) 153 | 154 | (defun dw/exwm-fake-command-wrapper (orig-fn &rest args) 155 | (debug-on-variable-change 'last-command) 156 | (apply orig-fn args) 157 | (cancel-debug-on-variable-change 'last-command)) 158 | 159 | ;; NOTE: This isn't being used now, leaving it here for reference 160 | ;; (advice-add 'exwm-input--fake-last-command :around #'dw/exwm-fake-command-wrapper) 161 | 162 | ;; Kudos to Timor for this suggestion: 163 | (defun xcb-debug:message (format-string &rest objects) 164 | "Print a message to `xcb-debug:buffer'. 165 | 166 | The FORMAT-STRING argument follows the speficies how to print each of 167 | the passed OBJECTS. See `format' for details." 168 | (let ((str (apply #'format format-string objects))) 169 | (xcb-debug:-with-debug-buffer 170 | (insert str)) 171 | (princ str 'external-debugging-output))) 172 | 173 | ;; NOTE: To save logs to a file, use: 174 | ;; 175 | ;; emacs 2>exwm.log 176 | ;; 177 | 178 | ;; Log each window that get opened 179 | (add-hook 'exwm-manage-finish-hook 180 | (lambda () 181 | (exwm--log "WINDOW DISPLAYED: %s (%s)" exwm-class-name exwm-title))) 182 | 183 | (split-window-right) 184 | (other-window 1) 185 | ;; (start-process-shell-command "gnome-mahjongg" nil "gnome-mahjongg") 186 | ;; (start-process-shell-command "calibre" nil "calibre") 187 | 188 | #+end_src 189 | 190 | * Bug Investigations 191 | 192 | ** FIXED - #842: Hang when clicking on X window after isearch 193 | 194 | Link: https://github.com/ch11ng/exwm/issues/842 195 | 196 | *Notes* 197 | 198 | This was caused by a misbehaving function in =isearch= which was being added to the =pre-command-hook= that gets invoked by =exwm-input--fake-last-command=. We fixed the issue by wrapping the =run-hooks= calls with a =condition-case= macro to prevent errors from breaking the EXWM session. 199 | 200 | ** Backlog 201 | 202 | - monitor size issues: https://github.com/ch11ng/exwm/issues/847 203 | - closed windows process not being killed: https://github.com/ch11ng/exwm/issues/844 204 | -------------------------------------------------------------------------------- /content/emacs/help-cheatsheet.org: -------------------------------------------------------------------------------- 1 | #+title: Help Cheatsheet 2 | 3 | * Hints to find what you are looking for 4 | 5 | Emacs is self documented, the code's documentation is searchable, accessible within emacs. 6 | 7 | - functions, commands, variables are usually prefixed by the mode name. For example, org-roam is the prefix for *org-roam*-db-build-cache command. 8 | - All these shortcuts present you with a minibuffer, or a selection prompt (ex: ivy, helm). The user experience really depends on your configuration. 9 | 10 | * Cheatsheet 11 | 12 | Here are the most helpful shortcuts to reach the Emacs help system: 13 | 14 | | Key | command | Purpose | 15 | |-------+----------------------+-------------------------------------------------------------------------------------| 16 | | C-h i | info | User guide for emacs and important modes | 17 | | | | Also displays Linux tools [[https://en.wikipedia.org/wiki/Info_(Unix)][info pages]] | 18 | | C-h r | info-emacs-manual | Emacs User Manual | 19 | | C-h f | describe-function | show detailed information about functions and commands | 20 | | C-h v | describe-variable | variables detailed information | 21 | | C-h b | describe-bindings | describes the enabled key bindings with the functions/commands they call | 22 | | C-h m | describe-mode | describes the current major mode enabled with all enabled minor modes | 23 | | | | Also lists key bindings | 24 | | C-h a | apropos-command | Search documentation related to a command | 25 | | C-h d | apropos-documentaion | Search documentation for a specific keyword | 26 | 27 | -------------------------------------------------------------------------------- /content/emacs/index.org: -------------------------------------------------------------------------------- 1 | #+title: GNU Emacs 2 | 3 | Refer to the video series and show notes on Emacs for more thorough "tutorial" style content that David has put together. Here are some quick jumping off points: 4 | 5 | * Emacs Essentials 6 | This is a [[https://systemcrafters.net/emacs-essentials/][series]] for true beginners and explains the fundamentals of Emacs. 7 | 8 | * Emacs from scratch 9 | This is a [[https://systemcrafters.net/emacs-from-scratch/][series]] geared towards crafting your custom Emacs configuration. Out of the box configurations like [[https://github.com/hlissner/doom-emacs][doom]], [[https://www.spacemacs.org/][spacemacs]], and [[https://github.com/bbatsov/prelude][prelude]] are also good options to see how these "opinionated" setup the emacs environment so you can hack on your own setup more. 10 | 11 | * Emacs's help system 12 | 13 | Emacs is a self documented editor, meaning with couple of key presses, you can find user guides, description of commands, functions, variables and more. Head over the [[/emacs/help-cheatsheet/][help cheatsheet]] to learn more about this awesome documentation system. 14 | 15 | * More Emacs Content 16 | 17 | There's a lot more content on the [[https://systemcrafters.net/videos][Videos]] page. 18 | 19 | * Emacs and org-mode 20 | org-mode is an outline markup format that helps you take notes, manage and schedule your TODOs, and a lot more. 21 | 22 | Here are some useful related packages: 23 | - [[/emacs/org-roam/][org-roam]]: A plain-text personal knowledge management system 24 | - deft: Deft is an Emacs mode for quickly browsing, filtering, and editing directories of plain text notes, inspired by Notational Velocity 25 | - org-super-agenda: This package lets you “supercharge” your Org daily/weekly agenda. The idea is to group items into sections, rather than having them all in one big list 26 | 27 | * Transitioning to Emacs 28 | There is a good possibility that there is an overlap between the Emacs-curious and keyboard shortcut users. However, the Emacs keybidings are quite different than the Common User Access (CUA) that a lot of users are familiar with. Here's a quick snippet of configuration that provides a more familiar way to start exploring Emacs: 29 | #+begin_src elisp 30 | ;; CUA type customizations and conveniences===================================== 31 | ;; Simpleclip to access system clipboard 32 | (require 'simpleclip) 33 | (setq simpleclip-mode 1) 34 | 35 | (map! :gin "C-S-x" #'simpleclip-cut ;Was: C-x chord 36 | :gin "C-S-c" #'simpleclip-copy ;Was: C-x chord 37 | :gin "C-S-v" #'clipboard-yank ;freezing on Ubuntu: 'simpleclip-paste ;Was: C-x chord 38 | :gin "C-z" #'undo ; Was: enable Emacs state 39 | :gin "C-S-z" #'redo ;Was: C-x chor 40 | :gin "C-" #'switch-to-next-buffer ;Was: aya-create snippet 41 | :gin "C-S-" #'switch-to-prev-buffer ;Was: C-x chord 42 | :gin "C-w" #'kill-buffer ;Was: evil-window-map 43 | :gin "C-a" #'mark-whole-buffer ;Was: doom/backward-to-bol-or-indent 44 | ) 45 | 46 | ;; Save. Was: isearch-forward 47 | (map! "C-s" #'save-buffer) 48 | ;; Save as. Was: nil 49 | (map! "C-S-s" #'write-file) 50 | 51 | ;; Ctrl shift P like Sublime Text Editor for command launching 52 | (map! "C-S-p" #'execute-extended-command) 53 | #+end_src 54 | =Note=: Emacs has a default option called CUA mode (available through the menu) or ~(setq cua-mode 1)~ but the configuration above provides a little more expected functionality by using a simple clipboard and redo/undo model. 55 | -------------------------------------------------------------------------------- /content/emacs/org-roam.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Org Roam 2 | 3 | * What is it? 4 | 5 | [[https://www.orgroam.com/manual.html#Introduction][Org-roam]] is a solution, built on org-mode, to capture notes in a non-hierarchical way. 6 | 7 | Notes can relate to each other, creating a web of relations. It helps you implement a digital [[https://en.wikipedia.org/wiki/Zettelkasten][Zettelkasten]] slip box of notes. 8 | 9 | * What can you use it for 10 | 11 | With org-roam, you can create your own wiki, powered by Emacs, org-mode features. 12 | 13 | Org-roam helps you search, link to other notes, and also has a graphical view (using graphviz) of the relations between your notes. 14 | 15 | * Getting started 16 | 17 | Have a look at the Org-roam [[https://www.orgroam.com/manual.html#Getting-Started][Getting Started]] page. 18 | 19 | The main actions you will perform: 20 | 1. create new notes (uses org-roam's own [[https://www.orgroam.com/manual.html#The-Templating-System][org-capture templates]]). Command org-roam-find-file on a new title. 21 | 2. search notes by name / tags. Command org-roam-find-file 22 | 3. create links to existing notes (manually, or using auto [[https://www.orgroam.com/manual.html#Completions][completion]] frameworks) 23 | 4. use any features of org mode you like (tables, source code block, bibliography, etc..) 24 | 25 | If you enjoy video content, you might want to watch the System Crafters playlist [[https://www.youtube.com/watch?v=AyhPmypHDEw&list=PLEoMzSkcN8oN3x3XaZQ-AXFKv52LZzjqD][Building a Second Brain in Emacs]]. 26 | 27 | * Hints 28 | 29 | ** You can't find your notes, or they are not named properly 30 | 31 | Org-roam indexes your notes, and it's possible that the index was not created yet, or is out of sync. 32 | 33 | You can solve this problem in couple of ways: 34 | 1. make sure you followed the getting started steps to setup indexing, the after-init-hook and the update method 35 | 2. If your configuration is correct, but you still have an issue 36 | 1. you have a wrongly named entry in your search, clear and rebuild your cache with the following commands (M-x): 37 | #+begin_src 38 | org-roam-db-clear-cache 39 | org-roam-db-build-cache 40 | #+end_src 41 | 2. you are missing some entry, build the cache manually with the following command (M-x): 42 | `org-roam-db-build-cache` 43 | 44 | ** Renaming notes 45 | 46 | Renaming titles within your note has an impact to the search. Make sure the index has the original name before changing a title. This is usually done by saving your note (C-c C-c, and possibly C-x C-s). 47 | 48 | Without the note properly indexed, the changes will not be visible in the org-roam-find-file command. 49 | 50 | 51 | ** Want different colors for org-roam links vs other links? 52 | 53 | To get some visual queue about regular links vs org-roam links, you can set a different color for org-roam links like here: 54 | 55 | #+begin_src emacs-lisp :noeval 56 | (custom-set-faces 57 | '((org-roam-link org-roam-link-current) 58 | :foreground "#e24888" :underline t)) 59 | #+end_src 60 | 61 | /contributed by nackjicholson on IRC/ 62 | 63 | ** Please contribute your own hints and tricks 64 | 65 | What else do you know about org-roam that can be useful to all? 66 | -------------------------------------------------------------------------------- /content/emacs/try-gccemacs.org: -------------------------------------------------------------------------------- 1 | In this article we will see various steps to test/try =emacs-28= with native compilation support on =Ubuntu 20.04LTS=. We will not touch existing emacs installed using ~apt~ on the Ubuntu, but will manually compile another version of =emacs-28= with =native-compilation= support (called =gccemacs= henceforth) in the =~/opt/emacs-native= folder. These two versions of emacs (already installed and =gccemacs=) will use different config files (=init.el=) and user-directories (=~/.emacs.d=) using =chemacs2=, so that they don't interfere with each other. Using this approach users can try =gccemacs= without breaking their stable emacs config. 2 | 3 | Please help us improving this wiki by reporting any bugs/issues in the wiki github repo. 4 | 5 | * Installing gccemacs 6 | check for any errors during ~./configure~ step, you may be missing some libraries, which need to be installed using ~apt~. 7 | 8 | #+begin_src shell 9 | mkdir -p ~/opt 10 | mkdir -p ~/opt/emacs-native 11 | cd ~/opt 12 | sudo add-apt-repository ppa:ubuntu-toolchain-r/ppa 13 | sudo apt install gcc-10 g++-10 libgccjit0 libgccjit-10-dev libjansson4 libjansson-dev 14 | sudo apt install libxpm-dev libgif-dev libtiff-dev libgnutls28-dev libmagick++-dev 15 | git clone git://git.sv.gnu.org/emacs.git gccemacs 16 | cd gccemacs 17 | git checkout master 18 | export CC=/usr/bin/gcc-10 CXX=/usr/bin/gcc-10 19 | ./autogen.sh 20 | ./configure --with-cairo --with-modules --without-compress-install --with-x-toolkit=no --with-gnutls --without-gconf --without-xwidgets --without-toolkit-scroll-bars --without-xaw3d --without-gsettings --with-mailutils --with-native-compilation --with-json --with-harfbuzz --with-imagemagick --with-jpeg --with-png --with-rsvg --with-tiff --with-wide-int --with-xft --with-xml2 --with-xpm CFLAGS="-O3 -mtune=native -march=native -fomit-frame-pointer" prefix=~/opt/emacs-native 21 | make -j2 NATIVE_FULL_AOT=1 22 | make install 23 | #+end_src 24 | 25 | * Using emacs-profiles 26 | 27 | - Install [[https://github.com/plexus/chemacs2][chemacs2]] using following script 28 | #+begin_src shell 29 | [ -f ~/.emacs ] && mv ~/.emacs ~/.emacs.bak 30 | [ -d ~/.emacs.d ] && mv ~/.emacs.d ~/.emacs.default 31 | git clone https://github.com/plexus/chemacs2.git ~/.emacs.d 32 | #+end_src 33 | 34 | - save following in =~/.emacs-profile.el= 35 | #+begin_src emacs-lisp 36 | ( 37 | ("default" . ((user-emacs-directory . "~/.emacs.default") 38 | (server-name . "default-server"))) 39 | ("gccemacs" . ((user-emacs-directory . "~/.gccemacs.d") 40 | (server-name . "gccemacs-server"))) 41 | ) 42 | #+end_src 43 | 44 | - copy your default config ~init.el~ to gccemacs folder 45 | #+begin_src shell 46 | mkdir -p ~/.gccemacs.d 47 | cp ~/.emacs.default/init.el ~/.gccemacs.d/init.el 48 | #+end_src 49 | 50 | * Some changes in config file for gccemacs 51 | 52 | - You can add following lines in your new ~init.el~ (in the =~/.gccemacs.d= folder)just to check if native-compilation and native json is working 53 | #+begin_src emacs-lisp 54 | (setq comp-deferred-compilation t) 55 | 56 | (if (and (fboundp 'native-comp-available-p) 57 | (native-comp-available-p)) 58 | (message "Native compilation is available") 59 | (message "Native complation is *not* available")) 60 | 61 | (if (functionp 'json-serialize) 62 | (message "Native JSON is available") 63 | (message "Native JSON is *not* available")) 64 | 65 | #+end_src 66 | 67 | - =straight.el= uses its own native compilation which can create some problems. You can switch off this using =:build (:not native-compile)=, for e.g. in case of =doom-themes=, one can use the following 68 | 69 | #+begin_src emacs-lisp 70 | (use-package doom-themes 71 | :straight '(doom-themes :build (:not native-compile)) 72 | :init 73 | (load-theme 'doom-nord t) 74 | ) 75 | #+end_src 76 | 77 | * Running parallel emacs 78 | ** default emacs 79 | - run emacs without daemon (It is better to run this if you are running emacs first time after making all changes using =chemacs2=). Try it 2-3 times so that no error/installation is left. 80 | #+begin_src emacs-lisp 81 | emacs --with-profile=default 82 | #+end_src 83 | - If you are emacs daemon user then following will work 84 | #+begin_src shell 85 | emacs --with-profile=default --daemon 86 | #+end_src 87 | - run a instance of daemon using (after previous step) 88 | #+begin_src shell 89 | emacsclient -c -s /run/user/1000/emacs/default-server 90 | #+end_src 91 | 92 | ** gccemacs 93 | 94 | - run emacs without daemon (It is better to run this if you are running emacs first time after making all changes using =chemacs2=). Try it 2-3 times so that no error/installtion is left. 95 | #+begin_src emacs-lisp 96 | ~/opt/emacs-native/bin/emacs --with-profile=gccemacs 97 | #+end_src 98 | - If you are emacs daemon user then following will work 99 | #+begin_src shell 100 | ~/opt/emacs-native/bin/emacs --with-profile=gccemacs --daemon 101 | #+end_src 102 | - run a instance of daemon using (after previous step) 103 | #+begin_src shell 104 | ~/opt/emacs-native/bin/emacsclient -c -s /run/user/1000/emacs/gccemacs-server 105 | #+end_src 106 | 107 | * Issues/Bugs and the solutions 108 | 109 | - Some packages like ~vterm~, ~pdf-tools~ couldn't compile for first time, but after restarting the computer somehow, they are working fine. 110 | - Many packages show lot of ~warning~ messages. This happens when you are using these packages for first time. Shouldn't be a problem after that. 111 | - Some user reported problem using ~exwm~, didn't try it yet. 112 | -------------------------------------------------------------------------------- /content/guix/browsers.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Browsers 2 | #+AUTHOR: Daniel Rose 3 | 4 | By default, Guix does not have many options for browsers. However, 5 | with nonguix, Nix, Flatpak, or Docker, you have many more 6 | options. Nonfree options are indicated with a bold *NF* next to the 7 | heading, and this includes things not in the official Guix 8 | repositories. 9 | 10 | If you have yet to set up Nix, and would like to, please visit the 11 | "Nix" page . Nix is the recommended way to install most 12 | nonfree software over Flatpak and Docker (allows for maintaining a declarative 13 | configuration.) 14 | 15 | * Table of Contents :toc: 16 | - [[#icecat][Icecat]] 17 | - [[#installation][Installation]] 18 | - [[#troubleshooting][Troubleshooting]] 19 | - [[#firefox---nf][Firefox - *NF*]] 20 | - [[#installation-1][Installation]] 21 | - [[#troubleshooting-1][Troubleshooting]] 22 | - [[#ungoogled-chromium][Ungoogled Chromium]] 23 | - [[#installation-2][Installation]] 24 | - [[#troubleshooting-2][Troubleshooting]] 25 | - [[#nyxt][Nyxt]] 26 | - [[#installation-3][Installation]] 27 | - [[#troubleshooting-3][Troubleshooting]] 28 | - [[#qutebrowser][Qutebrowser]] 29 | - [[#installation-4][Installation]] 30 | - [[#troubleshooting-4][Troubleshooting]] 31 | - [[#chromium---nf][Chromium - *NF*]] 32 | - [[#installation-5][Installation]] 33 | - [[#troubleshooting-5][Troubleshooting]] 34 | - [[#brave---nf][Brave - *NF*]] 35 | - [[#installation-6][Installation]] 36 | - [[#troubleshooting-6][Troubleshooting]] 37 | - [[#reporting-issues][Reporting Issues]] 38 | 39 | * Icecat 40 | 41 | Icecat is the fully free (as in freedom) fork of Firefox. It usually 42 | lags behind by quite a few versions (using the Icecat ESR version,) 43 | but otherwise is a safer Firefox. It comes by default with quite a few 44 | add-ons, including LibreJS (explicitly asking you if you want to run 45 | nonfree JS), Searxes' (which allows you to choose which CDNs to 46 | enable), and a few others. Icecat has settings to disable unsafe 47 | options, such as WebGL and WebRTC. LibreJS can also be a major issue 48 | for websites, but can be disabled. If you do not need Chromium or 49 | Firefox, consider using Icecat. 50 | 51 | *Homepage:* [[https://www.gnu.org/software/gnuzilla/][www.gnu.org/software/gnuzilla]] 52 | 53 | ** Installation 54 | 55 | Icecat is in the official repository, and has substitutes (no need to 56 | compile.) 57 | 58 | ** Troubleshooting 59 | 60 | No issues currently reported! 61 | 62 | * Firefox - *NF* 63 | 64 | Firefox is an open source browser from Mozilla. One of the most 65 | popular browsers for GNU/Linux, many forks of Firefox exist to improve 66 | it and make it more private (such as Icecat or Librewolf.) Permission 67 | is needed to use the Firefox name from Mozilla, as well as other 68 | restrictions, which make it a restrictive package, even if it is open 69 | source software. This bars it from being in the official repositories. 70 | 71 | *Homepage:* [[https://www.mozilla.org/firefox][www.mozilla.org/firefox]] 72 | 73 | ** Installation 74 | 75 | You can install Firefox through Nonguix, Nix, Flatpak, and even 76 | Docker. To install through Nix, please view the "Nix" page 77 | and install as you would any other program (either 78 | declarative or imperative.) 79 | 80 | The preferred way to install Firefox is through nonguix if you would 81 | like to keep your configurations in Scheme/Guix and are alright with 82 | compiling it, or Nix if you want a pre-compiled binary. 83 | 84 | ** Troubleshooting 85 | 86 | *** Firefox crashes when saving a file or uploading a file 87 | 88 | If you do not have a GTK theme installed, Firefox will crash when 89 | performing actions with a file explorer (and potentially more 90 | processes.) Install a GTK theme in the same profile as your Firefox 91 | install to prevent this issue. 92 | 93 | *** No audio in browser 94 | 95 | Sometimes Firefox does not connect to Pulseaudio; solution currently 96 | unknown. Restarting the browser has fixed this every time for me. This 97 | issue does not occur commonly at all. 98 | 99 | -Daniel 100 | 101 | *** No WebGL 102 | 103 | Firefox may not have any WebGL capabilities under certain combinations 104 | of installed packages or settings (such as WebRender.) No exact 105 | combination is documented that can replicate this, and I have yet to 106 | experience it again. 107 | 108 | -Daniel 109 | 110 | * Ungoogled Chromium 111 | 112 | If you prefer Chromium to the Firefox family of browsers but want to 113 | maintain your safety and privacy, look no further. Ungoogled Chromium 114 | is "Google Chromium, sans integration with Google." Ungoogled Chromium 115 | has numerous patches to Chromium and enhancing features. 116 | 117 | *Homepage:* [[https://github.com/Eloston/ungoogled-chromium][github.com/Eloston/ungoogled-chromium]] 118 | 119 | ** Installation 120 | 121 | Ungoogled Chromium is in the official repository, and has substitutes 122 | (no need to compile.) 123 | 124 | ** Troubleshooting 125 | 126 | No issues currently reported! 127 | 128 | * Nyxt 129 | 130 | Nyxt is a "keyboard-oriented, infinitely extensible web browser 131 | designed for power users." It is written in Common Lisp, and has 132 | keybindings for Emacs, vi, and CUA. Put simply, it is a "Common Lisp 133 | based Qutebrowser." Everything is configurable in Lisp, and the 134 | browser itself is based on buffers instead of tabs, and uses WebKit 135 | and WebEngine. It does not currently have support for WebExtensions, 136 | but is underway. 137 | 138 | *Homepage:* [[https://nyxt.atlas.engineer/][nyxt.atlas.engineer]] 139 | 140 | ** Installation 141 | 142 | Nyxt is in the official repository, and has substitutes (no need to 143 | compile.) 144 | 145 | ** Troubleshooting 146 | 147 | *** No HTML video 148 | 149 | Ensure that you have the following packages installed: 150 | 151 | #+BEGIN_SRC scheme 152 | "gst-libav" 153 | "gst-plugins-bad" 154 | "gst-plugins-base" 155 | "gst-plugins-good" 156 | "gst-plugins-ugly" 157 | #+END_SRC 158 | 159 | * Qutebrowser 160 | 161 | Qutebrowser is a keyboard and vi focused browser. It is written and 162 | configured in Python. It is similar to dwb and Nyxt. Tab and 163 | adblocking support is built in. 164 | 165 | *Homepage:* [[https://qutebrowser.org/][qutebrowser.org]] 166 | 167 | ** Installation 168 | 169 | Qutebrowser is in the official repository, and has substitutes (no need to 170 | compile.) 171 | 172 | ** Troubleshooting 173 | 174 | No issues currently reported! 175 | 176 | * Chromium - *NF* 177 | 178 | Chromium is an open-source browser from Google. Unless you need it, 179 | Ungoogled Chromium is recommended over regular Chromium to better 180 | protect your privacy and add enhancements. 181 | 182 | *Homepage:* [[https://www.chromium.org/][www.chromium.org]] 183 | 184 | ** Installation 185 | 186 | Chromium is not in the Guix repositories, but can be installed from 187 | Nix or Flatpak (might be possible through other methods.) 188 | 189 | ** Troubleshooting 190 | 191 | No issues currently reported! 192 | * Brave - *NF* 193 | 194 | Brave is a privacy-oriented Chromium-based browser. It features its 195 | own cryptocurrency, BAT, and has features such as IPFS built in. 196 | 197 | *Homepage:* [[https://brave.com/][brave.com]] 198 | 199 | ** Installation 200 | 201 | Brave is not in the Guix repositories, but can be installed through 202 | Nix or Snap. 203 | 204 | ** Troubleshooting 205 | 206 | No issues currently reported! 207 | 208 | * Reporting Issues 209 | 210 | If you have any issues with these browsers, please open an issues at 211 | the wiki repository at GitHub: 212 | [[https://github.com/systemcrafters/wiki-site][github.com/systemcrafters/wiki-site]]. Your issues help us solve and 213 | document them for everyone! 214 | -------------------------------------------------------------------------------- /content/guix/faqs.org: -------------------------------------------------------------------------------- 1 | #+TITLE: FAQs 2 | #+AUTHOR: Daniel Rose 3 | 4 | Questions regarding Guix as an OS, Guix as a package manager, and the wiki itself. 5 | 6 | * Table of Contents :toc: 7 | - [[#what-is-gnu-guix][What is GNU Guix?]] 8 | - [[#should-i-use-the-package-manager-or-the-os][Should I use the package manager or the OS?]] 9 | - [[#how-do-i-install-guix][How do I install Guix?]] 10 | - [[#but-how-do-i-work-with-only-free-software][But how do I work with only free software?]] 11 | - [[#what-is-a-declarative-configuration][What is a declarative configuration?]] 12 | - [[#what-are-the-differences-between-guix-and-nix][What are the differences between Guix and Nix?]] 13 | - [[#im-stuck-where-do-i-ask-for-help][I'm stuck! Where do I ask for help?]] 14 | 15 | * What is GNU Guix? 16 | 17 | GNU Guix (or simply Guix) is a liberating, dependable, and hackable 18 | GNU/Linux distro configured using Guile Scheme. It is liberating 19 | because by default it uses only free software, and the Linux libre 20 | kernel. It is dependable because it is reproducable, supports 21 | rollbacks through "generations," and has transactional upgrades (as 22 | well as much more), and is hackable because it has Guile Scheme APIs 23 | for the entire system and packages. 24 | 25 | More practically, this means that Guix is configurable in your 26 | dotfiles (your GNU/Linux preferences, nicknamed dotfiles because they 27 | often start with a period) and are reproducable on all your 28 | machines. Your configuration can be copied across them all, and kept 29 | in version control (such as git). 30 | 31 | * Should I use the package manager or the OS? 32 | 33 | You can install Guix either as an OS or as a package manager in a 34 | foreign distribution of GNU/Linux. There are benefits to both, however 35 | if you truly want to reap all the benefits of Guix, you should use it 36 | as an OS. The choice is up to you. 37 | 38 | * How do I install Guix? 39 | 40 | If installing as a package manager, Guix can be downloaded as a binary 41 | from the official website at [[https://guix.gnu.org/download][guix.gnu.org]], from your distro's package 42 | repositories, or using the [[https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh][shell installer script]]. 43 | 44 | If installing as an OS, you can go back to the System Crafters main 45 | wiki page for GNU Guix to see the options between nonguix and normal 46 | installation. 47 | 48 | * But how do I work with only free software? 49 | 50 | Well, you find alternatives! The FSF has a great article about this 51 | (written specifically for the COVID-19 pandemic, but always 52 | applicable): [[https://www.fsf.org/blogs/community/better-than-zoom-try-these-free-software-tools-for-staying-in-touch][free software alternatives]]. For other general things, 53 | consider LibreOffice for Microsoft Office, Gimp for Photoshop, 54 | Inkscape for Illustrator, and there are many other good alternatives 55 | to look for that respect your freedom. 56 | 57 | That said, we all have programs that we need for work that aren't free 58 | (and if you don't, consider yourself lucky.) Guix System, the name for 59 | the OS version, has options for nonfree software, such as nonguix, 60 | Nix, and Flatpak. 61 | 62 | * What is a declarative configuration? 63 | 64 | A declarative configuration is, put simply, when you write out your 65 | settings and packages instead of running a command. This allows for 66 | reproducibility, and easier management of installed packages. Think of 67 | it as declaring what you are going to do before doing it, as opposed 68 | to doing it without writing it down or alerting people. 69 | 70 | * What are the differences between Guix and Nix? 71 | 72 | First and foremost, Guix is configured in Guile Scheme, a Scheme 73 | (which in itself is a Lisp), while Nix is configured in... Nix. A bit 74 | confusing :smile:. Guile Scheme is a full fledged Scheme programming 75 | language, which means you can do some powerful things in it. Packages 76 | as well as system configurations are written in Guile in Guix. Guile 77 | also has more unified commands, while Nix has many for different 78 | purposes. 79 | 80 | * I'm stuck! Where do I ask for help? 81 | 82 | Check out one of the System Crafters channels on Discord, IRC, and 83 | Matrix. You can also watch some of the System Crafters videos, read 84 | this wiki, or ask in ~#guix~ for free and ~#nonguix~ for nonfree on [[https://libera.chat][Libera.Chat]] 85 | IRC. 86 | -------------------------------------------------------------------------------- /content/guix/general-recommendations.org: -------------------------------------------------------------------------------- 1 | #+TITLE: General Recommendations 2 | #+AUTHOR: Daniel Rose 3 | 4 | The following are recommendations for your new Guix system. Some are 5 | nonfree, these are indicated with a bold *NF* next to the heading. 6 | 7 | * Table of Contents :toc: 8 | - [[#desktop-environments-and-window-managers][Desktop Environments and Window Managers]] 9 | 10 | * Desktop Environments and Window Managers 11 | 12 | More likely than not, you want to install a window manager or desktop 13 | environment. KDE is /not/ installable on Guix due to numerous issues, 14 | XFCE would be a good alternative to look at. 15 | 16 | Quite a few window managers have built in support: 17 | - i3 18 | - EXWM 19 | - dwm 20 | - Xmonad 21 | - StumpWM 22 | 23 | There are also desktop environments for those who prefer them: 24 | - XFCE 25 | - GNOME 26 | -------------------------------------------------------------------------------- /content/guix/index.org: -------------------------------------------------------------------------------- 1 | #+TITLE: GNU Guix 2 | 3 | /A liberating, dependable, and hackable functional OS and package manager./ 4 | 5 | * Welcome to the System Crafters' Community GNU Guix Wiki! 6 | 7 | GNU Guix is a functional, reproducible GNU/Linux package manager and 8 | OS. A free (as in freedom), Guile Scheme based alternative to Nix, 9 | Guix provides the power of a functional OS and more. While powerful, 10 | many of Guix's configurations and options seem arcane and 11 | inaccessible. This wiki is here to show that the complete opposite is 12 | true! 13 | 14 | If you enjoy video content, you might want to watch the System Crafters playlist [[https://www.youtube.com/watch?v=iBaqOK75cho&list=PLEoMzSkcN8oNxnj7jm5V2ZcGc52002pQU][Craft Your System with GNU Guix]]. 15 | 16 | ** Why if so many other places (and the manual) exist? 17 | 18 | Truthfully, there aren’t that many other places. The System Crafters' 19 | wiki is attempting to enable more people to use GNU Guix with free and 20 | non-free software. The community should understand and be open to the 21 | fact that not all can realistically use only free software; this is 22 | not to say that the FSF is wrong or bad, but that we should ease 23 | people into using free as in freedom software and utilities. The 24 | System Crafters community believes there is a lot we can do to improve 25 | the experience for all. 26 | 27 | ** Where to start? 28 | 29 | *** If you've never used or heard of GNU Guix 30 | 31 | you should start at [[/guix/faqs][FAQs]]. 32 | 33 | *** If you've used Nix before, or are feeling courageous 34 | 35 | start right away at [[https://guix.gnu.org/manual/en/html_node/System-Installation.html][Official Installation Guide]] if you want a fully 36 | free experience, or if you are not sure what that means or want 37 | nonfree (recommended choice), start at the [[/guix/nonguix-installation-guide][Nonguix Installation Guide]]. 38 | 39 | Note that the official installation guide is from the GNU Guix manual, 40 | and links to that site. It is still recommended to read [[/guix/general-recommendations][general 41 | recommendations]] afterwards, although you might not want to follow the 42 | nonfree advice on there. 43 | 44 | ** Featured News and Articles 45 | 46 | *** TODO Possibly randomly select articles here, or show commonly 47 | sought after things (Firefox, Nix.) 48 | -------------------------------------------------------------------------------- /content/guix/nonguix-installation-guide.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Nonguix Installation Guide 2 | #+AUTHOR: Daniel Rose 3 | 4 | This document is a guide for installing GNU Guix using the live system 5 | booted from a ~nonguix~ installation medium. The installation medium 6 | is provided by a GitHub Action from System Crafters, and uses the full 7 | Linux kernel, as opposed to the libre one. This allows for more driver 8 | support, such as WiFi on many modern laptops, and makes the 9 | installation process much easier. 10 | 11 | Before installing, it would be advised to view the [[/guix/faqs][FAQs]]. 12 | 13 | For installations of software and specific issues, please search for 14 | your topic or look in the categories. 15 | 16 | GNU Guix should run on most x86-64 compatible PCs. As the installation 17 | process needs to retrieve packages from a remote repository, this 18 | guide assumes a working internet connection is available. The Nonguix 19 | installation medium should cover WiFi issues normally present in the 20 | Guix installer. 21 | 22 | * Table of Contents :toc: 23 | - [[#pre-installation][Pre-installation]] 24 | - [[#download-the-installation-image][Download the installation image]] 25 | - [[#booting][Booting]] 26 | - [[#connecting-to-the-internet][Connecting to the internet]] 27 | - [[#partition-the-disks][Partition the disks]] 28 | - [[#installation][Installation]] 29 | - [[#herd-store][Herd store]] 30 | - [[#system-configuration][System configuration]] 31 | - [[#channels][Channels]] 32 | - [[#update-system-configuration][Update system configuration]] 33 | - [[#initialize-system][Initialize system]] 34 | - [[#post-installation][Post-installation]] 35 | - [[#user-accounts][User accounts]] 36 | - [[#dotfiles][Dotfiles]] 37 | - [[#channels-1][Channels]] 38 | - [[#general-recommendations][General recommendations]] 39 | - [[#further-reading][Further Reading]] 40 | 41 | * Pre-installation 42 | 43 | ** Download the installation image 44 | 45 | The installation image is kept at a repo in the System Crafters 46 | organization. Click [[https://github.com/SystemCrafters/guix-installer/releases/latest][here]] to download the latest ISO. Burn this ISO to 47 | an installation medium (flash drive or DVD), and boot from it. For 48 | example, to burn it to a USB flash drive at ~/dev/sdX~, run the 49 | following command: 50 | 51 | #+BEGIN_SRC sh 52 | dd if=guix-installer.iso of=/dev/sdX status=progress bs=4M 53 | #+END_SRC 54 | 55 | ** Booting 56 | 57 | Boot from the installation medium, select your language and country, 58 | and select "Install using the shell based process" when 59 | prompted. Although this makes the installation slightly more 60 | difficult, it allows for setting up your new installation with the 61 | full Linux kernel (necessary for the nonfree installation.) 62 | 63 | ** Connecting to the internet 64 | 65 | If you have ethernet, simply plug in your cable and continue to the 66 | next step. If you have WiFi, use an editor (or ~echo~) to create a new 67 | file called ~wifi.conf~ to store the WiFi configuration. Make sure to 68 | set ~ssid~ to the name of your WiFi network name, and ~psk~ to the 69 | passphrase for your WiFi. You may also need to change the ~key_mgmt~ 70 | parameter depending on the type of authentication your wifi router 71 | supports. 72 | 73 | #+BEGIN_SRC sh 74 | network={ 75 | ssid="ssid-name" 76 | key_mgmt=WPA-PSK 77 | psk="unencrypted passphrase" 78 | } 79 | #+END_SRC 80 | 81 | Next, run the following commands to unblock the WiFi card, determine 82 | its device name, and connect using the device name received. In the 83 | example, the name is ~wlp4s0~, so ~wpa_supplicant~ is passed the flag 84 | ~-i wlp4s0~. Change this accordingly: 85 | 86 | #+BEGIN_SRC sh 87 | rfkill unblock all 88 | ifconfig -a 89 | wpa_supplicant -c wifi.conf -i wlp4s0 -B 90 | #+END_SRC 91 | 92 | #+BEGIN_QUOTE 93 | *NOTE:* If for any reason running =wpa_supplicant= fails, make sure to 94 | kill any background instances of it before trying to run it again 95 | because the old instances will block new runs from working. This 96 | wasted a couple hours the first time I tried installing Guix! 97 | #+END_QUOTE 98 | 99 | Finally, run ~dhclient~ to turn on DNS, remembering to replace 100 | ~wlp4s0~ with your device name returned from ~ifconfig -a~: 101 | 102 | #+BEGIN_SRC sh 103 | dhclient -v wlp4s0 104 | #+END_SRC 105 | 106 | ** Partition the disks 107 | 108 | When disks are detected by the system, they are assigned a block 109 | device. To list these block devices, run ~lsblk~ or ~fdisk -l~. 110 | 111 | For example, running ~lsblk~ on my laptop returns these results: 112 | 113 | #+BEGIN_SRC sh 114 | $ lsblk 115 | 116 | NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT 117 | sda 8:0 0 465.8G 0 disk 118 | ├─sda1 8:1 0 549M 0 part /boot/efi 119 | ├─sda2 8:2 0 153.5G 0 part 120 | │ └─cryptroot 253:0 0 153.5G 0 crypt / 121 | └─sda3 8:3 0 311.7G 0 part 122 | └─crypthome 253:1 0 311.7G 0 crypt /home 123 | sr0 11:0 1 1024M 0 rom 124 | #+END_SRC 125 | 126 | I have an encrypted root and home (if you don't know what that is, 127 | don't worry, it just means I have to put in two passwords before I can 128 | use my computer), so my devices might appear differently than yours, 129 | but the rough idea is the same. You might have no partitions (the 130 | numbered versions, such as ~/dev/sda1~) if you just wiped your drive, 131 | or many if you are coming from a different GNU/Linux OS or Windows. 132 | 133 | *** Encrypted 134 | 135 | If you would like to have encrypted block devices (entire partitions), 136 | use LUKS. If you do not want encryption, continue reading at 137 | "Regular." 138 | 139 | Your encrypted blocks can be all or none, however in this example only 140 | the root will be encrypted and UEFI will be used. If unsure, look at 141 | "Regular" and see the potential layouts (or read the linked article 142 | for the Arch Wiki there). 143 | 144 | | Mount point | Partition | Partition type | Suggested size | 145 | |-----------------+-----------------------------+---------------------------+-----------------------------| 146 | | ~/mnt/boot/efi~ | ~/dev/efi_system_partition~ | EFI system partition | At least 260 MiB | 147 | | ~[SWAP]~ | ~/dev/swap_partition~ | Linux swap | More than 512 MiB | 148 | | ~/mnt~ | ~/dev/root_partition~ | Linux x86-64 root (/) | Remainder of the device | 149 | 150 | #+BEGIN_SRC sh 151 | cfdisk /dev/root_partition 152 | #+END_SRC 153 | 154 | Once your partitions are created, you can enable LUKS on the root 155 | partition by running the following commands. You can change 156 | ~system-root~ to whatever you desire: 157 | 158 | #+BEGIN_SRC sh 159 | cryptsetup luksFormat /dev/root_partition 160 | cryptsetup open --type luks /dev/root_partition system-root 161 | mkfs.ext4 -L system-root /dev/mapper/system-root 162 | mount LABEL=system-root /mnt 163 | #+END_SRC 164 | 165 | Finally, ensure your EFI system partition and swap are both 166 | activated/mounted: 167 | 168 | #+BEGIN_SRC sh 169 | mkdir -p /mnt/boot/efi 170 | mount /dev/efi_system_partition /mnt/boot/efi 171 | 172 | swapon /dev/swap_partition 173 | #+END_SRC 174 | 175 | Proceed to "Installation." 176 | 177 | *** Regular 178 | 179 | If you would not like to have encrypted block devices (entire 180 | partitions), you can partition your drives just as you would for any 181 | other GNU/Linux OS. For example, you could have the following layout 182 | (as suggested by the Arch Wiki) if using UEFI (most modern computers): 183 | 184 | | Mount point | Partition | Partition type | Suggested size | 185 | |-----------------+-----------------------------+---------------------------+----------------------------- | 186 | | ~/mnt/boot/efi~ | ~/dev/efi_system_partition~ | EFI system partition | At least 260 MiB | 187 | | ~[SWAP]~ | ~/dev/swap_partition~ | Linux swap | More than 512 MiB | 188 | | ~/mnt~ | ~/dev/root_partition~ | Linux x86-64 root (/) | At least 1/3 of your device | 189 | | ~/mnt/home~ | ~/dev/home_partition~ | Linux x86-64 home (/home) | Remainder of the device | 190 | 191 | For BIOS with MBR, the Arch Wiki suggests the following: 192 | 193 | | Mount point | Partition | Partition type | Suggested size | 194 | |-------------+-----------------------+----------------+-----------------------------| 195 | | ~[SWAP]~ | ~/dev/swap_partition~ | Linux swap | More than 512 MiB | 196 | | ~/mnt~ | ~/dev/root_partition~ | Linux | At least 1/3 of your device | 197 | | ~/mnt/home~ | ~/dev/home_partition~ | Linux | Remainder of the device | 198 | 199 | Many other partitioning schemes exist: if you'd like to try other ones 200 | or learn about your options, check out the Arch Wiki's page for 201 | [[https://wiki.archlinux.org/title/Partitioning#Example_layouts][partitioning]]. 202 | 203 | Partition your disks using either ~cfdisk~ or ~fdisk~: 204 | 205 | #+BEGIN_SRC sh 206 | cfdisk /dev/sdX 207 | 208 | fdisk /dev/sdX 209 | #+END_SRC 210 | 211 | Next, you should format your partitions with the correct file 212 | system. To create an Ext4 file system on ~/dev/root_partition~, run: 213 | 214 | #+BEGIN_SRC sh 215 | mkfs.ext4 /dev/root_partition 216 | #+END_SRC 217 | 218 | To initialize swap, run the following command: 219 | 220 | #+BEGIN_SRC sh 221 | mkswap /dev/swap_partition 222 | #+END_SRC 223 | 224 | Now it is time to mount your partitions. This will change depending on 225 | your chosen layout, but all drives are mounted as such: 226 | 227 | #+BEGIN_SRC sh 228 | mount /dev/partition_name /mnt 229 | #+END_SRC 230 | 231 | Replace ~partition_name~ with the partition's name, and ~/mnt~ with 232 | the necessary location. The following locations are used: 233 | 234 | - Root partition: ~/mnt~ 235 | - Home partition: ~/mnt/home~ 236 | - EFI system partition: ~/mnt/boot/efi~ 237 | 238 | In order to mount a partition, that directory (folder) needs to 239 | exist. For ~/mnt/home~ and ~/mnt/boot/efi~ (if created) create the 240 | directories as follows /after/ mounting ~/mnt~: 241 | 242 | #+BEGIN_SRC sh 243 | mkdir -p /mnt/boot/efi 244 | 245 | mkdir -p /mnt/home 246 | #+END_SRC 247 | 248 | Swap is activated with the ~swapon~ command: 249 | 250 | #+BEGIN_SRC sh 251 | swapon /dev/swap_partition 252 | #+END_SRC 253 | 254 | * Installation 255 | 256 | ** Herd store 257 | 258 | Once all partitions are mounted, you can begin the 259 | installation. First, set up the installation environment using ~herd~: 260 | 261 | #+BEGIN_SRC sh 262 | herd start cow-store /mnt 263 | #+END_SRC 264 | 265 | ** System configuration 266 | 267 | The following steps will change depending on your approach. If you've 268 | used Guix in the past and would like to use your dotfiles and system 269 | configuration (your custom configurations), clone your repository now. 270 | 271 | If you would like to make your own, you need to at least have the 272 | nonguix channels setup for the installation medium. If you aren't sure 273 | what that means, or how to do that yourself, follow the instructions 274 | below for now, only copying the ~channels.scm~. 275 | 276 | If you do not have personal dotfiles yet, and would like to try David 277 | Wilson's, clone the following repository using ~git~ into your current 278 | directory (i.e. not ~/mnt~): 279 | 280 | #+BEGIN_SRC sh 281 | git clone https://github.com/daviwil/dotfiles 282 | #+END_SRC 283 | 284 | ** Channels 285 | 286 | Regardless of your path, you should now add the nonguix and necessary 287 | custom channels to the installation medium. Run the following commands 288 | to set up the necessary channels and run ~guix pull~ (equivalent to 289 | ~apt update~, updates the files available without updating the ones on 290 | the system): 291 | 292 | #+BEGIN_SRC sh 293 | mkdir -p ~/.config/guix 294 | # If you cloned David Wilson's dotfiles: 295 | cp dotfiles/guix/channels.scm ~/.config/guix 296 | # Otherwise, add the channels.scm file yourself and edit it with nonguix and your necessary channels 297 | guix pull 298 | # This is necessary to ensure the updated profile path is active! 299 | hash guix 300 | #+END_SRC 301 | 302 | The pull operation can take quite a while, depending upon your machine 303 | and the last time the nonguix installation ISO was updated. I'd 304 | recommend getting a cup of coffee (or tea, or whatever your preferred 305 | beverage is!) 306 | 307 | ** Update system configuration 308 | 309 | Once the operation is finished, you will need to update your 310 | configuration to point to your partition UUIDs and labels for the 311 | system that you are installing. In order to get your UUIDs, run the 312 | following command: 313 | 314 | #+BEGIN_SRC sh 315 | blkid 316 | #+END_SRC 317 | 318 | This will return a long list of IDs that you can write down, take a 319 | picture of, ~cat~ or ~echo~ into your configuration, depending on 320 | which is more comfortable to you (if you're not too familiar with 321 | GNU/Linux, I'd recommend writing the IDs down. They are long, but it 322 | is faster and safer in the long run.) You can also switch to another 323 | TTY using ~Ctrl-Alt-F#~ and press ~Enter~ or ~Return~ to get to 324 | another root prompt. You can then switch back and forth between the 325 | previous TTY on ~F3~ instead of writing down your IDs. 326 | 327 | If you have encrypted partitions, you can use the following command 328 | to find the UUID: 329 | 330 | #+BEGIN_SRC sh 331 | cryptsetup luksUUID /dev/root_partition 332 | #+END_SRC 333 | 334 | ** Initialize system 335 | 336 | Finally, we can initialize the system by running the following command: 337 | 338 | #+BEGIN_SRC sh 339 | # Change the .dotfiles directory to your dotfiles if necessary 340 | guix system -L ~/.dotfiles/.config/guix/systems init path/to/config.scm /mnt 341 | #+END_SRC 342 | 343 | This can take a /very/ long time depending on your internet connection 344 | and computer. If using a laptop, please ensure it is plugged in. If 345 | any errors occur during the installation, simply resume the 346 | installation as the Guix store has the previous packages saved. If the 347 | error continues, consider contacting someone at the System Crafters' 348 | Discord, IRC, or Matrix "Links?" . 349 | 350 | * Post-installation 351 | 352 | ** User accounts 353 | 354 | Congratulations! Your GNU Guix System installation is (almost) 355 | complete. Reboot your system, take out your installation medium, and 356 | login as root when you are faced with a login prompt. Your last 357 | crucial step is to add a password for your accounts. Once logged in, 358 | run the following commands: 359 | 360 | #+BEGIN_SRC sh 361 | # Set the password for your root account 362 | passwd 363 | # Set the password for your user 364 | passwd 365 | #+END_SRC 366 | 367 | Log out, and log into your user account. 368 | 369 | ** Dotfiles 370 | 371 | Clone your dotfiles repository (or David Wilson's again) and ensure 372 | that the channels include nonguix. If using David Wilson's dotfiles, 373 | ~cd~ into the directory and run: 374 | 375 | #+BEGIN_SRC sh 376 | stow . 377 | #+END_SRC 378 | 379 | If using your own dotfiles, you know how to deploy them. If you don't 380 | have a good way to deploy your dotfiles yet, consider using ~stow~ 381 | "Link?" . 382 | 383 | ** Channels 384 | 385 | Verify that your ~channels.scm~ file is in the target path 386 | (~\~/.config/guix~) and then run the following to update your 387 | channels: 388 | 389 | #+BEGIN_SRC sh 390 | guix pull 391 | #+END_SRC 392 | 393 | ** General recommendations 394 | 395 | You can now install whatever packages or manifests you need and 396 | have. If you are new to GNU Guix, continue reading at the "Basics of 397 | GNU GUIX" page . If interested in basic system setups and 398 | advice, continue reading at [[/guix/general-recommendations][general recommendations]]. Otherwise, once 399 | again, congratulations! You have officially installed a 400 | nonfree/nonguix Guix System! 401 | 402 | * Further Reading 403 | 404 | For more information, and to read the official installation guide, 405 | look at the following links: 406 | - [[https://guix.gnu.org/manual/devel/en/html_node/System-Installation.html#System-Installation][Installation in the Guix manual]] 407 | - [[https://gitlab.com/nonguix/nonguix/][Nonguix GitLab repository]] 408 | -------------------------------------------------------------------------------- /content/guix/nvidia.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Proprietary NVIDIA Drivers 2 | #+AUTHOR: Demis Balbach 3 | GNU Guix makes installing and using the proprietary NVIDIA drivers more difficult than one may be used to coming from other distributions. However, it is possible and explained here. 4 | 5 | * Installation 6 | 7 | ** Using the channel 8 | If using the ~nonguix~ channel, the ~nvidia-driver~ package contains the proprietary drivers for GNU Guix. If you followed the [[/guix/nonguix-installation-guide][nonguix installation guide]], this should already be set up by default. From now on it will be assumed that the nonguix channel is available on your system. 9 | 10 | ** The system configuration 11 | Your system configuration is usually located at ~/etc/config.scm~. We need to add several lines of code to make your system load the drivers properly. Open the file to edit it, and make sure you have write permissions. 12 | 13 | *** Package definition 14 | You need to add the nvidia package definition to your ~define-module~ function so Guix knows where to load it from: 15 | 16 | #+begin_src scheme 17 | (define-module (your-module) 18 | ;; ... 19 | ;; some stuff here 20 | ;; ... 21 | #:use-module (nongnu packages nvidia)) 22 | #+end_src 23 | 24 | *** Renaming for grafting 25 | In order to have ~libglx~ working, the ~nvidia-driver~ package needs to be grafted instead of ~mesa~. It needs to be renamed to have the same number of characters as ~mesa~. More information can be found [[https://gitlab.com/nonguix/nonguix/-/issues/31#note_481501721][here]]. Add the following function: 26 | 27 | #+begin_src scheme 28 | (define transform 29 | (options->transformation 30 | '((with-graft . "mesa=nvda")))) 31 | #+end_src 32 | 33 | *** OS configuration 34 | From here on, everything mentioned should be placed in your ~operating-system~ block: 35 | 36 | #+begin_src scheme 37 | (define-public base-operating-system 38 | ;; ... 39 | (operating-system 40 | ;; here! 41 | ...)) 42 | #+end_src 43 | 44 | **** Kernel modules 45 | You should blacklist the ~nouveau~ kernel module to avoid conflicts. 46 | 47 | #+begin_src scheme 48 | (kernel-arguments (append 49 | '("modprobe.blacklist=nouveau") 50 | %default-kernel-arguments)) 51 | #+end_src 52 | 53 | In addition, you should also add ~nvidia-driver~ to the loadable kernel modules: 54 | 55 | #+begin_src scheme 56 | (kernel-loadable-modules (list nvidia-driver)) 57 | #+end_src 58 | 59 | **** Services 60 | Now add two services. One for a custom udev rule and one to make sure the modules get loaded: 61 | 62 | #+begin_src scheme 63 | (services (cons* (simple-service 64 | 'custom-udev-rules udev-service-type 65 | (list nvidia-driver)) 66 | (service kernel-module-loader-service-type 67 | '("ipmi_devintf" 68 | "nvidia" 69 | "nvidia_modeset" 70 | "nvidia_uvm")) 71 | ...)) 72 | #+end_src 73 | 74 | ** Login manager 75 | The system configuration is now complete. However, you probably want to setup a login manager. No matter what login manager you use, you need to list the ~nvidia-driver~ in the ~xorg-configuration~ block. Here is a minimal example using ~slim~: 76 | 77 | #+begin_src scheme 78 | (service slim-service-type 79 | (slim-configuration 80 | (xorg-configuration (xorg-configuration 81 | (modules (cons* nvidia-driver %default-xorg-modules)) 82 | (server (transform xorg-server)) 83 | (drivers '("nvidia")))))) 84 | #+end_src 85 | 86 | Please consult the manual for all possible ~xorg-configuration~ options. 87 | 88 | ** Additional Xorg configuration 89 | If you used to use special xorg configuration files (like ~/etc/X11/xorg.conf.d/10-nvidia.conf~) you can also add them in Guix. Add the following to your ~xorg-configuration~ function: ~(extra-config (list %xorg-config))~. You can rename ~%xorg-config~ 90 | to whatever you want. Just define the variable and add your configuration: 91 | 92 | #+begin_src scheme 93 | (define %xorg-config 94 | "Section \"Device\" 95 | Identifier \"Device0\" 96 | Driver \"nvidia\" 97 | VendorName \"NVIDIA Corporation\" 98 | BoardName \"GeForce GTX 1050 Ti\" 99 | EndSection") 100 | #+end_src 101 | 102 | You can find examples for additional configurations in [[https://github.com/daviwil/dotfiles/blob/master/Systems.org][David's]] and [[https://github.com/minikN/guix/blob/main/base-system.scm#L37-L103][minikN's]] config. 103 | 104 | * Reconfiguring the system 105 | That's about it. The last thing you need to do is to reconfigure the system so your changes get applied. You need ~sudo~ in order to do that. You can use the following command: 106 | 107 | #+begin_src sh 108 | sudo -E guix system --cores=$(nproc) -L /path/to/your/config.scm reconfigure 109 | #+end_src 110 | 111 | * Screen tearing 112 | After doing this, One may notice screen tearing when watching YouTube videos. To remedy this issue one has two options. 113 | 114 | ** Force full composition pipeline 115 | Forcing a full composition pipeline can help to avoid screen tearing. You can consult the [[https://wiki.archlinux.org/title/NVIDIA/Troubleshooting#Avoid_screen_tearing][Arch Wiki]] if you want to know about it. To put it simple, you need to add the ~MetaModes~ option to your screen ~Section~ block of your xorg configuration. 116 | Like this: 117 | 118 | #+begin_src conf 119 | Section "Device" 120 | Identifier "Nvidia Card" 121 | Driver "nvidia" 122 | VendorName "NVIDIA Corporation" 123 | BoardName "GeForce GTX 1050 Ti" 124 | EndSection 125 | 126 | Section "Screen" 127 | Identifier "Screen0" 128 | Device "Device0" 129 | Monitor "Monitor0" 130 | Option "MetaModes" "nvidia-auto-select +0+0 {ForceFullCompositionPipeline=On}" 131 | Option "AllowIndirectGLXProtocol" "off" 132 | Option "TripleBuffer" "on" 133 | EndSection 134 | #+end_src 135 | 136 | However, the actual value of the option is dependent on your monitor setup. This was explained on the [[https://github.com/ch11ng/exwm/wiki#issues-with-screen-tearing][EXWM Wiki]] in greater detail. 137 | 138 | ** Using a compositor 139 | Generally, enabling the full composition pipeline works to get rid of screen tearing. However on GNU Guix it didn't for some reason. Maybe it'll work for you? In any case, another way is to use a compositor like [[https://github.com/yshui/picom][picom]] (formely known as compton). There are multiple ways to set up a compositor. 140 | 141 | *** Using EXWM 142 | This example shows how to use ~picom~ with EXWM as a window manager. There is an [[https://guix.gnu.org/en/packages/emacs-exwm-0.24/][emacs-exwm]] 143 | package. Unfortunately, one can not easily configure it to load ~picom~ as well. In addition, it still runs on Emacs 27.2, it could be benefitial to change to version 28 featuring native compilation. This package definition inheriting from emacs-exwm automatically starts picom and uses the native-compilation branch. Feel free to use it. It requires you to have set up [[https://github.com/flatwhatson/guix-channel][flatwhatson]]'s guix channel: 144 | 145 | #+begin_src scheme 146 | ;; Override emacs-exwm package definition 147 | ;; To include emacs-native-comp and picom. 148 | (define-public emacs-native-comp-exwm 149 | (package 150 | (inherit emacs-exwm) 151 | (name "emacs-native-comp-exwm") 152 | (synopsis "Emacs 28 with native compilation and picom as a compositor.") 153 | (inputs 154 | `(("picom" ,picom) 155 | ,@(package-inputs emacs-exwm))) 156 | (arguments 157 | `(,@(package-arguments emacs-exwm) 158 | #:emacs ,emacs-native-comp 159 | #:phases (modify-phases %standard-phases 160 | (add-after 'build 'install-xsession 161 | (lambda* (#:key inputs outputs #:allow-other-keys) 162 | (let* ((out (assoc-ref outputs "out")) 163 | (xsessions (string-append out "/share/xsessions")) 164 | (bin (string-append out "/bin")) 165 | (exwm-executable (string-append bin "/exwm"))) 166 | 167 | ;; Add a .desktop file to xsessions 168 | (mkdir-p xsessions) 169 | (mkdir-p bin) 170 | (make-desktop-entry-file 171 | (string-append xsessions "/exwm.desktop") 172 | #:name ,name 173 | #:comment ,synopsis 174 | #:exec exwm-executable 175 | #:try-exec exwm-executable) 176 | 177 | ;; Add a shell wrapper to bin 178 | (with-output-to-file exwm-executable 179 | (lambda _ 180 | (format #t "#!~a ~@ 181 | ~a +SI:localuser:$USER ~@ 182 | ~a & 183 | exec ~a --exit-with-session ~a \"$@\" --eval '~s' ~%" 184 | (string-append (assoc-ref inputs "bash") "/bin/sh") 185 | (string-append (assoc-ref inputs "xhost") "/bin/xhost") 186 | (string-append (assoc-ref inputs "picom") "/bin/picom") 187 | (string-append (assoc-ref inputs "dbus") "/bin/dbus-launch") 188 | (string-append (assoc-ref inputs "emacs") "/bin/emacs") 189 | '(cond 190 | ((file-exists-p "~/.exwm") 191 | (load-file "~/.exwm")) 192 | ((not (featurep 'exwm)) 193 | (require 'exwm) 194 | (require 'exwm-config) 195 | (exwm-config-default) 196 | (message (concat "exwm configuration not found. " 197 | "Falling back to default configuration..."))))))) 198 | (chmod exwm-executable #o555) 199 | #t)))))))) 200 | #+end_src 201 | -------------------------------------------------------------------------------- /content/guix/wsl.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Installing GuixSD on WSL2 2 | #+AUTHOR: Demis Balbach 3 | The Windows Subsystem for Linux enables Windows to run software, including whole distributions, written for Linux. This article goes through the process of installing GuixSD as a WSL distribution. 4 | 5 | *Note*: GuixSD refers to the Guix System Distribution. Not Guix the package manager. This article won't cover how to install the package manager into an existing distribution (like Ubuntu or Debian), but rather how to create a custom distribution containing the full Guix system. 6 | 7 | * Table Of Contents :TOC: 8 | - [[#prerequisites][Prerequisites]] 9 | - [[#base-distribution][Base Distribution]] 10 | - [[#roll-back][Roll back]] 11 | - [[#installation][Installation]] 12 | - [[#manifest][Manifest]] 13 | - [[#initialization][Initialization]] 14 | - [[#updating-the-system][Updating the system]] 15 | - [[#tidying-up][Tidying up]] 16 | - [[#gui-applications][GUI applications]] 17 | - [[#desktop-shortcuts][Desktop shortcuts]] 18 | - [[#sources][Sources]] 19 | 20 | * Prerequisites 21 | 22 | - Windows 10 with a properly [[https://docs.microsoft.com/en-us/windows/wsl/install-win10][configured]] WSL2 23 | 24 | * Base Distribution 25 | 26 | Guix will use a minimal WSL distribution based on [[https://busybox.net/][busybox]] by 0xbadfca11. Download the =rootfs.tgz= of the latest release [[https://github.com/0xbadfca11/miniwsl/releases/download/release3041562/rootfs.tgz][here]]. However, one could also [[https://github.com/giuliano108/guix-packages/blob/master/notes/Guix-on-WSL2.md#minimal-rootfs-archive][create]] a rootfs from scratch. 27 | In any case, with an appropriate =rootfs.tgz= available, open up =PowerShell=, navigate to the folder with the file and execute 28 | 29 | #+begin_src sh :tangle no 30 | wsl --import guix /guix rootfs.tgz --version 2 31 | #+end_src 32 | 33 | *Note*: The =--version 2= flag specifies the WSL version to use and must not be changed. 34 | 35 | * Roll back 36 | 37 | The current distribution can erased by executing 38 | 39 | #+begin_src sh :tangle no 40 | wsl --unregister guix 41 | #+end_src 42 | 43 | Windows will delete any files associated with the given distribution. One may then start from scratch again. 44 | 45 | * Installation 46 | 47 | The following script adds the folder and files required by Guix so that a full system can be built. 48 | 49 | #+begin_src sh :tangle no 50 | #!/bin/sh 51 | 52 | # Creating necessary folders 53 | mkdir -p /root /etc/guix /tmp /var/run /run /home 54 | chmod 1777 /tmp 55 | 56 | # Adding guix workers 57 | rm /etc/passwd 58 | cat <> /etc/passwd 59 | root:x:0:0:root:/root:/bin/bash 60 | guixbuilder01:x:999:999:Guix build user 01:/var/empty:/usr/sbin/nologin 61 | guixbuilder02:x:998:999:Guix build user 02:/var/empty:/usr/sbin/nologin 62 | guixbuilder03:x:997:999:Guix build user 03:/var/empty:/usr/sbin/nologin 63 | guixbuilder04:x:996:999:Guix build user 04:/var/empty:/usr/sbin/nologin 64 | guixbuilder05:x:995:999:Guix build user 05:/var/empty:/usr/sbin/nologin 65 | guixbuilder06:x:994:999:Guix build user 06:/var/empty:/usr/sbin/nologin 66 | guixbuilder07:x:993:999:Guix build user 07:/var/empty:/usr/sbin/nologin 67 | guixbuilder08:x:992:999:Guix build user 08:/var/empty:/usr/sbin/nologin 68 | guixbuilder09:x:991:999:Guix build user 09:/var/empty:/usr/sbin/nologin 69 | guixbuilder10:x:990:999:Guix build user 10:/var/empty:/usr/sbin/nologin 70 | EOM 71 | 72 | rm /etc/group 73 | cat <> /etc/group 74 | root:x:0: 75 | guixbuild:x:999:guixbuilder01,guixbuilder02,guixbuilder03,guixbuilder04,guixbuilder05,guixbuilder06,guixbuilder07,guixbuilder08,guixbuilder09,guixbuilder10 76 | EOM 77 | 78 | # Adding services 79 | cat <> /etc/services 80 | ftp-data 20/tcp 81 | ftp 21/tcp 82 | ssh 22/tcp # SSH Remote Login Protocol 83 | domain 53/tcp # Domain Name Server 84 | domain 53/udp 85 | http 80/tcp www # WorldWideWeb HTTP 86 | https 443/tcp # http protocol over TLS/SSL 87 | ftps-data 989/tcp # FTP over SSL (data) 88 | ftps 990/tcp 89 | http-alt 8080/tcp webcache # WWW caching service 90 | http-alt 8080/udp 91 | EOM 92 | 93 | # Adding Guix channels 94 | cat <> /etc/guix/channels.scm 95 | ;; Your guix channels here 96 | EOM 97 | 98 | # Preparing environment 99 | cd /tmp 100 | wget http://ftp.gnu.org/gnu/guix/guix-binary-1.3.0.x86_64-linux.tar.xz 101 | tar -C / -xvJf /tmp/guix-binary-1.3.0.x86_64-linux.tar.xz 102 | mkdir -p ~root/.config/guix 103 | ln -sf /var/guix/profiles/per-user/root/current-guix ~root/.config/guix/current 104 | GUIX_PROFILE="`echo ~root`/.config/guix/current" 105 | source $GUIX_PROFILE/etc/profile 106 | guix-daemon --build-users-group=guixbuild & 107 | guix archive --authorize < /var/guix/profiles/per-user/root/current-guix/share/guix/ci.guix.gnu.org.pub 108 | 109 | # Reconfiguring the system 110 | guix system reconfigure --no-bootloader --no-grafts -L $(dirname $(readlink -f $1)) $1 111 | #+end_src 112 | 113 | Custom Guix channels can be added here 114 | 115 | #+begin_src sh 116 | # Adding Guix channels 117 | cat <> /etc/guix/channels.scm 118 | ;; Your guix channels here 119 | EOM 120 | #+end_src 121 | 122 | If this is not required, the lines can be safely deleted. In any case, this script should copied to a location accessible by both Windows and the WSL distribution (E.g. =C:\Users\\Desktop\guix\guix-install.sh=). 123 | 124 | ** Manifest 125 | 126 | Guix needs a manifest file as a blueprint to build the system. This minimal scheme file contains everything needed for a successful installation: 127 | 128 | #+begin_src scheme :tangle no 129 | (define-module (wsl) 130 | #:use-module (gnu) 131 | #:use-module (gnu services ssh) 132 | #:use-module (gnu services networking) 133 | #:use-module (gnu packages version-control) 134 | #:use-module (guix channels) 135 | #:use-module (guix packages) 136 | #:use-module (guix profiles) 137 | #:use-module (ice-9 pretty-print) 138 | #:use-module (srfi srfi-1)) 139 | 140 | (define-public wsl-operating-system 141 | (operating-system 142 | (host-name "guix") 143 | (keyboard-layout (keyboard-layout "us" "altgr-intl")) 144 | (timezone "Europe/Paris") 145 | 146 | ;; User account 147 | (users (cons (user-account 148 | (name "wsl") 149 | (group "users") 150 | (home-directory "/home/wsl") 151 | (supplementary-groups '("wheel"))) 152 | %base-user-accounts)) 153 | 154 | (kernel hello) 155 | (initrd (lambda* (. rest) (plain-file "dummyinitrd" "dummyinitrd"))) 156 | (initrd-modules '()) 157 | (firmware '()) 158 | 159 | (bootloader 160 | (bootloader-configuration 161 | (bootloader 162 | (bootloader 163 | (name 'dummybootloader) 164 | (package hello) 165 | (configuration-file "/dev/null") 166 | (configuration-file-generator (lambda* (. rest) (computed-file "dummybootloader" #~(mkdir #$output)))) 167 | (installer #~(const #t)))))) 168 | 169 | (file-systems (list (file-system 170 | (device "/dev/sdb") 171 | (mount-point "/") 172 | (type "ext4") 173 | (mount? #t)))) 174 | 175 | (services (list (service guix-service-type) 176 | (service special-files-service-type 177 | `(("/usr/bin/env" ,(file-append coreutils "/bin/env")))))))) 178 | wsl-operating-system 179 | #+end_src 180 | 181 | Place the file in the same folder as the script above. Inside =PowerShell=, execute 182 | 183 | #+begin_src sh :tangle no 184 | wsl -d guix --exec /bin/busybox sh -c "/mnt/c/path/to/guix-install.sh /mnt/c/path/to/wsl.scm" 185 | #+end_src 186 | 187 | The path is relative to the root folder of the WSL distribution. If the two files are located at =C:\Users\\Desktop\guix= the path would then be =/mnt/c/Users//Desktop/guix=. 188 | 189 | *Note*: The install script and the manifest file don't have to be in the same folder. The script also sets the load path to the folder containing the manifest file, this means =wsl.scm= may inherit from other modules located in the same load path (like a =base-system.scm= for example). 190 | 191 | * Initialization 192 | 193 | After the installation is finished, it will most likely output a warning along the lines of 194 | 195 | #+begin_src sh :tangle no 196 | guix system: warning: while talking to shepherd: No such file or directory 197 | #+end_src 198 | 199 | This is to be expected. Because WSL distributions don't boot the same way a normal distribution would, Guix could not populate =/run=. More information about this can be found [[https://gist.github.com/giuliano108/49ec5bd0a9339db98535bc793ceb5ab4#booting-the-guix-wsl-distro-as-if-it-were-a-guixsd-system][here]]. This has to be done manually or rather automated via a shell script: 200 | 201 | #+begin_src sh :tangle no 202 | #!/bin/busybox sh 203 | 204 | export GUIX_NEW_SYSTEM=$(/bin/busybox readlink -f /var/guix/profiles/system) 205 | # $GUIX_NEW_SYSTEM/boot needs this to exist even though /run is expected to be empty. 206 | # I installed GuixSD in a proper VM and /run is not on tmpfs, so I'm not sure. 207 | /bin/busybox ln -s none /run/current-system 208 | setsid /var/guix/profiles/system/profile/bin/guile --no-auto-compile $GUIX_NEW_SYSTEM/boot >/dev/null & 209 | 210 | /bin/busybox sleep 3 211 | source /etc/profile 212 | 213 | # why are these permissions not there in the first place? 214 | for f in ping su sudo; do 215 | chmod 4755 $(readlink -f $(which $f)) 216 | done 217 | 218 | # Setting up WSLg 219 | if [ -d "/mnt/wslg" ]; then 220 | rm -r /tmp/.X11-unix 221 | ln -s /mnt/wslg/.X11-unix /tmp/.X11-unix 222 | # Add "export DISPLAY=:0" in your .bashrc! 223 | fi 224 | 225 | su -l 226 | #+end_src 227 | 228 | Change the last line to your user name and copy the script to the same folder like the other scripts and execute it with 229 | 230 | #+begin_src sh :tangle no 231 | wsl -d guix --exec /bin/busybox sh -c "/mnt/c/path/to/guix-init.sh" 232 | #+end_src 233 | 234 | This script /can/ be safely run every time one logs into the distribution (See [[#tidying-up][Tidying up]]), however, it /needs/ to be run after rebooting the host system or executing =wsl -t guix= or =wsl --shutdown=. The script will automatically log your user in after setting up the system. 235 | 236 | A bash prompt should be waiting for input. Congratulations. 237 | 238 | Now is a good time to set some passwords 239 | 240 | #+begin_src sh :tangle no 241 | passwd 242 | passwd 243 | #+end_src 244 | 245 | One can either switch to the user with =su -l = or log the user in directly by executing =wsl -u -d guix=. 246 | 247 | * Updating the system 248 | 249 | The system can be updated like one would expect: 250 | 251 | #+begin_src sh :tangle no 252 | guix pull 253 | sudo guix system reconfigure /mnt/c/path/to/wsl.scm 254 | #+end_src 255 | 256 | This creates a new system generation and switches to it. 257 | 258 | * Tidying up 259 | 260 | At this point the installation is complete. However there are a couple of things that can be done to make interacting with the distribution easier. At the moment, there are three files on the host file system. The installation script (=guix-install.sh=) can be deleted as it is not needed anymore. 261 | 262 | =wsl.scm= is only really needed inside the distribution. One can save it in the user space, for example 263 | 264 | #+begin_src sh :tangle no 265 | mkdir -p $HOME/.config/guix/manifests && mv /mnt/c/Users//Desktop/guix/wsl.scm $HOME/.config/guix/manifests 266 | #+end_src 267 | 268 | moves the file to =~/.config/guix/manifests=. 269 | 270 | =guix-init.sh= can be copied to =/root/boot.sh= and the distribution started by executing 271 | 272 | #+begin_src sh :tangle no 273 | wsl -d guix --exec /bin/busybox sh -c "/root/boot.sh" 274 | #+end_src 275 | 276 | This is really up to the individual setup, both files may very well be incorporated into an already existing configuration. [[https://github.com/minikN/guix/blob/main/Systems.org#wsl][minikN]]'s dotfiles showcase a possible approach to this. 277 | 278 | * GUI applications 279 | 280 | Launching GUI applications from within WSL assumes a working X server running on the host. There a couple of alternatives to consider: 281 | 282 | - [[https://sourceforge.net/projects/xming/][Xming]] 283 | - [[https://sourceforge.net/projects/vcxsrv/][VcXsrv]] 284 | - [[https://x410.dev/][X410]] 285 | - [[https://mobaxterm.mobatek.net/][MobaXTerm]] 286 | - [[https://github.com/microsoft/wslg][WSLG]] 287 | 288 | *Note*: Both Xming and VcXsrv may suffer from display [[https://github.com/sebastiencs/company-box/issues/76][glitches]] when using Emacs' child frames due to an error in their GLX [[https://sourceforge.net/p/vcxsrv/bugs/102/][implementation]]. 289 | 290 | This guide will not focus on how to configure each X server, because there are already plenty of resources available on the subject. 291 | 292 | Once The X server is up and running, the =DISPLAY= variable has to be populated properly. A wrapper script can be used for this purpose (although, as always, there are other ways to achieve the same thing): 293 | 294 | #+begin_src sh 295 | if uname -r | grep -q 'microsoft'; then 296 | export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2; exit;}'):0.0 297 | export LIBGL_ALWAYS_INDIRECT=1 298 | export XCURSOR_SIZE=16 299 | setsid $1 300 | fi 301 | #+end_src 302 | 303 | *Note:* If =WSLg= is the preferred option to run GUI applications, the init script automatically sets up the necessary X socket. One only needs to 304 | #+begin_src sh 305 | export DISPLAY=:0 306 | #+end_src 307 | somewhere in user space (=.profile=, =.bash_profile=, =...=). Do not use the provided wrapper script for this approach as it will set =$DISPLAY= wrong. 308 | 309 | This script has to be available somewhere in the =PATH=. It should also be named appropriately and made executable: =chmod +x run-wsl=. 310 | 311 | GUI applications can now be started with 312 | 313 | #+begin_src sh 314 | run-wsl emacs 315 | #+end_src 316 | 317 | from within the distribution itself. However, it's more convenient to launch them from Windows directly via desktop shortcuts. In order to do that a minimal generic launcher can be written in =vbs= like so: 318 | 319 | #+begin_src vbs 320 | WScript.CreateObject("WScript.Shell").Run "wsl ~ -u -d guix /path/to/run-wsl " & WScript.Arguments(0), 0, false 321 | #+end_src 322 | 323 | *Note*: Adjust the == and the path to the script accordingly. 324 | 325 | * Desktop shortcuts 326 | 327 | This launcher will run the =run-wsl= script with its first argument. Now shortcuts for applications can be added by creating a shortcut to the launcher itself (=Right click -> Send to -> Desktop (create shortcut)=). After that edit the shortcuts target like so: =C:\Users\\Desktop\guix-launcher.vbs emacs= where =emacs= is the application to launch. 328 | 329 | The launcher can obviously reside anywhere on the file system, doesn't have to be the desktop. One may also change the shortcuts icon to something more appropriate like the emacs icon. 330 | 331 | * Sources 332 | - [[https://gist.github.com/giuliano108/49ec5bd0a9339db98535bc793ceb5ab4][giuliano108/Guix-on-WSL2.md]] 333 | - [[https://gist.github.com/vldn-dev/de379bf81a80ff0a53cd851bcc3bbff2][vldn-dev/guix-infect.sh]] 334 | -------------------------------------------------------------------------------- /content/index.org: -------------------------------------------------------------------------------- 1 | #+TITLE: Welcome to the System Crafters Wiki! 2 | 3 | This site is a collaborative effort by the System Crafters community 4 | to provide useful resources for system crafting with GNU Emacs, GNU 5 | Guix, and all other related tools. There are also resources for how 6 | you can connect with other members of the community over Discord, 7 | Matrix, and IRC! 8 | 9 | * Topics 10 | 11 | ** [[emacs/][GNU Emacs]] 12 | 13 | Information regarding Emacs configuration and various packages. 14 | 15 | ** [[guix/][GNU Guix]] 16 | 17 | Overview of the GNU Guix operating system and information regarding 18 | installation and packages. 19 | 20 | ** [[articles/][All Articles]] 21 | 22 | A master list of all articles if you prefer searching/exploring in 23 | there yourself. 24 | 25 | * Our community 26 | 27 | ** [[community/getting-involved/][Getting involved]] 28 | 29 | Ways that you can contribute to the System Crafters wiki. 30 | 31 | ** [[community/chat-with-us/][Chatting with the community]] 32 | 33 | How to get in touch with other members of the System Crafters 34 | community on various platforms. 35 | 36 | ** [[community/code-of-conduct/][Code of Conduct]] 37 | 38 | Guidelines for the System Crafters wiki. 39 | 40 | * Why not use [some other wiki]? 41 | 42 | We decided to make this a site instead of use GitHub wiki, Sourcehut 43 | man, or other sites so that we can more easily control the 44 | presentation and also provide this content in other offline forms. 45 | We're open to suggestions too! 46 | -------------------------------------------------------------------------------- /local-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | emacs -q --batch -l ./publish.el --funcall dw/publish 3 | -------------------------------------------------------------------------------- /ox-slimhtml.el: -------------------------------------------------------------------------------- 1 | ;;; ox-slimhtml.el --- a minimal HTML org export backend -*- lexical-binding: t; -*- 2 | ;; Copyright (C) 2021 Free Software Foundation Inc. 3 | 4 | ;; Author: Elo Laszlo 5 | ;; Created: August 2016 6 | ;; Package-Version: 0.5.0 7 | ;; Keywords: files 8 | ;; Package-Requires: ((emacs "24") (cl-lib "0.6")) 9 | 10 | ;; This file is part of GNU Emacs 11 | 12 | ;;; License: 13 | ;; This program is free software; you can redistribute it and/or modify 14 | ;; it under the terms of the GNU General Public License as published by 15 | ;; the Free Software Foundation, either version 3 of the License, or 16 | ;; (at your option) any later version. 17 | ;; 18 | ;; This program is distributed in the hope that it will be useful, 19 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | ;; GNU General Public License for more details. 22 | ;; 23 | ;; You should have received a copy of the GNU General Public License 24 | ;; along with this file. If not, see . 25 | 26 | ;;; Commentary: 27 | ;; slimhtml is an Emacs org mode export backend. It is a set of 28 | ;; transcoders for common org elements which outputs minimal 29 | ;; HTML. The aim is not to re-invent the wheel over the default 30 | ;; org-mode HTML exporter - as it tackles a much bigger, and 31 | ;; different problem - but to provide a small set of components for 32 | ;; easier customization of HTML output from org. 33 | 34 | ;;; Code: 35 | (require 'ox-html) 36 | (require 'cl-lib) 37 | 38 | ;; formatting 39 | ;; #+BEGIN_EXAMPLE 40 | ;; ,*bold* # bold 41 | ;; /italic/ # italic 42 | ;; =verbatim= # verbatim 43 | ;; #+END_EXAMPLE 44 | 45 | (defun ox-slimhtml-bold (bold contents info) 46 | "Transcode BOLD from Org to HTML. 47 | 48 | CONTENTS is the text with bold markup. 49 | INFO is a plist holding contextual information." 50 | (when contents (format "%s" contents))) 51 | 52 | (defun ox-slimhtml-italic (italic contents info) 53 | "Transcode ITALIC from Org to HTML. 54 | 55 | CONTENTS is the text with italic markup. 56 | INFO is a plist holding contextual information." 57 | (when contents (format "%s" contents))) 58 | 59 | (defun ox-slimhtml-verbatim (verbatim contents info) 60 | "Transcode VERBATIM string from Org to HTML. 61 | 62 | CONTENTS is nil. 63 | INFO is a plist holding contextual information." 64 | (let ((contents (org-html-encode-plain-text 65 | (org-element-property :value verbatim)))) 66 | (when contents (format "%s" contents)))) 67 | 68 | ;; headlines 69 | ;; #+BEGIN_EXAMPLE 70 | ;; ,* headline text #
71 | ;; :PROPERTIES: #

headline text

72 | ;; :attr_html: :class headline #
73 | ;; :html_container: section 74 | ;; :html_container_class: container 75 | ;; :END: 76 | 77 | ;; ,#+OPTIONS: H:[headline level] 78 | ;; ,#+HTML_CONTAINER: [default container] 79 | ;; #+END_EXAMPLE 80 | 81 | (defun ox-slimhtml-headline (headline contents info) 82 | "Transcode HEADLINE from Org to HTML. 83 | 84 | CONTENTS is the section as defined under the HEADLINE. 85 | INFO is a plist holding contextual information." 86 | (let* ((text (org-export-data (org-element-property :title headline) info)) 87 | (level (org-export-get-relative-level headline info)) 88 | (attributes (org-element-property :ATTR_HTML headline)) 89 | (container (org-element-property :HTML_CONTAINER headline)) 90 | (container-class (and container (org-element-property :HTML_CONTAINER_CLASS headline)))) 91 | (when attributes 92 | (setq attributes 93 | (format " %s" (org-html--make-attribute-string 94 | (org-export-read-attribute 'attr_html `(nil 95 | (attr_html ,(split-string attributes)))))))) 96 | (concat 97 | (when (and container (not (string= "" container))) 98 | (format "<%s%s>" container (if container-class (format " class=\"%s\"" container-class) ""))) 99 | (if (not (org-export-low-level-p headline info)) 100 | (format "%s%s" level (or attributes "") text level (or contents "")) 101 | (concat 102 | (when (org-export-first-sibling-p headline info) "
    ") 103 | (format "
  • %s%s
  • " text (or contents "")) 104 | (when (org-export-last-sibling-p headline info) "
"))) 105 | (when (and container (not (string= "" container))) 106 | (format "" (cl-subseq container 0 (cl-search " " container))))))) 107 | 108 | ;; sections 109 | 110 | (defun ox-slimhtml-section (section contents info) 111 | "Transcode a SECTION element from Org to HTML. 112 | 113 | CONTENTS is the contents of the section. 114 | INFO is a plist holding contextual information. 115 | 116 | Sections are child elements of org headlines; 117 | 'container' settings are found in slim-headlines." 118 | contents) 119 | 120 | ;; links 121 | ;; #+BEGIN_EXAMPLE 122 | ;; ,#+attr_html: :class link # content 123 | ;; [[link][content]] 124 | 125 | ;; ,#+OPTIONS: html-link-org-files-as-html:[t/nil] || org-html-link-org-files-as-html 126 | ;; ,#+HTML_EXTENSION: [html] || org-html-extension 127 | 128 | ;; ,#+OPTIONS: html-link-use-abs-url:[t/nil] || org-html-link-use-abs-url 129 | ;; #+END_EXAMPLE 130 | 131 | (defun ox-slimhtml-link (link contents info) 132 | "Transcode LINK from Org to HTML. 133 | 134 | CONTENTS is the text of the link. 135 | INFO is a plist holding contextual information." 136 | (if (ox-slimhtml--immediate-child-of-p link 'link) (org-element-property :raw-link link) 137 | (if (not contents) (format "%s" (org-element-property :path link)) 138 | (let ((link-type (org-element-property :type link)) 139 | (href (org-element-property :raw-link link)) 140 | (attributes (if (ox-slimhtml--immediate-child-of-p link 'paragraph) 141 | (ox-slimhtml--attr (org-export-get-parent link)) 142 | "")) 143 | (element "%s")) 144 | (cond ((string= "file" link-type) 145 | (let ((html-extension (or (plist-get info :html-extension) "")) 146 | (use-abs-url (plist-get info :html-link-use-abs-url)) 147 | (link-org-files-as-html (plist-get info :html-link-org-as-html)) 148 | (path (or (org-element-property :path link) ""))) 149 | (format element 150 | (concat (if (and use-abs-url (file-name-absolute-p path)) "file:" "") 151 | (if (and link-org-files-as-html (string= "org" (downcase (or (file-name-extension path) "")))) 152 | (if (and html-extension (not (string= "" html-extension))) 153 | (concat (file-name-sans-extension path) "." html-extension) 154 | (file-name-sans-extension path)) 155 | path)) 156 | attributes contents))) 157 | (t 158 | (format element href attributes contents))))))) 159 | 160 | ;; plain lists 161 | ;; #+BEGIN_EXAMPLE 162 | ;; ,#+attr_html: :class this #
    163 | ;; - item 1 #
  • item 1
  • 164 | ;; - item 2 #
  • item 2
  • 165 | ;; #
166 | 167 | ;; + item 1 #
  1. item 1
168 | ;; - definition :: list #
definition
list
169 | ;; #+END_EXAMPLE 170 | 171 | (defun ox-slimhtml-plain-list (plain-list contents info) 172 | "Transcode a PLAIN-LIST string from Org to HTML. 173 | 174 | CONTENTS is the contents of the list element. 175 | INFO is a plist holding contextual information." 176 | (when contents 177 | (let ((type (cl-case (org-element-property :type plain-list) 178 | (ordered "ol") 179 | (unordered "ul") 180 | (descriptive "dl")))) 181 | (format "<%s%s>%s" type (ox-slimhtml--attr plain-list) contents type)))) 182 | 183 | ;; paragraphs 184 | ;; #+BEGIN_EXAMPLE 185 | ;; ,#+attr_html: :class this #

content

186 | ;; content 187 | ;; #+END_EXAMPLE 188 | 189 | (defun ox-slimhtml-paragraph (paragraph contents info) 190 | "Transcode a PARAGRAPH element from Org to HTML. 191 | 192 | CONTENTS is the contents of the paragraph. 193 | INFO is a plist holding contextual information." 194 | (when contents 195 | (if (or (ox-slimhtml--immediate-child-of-p paragraph 'item) 196 | (ox-slimhtml--immediate-child-of-p paragraph 'special-block)) 197 | contents 198 | (if (ox-slimhtml--has-immediate-child-of-p paragraph 'link) 199 | (format "

%s

" contents) 200 | (format "%s

" (ox-slimhtml--attr paragraph) contents))))) 201 | 202 | ;; examples 203 | ;; #+BEGIN_EXAMPLE 204 | ;; ,#+BEGIN_EXAMPLE # content 205 | ;; content 206 | ;; ,#+END_EXAMPLE 207 | ;; #+END_EXAMPLE 208 | 209 | (defun ox-slimhtml-example-block (example-block contents info) 210 | "Transcode an EXAMPLE-BLOCK element from Org to HTML. 211 | 212 | CONTENTS is nil. INFO is a plist holding contextual information." 213 | (let ((code (org-html-format-code example-block info))) 214 | (when code 215 | (format "
%s
" 216 | (or (org-element-property :language example-block) "example") 217 | code)))) 218 | 219 | ;; raw html 220 | ;; #+BEGIN_EXAMPLE 221 | ;; ,#+BEGIN_EXPORT html # export block 222 | ;; export block 223 | ;; ,#+END_EXPORT 224 | 225 | ;; ,#+BEGIN_EXPORT javascript # 226 | ;; console.log() 227 | ;; ,#+END_EXPORT 228 | 229 | ;; ,#+BEGIN_EXPORT css # 230 | ;; span {} 231 | ;; ,#+END_EXPORT 232 | ;; #+END_EXAMPLE 233 | 234 | (defun ox-slimhtml-export-block (export-block contents info) 235 | "Transcode an EXPORT-BLOCK element from Org to HTML. 236 | 237 | CONTENTS is nil. INFO is a plist holding contextual information." 238 | (let ((contents (org-element-property :value export-block)) 239 | (language (org-element-property :type export-block))) 240 | (when contents 241 | (cond ((string= "JAVASCRIPT" language) 242 | (format "" contents)) 243 | ((string= "CSS" language) 244 | (format "" contents)) 245 | (t 246 | (org-remove-indentation contents)))))) 247 | 248 | ;; snippet 249 | ;; #+BEGIN_EXAMPLE 250 | ;; @@html:snippet@@ # snippet 251 | ;; #+END_EXAMPLE 252 | 253 | (defun ox-slimhtml-export-snippet (export-snippet contents info) 254 | "Transcode a EXPORT-SNIPPET object from Org to HTML. 255 | 256 | CONTENTS is nil. INFO is a plist holding contextual information." 257 | (let ((contents (org-element-property :value export-snippet))) 258 | (when contents contents))) 259 | 260 | ;; special block 261 | ;; #+BEGIN_EXAMPLE 262 | ;; ,#+attr_html: :type text/css # 265 | ;; ,#+END_STYLE 266 | ;; #+END_EXAMPLE 267 | 268 | (defun ox-slimhtml-special-block (special-block contents info) 269 | "Transcode SPECIAL-BLOCK from Org to HTML. 270 | 271 | CONTENTS is the text within the #+BEGIN_ and #+END_ markers. 272 | INFO is a plist holding contextual information." 273 | (when contents 274 | (let ((block-type (downcase (org-element-property :type special-block)))) 275 | (format "<%s%s>%s" block-type (ox-slimhtml--attr special-block) contents block-type)))) 276 | 277 | ;; source code 278 | ;; #+BEGIN_EXAMPLE 279 | ;; ,#+BEGIN_SRC javascript #
280 | ;;     code                                     # code
281 | ;;   ,#+END_SRC                                  # 
282 | ;; #+END_EXAMPLE 283 | 284 | (defun ox-slimhtml-src-block (src-block contents info) 285 | "Transcode SRC-BLOCK from Org to HTML. 286 | 287 | CONTENTS is the text of a #+BEGIN_SRC...#+END_SRC block. 288 | INFO is a plist holding contextual information." 289 | (let ((code (org-html-format-code src-block info)) 290 | (language (org-element-property :language src-block))) 291 | (when code 292 | (format "
%s
" 293 | language (ox-slimhtml--attr src-block) code)))) 294 | 295 | ;; body 296 | ;; #+BEGIN_EXAMPLE 297 | ;; ,#+HTML_PREAMBLE: preamble {{{macro}}} # preamble 298 | ;; content # content 299 | ;; ,#+HTML_POSTAMBLE: postamble {{{macro}}} # postamble 300 | ;; #+END_EXAMPLE 301 | 302 | (defun ox-slimhtml-inner-template (contents info) 303 | "Return body of document string after HTML conversion. 304 | 305 | CONTENTS is the transcoded contents string. 306 | INFO is a plist holding export options." 307 | (when (and contents (not (string= "" contents))) 308 | (let ((container (plist-get info :html-container))) 309 | (concat 310 | (when (and container (not (string= "" container))) (format "<%s>" container)) 311 | (or (ox-slimhtml--expand-macros (plist-get info :html-preamble) info) "") 312 | contents 313 | (or (ox-slimhtml--expand-macros (plist-get info :html-postamble) info) "") 314 | (when (and container (not (string= "" container))) 315 | (format "" (cl-subseq container 0 (cl-search " " container)))))))) 316 | 317 | ;; html page 318 | ;; #+BEGIN_EXAMPLE 319 | ;; ,#+HTML_DOCTYPE: || org-html-doctype # ; html5 320 | ;; ,#+HTML_HEAD: || org-html-head # ; when language is set 321 | ;; ,#+HTML_TITLE: %t # 322 | ;; ,#+HTML_HEAD_EXTRA: || org-html-head-extra # head 323 | ;; ,#+HTML_BODY_ATTR: id="test" # document title 324 | ;; ,#+HTML_HEADER: {{{macro}}} # head-extra 325 | ;; ,#+HTML_FOOTER: {{{macro}}} # 326 | ;; # 327 | ;; # header 328 | ;; # content 329 | ;; # footer 330 | ;; # 331 | ;; # 332 | 333 | ;; {{{macro}}} tokens can also be set in INFO; 334 | ;; :html-head, :html-head-extra and :html-header. 335 | 336 | ;; :html-title is a string with optional tokens; 337 | ;; %t is the document's #+TITLE: property. 338 | ;; #+END_EXAMPLE 339 | 340 | (defun ox-slimhtml-template (contents info) 341 | "Return full document string after HTML conversion. 342 | 343 | CONTENTS is the transcoded contents string. 344 | INFO is a plist holding export options." 345 | (let ((doctype (assoc (plist-get info :html-doctype) org-html-doctype-alist)) 346 | (language (plist-get info :language)) 347 | (head (ox-slimhtml--expand-macros (plist-get info :html-head) info)) 348 | (head-extra (ox-slimhtml--expand-macros (plist-get info :html-head-extra) info)) 349 | (title (plist-get info :title)) 350 | (title-format (plist-get info :html-title)) 351 | (body-attr (plist-get info :html-body-attr)) 352 | (header (plist-get info :html-header)) 353 | (newline "\n")) 354 | (when (listp title) 355 | (setq title (car title))) 356 | (concat 357 | (when doctype (concat (cdr doctype) newline)) 358 | "" newline 359 | "" newline 360 | (when (not (string= "" head)) (concat head newline)) 361 | (when (and title (not (string= "" title))) 362 | (if title-format 363 | (format-spec (concat "" title-format "\n") 364 | (format-spec-make ?t title)) 365 | (concat "" title "" newline))) 366 | (when (not (string= "" head-extra)) (concat head-extra newline)) 367 | "" newline 368 | "" 369 | (when (and header (not (string= "" header))) 370 | (or (ox-slimhtml--expand-macros header info) "")) 371 | contents 372 | (or (ox-slimhtml--expand-macros (plist-get info :html-footer) info) "") 373 | "" newline 374 | ""))) 375 | 376 | ;; plain text 377 | 378 | (defun ox-slimhtml-plain-text (plain-text info) 379 | "Transcode a PLAIN-TEXT string from Org to HTML. 380 | 381 | PLAIN-TEXT is the string to transcode. 382 | INFO is a plist holding contextual information." 383 | (org-html-encode-plain-text plain-text)) 384 | 385 | ;; attributes 386 | 387 | (defun ox-slimhtml--attr (element &optional property) 388 | "Return ELEMENT's html attribute properties as a string. 389 | 390 | When optional argument PROPERTY is non-nil, return the value of 391 | that property within attributes." 392 | (let ((attributes (org-export-read-attribute :attr_html element property))) 393 | (if attributes (concat " " (org-html--make-attribute-string attributes)) ""))) 394 | 395 | ;; is an immediate child of [element]? 396 | 397 | (defun ox-slimhtml--immediate-child-of-p (element container-type) 398 | "Is ELEMENT an immediate child of an org CONTAINER-TYPE element?" 399 | (let ((container (org-export-get-parent element))) 400 | (and (eq (org-element-type container) container-type) 401 | (= (org-element-property :begin element) 402 | (org-element-property :contents-begin container))))) 403 | 404 | ;; has an immediate child of [element-type]? 405 | 406 | (defun ox-slimhtml--has-immediate-child-of-p (element element-type) 407 | "Does ELEMENT have an immediate ELEMENT-TYPE child?" 408 | (org-element-map element element-type 409 | (lambda (link) (= (org-element-property :begin link) 410 | (org-element-property :contents-begin element))) 411 | nil t)) 412 | 413 | ;; expand macros 414 | ;; Macro expansion takes place in a separate buffer - as such buffer local variables 415 | ;; are not directly available, which might be important when using self-evaluating 416 | ;; macros such as =,#+MACRO: x (eval (fn $1))=. To help with this, the original 417 | ;; =buffer-file-name= is shadowed. 418 | 419 | (defun ox-slimhtml--expand-macros (contents info) 420 | "Return CONTENTS string, with macros expanded. 421 | 422 | CONTENTS is a string, optionally with {{{macro}}} 423 | tokens. INFO is a plist holding export options." 424 | (if (cl-search "{{{" contents) 425 | (let* ((author (org-element-interpret-data (plist-get info :author))) 426 | (date (org-element-interpret-data (plist-get info :date))) 427 | (email (or (plist-get info :email) "")) 428 | (title (org-element-interpret-data (plist-get info :title))) 429 | (export-specific-templates 430 | (list (cons "author" author) 431 | (cons "date" 432 | (format "(eval (format-time-string \"$1\" '%s))" 433 | (org-read-date nil t date nil))) 434 | (cons "email" email) 435 | (cons "title" title))) 436 | (templates (org-combine-plists export-specific-templates 437 | org-macro-templates)) 438 | (buffer-name buffer-file-name)) 439 | (with-temp-buffer (insert contents) 440 | (let ((buffer-file-name buffer-name)) 441 | (org-macro-replace-all templates)) 442 | (buffer-string))) 443 | contents)) 444 | 445 | ;; org-mode publishing function 446 | ;; #+BEGIN_EXAMPLE 447 | ;; (setq org-publish-project-alist 448 | ;; '(("project-name" 449 | ;; :base-directory "~/src" 450 | ;; :publishing-directory "~/public" 451 | ;; :publishing-function ox-slimhtml-publish-to-html))) 452 | ;; #+END_EXAMPLE 453 | 454 | ;;;###autoload 455 | (defun ox-slimhtml-publish-to-html (plist filename pub-dir) 456 | "Publish an org file to html. 457 | 458 | PLIST is the property list for the given project. FILENAME 459 | is the filename of the Org file to be published. PUB-DIR is 460 | the publishing directory. 461 | 462 | Return output file name." 463 | (let ((html-extension (or (plist-get plist :html-extension) org-html-extension))) 464 | (org-publish-org-to 'slimhtml 465 | filename 466 | (if (and html-extension (not (string= "" html-extension))) 467 | (concat "." html-extension) "") 468 | plist 469 | pub-dir))) 470 | 471 | ;; org-export backend definition 472 | (org-export-define-backend 473 | 'slimhtml 474 | '((bold . ox-slimhtml-bold) 475 | (example-block . ox-slimhtml-example-block) 476 | (export-block . ox-slimhtml-export-block) 477 | (export-snippet . ox-slimhtml-export-snippet) 478 | (headline . ox-slimhtml-headline) 479 | (inner-template . ox-slimhtml-inner-template) 480 | (italic . ox-slimhtml-italic) 481 | (item . org-html-item) 482 | (link . ox-slimhtml-link) 483 | (paragraph . ox-slimhtml-paragraph) 484 | (plain-list . ox-slimhtml-plain-list) 485 | (plain-text . ox-slimhtml-plain-text) 486 | (section . ox-slimhtml-section) 487 | (special-block . ox-slimhtml-special-block) 488 | (src-block . ox-slimhtml-src-block) 489 | (template . ox-slimhtml-template) 490 | (verbatim . ox-slimhtml-verbatim)) 491 | :menu-entry 492 | '(?s "Export to slimhtml" 493 | ((?H "As slimhtml buffer" ox-slimhtml-export-as-html) 494 | (?h "As slimhtml file" ox-slimhtml-export-to-html))) 495 | :options-alist 496 | '((:html-extension "HTML_EXTENSION" nil org-html-extension) 497 | (:html-link-org-as-html nil "html-link-org-files-as-html" org-html-link-org-files-as-html) 498 | (:html-doctype "HTML_DOCTYPE" nil org-html-doctype) 499 | (:html-container "HTML_CONTAINER" nil org-html-container-element t) 500 | (:html-link-use-abs-url nil "html-link-use-abs-url" org-html-link-use-abs-url) 501 | (:html-link-home "HTML_LINK_HOME" nil org-html-link-home) 502 | (:html-preamble "HTML_PREAMBLE" nil "" newline) 503 | (:html-postamble "HTML_POSTAMBLE" nil "" newline) 504 | (:html-head "HTML_HEAD" nil org-html-head newline) 505 | (:html-head-extra "HTML_HEAD_EXTRA" nil org-html-head-extra newline) 506 | (:html-header "HTML_HEADER" nil "" newline) 507 | (:html-footer "HTML_FOOTER" nil "" newline) 508 | (:html-title "HTML_TITLE" nil "%t" t) 509 | (:html-body-attr "HTML_BODY_ATTR" nil "" t))) 510 | 511 | ;;;###autoload 512 | (defun ox-slimhtml-export-as-html 513 | (&optional async subtreep visible-only body-only ext-plist) 514 | "Export current buffer to a SLIMHTML buffer. 515 | 516 | Export as `org-html-export-as-html' does, with slimhtml 517 | org-export-backend. 518 | 519 | If narrowing is active in the current buffer, only export its 520 | narrowed part. 521 | 522 | If a region is active, export that region. 523 | 524 | A non-nil optional argument ASYNC means the process should happen 525 | asynchronously. The resulting buffer should be accessible 526 | through the `org-export-stack' interface. 527 | 528 | When optional argument SUBTREEP is non-nil, export the sub-tree 529 | at point, extracting information from the headline properties 530 | first. 531 | 532 | When optional argument VISIBLE-ONLY is non-nil, don't export 533 | contents of hidden elements. 534 | 535 | When optional argument BODY-ONLY is non-nil, only write code 536 | between \"\" and \"\" tags. 537 | 538 | EXT-PLIST, when provided, is a property list with external 539 | parameters overriding Org default settings, but still inferior to 540 | file-local settings. 541 | 542 | Export is done in a buffer named \"*Org SLIMHTML export*\", which 543 | will be displayed when `org-export-show-temporary-export-buffer' 544 | is non-nil." 545 | (interactive) 546 | (org-export-to-buffer 'slimhtml "*Org SLIMHTML Export*" 547 | async subtreep visible-only body-only ext-plist 548 | (lambda () (set-auto-mode t)))) 549 | 550 | ;;;###autoload 551 | (defun ox-slimhtml-export-to-html (&optional async subtreep visible-only body-only ext-plist) 552 | "Export current buffer to an HTML file. 553 | 554 | Export as `org-html-export-as-html' does, with slimhtml 555 | org-export-backend. 556 | 557 | If narrowing is active in the current buffer, only export its 558 | narrowed part. 559 | 560 | If a region is active, export that region. 561 | 562 | A non-nil optional argument ASYNC means the process should happen 563 | asynchronously. The resulting file should be accessible through 564 | the `org-export-stack' interface. 565 | 566 | When optional argument SUBTREEP is non-nil, export the sub-tree 567 | at point, extracting information from the headline properties 568 | first. 569 | 570 | When optional argument VISIBLE-ONLY is non-nil, don't export 571 | contents of hidden elements. 572 | 573 | When optional argument BODY-ONLY is non-nil, only write code 574 | between \"\" and \"\" tags. 575 | 576 | EXT-PLIST, when provided, is a property list with external 577 | parameters overriding Org default settings, but still inferior to 578 | file-local settings. 579 | 580 | Return output file's name." 581 | (interactive) 582 | (let* ((extension (concat "." (or (plist-get ext-plist :html-extension) 583 | org-html-extension 584 | "html"))) 585 | (file (org-export-output-file-name extension subtreep)) 586 | (org-export-coding-system org-html-coding-system)) 587 | (org-export-to-file 'slimhtml file 588 | async subtreep visible-only body-only ext-plist))) 589 | 590 | (provide 'ox-slimhtml) 591 | ;;; ox-slimhtml.el ends here 592 | -------------------------------------------------------------------------------- /publish.el: -------------------------------------------------------------------------------- 1 | ;;; publish.el --- Build wiki.systemcrafters.net 2 | 3 | ;; Copyright (C) 2018 Pierre Neidhardt 4 | ;; Copyright (C) 2021 David Wilson 5 | 6 | ;; Author: David Wilson 7 | ;; Maintainer: David Wilson 8 | ;; URL: https://sr.ht/~systemcrafters/site 9 | ;; Version: 0.0.1 10 | ;; Package-Requires: ((emacs "26.1")) 11 | ;; Keywords: hypermedia, blog, feed, rss 12 | 13 | ;; This file is not part of GNU Emacs. 14 | 15 | ;; This file is loosely based on Pierre Neidhardt's publish.el, here's his 16 | ;; authorship details: 17 | 18 | ;; Author: Pierre Neidhardt 19 | ;; Maintainer: Pierre Neidhardt 20 | ;; URL: https://gitlab.com/Ambrevar/ambrevar.gitlab.io 21 | 22 | ;; This program is free software; you can redistribute it and/or modify 23 | ;; it under the terms of the GNU General Docs License as published by 24 | ;; the Free Software Foundation, either version 3 of the License, or 25 | ;; (at your option) any later version. 26 | ;; 27 | ;; This program is distributed in the hope that it will be useful, 28 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 | ;; GNU General Docs License for more details. 31 | ;; 32 | ;; You should have received a copy of the GNU General Docs License 33 | ;; along with this program. If not, see . 34 | 35 | ;; Usage: 36 | ;; emacs -Q --batch -l ./publish.el --funcall dw/publish 37 | 38 | ;; Initialize package sources 39 | (require 'package) 40 | 41 | ;; Set the package installation directory so that packages aren't stored in the 42 | ;; ~/.emacs.d/elpa path. 43 | (setq package-user-dir (expand-file-name "./.packages")) 44 | 45 | (setq package-archives '(("melpa" . "https://melpa.org/packages/") 46 | ("melpa-stable" . "https://stable.melpa.org/packages/") 47 | ("elpa" . "https://elpa.gnu.org/packages/"))) 48 | 49 | ;; Initialize the package system 50 | (package-initialize) 51 | (unless package-archive-contents 52 | (package-refresh-contents)) 53 | 54 | ;; Install use-package 55 | (unless (package-installed-p 'use-package) 56 | (package-install 'use-package)) 57 | (require 'use-package) 58 | 59 | ;; Unfortunately this is necessary for now... 60 | (load-file "./ox-slimhtml.el") 61 | 62 | ;; Install other dependencies 63 | (use-package esxml 64 | :pin melpa-stable 65 | :ensure t) 66 | 67 | (use-package ox-gemini 68 | :ensure t) 69 | 70 | (use-package htmlize 71 | :ensure t) 72 | 73 | (use-package webfeeder 74 | :ensure t) 75 | 76 | (require 'ox-publish) 77 | 78 | (defvar yt-iframe-format 79 | ;; TODO: Change this after switching from Bootstrap 80 | (concat "
" 81 | " " 82 | "
")) 83 | 84 | (setq dw/site-url "https://systemcrafters.net") 85 | 86 | (org-link-set-parameters 87 | "yt" 88 | :follow 89 | (lambda (handle) 90 | (browse-url 91 | (concat "https://www.youtube.com/watch?v=" 92 | handle))) 93 | :export 94 | (lambda (path desc backend channel) 95 | (when (eq backend 'html) 96 | (format yt-iframe-format 97 | path (or desc ""))))) 98 | 99 | (setq dw/site-title "System Crafters") 100 | (setq dw/site-tagline "") 101 | 102 | (setq org-publish-use-timestamps-flag t 103 | org-publish-timestamp-directory "./.org-cache/" 104 | org-export-with-section-numbers nil 105 | org-export-use-babel nil 106 | org-export-with-smart-quotes t 107 | org-export-with-sub-superscripts nil 108 | org-export-with-tags 'not-in-toc 109 | org-export-with-toc t) 110 | 111 | ;; We're using Git, we don't need no steenking backups 112 | (setq make-backup-files nil) 113 | 114 | (defun dw/site-header (info) 115 | (let* ((file (plist-get info :output-file))) 116 | `(div (div (@ (class "blog-header")) 117 | (div (@ (class "container")) 118 | (div (@ (class "row align-items-center justify-content-between")) 119 | (div (@ (class "col-sm-12 col-md-8")) 120 | (div (@ (class "blog-title")) 121 | ,dw/site-title)) 122 | (div (@ (class "col-sm col-md")) 123 | (div (@ (class "blog-description text-sm-left text-md-right text-lg-right text-xl-right")) 124 | ,dw/site-tagline))))) 125 | 126 | (div (@ (class "blog-masthead")) 127 | (div (@ (class "container")) 128 | (div (@ (class "row align-items-center justify-content-between")) 129 | (div (@ (class "col-sm-12 col-md-12")) 130 | (nav (@ (class "nav")) 131 | (a (@ (class "nav-link") (href "/")) "Main Page") " " 132 | (a (@ (class "nav-link") (href "/emacs")) "GNU Emacs") " " 133 | (a (@ (class "nav-link") (href "/guix")) "GNU Guix") 134 | (a (@ (class "nav-link") (href "https://systemcrafters.net")) "System Crafters Home") 135 | (form (@ (class "navbar-form navbar-right") (role "search") (action "https://duckduckgo.com/")) 136 | (div (@ (class "form-group")) 137 | (input (@ (type "text") (name "q") (class "form-control") (placeholder "Search Wiki") (style "overflow: hidden;margin-top: 3%;margin-bottom: 2%;"))) 138 | (input (@ (type "hidden") (name "sites") (value "wiki.systemcrafters.net"))))) 139 | " ")))))))) 140 | 141 | (defun dw/site-footer (info) 142 | (list 143 | `(footer (@ (class "blog-footer")) 144 | (div (@ (class "container")) 145 | (div (@ (class "row")) 146 | (div (@ (class "col-sm col-md text-sm-left text-md-right text-lg-right text-xl-right")) 147 | (p "Made with " ,(plist-get info :creator)) 148 | (p (a (@ (href "https://systemcrafters.net/privacy-policy/")) "Privacy Policy")))))) 149 | `(script (@ (src "/js/bootstrap.bundle.min.js"))))) 150 | 151 | (defun get-article-output-path (org-file pub-dir) 152 | (let ((article-dir (concat pub-dir 153 | (downcase 154 | (file-name-as-directory 155 | (file-name-sans-extension 156 | (file-name-nondirectory org-file))))))) 157 | 158 | (if (string-match "\\/index.org$" org-file) 159 | pub-dir 160 | (progn 161 | (unless (file-directory-p article-dir) 162 | (make-directory article-dir t)) 163 | article-dir)))) 164 | 165 | (defun dw/org-html-template (contents info) 166 | (concat 167 | "\n" 168 | "" 169 | (sxml-to-xml 170 | `(html (@ (lang "en")) 171 | (head 172 | (meta (@ (charset "utf-8"))) 173 | (meta (@ (author "David Wilson"))) 174 | (meta (@ (name "viewport") 175 | (content "width=device-width, initial-scale=1, shrink-to-fit=no"))) 176 | (link (@ (rel "stylesheet") 177 | (href "/css/bootstrap.min.css"))) 178 | (link (@ (rel "stylesheet") 179 | (href "/fonts/iosevka-aile/iosevka-aile.css"))) 180 | (link (@ (rel "stylesheet") 181 | (href "/fonts/jetbrains-mono/jetbrains-mono.css"))) 182 | (link (@ (rel "stylesheet") 183 | (href "/css/code.css"))) 184 | (link (@ (rel "stylesheet") 185 | (href "/css/site.css"))) 186 | (script (@ (defer "defer") 187 | (data-domain "wiki.systemcrafters.net") 188 | (src "https://plausible.io/js/plausible.js")) 189 | ;; Empty string to cause a closing tag 190 | "") 191 | (title ,(concat (org-export-data (plist-get info :title) info) " - System Crafters"))) 192 | (body 193 | ,@(dw/site-header info) 194 | (div (@ (class "container")) 195 | (div (@ (class "row")) 196 | (div (@ (class "col-sm-12 blog-main")) 197 | (div (@ (class "blog-post")) 198 | (h1 (@ (class "blog-post-title")) 199 | ,(org-export-data (plist-get info :title) info)) 200 | (p (@ (class "blog-post-meta")) 201 | ,(org-export-data (org-export-get-date info "%B %e, %Y") info)) 202 | ,contents 203 | ,(let ((tags (plist-get info :filetags))) 204 | (when (and tags (> (list-length tags) 0)) 205 | `(p (@ (class "blog-post-tags")) 206 | "Tags: " 207 | ,(mapconcat (lambda (tag) tag) 208 | ;; TODO: We don't have tag pages yet 209 | ;; (format "%s" tag tag)) 210 | (plist-get info :filetags) 211 | ", ")))) 212 | ,(when (equal "article" (plist-get info :page-type)) 213 | ;; TODO: Link to mailing list 214 | ""))))) 222 | 223 | ,@(dw/site-footer info)))))) 224 | 225 | ;; Thanks Ashraz! 226 | (defun dw/org-html-link (link contents info) 227 | "Removes file extension and changes the path into lowercase file:// links." 228 | (when (string= 'file (org-element-property :type link)) 229 | (org-element-put-property link :path 230 | (downcase 231 | (file-name-sans-extension 232 | (org-element-property :path link))))) 233 | 234 | (let ((exported-link (org-export-custom-protocol-maybe link contents 'html info))) 235 | (cond 236 | (exported-link exported-link) 237 | ((equal contents nil) 238 | (format "%s" 239 | (org-element-property :raw-link link) 240 | (org-element-property :raw-link link))) 241 | (t (org-export-with-backend 'slimhtml link contents info))))) 242 | 243 | ;; Make sure we have thread-last 244 | (require 'subr-x) 245 | 246 | (defun dw/make-heading-anchor-name (headline-text) 247 | (thread-last headline-text 248 | (downcase) 249 | (replace-regexp-in-string " " "-") 250 | (replace-regexp-in-string "[^[:alnum:]_-]" ""))) 251 | 252 | (defun dw/org-html-headline (headline contents info) 253 | (let* ((text (org-export-data (org-element-property :title headline) info)) 254 | (level (org-export-get-relative-level headline info)) 255 | (level (min 7 (when level (1+ level)))) 256 | (anchor-name (dw/make-heading-anchor-name text)) 257 | (attributes (org-element-property :ATTR_HTML headline)) 258 | (container (org-element-property :HTML_CONTAINER headline)) 259 | (container-class (and container (org-element-property :HTML_CONTAINER_CLASS headline)))) 260 | (when attributes 261 | (setq attributes 262 | (format " %s" (org-html--make-attribute-string 263 | (org-export-read-attribute 'attr_html `(nil 264 | (attr_html ,(split-string attributes)))))))) 265 | (concat 266 | (when (and container (not (string= "" container))) 267 | (format "<%s%s>" container (if container-class (format " class=\"%s\"" container-class) ""))) 268 | (if (not (org-export-low-level-p headline info)) 269 | (format "%s%s" 270 | level 271 | (or attributes "") 272 | anchor-name 273 | anchor-name 274 | text 275 | level 276 | (or contents "")) 277 | (concat 278 | (when (org-export-first-sibling-p headline info) "
    ") 279 | (format "
  • %s%s
  • " text (or contents "")) 280 | (when (org-export-last-sibling-p headline info) "
"))) 281 | (when (and container (not (string= "" container))) 282 | (format "" (cl-subseq container 0 (cl-search " " container))))))) 283 | 284 | 285 | ;;; Missing table handling for slimhtml 286 | (defvar bk/org-minimal--table-classes '("table" "table-dark") 287 | "CSS classes that shall be used on exported tables in `bk/org-minimal--table'. 288 | 289 | As the default template uses a dark bootstrap, dark variants of 290 | any bootstrap class should be used. Valid values are: 291 | 292 | - table (MUST be used if any other bootstrap values are used) 293 | - table-light for light tables, cannot be active on a .table-dark table 294 | - table-dark for dark tables, cannot be active on a .table-light table 295 | - table-striped for striped tables (can be combined with others) 296 | 297 | See also `bk/org-minimal--table-thead-classes'.") 298 | 299 | (defvar bk/org-minimal--table-thead-classes '("thead-dark") 300 | "CSS classes that shall be used on exported table theads in `bk/org-minimal--table-row'. 301 | 302 | See also `bk/org-minimal--table-classes'.") 303 | 304 | (defun bk/org-minimal--table (_table contents _info) 305 | "Wraps the table CONTENTS in tags. 306 | 307 | Any classes set in `bk/org-minimal--table-classes' will be applied to the 308 | generated
tag." 309 | (format "
%s
" 310 | (mapconcat #'identity bk/org-minimal--table-classes " ") 311 | contents)) 312 | 313 | (defun bk/org-minimal--table-row (table-row contents info) 314 | "Wraps the table row's CONTENTS in tags. 315 | 316 | Note that any hline TABLE-ROW will be removed." 317 | (when (eq (org-element-property :type table-row) 'standard) 318 | ;; This function is heavily inspired by `org-html-table-row', although it is somewhat simplified. 319 | (let* ((group (org-export-table-row-group table-row info)) 320 | ;; In order to have proper and groups, we have to check whether 321 | ;; we're in the first group (see group above) and whether Org recognizes the first 322 | ;; row as a header (see `org-export-table-has-header-p' below). 323 | (group-tags 324 | (cond 325 | ((not (= 1 group)) '("" . "")) 326 | ((org-export-table-has-header-p (org-export-get-parent-table table-row) info) 327 | (cons (format "" (mapconcat #'identity bk/org-minimal--table-thead-classes " ")) 328 | "")) 329 | (t '("" . ""))))) 330 | ;; We only use the group-tags if we either start or stop a group. 331 | (concat (and (org-export-table-row-starts-rowgroup-p table-row info) (car group-tags)) 332 | "" contents "" 333 | (and (org-export-table-row-ends-rowgroup-p table-row info) (cdr group-tags)))))) 334 | 335 | (defun bk/org-minimal--table-cell (_table-cell contents _info) 336 | "Wraps the table-cell's CONTENTS in tags." 337 | (format "%s" (if contents contents ""))) 338 | 339 | (org-export-define-derived-backend 'site-html 340 | 'slimhtml 341 | :translate-alist 342 | '((template . dw/org-html-template) 343 | (link . dw/org-html-link) 344 | (code . ox-slimhtml-verbatim) 345 | (headline . dw/org-html-headline) 346 | (table . bk/org-minimal--table) 347 | (table-row . bk/org-minimal--table-row) 348 | (table-cell . bk/org-minimal--table-cell)) 349 | :options-alist 350 | '((:page-type "PAGE-TYPE" nil nil t) 351 | (:html-use-infojs nil nil nil))) 352 | 353 | (defun org-html-publish-to-html (plist filename pub-dir) 354 | "Publish an org file to HTML, using the FILENAME as the output directory." 355 | (let ((article-path (get-article-output-path filename pub-dir))) 356 | (cl-letf (((symbol-function 'org-export-output-file-name) 357 | (lambda (extension &optional subtreep pub-dir) 358 | (concat article-path "index" extension)))) 359 | (org-publish-org-to 'site-html 360 | filename 361 | (concat "." (or (plist-get plist :html-extension) 362 | "html")) 363 | plist 364 | article-path)))) 365 | 366 | (defun dw/org-gemini-publish-to-gemini (plist filename pub-dir) 367 | (let ((article-path (get-article-output-path filename pub-dir))) 368 | (cl-letf (((symbol-function 'org-export-output-file-name) 369 | (lambda (extension &optional subtreep pub-dir) 370 | (concat article-path "index" extension)))) 371 | (org-publish-org-to 372 | 'gemini filename ".gmi" plist pub-dir)))) 373 | 374 | (defun dw/sitemap-entry (entry style project) 375 | (format "

Last Updated: %s - %s

" 376 | (format-time-string "%Y-%m-%d" (org-publish-find-date entry project)) 377 | (concat "/" (file-name-sans-extension entry) "/") 378 | (org-publish-find-title entry project))) 379 | 380 | (defun dw/generate-sitemap (title list) 381 | (concat 382 | "#+TITLE: " title "\n\n" 383 | "#+BEGIN_EXPORT html\n" 384 | (mapconcat (lambda (item) 385 | (car item)) 386 | (cdr list) 387 | "\n") 388 | "\n#+END_EXPORT\n")) 389 | 390 | (setq org-html-preamble #'dw/site-header 391 | org-html-postamble #'dw/site-footer 392 | org-html-metadata-timestamp-format "%Y-%m-%d" 393 | org-html-checkbox-type 'site-html 394 | org-html-html5-fancy nil 395 | org-html-htmlize-output-type 'css 396 | org-html-self-link-headlines t 397 | org-html-validation-link nil 398 | org-html-doctype "html5") 399 | 400 | (setq org-publish-project-alist 401 | (list 402 | (list "systemcrafters:main" 403 | :recursive t 404 | :base-directory "./content" 405 | :base-extension "org" 406 | :auto-sitemap t 407 | :sitemap-filename "articles.org" 408 | :sitemap-style 'list 409 | :sitemap-title "All Articles" 410 | :sitemap-function 'dw/generate-sitemap 411 | :sitemap-format-entry 'dw/sitemap-entry 412 | :publishing-function '(org-html-publish-to-html) 413 | :publishing-directory "./public" 414 | :with-timestamps t 415 | :with-title nil) 416 | (list "systemcrafters:gemini" 417 | :recursive t 418 | :base-extension "org" 419 | :base-directory "./content" 420 | :publishing-function '(dw/org-gemini-publish-to-gemini) 421 | :publishing-directory "./gemini" 422 | :with-timestamps t))) 423 | 424 | (defun dw/publish () 425 | (interactive) 426 | (org-publish-all t)) 427 | --------------------------------------------------------------------------------